]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/hid.cpp
add implementation fallback for not yet instantiated control peers
[wxWidgets.git] / src / mac / carbon / hid.cpp
1 #include "hid.h"
2
3 #define wxFORCECHECK_MSG(arg, msg) \
4 {\
5 if (arg) \
6 {\
7 wxLogSysError(wxString::Format(wxT("Message:%s\nHID: %s failed!"), wxT(msg), wxT(#arg)));\
8 return false;\
9 }\
10 }
11 #define wxIOCHECK(arg, msg) wxFORCECHECK_MSG(arg != kIOReturnSuccess, msg)
12 #define wxKERNCHECK(arg, msg) wxFORCECHECK_MSG(arg != KERN_SUCCESS, msg)
13 #define wxSCHECK(arg, msg) wxFORCECHECK_MSG(arg != S_OK, msg)
14
15 void CFShowTypeIDDescription(CFTypeRef pData)
16 {
17 if(!pData)
18 {
19 wxMessageBox("AHHH!");
20 return;
21 }
22
23 wxMessageBox(
24 CFStringGetCStringPtr(
25 CFCopyTypeIDDescription(CFGetTypeID(pData)),CFStringGetSystemEncoding()
26 )
27 );
28 }
29
30 // ============================================================================
31 // implementation
32 // ============================================================================
33
34
35 bool wxHIDDevice::Create (const int& nClass, const int& nType)
36 {
37 //Create the mach port
38 wxIOCHECK(IOMasterPort(bootstrap_port, &m_pPort), "Could not create mach port");
39
40 //Dictionary that will hold first
41 //the matching dictionary for determining which kind of devices we want,
42 //then later some registry properties from an iterator (see below)
43 CFMutableDictionaryRef pDictionary;
44
45 //Create a dictionary
46 //The call to IOServiceMatching filters down the
47 //the services we want to hid services (and also eats the
48 //dictionary up for us (consumes one reference))
49 wxASSERT((pDictionary = IOServiceMatching(kIOHIDDeviceKey)) != NULL );
50
51 //Here we'll filter down the services to what we want
52 if (nType != -1)
53 {
54 CFNumberRef pType = CFNumberCreate(kCFAllocatorDefault,
55 kCFNumberIntType, &nType);
56 CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsageKey), pType);
57 CFRelease(pType);
58 }
59 if (nClass != -1)
60 {
61 CFNumberRef pClass = CFNumberCreate(kCFAllocatorDefault,
62 kCFNumberIntType, &nClass);
63 CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsagePageKey), pClass);
64 CFRelease(pClass);
65 }
66
67 //Now get the maching services
68 io_iterator_t pIterator;
69 wxIOCHECK(IOServiceGetMatchingServices(m_pPort, pDictionary, &pIterator), "No Matching HID Services");
70 wxASSERT(pIterator != NULL);
71
72 //Now we iterate through them
73 io_object_t pObject;
74 while ( (pObject = IOIteratorNext(pIterator)) != NULL)
75 {
76 wxASSERT(IORegistryEntryCreateCFProperties(pObject, &pDictionary,
77 kCFAllocatorDefault, kNilOptions) == KERN_SUCCESS);
78
79 //Just for sanity :)
80 wxASSERT(CFGetTypeID(CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductKey))) == CFStringGetTypeID());
81
82 //Get [product] name
83 m_szName = CFStringGetCStringPtr (
84 (CFStringRef) CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductKey)),
85 CFStringGetSystemEncoding()
86 );
87
88 //
89 //Now the hard part - in order to scan things we need "cookies" -
90 //
91 wxCFArray CookieArray = CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDElementKey));
92 BuildCookies(CookieArray);
93 if (m_ppQueue != NULL)
94 wxASSERT((*m_ppQueue)->start(m_ppQueue) == S_OK);
95
96 //Create the interface (good grief - long function names!)
97 SInt32 nScore;
98 IOCFPlugInInterface** ppPlugin;
99 wxIOCHECK(IOCreatePlugInInterfaceForService(pObject, kIOHIDDeviceUserClientTypeID,
100 kIOCFPlugInInterfaceID, &ppPlugin, &nScore), "");
101
102 //Now, the final thing we can check before we fall back to asserts
103 //(because the dtor only checks if the device is ok, so if anything
104 //fails from now on the dtor will delete the device anyway, so we can't break from this).
105
106 //Get the HID interface from the plugin to the mach port
107 wxSCHECK((*ppPlugin)->QueryInterface(ppPlugin,
108 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (void**) &m_ppDevice), "");
109
110 //release the plugin
111 (*ppPlugin)->Release(ppPlugin);
112
113 //open the HID interface...
114 wxASSERT((*m_ppDevice)->open(m_ppDevice, 0) == S_OK);
115
116 //cleanup
117 CFRelease(pDictionary);
118 IOObjectRelease(pObject);
119 break;
120 }
121 //iterator cleanup
122 IOObjectRelease(pIterator);
123
124 return true;
125 }//end Create()
126
127 void wxHIDDevice::AddCookie(CFTypeRef Data, const int& i)
128 {
129 CFNumberGetValue(
130 (CFNumberRef) CFDictionaryGetValue ( (CFDictionaryRef) Data
131 , CFSTR(kIOHIDElementCookieKey)
132 ),
133 kCFNumberIntType,
134 &m_pCookies[i]
135 );
136 }
137
138 void wxHIDDevice::AddCookieInQueue(CFTypeRef Data, const int& i)
139 {
140 AddCookie(Data, i);
141 wxASSERT((*m_ppQueue)->addElement(m_ppQueue, m_pCookies[i], 0) == S_OK);//3rd Param flags (none yet)
142 }
143
144 void wxHIDDevice::InitCookies(const size_t& dwSize, bool bQueue)
145 {
146 m_pCookies = new IOHIDElementCookie[dwSize];
147 if (bQueue)
148 {
149 wxASSERT( m_ppQueue != NULL);
150 wxASSERT( (m_ppQueue = (*m_ppDevice)->allocQueue(m_ppDevice)) != NULL);
151 wxASSERT( (*m_ppQueue)->create(m_ppQueue, 0, 512) == S_OK); //Param 2, flags, none yet
152 }
153 }
154
155 bool wxHIDDevice::IsActive(const int& nIndex)
156 {
157 wxASSERT(m_pCookies[nIndex] != NULL);
158 IOHIDEventStruct Event;
159 (*m_ppDevice)->getElementValue(m_ppDevice, m_pCookies[nIndex], &Event);
160 return !!Event.value;
161 }
162
163
164 wxHIDDevice::~wxHIDDevice()
165 {
166 if (m_ppDevice != NULL)
167 {
168 (*m_ppDevice)->close(m_ppDevice);
169 (*m_ppDevice)->Release(m_ppDevice);
170 mach_port_deallocate(mach_task_self(), m_pPort);
171 }
172
173 if (m_pCookies != NULL)
174 {
175 delete [] m_pCookies;
176 if (m_ppQueue != NULL)
177 {
178 (*m_ppQueue)->stop(m_ppQueue);
179 (*m_ppQueue)->dispose(m_ppQueue);
180 (*m_ppQueue)->Release(m_ppQueue);
181 }
182 }
183 }
184 /*
185 enum
186 {
187 kHIDUsage_KeyboardHyphen = 0x2D,
188 kHIDUsage_KeyboardEqualSign = 0x2E,
189 kHIDUsage_KeyboardOpenBracket = 0x2F,
190 kHIDUsage_KeyboardCloseBracket = 0x30,
191 kHIDUsage_KeyboardBackslash = 0x31, //* \ or | *
192 kHIDUsage_KeyboardNonUSPound = 0x32, /* Non-US # or _ *
193 kHIDUsage_KeyboardSemicolon = 0x33, /* ; or : *
194 kHIDUsage_KeyboardQuote = 0x34, /* ' or " *
195 kHIDUsage_KeyboardGraveAccentAndTilde = 0x35, /* Grave Accent and Tilde *
196 kHIDUsage_KeyboardComma = 0x36, /* , or < *
197 kHIDUsage_KeyboardPeriod = 0x37, /* . or > *
198 kHIDUsage_KeyboardSlash = 0x38, /* / or ? *
199 kHIDUsage_KeyboardCapsLock = 0x39, /* Caps Lock *
200
201 kHIDUsage_KeyboardPrintScreen = 0x46, /* Print Screen *
202 kHIDUsage_KeyboardScrollLock = 0x47, /* Scroll Lock *
203 kHIDUsage_KeyboardPause = 0x48, /* Pause *
204 kHIDUsage_KeyboardInsert = 0x49, /* Insert *
205 kHIDUsage_KeyboardHome = 0x4A, /* Home *
206 kHIDUsage_KeyboardDeleteForward = 0x4C, /* Delete Forward *
207
208 kHIDUsage_KeyboardUpArrow
209 kHIDUsage_KeypadNumLock
210 kHIDUsage_KeypadSlash
211 kHIDUsage_KeypadAsterisk
212 kHIDUsage_KeypadHyphen
213 kHIDUsage_KeypadPlus
214 kHIDUsage_KeypadEnter
215 kHIDUsage_KeypadPeriod
216 kHIDUsage_KeyboardNonUSBackslash
217 kHIDUsage_KeyboardApplication
218 kHIDUsage_KeyboardPower
219 kHIDUsage_KeypadEqualSign
220 };
221 /*
222 enum wxKeyCode
223 {
224
225 WXK_START = 300,
226 WXK_LBUTTON,
227 WXK_RBUTTON,
228 WXK_CANCEL,
229 WXK_MBUTTON,
230 WXK_CLEAR,
231 WXK_SHIFT,
232 WXK_ALT,
233 WXK_CONTROL,
234 WXK_MENU,
235 WXK_PAUSE,
236 WXK_PRIOR, * Page up *
237 WXK_NEXT, * Page down *
238 WXK_END,
239 WXK_HOME,
240 WXK_LEFT,
241 WXK_UP,
242 WXK_RIGHT,
243 WXK_DOWN,
244 WXK_SELECT,
245 WXK_PRINT,
246 WXK_EXECUTE,
247 WXK_SNAPSHOT,
248 WXK_INSERT,
249 WXK_HELP,
250 WXK_MULTIPLY,
251 WXK_ADD,
252 WXK_SEPARATOR,
253 WXK_SUBTRACT,
254 WXK_DECIMAL,
255 WXK_DIVIDE,
256 WXK_PAGEUP,
257 WXK_PAGEDOWN,
258
259 WXK_NUMPAD_SPACE,
260 WXK_NUMPAD_TAB,
261 WXK_NUMPAD_ENTER,
262 WXK_NUMPAD_HOME,
263 WXK_NUMPAD_LEFT,
264 WXK_NUMPAD_UP,
265 WXK_NUMPAD_RIGHT,
266 WXK_NUMPAD_DOWN,
267 WXK_NUMPAD_PRIOR,
268 WXK_NUMPAD_PAGEUP,
269 WXK_NUMPAD_NEXT,
270 WXK_NUMPAD_PAGEDOWN,
271 WXK_NUMPAD_END,
272 WXK_NUMPAD_BEGIN,
273 WXK_NUMPAD_INSERT,
274 WXK_NUMPAD_DELETE,
275 WXK_NUMPAD_EQUAL,
276 WXK_NUMPAD_MULTIPLY,
277 WXK_NUMPAD_ADD,
278 WXK_NUMPAD_SEPARATOR,
279 WXK_NUMPAD_SUBTRACT,
280 WXK_NUMPAD_DECIMAL,
281 WXK_NUMPAD_DIVIDE,
282
283 WXK_WINDOWS_LEFT,
284 WXK_WINDOWS_RIGHT,
285 WXK_WINDOWS_MENU ,
286 WXK_COMMAND
287 };
288
289 */
290 enum
291 {
292 WXK_RSHIFT = 400,
293 WXK_RALT,
294 WXK_RCONTROL,
295 WXK_RMENU
296
297 };
298
299 bool wxHIDKeyboard::Create()
300 {
301 return wxHIDDevice::Create(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard);
302 }
303
304 void wxHIDKeyboard::BuildCookies(wxCFArray& Array)
305 {
306 Array = CFDictionaryGetValue((CFDictionaryRef)Array[0], CFSTR(kIOHIDElementKey));
307 InitCookies(500);
308 int i,
309 nUsage;
310 for (i = 0; i < Array.Count(); ++i)
311 {
312 CFNumberGetValue(
313 (CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) Array[i], CFSTR(kIOHIDElementUsageKey)),
314 kCFNumberLongType, &nUsage);
315
316 if (nUsage >= kHIDUsage_KeyboardA && nUsage <= kHIDUsage_KeyboardZ)
317 AddCookie(Array[i], 'A' + (nUsage - kHIDUsage_KeyboardA) );
318 else if (nUsage >= kHIDUsage_Keyboard1 && nUsage <= kHIDUsage_Keyboard9)
319 AddCookie(Array[i], '1' + (nUsage - kHIDUsage_Keyboard1) );
320 else if (nUsage >= kHIDUsage_KeyboardF1 && nUsage <= kHIDUsage_KeyboardF12)
321 AddCookie(Array[i], WXK_F1 + (nUsage - kHIDUsage_KeyboardF1) );
322 else if (nUsage >= kHIDUsage_KeyboardF13 && nUsage <= kHIDUsage_KeyboardF24)
323 AddCookie(Array[i], WXK_F13 + (nUsage - kHIDUsage_KeyboardF13) );
324 else if (nUsage >= kHIDUsage_Keypad1 && nUsage <= kHIDUsage_Keypad9)
325 AddCookie(Array[i], WXK_NUMPAD1 + (nUsage - kHIDUsage_Keypad1) );
326 else switch (nUsage)
327 {
328 //0's (wx & ascii go 0-9, but HID goes 1-0)
329 case kHIDUsage_Keyboard0:
330 AddCookie(Array[i],'0');
331 break;
332 case kHIDUsage_Keypad0:
333 AddCookie(Array[i],WXK_NUMPAD0);
334 break;
335
336 //Basic
337 case kHIDUsage_KeyboardReturnOrEnter:
338 AddCookie(Array[i], WXK_RETURN);
339 break;
340 case kHIDUsage_KeyboardEscape:
341 AddCookie(Array[i], WXK_ESCAPE);
342 break;
343 case kHIDUsage_KeyboardDeleteOrBackspace:
344 AddCookie(Array[i], WXK_BACK);
345 break;
346 case kHIDUsage_KeyboardTab:
347 AddCookie(Array[i], WXK_TAB);
348 break;
349 case kHIDUsage_KeyboardSpacebar:
350 AddCookie(Array[i], WXK_SPACE);
351 break;
352 case kHIDUsage_KeyboardPageUp:
353 AddCookie(Array[i], WXK_PRIOR);
354 break;
355 case kHIDUsage_KeyboardEnd:
356 AddCookie(Array[i], WXK_END);
357 break;
358 case kHIDUsage_KeyboardPageDown:
359 AddCookie(Array[i], WXK_NEXT);
360 break;
361 case kHIDUsage_KeyboardRightArrow:
362 AddCookie(Array[i], WXK_RIGHT);
363 break;
364 case kHIDUsage_KeyboardLeftArrow:
365 AddCookie(Array[i], WXK_LEFT);
366 break;
367 case kHIDUsage_KeyboardDownArrow:
368 AddCookie(Array[i], WXK_DOWN);
369 break;
370 case kHIDUsage_KeyboardUpArrow:
371 AddCookie(Array[i], WXK_UP);
372 break;
373
374 //LEDS
375 case kHIDUsage_KeyboardCapsLock:
376 AddCookie(Array[i],WXK_CAPITAL);
377 break;
378 case kHIDUsage_KeypadNumLock:
379 AddCookie(Array[i],WXK_NUMLOCK);
380 break;
381 case kHIDUsage_KeyboardScrollLock:
382 AddCookie(Array[i],WXK_SCROLL);
383 break;
384
385 //Menu keys, Shift, other specials
386 case kHIDUsage_KeyboardLeftControl:
387 AddCookie(Array[i],WXK_CONTROL);
388 break;
389 case kHIDUsage_KeyboardLeftShift:
390 AddCookie(Array[i],WXK_SHIFT);
391 break;
392 case kHIDUsage_KeyboardLeftAlt:
393 AddCookie(Array[i],WXK_ALT);
394 break;
395 case kHIDUsage_KeyboardLeftGUI:
396 AddCookie(Array[i],WXK_MENU);
397 break;
398 case kHIDUsage_KeyboardRightControl:
399 AddCookie(Array[i],WXK_RCONTROL);
400 break;
401 case kHIDUsage_KeyboardRightShift:
402 AddCookie(Array[i],WXK_RSHIFT);
403 break;
404 case kHIDUsage_KeyboardRightAlt:
405 AddCookie(Array[i],WXK_RALT);
406 break;
407 case kHIDUsage_KeyboardRightGUI:
408 AddCookie(Array[i],WXK_RMENU);
409 break;
410
411 //Default
412 default:
413 //not in wx keycodes - do nothing....
414 break;
415 }
416 }
417 }//end buildcookies