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");
114 wxASSERT_MSG(pIterator
!= 0, wxT("No devices found!"));
116 //Now we iterate through them
118 while ( (pObject
= IOIteratorNext(pIterator
)) != 0)
123 if ( IORegistryEntryCreateCFProperties
131 wxLogDebug(_T("IORegistryEntryCreateCFProperties failed"));
135 wxASSERT(CFGetTypeID(CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDProductKey
))) == CFStringGetTypeID());
141 kIOHIDVersionNumberKey;
142 kIOHIDManufacturerKey;
143 kIOHIDSerialNumberKey;
144 if !kIOHIDLocationIDKey
145 kUSBDevicePropertyLocationID
146 kIOHIDPrimaryUsageKey
147 kIOHIDPrimaryUsagePageKey
153 m_szProductName
= wxMacCFStringHolder( (CFStringRef
) CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDProductKey
)), false ).AsString();
155 CFNumberRef nref
= (CFNumberRef
) CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDProductIDKey
));
164 nref
= (CFNumberRef
) CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDVendorIDKey
));
172 //Create the interface (good grief - long function names!)
174 IOCFPlugInInterface
** ppPlugin
;
175 wxIOCHECK(IOCreatePlugInInterfaceForService(pObject
, kIOHIDDeviceUserClientTypeID
,
176 kIOCFPlugInInterfaceID
, &ppPlugin
, &nScore
), "");
178 //Now, the final thing we can check before we fall back to asserts
179 //(because the dtor only checks if the device is ok, so if anything
180 //fails from now on the dtor will delete the device anyway, so we can't break from this).
182 //Get the HID interface from the plugin to the mach port
183 wxSCHECK((*ppPlugin
)->QueryInterface(ppPlugin
,
184 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID
), (void**) &m_ppDevice
), "");
187 (*ppPlugin
)->Release(ppPlugin
);
189 //open the HID interface...
190 if ( (*m_ppDevice
)->open(m_ppDevice
, 0) != S_OK
)
191 wxLogDebug(_T("HID device: open failed"));
194 //Now the hard part - in order to scan things we need "cookies" -
196 wxCFArray CookieArray
= CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDElementKey
));
197 BuildCookies(CookieArray
);
200 CFRelease(pDictionary
);
201 IOObjectRelease(pObject
);
205 IOObjectRelease(pIterator
);
210 int wxHIDDevice::GetCount (int nClass
, int nType
)
214 //Create the mach port
215 wxIOCHECK(IOMasterPort(bootstrap_port
, &m_pPort
), "Could not create mach port");
217 //Dictionary that will hold first
218 //the matching dictionary for determining which kind of devices we want,
219 //then later some registry properties from an iterator (see below)
220 CFMutableDictionaryRef pDictionary
= IOServiceMatching(kIOHIDDeviceKey
);
221 wxCHECK_MSG( pDictionary
, 0,
222 _T("IOServiceMatching(kIOHIDDeviceKey) failed") );
224 //Here we'll filter down the services to what we want
227 CFNumberRef pType
= CFNumberCreate(kCFAllocatorDefault
,
228 kCFNumberIntType
, &nType
);
229 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsageKey
), pType
);
234 CFNumberRef pClass
= CFNumberCreate(kCFAllocatorDefault
,
235 kCFNumberIntType
, &nClass
);
236 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsagePageKey
), pClass
);
240 //Now get the maching services
241 io_iterator_t pIterator
;
242 wxIOCHECK(IOServiceGetMatchingServices(m_pPort
, pDictionary
, &pIterator
), "No Matching HID Services");
247 //Now we iterate through them
252 while ( (pObject
= IOIteratorNext(pIterator
)) != 0)
256 IOObjectRelease(pIterator
);
261 void wxHIDDevice::AddCookie(CFTypeRef Data
, int i
)
264 (CFNumberRef
) CFDictionaryGetValue ( (CFDictionaryRef
) Data
265 , CFSTR(kIOHIDElementCookieKey
)
272 void wxHIDDevice::AddCookieInQueue(CFTypeRef Data
, int i
)
274 //3rd Param flags (none yet)
276 if ( (*m_ppQueue
)->addElement(m_ppQueue
, m_pCookies
[i
], 0) != S_OK
)
277 wxLogDebug(_T("HID device: adding element failed"));
280 void wxHIDDevice::InitCookies(size_t dwSize
, bool bQueue
)
282 m_pCookies
= new IOHIDElementCookie
[dwSize
];
285 wxASSERT( m_ppQueue
== NULL
);
286 m_ppQueue
= (*m_ppDevice
)->allocQueue(m_ppDevice
);
289 wxLogDebug(_T("HID device: allocQueue failed"));
293 //Param 2, flags, none yet
294 if ( (*m_ppQueue
)->create(m_ppQueue
, 0, 512) != S_OK
)
296 wxLogDebug(_T("HID device: create failed"));
301 bool wxHIDDevice::IsActive(int nIndex
)
303 wxASSERT(m_pCookies
[nIndex
] != NULL
);
304 IOHIDEventStruct Event
;
305 (*m_ppDevice
)->getElementValue(m_ppDevice
, m_pCookies
[nIndex
], &Event
);
308 ss << _T("[") << (int) m_pCookies[nIndex] << _T("] = ") << Event.value << _T(" SIZE:") << Event.longValueSize;
312 return !!Event
.value
;
315 bool wxHIDDevice::HasElement(int nIndex
)
317 return m_pCookies
[nIndex
] != NULL
;
320 wxHIDDevice::~wxHIDDevice()
322 if (m_ppDevice
!= NULL
)
324 if (m_ppQueue
!= NULL
)
326 (*m_ppQueue
)->stop(m_ppQueue
);
327 (*m_ppQueue
)->dispose(m_ppQueue
);
328 (*m_ppQueue
)->Release(m_ppQueue
);
330 (*m_ppDevice
)->close(m_ppDevice
);
331 (*m_ppDevice
)->Release(m_ppDevice
);
332 mach_port_deallocate(mach_task_self(), m_pPort
);
335 if (m_pCookies
!= NULL
)
337 delete [] m_pCookies
;
341 // ---------------------------------------------------------------------------
343 // ---------------------------------------------------------------------------
354 bool wxHIDKeyboard::Create()
356 return wxHIDDevice::Create(kHIDPage_GenericDesktop
, kHIDUsage_GD_Keyboard
);
359 void wxHIDKeyboard::BuildCookies(wxCFArray
& Array
)
361 Array
= CFDictionaryGetValue((CFDictionaryRef
)Array
[0], CFSTR(kIOHIDElementKey
));
365 bool bEOTriggered
= false;
366 for (i
= 0; i
< Array
.Count(); ++i
)
369 (CFNumberRef
) CFDictionaryGetValue((CFDictionaryRef
) Array
[i
], CFSTR(kIOHIDElementUsageKey
)),
370 kCFNumberLongType
, &nUsage
);
373 // OK, this is strange - basically this kind of strange -
374 // Starting from 0xEO these elements (like shift) appear twice in
375 // the array! The ones at the end are bogus I guess - the funny part
376 // is that besides the fact that the ones at the front have a Unit
377 // and UnitExponent key with a value of 0 and a different cookie value,
378 // there is no discernable difference between the two...
380 // Will the real shift please stand up?
382 // Something to spend a support request on, if I had one, LOL.
394 (CFNumberRef) CFDictionaryGetValue ( (CFDictionaryRef) Array[i]
395 , CFSTR(kIOHIDElementCookieKey)
401 msg << wxT("KEY:") << nUsage << wxT("COOKIE:") << cookie;
405 if (nUsage
>= kHIDUsage_KeyboardA
&& nUsage
<= kHIDUsage_KeyboardZ
)
406 AddCookie(Array
[i
], 'A' + (nUsage
- kHIDUsage_KeyboardA
) );
407 else if (nUsage
>= kHIDUsage_Keyboard1
&& nUsage
<= kHIDUsage_Keyboard9
)
408 AddCookie(Array
[i
], '1' + (nUsage
- kHIDUsage_Keyboard1
) );
409 else if (nUsage
>= kHIDUsage_KeyboardF1
&& nUsage
<= kHIDUsage_KeyboardF12
)
410 AddCookie(Array
[i
], WXK_F1
+ (nUsage
- kHIDUsage_KeyboardF1
) );
411 else if (nUsage
>= kHIDUsage_KeyboardF13
&& nUsage
<= kHIDUsage_KeyboardF24
)
412 AddCookie(Array
[i
], WXK_F13
+ (nUsage
- kHIDUsage_KeyboardF13
) );
413 else if (nUsage
>= kHIDUsage_Keypad1
&& nUsage
<= kHIDUsage_Keypad9
)
414 AddCookie(Array
[i
], WXK_NUMPAD1
+ (nUsage
- kHIDUsage_Keypad1
) );
417 //0's (wx & ascii go 0-9, but HID goes 1-0)
418 case kHIDUsage_Keyboard0
:
419 AddCookie(Array
[i
],'0');
421 case kHIDUsage_Keypad0
:
422 AddCookie(Array
[i
],WXK_NUMPAD0
);
426 case kHIDUsage_KeyboardReturnOrEnter
:
427 AddCookie(Array
[i
], WXK_RETURN
);
429 case kHIDUsage_KeyboardEscape
:
430 AddCookie(Array
[i
], WXK_ESCAPE
);
432 case kHIDUsage_KeyboardDeleteOrBackspace
:
433 AddCookie(Array
[i
], WXK_BACK
);
435 case kHIDUsage_KeyboardTab
:
436 AddCookie(Array
[i
], WXK_TAB
);
438 case kHIDUsage_KeyboardSpacebar
:
439 AddCookie(Array
[i
], WXK_SPACE
);
441 case kHIDUsage_KeyboardPageUp
:
442 AddCookie(Array
[i
], WXK_PRIOR
);
444 case kHIDUsage_KeyboardEnd
:
445 AddCookie(Array
[i
], WXK_END
);
447 case kHIDUsage_KeyboardPageDown
:
448 AddCookie(Array
[i
], WXK_NEXT
);
450 case kHIDUsage_KeyboardRightArrow
:
451 AddCookie(Array
[i
], WXK_RIGHT
);
453 case kHIDUsage_KeyboardLeftArrow
:
454 AddCookie(Array
[i
], WXK_LEFT
);
456 case kHIDUsage_KeyboardDownArrow
:
457 AddCookie(Array
[i
], WXK_DOWN
);
459 case kHIDUsage_KeyboardUpArrow
:
460 AddCookie(Array
[i
], WXK_UP
);
464 case kHIDUsage_KeyboardCapsLock
:
465 AddCookie(Array
[i
],WXK_CAPITAL
);
467 case kHIDUsage_KeypadNumLock
:
468 AddCookie(Array
[i
],WXK_NUMLOCK
);
470 case kHIDUsage_KeyboardScrollLock
:
471 AddCookie(Array
[i
],WXK_SCROLL
);
474 //Menu keys, Shift, other specials
475 case kHIDUsage_KeyboardLeftControl
:
476 AddCookie(Array
[i
],WXK_CONTROL
);
478 case kHIDUsage_KeyboardLeftShift
:
479 AddCookie(Array
[i
],WXK_SHIFT
);
481 case kHIDUsage_KeyboardLeftAlt
:
482 AddCookie(Array
[i
],WXK_ALT
);
484 case kHIDUsage_KeyboardLeftGUI
:
485 AddCookie(Array
[i
],WXK_MENU
);
487 case kHIDUsage_KeyboardRightControl
:
488 AddCookie(Array
[i
],WXK_RCONTROL
);
490 case kHIDUsage_KeyboardRightShift
:
491 AddCookie(Array
[i
],WXK_RSHIFT
);
493 case kHIDUsage_KeyboardRightAlt
:
494 AddCookie(Array
[i
],WXK_RALT
);
496 case kHIDUsage_KeyboardRightGUI
:
497 AddCookie(Array
[i
],WXK_RMENU
);
502 //not in wx keycodes - do nothing....
512 #include "wx/utils.h"
513 #include "wx/module.h"
515 class wxHIDModule
: public wxModule
517 DECLARE_DYNAMIC_CLASS(wxHIDModule
)
520 static wxHIDKeyboard
* sm_keyboard
;
522 virtual bool OnInit()
527 virtual void OnExit()
534 IMPLEMENT_DYNAMIC_CLASS(wxHIDModule
, wxModule
)
536 wxHIDKeyboard
* wxHIDModule::sm_keyboard
;
538 bool wxGetKeyState (wxKeyCode key
)
540 wxASSERT_MSG(key
!= WXK_LBUTTON
&& key
!= WXK_RBUTTON
&& key
!=
541 WXK_MBUTTON
, wxT("can't use wxGetKeyState() for mouse buttons"));
543 if (!wxHIDModule::sm_keyboard
)
545 wxHIDModule::sm_keyboard
= new wxHIDKeyboard();
546 bool bOK
= wxHIDModule::sm_keyboard
->Create();
550 delete wxHIDModule::sm_keyboard
;
551 wxHIDModule::sm_keyboard
= NULL
;
559 return wxHIDModule::sm_keyboard
->IsActive(WXK_SHIFT
) ||
560 wxHIDModule::sm_keyboard
->IsActive(WXK_RSHIFT
);
563 return wxHIDModule::sm_keyboard
->IsActive(WXK_ALT
) ||
564 wxHIDModule::sm_keyboard
->IsActive(WXK_RALT
);
567 return wxHIDModule::sm_keyboard
->IsActive(WXK_CONTROL
) ||
568 wxHIDModule::sm_keyboard
->IsActive(WXK_RCONTROL
);
571 return wxHIDModule::sm_keyboard
->IsActive(WXK_MENU
) ||
572 wxHIDModule::sm_keyboard
->IsActive(WXK_RMENU
);
575 return wxHIDModule::sm_keyboard
->IsActive(key
);