1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: DARWIN HID layer for WX Implementation
8 // Copyright: (c) Ryan Norton
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "hid.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
34 #include "wx/mac/corefoundation/hid.h"
35 #include "wx/string.h"
37 #include "wx/mac/corefoundation/cfstring.h"
40 // ---------------------------------------------------------------------------
42 // ---------------------------------------------------------------------------
44 #define wxFORCECHECK_MSG(arg, msg) \
48 wxLogSysError(wxString::Format(wxT("Message:%s\nHID: %s failed!"), wxT(msg), wxT(#arg)));\
52 #define wxIOCHECK(arg, msg) wxFORCECHECK_MSG(arg != kIOReturnSuccess, msg)
53 #define wxKERNCHECK(arg, msg) wxFORCECHECK_MSG(arg != KERN_SUCCESS, msg)
54 #define wxSCHECK(arg, msg) wxFORCECHECK_MSG(arg != S_OK, msg)
57 void CFShowTypeIDDescription(CFTypeRef pData)
66 CFStringGetCStringPtr(
67 CFCopyTypeIDDescription(CFGetTypeID(pData)),CFStringGetSystemEncoding()
73 // ============================================================================
75 // ============================================================================
77 // ---------------------------------------------------------------------------
79 // ---------------------------------------------------------------------------
81 bool wxHIDDevice::Create (int nClass
, int nType
, int nDev
)
83 //Create the mach port
84 wxIOCHECK(IOMasterPort(bootstrap_port
, &m_pPort
), "Could not create mach port");
86 //Dictionary that will hold first
87 //the matching dictionary for determining which kind of devices we want,
88 //then later some registry properties from an iterator (see below)
90 //The call to IOServiceMatching filters down the
91 //the services we want to hid services (and also eats the
92 //dictionary up for us (consumes one reference))
93 CFMutableDictionaryRef pDictionary
= IOServiceMatching(kIOHIDDeviceKey
);
94 wxCHECK_MSG( pDictionary
, false,
95 _T("IOServiceMatching(kIOHIDDeviceKey) failed") );
97 wxASSERT( pDictionary
);
99 //Here we'll filter down the services to what we want
102 CFNumberRef pType
= CFNumberCreate(kCFAllocatorDefault
,
103 kCFNumberIntType
, &nType
);
104 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsageKey
), pType
);
109 CFNumberRef pClass
= CFNumberCreate(kCFAllocatorDefault
,
110 kCFNumberIntType
, &nClass
);
111 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsagePageKey
), pClass
);
115 //Now get the maching services
116 io_iterator_t pIterator
;
117 wxIOCHECK(IOServiceGetMatchingServices(m_pPort
, pDictionary
, &pIterator
), "No Matching HID Services");
118 wxASSERT_MSG(pIterator
!= 0, wxT("No devices found!"));
120 //Now we iterate through them
122 while ( (pObject
= IOIteratorNext(pIterator
)) != 0)
127 if ( IORegistryEntryCreateCFProperties
135 wxLogDebug(_T("IORegistryEntryCreateCFProperties failed"));
139 wxASSERT(CFGetTypeID(CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDProductKey
))) == CFStringGetTypeID());
145 kIOHIDVersionNumberKey;
146 kIOHIDManufacturerKey;
147 kIOHIDSerialNumberKey;
148 if !kIOHIDLocationIDKey
149 kUSBDevicePropertyLocationID
150 kIOHIDPrimaryUsageKey
151 kIOHIDPrimaryUsagePageKey
157 m_szProductName
= wxMacCFStringHolder( (CFStringRef
) CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDProductKey
)), false ).AsString();
159 CFNumberRef nref
= (CFNumberRef
) CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDProductIDKey
));
168 nref
= (CFNumberRef
) CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDVendorIDKey
));
176 //Create the interface (good grief - long function names!)
178 IOCFPlugInInterface
** ppPlugin
;
179 wxIOCHECK(IOCreatePlugInInterfaceForService(pObject
, kIOHIDDeviceUserClientTypeID
,
180 kIOCFPlugInInterfaceID
, &ppPlugin
, &nScore
), "");
182 //Now, the final thing we can check before we fall back to asserts
183 //(because the dtor only checks if the device is ok, so if anything
184 //fails from now on the dtor will delete the device anyway, so we can't break from this).
186 //Get the HID interface from the plugin to the mach port
187 wxSCHECK((*ppPlugin
)->QueryInterface(ppPlugin
,
188 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID
), (void**) &m_ppDevice
), "");
191 (*ppPlugin
)->Release(ppPlugin
);
193 //open the HID interface...
194 if ( (*m_ppDevice
)->open(m_ppDevice
, 0) != S_OK
)
195 wxLogDebug(_T("HID device: open failed"));
198 //Now the hard part - in order to scan things we need "cookies" -
200 wxCFArray CookieArray
= CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDElementKey
));
201 BuildCookies(CookieArray
);
204 CFRelease(pDictionary
);
205 IOObjectRelease(pObject
);
209 IOObjectRelease(pIterator
);
214 int wxHIDDevice::GetCount (int nClass
, int nType
)
218 //Create the mach port
219 wxIOCHECK(IOMasterPort(bootstrap_port
, &m_pPort
), "Could not create mach port");
221 //Dictionary that will hold first
222 //the matching dictionary for determining which kind of devices we want,
223 //then later some registry properties from an iterator (see below)
224 CFMutableDictionaryRef pDictionary
= IOServiceMatching(kIOHIDDeviceKey
);
225 wxCHECK_MSG( pDictionary
, 0,
226 _T("IOServiceMatching(kIOHIDDeviceKey) failed") );
228 //Here we'll filter down the services to what we want
231 CFNumberRef pType
= CFNumberCreate(kCFAllocatorDefault
,
232 kCFNumberIntType
, &nType
);
233 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsageKey
), pType
);
238 CFNumberRef pClass
= CFNumberCreate(kCFAllocatorDefault
,
239 kCFNumberIntType
, &nClass
);
240 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsagePageKey
), pClass
);
244 //Now get the maching services
245 io_iterator_t pIterator
;
246 wxIOCHECK(IOServiceGetMatchingServices(m_pPort
, pDictionary
, &pIterator
), "No Matching HID Services");
251 //Now we iterate through them
256 while ( (pObject
= IOIteratorNext(pIterator
)) != 0)
260 IOObjectRelease(pIterator
);
265 void wxHIDDevice::AddCookie(CFTypeRef Data
, int i
)
268 (CFNumberRef
) CFDictionaryGetValue ( (CFDictionaryRef
) Data
269 , CFSTR(kIOHIDElementCookieKey
)
276 void wxHIDDevice::AddCookieInQueue(CFTypeRef Data
, int i
)
278 //3rd Param flags (none yet)
280 if ( (*m_ppQueue
)->addElement(m_ppQueue
, m_pCookies
[i
], 0) != S_OK
)
281 wxLogDebug(_T("HID device: adding element failed"));
284 void wxHIDDevice::InitCookies(size_t dwSize
, bool bQueue
)
286 m_pCookies
= new IOHIDElementCookie
[dwSize
];
289 wxASSERT( m_ppQueue
== NULL
);
290 m_ppQueue
= (*m_ppDevice
)->allocQueue(m_ppDevice
);
293 wxLogDebug(_T("HID device: allocQueue failed"));
297 //Param 2, flags, none yet
298 if ( (*m_ppQueue
)->create(m_ppQueue
, 0, 512) != S_OK
)
300 wxLogDebug(_T("HID device: create failed"));
305 bool wxHIDDevice::IsActive(int nIndex
)
307 wxASSERT(m_pCookies
[nIndex
] != NULL
);
308 IOHIDEventStruct Event
;
309 (*m_ppDevice
)->getElementValue(m_ppDevice
, m_pCookies
[nIndex
], &Event
);
312 ss << _T("[") << (int) m_pCookies[nIndex] << _T("] = ") << Event.value << _T(" SIZE:") << Event.longValueSize;
316 return !!Event
.value
;
319 bool wxHIDDevice::HasElement(int nIndex
)
321 return m_pCookies
[nIndex
] != NULL
;
324 wxHIDDevice::~wxHIDDevice()
326 if (m_ppDevice
!= NULL
)
328 if (m_ppQueue
!= NULL
)
330 (*m_ppQueue
)->stop(m_ppQueue
);
331 (*m_ppQueue
)->dispose(m_ppQueue
);
332 (*m_ppQueue
)->Release(m_ppQueue
);
334 (*m_ppDevice
)->close(m_ppDevice
);
335 (*m_ppDevice
)->Release(m_ppDevice
);
336 mach_port_deallocate(mach_task_self(), m_pPort
);
339 if (m_pCookies
!= NULL
)
341 delete [] m_pCookies
;
345 // ---------------------------------------------------------------------------
347 // ---------------------------------------------------------------------------
358 bool wxHIDKeyboard::Create()
360 return wxHIDDevice::Create(kHIDPage_GenericDesktop
, kHIDUsage_GD_Keyboard
);
363 void wxHIDKeyboard::BuildCookies(wxCFArray
& Array
)
365 Array
= CFDictionaryGetValue((CFDictionaryRef
)Array
[0], CFSTR(kIOHIDElementKey
));
369 bool bEOTriggered
= false;
370 for (i
= 0; i
< Array
.Count(); ++i
)
373 (CFNumberRef
) CFDictionaryGetValue((CFDictionaryRef
) Array
[i
], CFSTR(kIOHIDElementUsageKey
)),
374 kCFNumberLongType
, &nUsage
);
377 // OK, this is strange - basically this kind of strange -
378 // Starting from 0xEO these elements (like shift) appear twice in
379 // the array! The ones at the end are bogus I guess - the funny part
380 // is that besides the fact that the ones at the front have a Unit
381 // and UnitExponent key with a value of 0 and a different cookie value,
382 // there is no discernable difference between the two...
384 // Will the real shift please stand up?
386 // Something to spend a support request on, if I had one, LOL.
398 (CFNumberRef) CFDictionaryGetValue ( (CFDictionaryRef) Array[i]
399 , CFSTR(kIOHIDElementCookieKey)
405 msg << wxT("KEY:") << nUsage << wxT("COOKIE:") << cookie;
409 if (nUsage
>= kHIDUsage_KeyboardA
&& nUsage
<= kHIDUsage_KeyboardZ
)
410 AddCookie(Array
[i
], 'A' + (nUsage
- kHIDUsage_KeyboardA
) );
411 else if (nUsage
>= kHIDUsage_Keyboard1
&& nUsage
<= kHIDUsage_Keyboard9
)
412 AddCookie(Array
[i
], '1' + (nUsage
- kHIDUsage_Keyboard1
) );
413 else if (nUsage
>= kHIDUsage_KeyboardF1
&& nUsage
<= kHIDUsage_KeyboardF12
)
414 AddCookie(Array
[i
], WXK_F1
+ (nUsage
- kHIDUsage_KeyboardF1
) );
415 else if (nUsage
>= kHIDUsage_KeyboardF13
&& nUsage
<= kHIDUsage_KeyboardF24
)
416 AddCookie(Array
[i
], WXK_F13
+ (nUsage
- kHIDUsage_KeyboardF13
) );
417 else if (nUsage
>= kHIDUsage_Keypad1
&& nUsage
<= kHIDUsage_Keypad9
)
418 AddCookie(Array
[i
], WXK_NUMPAD1
+ (nUsage
- kHIDUsage_Keypad1
) );
421 //0's (wx & ascii go 0-9, but HID goes 1-0)
422 case kHIDUsage_Keyboard0
:
423 AddCookie(Array
[i
],'0');
425 case kHIDUsage_Keypad0
:
426 AddCookie(Array
[i
],WXK_NUMPAD0
);
430 case kHIDUsage_KeyboardReturnOrEnter
:
431 AddCookie(Array
[i
], WXK_RETURN
);
433 case kHIDUsage_KeyboardEscape
:
434 AddCookie(Array
[i
], WXK_ESCAPE
);
436 case kHIDUsage_KeyboardDeleteOrBackspace
:
437 AddCookie(Array
[i
], WXK_BACK
);
439 case kHIDUsage_KeyboardTab
:
440 AddCookie(Array
[i
], WXK_TAB
);
442 case kHIDUsage_KeyboardSpacebar
:
443 AddCookie(Array
[i
], WXK_SPACE
);
445 case kHIDUsage_KeyboardPageUp
:
446 AddCookie(Array
[i
], WXK_PRIOR
);
448 case kHIDUsage_KeyboardEnd
:
449 AddCookie(Array
[i
], WXK_END
);
451 case kHIDUsage_KeyboardPageDown
:
452 AddCookie(Array
[i
], WXK_NEXT
);
454 case kHIDUsage_KeyboardRightArrow
:
455 AddCookie(Array
[i
], WXK_RIGHT
);
457 case kHIDUsage_KeyboardLeftArrow
:
458 AddCookie(Array
[i
], WXK_LEFT
);
460 case kHIDUsage_KeyboardDownArrow
:
461 AddCookie(Array
[i
], WXK_DOWN
);
463 case kHIDUsage_KeyboardUpArrow
:
464 AddCookie(Array
[i
], WXK_UP
);
468 case kHIDUsage_KeyboardCapsLock
:
469 AddCookie(Array
[i
],WXK_CAPITAL
);
471 case kHIDUsage_KeypadNumLock
:
472 AddCookie(Array
[i
],WXK_NUMLOCK
);
474 case kHIDUsage_KeyboardScrollLock
:
475 AddCookie(Array
[i
],WXK_SCROLL
);
478 //Menu keys, Shift, other specials
479 case kHIDUsage_KeyboardLeftControl
:
480 AddCookie(Array
[i
],WXK_CONTROL
);
482 case kHIDUsage_KeyboardLeftShift
:
483 AddCookie(Array
[i
],WXK_SHIFT
);
485 case kHIDUsage_KeyboardLeftAlt
:
486 AddCookie(Array
[i
],WXK_ALT
);
488 case kHIDUsage_KeyboardLeftGUI
:
489 AddCookie(Array
[i
],WXK_MENU
);
491 case kHIDUsage_KeyboardRightControl
:
492 AddCookie(Array
[i
],WXK_RCONTROL
);
494 case kHIDUsage_KeyboardRightShift
:
495 AddCookie(Array
[i
],WXK_RSHIFT
);
497 case kHIDUsage_KeyboardRightAlt
:
498 AddCookie(Array
[i
],WXK_RALT
);
500 case kHIDUsage_KeyboardRightGUI
:
501 AddCookie(Array
[i
],WXK_RMENU
);
506 //not in wx keycodes - do nothing....
516 #include "wx/utils.h"
517 #include "wx/module.h"
519 class wxHIDModule
: public wxModule
521 DECLARE_DYNAMIC_CLASS(wxHIDModule
)
524 static wxHIDKeyboard
* sm_keyboard
;
526 virtual bool OnInit()
531 virtual void OnExit()
538 IMPLEMENT_DYNAMIC_CLASS(wxHIDModule
, wxModule
)
540 wxHIDKeyboard
* wxHIDModule::sm_keyboard
;
542 bool wxGetKeyState (wxKeyCode key
)
544 wxASSERT_MSG(key
!= WXK_LBUTTON
&& key
!= WXK_RBUTTON
&& key
!=
545 WXK_MBUTTON
, wxT("can't use wxGetKeyState() for mouse buttons"));
547 if (!wxHIDModule::sm_keyboard
)
549 wxHIDModule::sm_keyboard
= new wxHIDKeyboard();
550 bool bOK
= wxHIDModule::sm_keyboard
->Create();
554 delete wxHIDModule::sm_keyboard
;
555 wxHIDModule::sm_keyboard
= NULL
;
563 return wxHIDModule::sm_keyboard
->IsActive(WXK_SHIFT
) ||
564 wxHIDModule::sm_keyboard
->IsActive(WXK_RSHIFT
);
567 return wxHIDModule::sm_keyboard
->IsActive(WXK_ALT
) ||
568 wxHIDModule::sm_keyboard
->IsActive(WXK_RALT
);
571 return wxHIDModule::sm_keyboard
->IsActive(WXK_CONTROL
) ||
572 wxHIDModule::sm_keyboard
->IsActive(WXK_RCONTROL
);
575 return wxHIDModule::sm_keyboard
->IsActive(WXK_MENU
) ||
576 wxHIDModule::sm_keyboard
->IsActive(WXK_RMENU
);
579 return wxHIDModule::sm_keyboard
->IsActive(key
);