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