1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: DARWIN HID layer for WX Implementation
8 // Copyright: (c) Ryan Norton
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
30 #include "wx/mac/corefoundation/hid.h"
31 #include "wx/string.h"
33 #include "wx/mac/corefoundation/cfstring.h"
36 // ---------------------------------------------------------------------------
38 // ---------------------------------------------------------------------------
40 #define wxFORCECHECK_MSG(arg, msg) \
44 wxLogSysError(wxString::Format(wxT("Message:%s\nHID: %s failed!"), wxT(msg), wxT(#arg)));\
48 #define wxIOCHECK(arg, msg) wxFORCECHECK_MSG(arg != kIOReturnSuccess, msg)
49 #define wxKERNCHECK(arg, msg) wxFORCECHECK_MSG(arg != KERN_SUCCESS, msg)
50 #define wxSCHECK(arg, msg) wxFORCECHECK_MSG(arg != S_OK, msg)
53 void CFShowTypeIDDescription(CFTypeRef pData)
62 CFStringGetCStringPtr(
63 CFCopyTypeIDDescription(CFGetTypeID(pData)),CFStringGetSystemEncoding()
69 // ============================================================================
71 // ============================================================================
73 // ---------------------------------------------------------------------------
75 // ---------------------------------------------------------------------------
77 bool wxHIDDevice::Create (int nClass
, int nType
, int nDev
)
79 //Create the mach port
80 wxIOCHECK(IOMasterPort(bootstrap_port
, &m_pPort
), "Could not create mach port");
82 //Dictionary that will hold first
83 //the matching dictionary for determining which kind of devices we want,
84 //then later some registry properties from an iterator (see below)
86 //The call to IOServiceMatching filters down the
87 //the services we want to hid services (and also eats the
88 //dictionary up for us (consumes one reference))
89 CFMutableDictionaryRef pDictionary
= IOServiceMatching(kIOHIDDeviceKey
);
90 wxCHECK_MSG( pDictionary
, false,
91 _T("IOServiceMatching(kIOHIDDeviceKey) failed") );
93 wxASSERT( pDictionary
);
95 //Here we'll filter down the services to what we want
98 CFNumberRef pType
= CFNumberCreate(kCFAllocatorDefault
,
99 kCFNumberIntType
, &nType
);
100 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsageKey
), pType
);
105 CFNumberRef pClass
= CFNumberCreate(kCFAllocatorDefault
,
106 kCFNumberIntType
, &nClass
);
107 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsagePageKey
), pClass
);
111 //Now get the maching services
112 io_iterator_t pIterator
;
113 wxIOCHECK(IOServiceGetMatchingServices(m_pPort
, pDictionary
, &pIterator
), "No Matching HID Services");
115 return false; // No devices found
117 //Now we iterate through them
119 while ( (pObject
= IOIteratorNext(pIterator
)) != 0)
124 if ( IORegistryEntryCreateCFProperties
132 wxLogDebug(_T("IORegistryEntryCreateCFProperties failed"));
136 wxASSERT(CFGetTypeID(CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDProductKey
))) == CFStringGetTypeID());
142 kIOHIDVersionNumberKey;
143 kIOHIDManufacturerKey;
144 kIOHIDSerialNumberKey;
145 if !kIOHIDLocationIDKey
146 kUSBDevicePropertyLocationID
147 kIOHIDPrimaryUsageKey
148 kIOHIDPrimaryUsagePageKey
154 m_szProductName
= wxMacCFStringHolder( (CFStringRef
) CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDProductKey
)), false ).AsString();
156 CFNumberRef nref
= (CFNumberRef
) CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDProductIDKey
));
165 nref
= (CFNumberRef
) CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDVendorIDKey
));
173 //Create the interface (good grief - long function names!)
175 IOCFPlugInInterface
** ppPlugin
;
176 wxIOCHECK(IOCreatePlugInInterfaceForService(pObject
, kIOHIDDeviceUserClientTypeID
,
177 kIOCFPlugInInterfaceID
, &ppPlugin
, &nScore
), "");
179 //Now, the final thing we can check before we fall back to asserts
180 //(because the dtor only checks if the device is ok, so if anything
181 //fails from now on the dtor will delete the device anyway, so we can't break from this).
183 //Get the HID interface from the plugin to the mach port
184 wxSCHECK((*ppPlugin
)->QueryInterface(ppPlugin
,
185 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID
), (void**) &m_ppDevice
), "");
188 (*ppPlugin
)->Release(ppPlugin
);
190 //open the HID interface...
191 if ( (*m_ppDevice
)->open(m_ppDevice
, 0) != S_OK
)
192 wxLogDebug(_T("HID device: open failed"));
195 //Now the hard part - in order to scan things we need "cookies" -
197 wxCFArray CookieArray
= CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDElementKey
));
198 BuildCookies(CookieArray
);
201 CFRelease(pDictionary
);
202 IOObjectRelease(pObject
);
206 IOObjectRelease(pIterator
);
211 int wxHIDDevice::GetCount (int nClass
, int nType
)
215 //Create the mach port
216 wxIOCHECK(IOMasterPort(bootstrap_port
, &m_pPort
), "Could not create mach port");
218 //Dictionary that will hold first
219 //the matching dictionary for determining which kind of devices we want,
220 //then later some registry properties from an iterator (see below)
221 CFMutableDictionaryRef pDictionary
= IOServiceMatching(kIOHIDDeviceKey
);
222 wxCHECK_MSG( pDictionary
, 0,
223 _T("IOServiceMatching(kIOHIDDeviceKey) failed") );
225 //Here we'll filter down the services to what we want
228 CFNumberRef pType
= CFNumberCreate(kCFAllocatorDefault
,
229 kCFNumberIntType
, &nType
);
230 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsageKey
), pType
);
235 CFNumberRef pClass
= CFNumberCreate(kCFAllocatorDefault
,
236 kCFNumberIntType
, &nClass
);
237 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsagePageKey
), pClass
);
241 //Now get the maching services
242 io_iterator_t pIterator
;
243 wxIOCHECK(IOServiceGetMatchingServices(m_pPort
, pDictionary
, &pIterator
), "No Matching HID Services");
248 //Now we iterate through them
253 while ( (pObject
= IOIteratorNext(pIterator
)) != 0)
257 IOObjectRelease(pIterator
);
262 void wxHIDDevice::AddCookie(CFTypeRef Data
, int i
)
265 (CFNumberRef
) CFDictionaryGetValue ( (CFDictionaryRef
) Data
266 , CFSTR(kIOHIDElementCookieKey
)
273 void wxHIDDevice::AddCookieInQueue(CFTypeRef Data
, int i
)
275 //3rd Param flags (none yet)
277 if ( (*m_ppQueue
)->addElement(m_ppQueue
, m_pCookies
[i
], 0) != S_OK
)
278 wxLogDebug(_T("HID device: adding element failed"));
281 void wxHIDDevice::InitCookies(size_t dwSize
, bool bQueue
)
283 m_pCookies
= new IOHIDElementCookie
[dwSize
];
286 wxASSERT( m_ppQueue
== NULL
);
287 m_ppQueue
= (*m_ppDevice
)->allocQueue(m_ppDevice
);
290 wxLogDebug(_T("HID device: allocQueue failed"));
294 //Param 2, flags, none yet
295 if ( (*m_ppQueue
)->create(m_ppQueue
, 0, 512) != S_OK
)
297 wxLogDebug(_T("HID device: create failed"));
302 bool wxHIDDevice::IsActive(int nIndex
)
304 wxASSERT(m_pCookies
[nIndex
] != NULL
);
305 IOHIDEventStruct Event
;
306 (*m_ppDevice
)->getElementValue(m_ppDevice
, m_pCookies
[nIndex
], &Event
);
309 ss << _T("[") << (int) m_pCookies[nIndex] << _T("] = ") << Event.value << _T(" SIZE:") << Event.longValueSize;
313 return !!Event
.value
;
316 bool wxHIDDevice::HasElement(int nIndex
)
318 return m_pCookies
[nIndex
] != NULL
;
321 wxHIDDevice::~wxHIDDevice()
323 if (m_ppDevice
!= NULL
)
325 if (m_ppQueue
!= NULL
)
327 (*m_ppQueue
)->stop(m_ppQueue
);
328 (*m_ppQueue
)->dispose(m_ppQueue
);
329 (*m_ppQueue
)->Release(m_ppQueue
);
331 (*m_ppDevice
)->close(m_ppDevice
);
332 (*m_ppDevice
)->Release(m_ppDevice
);
333 mach_port_deallocate(mach_task_self(), m_pPort
);
336 if (m_pCookies
!= NULL
)
338 delete [] m_pCookies
;
342 // ---------------------------------------------------------------------------
344 // ---------------------------------------------------------------------------
355 bool wxHIDKeyboard::Create()
357 return wxHIDDevice::Create(kHIDPage_GenericDesktop
, kHIDUsage_GD_Keyboard
);
360 void wxHIDKeyboard::BuildCookies(wxCFArray
& Array
)
362 Array
= CFDictionaryGetValue((CFDictionaryRef
)Array
[0], CFSTR(kIOHIDElementKey
));
366 bool bEOTriggered
= false;
367 for (i
= 0; i
< Array
.Count(); ++i
)
370 (CFNumberRef
) CFDictionaryGetValue((CFDictionaryRef
) Array
[i
], CFSTR(kIOHIDElementUsageKey
)),
371 kCFNumberLongType
, &nUsage
);
374 // OK, this is strange - basically this kind of strange -
375 // Starting from 0xEO these elements (like shift) appear twice in
376 // the array! The ones at the end are bogus I guess - the funny part
377 // is that besides the fact that the ones at the front have a Unit
378 // and UnitExponent key with a value of 0 and a different cookie value,
379 // there is no discernable difference between the two...
381 // Will the real shift please stand up?
383 // Something to spend a support request on, if I had one, LOL.
395 (CFNumberRef) CFDictionaryGetValue ( (CFDictionaryRef) Array[i]
396 , CFSTR(kIOHIDElementCookieKey)
402 msg << wxT("KEY:") << nUsage << wxT("COOKIE:") << cookie;
406 if (nUsage
>= kHIDUsage_KeyboardA
&& nUsage
<= kHIDUsage_KeyboardZ
)
407 AddCookie(Array
[i
], 'A' + (nUsage
- kHIDUsage_KeyboardA
) );
408 else if (nUsage
>= kHIDUsage_Keyboard1
&& nUsage
<= kHIDUsage_Keyboard9
)
409 AddCookie(Array
[i
], '1' + (nUsage
- kHIDUsage_Keyboard1
) );
410 else if (nUsage
>= kHIDUsage_KeyboardF1
&& nUsage
<= kHIDUsage_KeyboardF12
)
411 AddCookie(Array
[i
], WXK_F1
+ (nUsage
- kHIDUsage_KeyboardF1
) );
412 else if (nUsage
>= kHIDUsage_KeyboardF13
&& nUsage
<= kHIDUsage_KeyboardF24
)
413 AddCookie(Array
[i
], WXK_F13
+ (nUsage
- kHIDUsage_KeyboardF13
) );
414 else if (nUsage
>= kHIDUsage_Keypad1
&& nUsage
<= kHIDUsage_Keypad9
)
415 AddCookie(Array
[i
], WXK_NUMPAD1
+ (nUsage
- kHIDUsage_Keypad1
) );
418 //0's (wx & ascii go 0-9, but HID goes 1-0)
419 case kHIDUsage_Keyboard0
:
420 AddCookie(Array
[i
],'0');
422 case kHIDUsage_Keypad0
:
423 AddCookie(Array
[i
],WXK_NUMPAD0
);
427 case kHIDUsage_KeyboardReturnOrEnter
:
428 AddCookie(Array
[i
], WXK_RETURN
);
430 case kHIDUsage_KeyboardEscape
:
431 AddCookie(Array
[i
], WXK_ESCAPE
);
433 case kHIDUsage_KeyboardDeleteOrBackspace
:
434 AddCookie(Array
[i
], WXK_BACK
);
436 case kHIDUsage_KeyboardTab
:
437 AddCookie(Array
[i
], WXK_TAB
);
439 case kHIDUsage_KeyboardSpacebar
:
440 AddCookie(Array
[i
], WXK_SPACE
);
442 case kHIDUsage_KeyboardPageUp
:
443 AddCookie(Array
[i
], WXK_PRIOR
);
445 case kHIDUsage_KeyboardEnd
:
446 AddCookie(Array
[i
], WXK_END
);
448 case kHIDUsage_KeyboardPageDown
:
449 AddCookie(Array
[i
], WXK_NEXT
);
451 case kHIDUsage_KeyboardRightArrow
:
452 AddCookie(Array
[i
], WXK_RIGHT
);
454 case kHIDUsage_KeyboardLeftArrow
:
455 AddCookie(Array
[i
], WXK_LEFT
);
457 case kHIDUsage_KeyboardDownArrow
:
458 AddCookie(Array
[i
], WXK_DOWN
);
460 case kHIDUsage_KeyboardUpArrow
:
461 AddCookie(Array
[i
], WXK_UP
);
465 case kHIDUsage_KeyboardCapsLock
:
466 AddCookie(Array
[i
],WXK_CAPITAL
);
468 case kHIDUsage_KeypadNumLock
:
469 AddCookie(Array
[i
],WXK_NUMLOCK
);
471 case kHIDUsage_KeyboardScrollLock
:
472 AddCookie(Array
[i
],WXK_SCROLL
);
475 //Menu keys, Shift, other specials
476 case kHIDUsage_KeyboardLeftControl
:
477 AddCookie(Array
[i
],WXK_CONTROL
);
479 case kHIDUsage_KeyboardLeftShift
:
480 AddCookie(Array
[i
],WXK_SHIFT
);
482 case kHIDUsage_KeyboardLeftAlt
:
483 AddCookie(Array
[i
],WXK_ALT
);
485 case kHIDUsage_KeyboardLeftGUI
:
486 AddCookie(Array
[i
],WXK_MENU
);
488 case kHIDUsage_KeyboardRightControl
:
489 AddCookie(Array
[i
],WXK_RCONTROL
);
491 case kHIDUsage_KeyboardRightShift
:
492 AddCookie(Array
[i
],WXK_RSHIFT
);
494 case kHIDUsage_KeyboardRightAlt
:
495 AddCookie(Array
[i
],WXK_RALT
);
497 case kHIDUsage_KeyboardRightGUI
:
498 AddCookie(Array
[i
],WXK_RMENU
);
503 //not in wx keycodes - do nothing....
513 #include "wx/utils.h"
514 #include "wx/module.h"
516 class wxHIDModule
: public wxModule
518 DECLARE_DYNAMIC_CLASS(wxHIDModule
)
521 static wxHIDKeyboard
* sm_keyboard
;
523 virtual bool OnInit()
528 virtual void OnExit()
535 IMPLEMENT_DYNAMIC_CLASS(wxHIDModule
, wxModule
)
537 wxHIDKeyboard
* wxHIDModule::sm_keyboard
;
539 bool wxGetKeyState (wxKeyCode key
)
541 wxASSERT_MSG(key
!= WXK_LBUTTON
&& key
!= WXK_RBUTTON
&& key
!=
542 WXK_MBUTTON
, wxT("can't use wxGetKeyState() for mouse buttons"));
544 if (!wxHIDModule::sm_keyboard
)
546 wxHIDModule::sm_keyboard
= new wxHIDKeyboard();
547 bool bOK
= wxHIDModule::sm_keyboard
->Create();
551 delete wxHIDModule::sm_keyboard
;
552 wxHIDModule::sm_keyboard
= NULL
;
560 return wxHIDModule::sm_keyboard
->IsActive(WXK_SHIFT
) ||
561 wxHIDModule::sm_keyboard
->IsActive(WXK_RSHIFT
);
564 return wxHIDModule::sm_keyboard
->IsActive(WXK_ALT
) ||
565 wxHIDModule::sm_keyboard
->IsActive(WXK_RALT
);
568 return wxHIDModule::sm_keyboard
->IsActive(WXK_CONTROL
) ||
569 wxHIDModule::sm_keyboard
->IsActive(WXK_RCONTROL
);
572 return wxHIDModule::sm_keyboard
->IsActive(WXK_MENU
) ||
573 wxHIDModule::sm_keyboard
->IsActive(WXK_RMENU
);
576 return wxHIDModule::sm_keyboard
->IsActive(key
);