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 # define wxVERIFY(arg) wxASSERT(arg)
59 # define wxVERIFY(arg) arg
63 void CFShowTypeIDDescription(CFTypeRef pData)
72 CFStringGetCStringPtr(
73 CFCopyTypeIDDescription(CFGetTypeID(pData)),CFStringGetSystemEncoding()
79 // ============================================================================
81 // ============================================================================
83 // ---------------------------------------------------------------------------
85 // ---------------------------------------------------------------------------
87 bool wxHIDDevice::Create (int nClass
, int nType
, int nDev
)
89 //Create the mach port
90 wxIOCHECK(IOMasterPort(bootstrap_port
, &m_pPort
), "Could not create mach port");
92 //Dictionary that will hold first
93 //the matching dictionary for determining which kind of devices we want,
94 //then later some registry properties from an iterator (see below)
95 CFMutableDictionaryRef pDictionary
;
98 //The call to IOServiceMatching filters down the
99 //the services we want to hid services (and also eats the
100 //dictionary up for us (consumes one reference))
101 wxVERIFY((pDictionary
= IOServiceMatching(kIOHIDDeviceKey
)) != NULL
);
103 //Here we'll filter down the services to what we want
106 CFNumberRef pType
= CFNumberCreate(kCFAllocatorDefault
,
107 kCFNumberIntType
, &nType
);
108 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsageKey
), pType
);
113 CFNumberRef pClass
= CFNumberCreate(kCFAllocatorDefault
,
114 kCFNumberIntType
, &nClass
);
115 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsagePageKey
), pClass
);
119 //Now get the maching services
120 io_iterator_t pIterator
;
121 wxIOCHECK(IOServiceGetMatchingServices(m_pPort
, pDictionary
, &pIterator
), "No Matching HID Services");
122 wxASSERT_MSG(pIterator
!= 0, wxT("No devices found!"));
124 //Now we iterate through them
126 while ( (pObject
= IOIteratorNext(pIterator
)) != 0)
131 wxVERIFY(IORegistryEntryCreateCFProperties(pObject
, &pDictionary
,
132 kCFAllocatorDefault
, kNilOptions
) == KERN_SUCCESS
);
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 wxVERIFY((*m_ppDevice
)->open(m_ppDevice
, 0) == S_OK
);
193 //Now the hard part - in order to scan things we need "cookies" -
195 wxCFArray CookieArray
= CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDElementKey
));
196 BuildCookies(CookieArray
);
199 CFRelease(pDictionary
);
200 IOObjectRelease(pObject
);
204 IOObjectRelease(pIterator
);
209 int wxHIDDevice::GetCount (int nClass
, int nType
)
213 //Create the mach port
214 wxIOCHECK(IOMasterPort(bootstrap_port
, &m_pPort
), "Could not create mach port");
216 //Dictionary that will hold first
217 //the matching dictionary for determining which kind of devices we want,
218 //then later some registry properties from an iterator (see below)
219 CFMutableDictionaryRef pDictionary
;
221 //Create a dictionary
222 //The call to IOServiceMatching filters down the
223 //the services we want to hid services (and also eats the
224 //dictionary up for us (consumes one reference))
225 wxVERIFY((pDictionary
= IOServiceMatching(kIOHIDDeviceKey
)) != NULL
);
227 //Here we'll filter down the services to what we want
230 CFNumberRef pType
= CFNumberCreate(kCFAllocatorDefault
,
231 kCFNumberIntType
, &nType
);
232 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsageKey
), pType
);
237 CFNumberRef pClass
= CFNumberCreate(kCFAllocatorDefault
,
238 kCFNumberIntType
, &nClass
);
239 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsagePageKey
), pClass
);
243 //Now get the maching services
244 io_iterator_t pIterator
;
245 wxIOCHECK(IOServiceGetMatchingServices(m_pPort
, pDictionary
, &pIterator
), "No Matching HID Services");
247 if(pIterator
== NULL
)
250 //Now we iterate through them
255 while ( (pObject
= IOIteratorNext(pIterator
)) != 0)
259 IOObjectRelease(pIterator
);
264 void wxHIDDevice::AddCookie(CFTypeRef Data
, int i
)
267 (CFNumberRef
) CFDictionaryGetValue ( (CFDictionaryRef
) Data
268 , CFSTR(kIOHIDElementCookieKey
)
275 void wxHIDDevice::AddCookieInQueue(CFTypeRef Data
, int i
)
278 wxVERIFY((*m_ppQueue
)->addElement(m_ppQueue
, m_pCookies
[i
], 0) == S_OK
);//3rd Param flags (none yet)
281 void wxHIDDevice::InitCookies(size_t dwSize
, bool bQueue
)
283 m_pCookies
= new IOHIDElementCookie
[dwSize
];
286 wxASSERT( m_ppQueue
== NULL
);
287 wxVERIFY( (m_ppQueue
= (*m_ppDevice
)->allocQueue(m_ppDevice
)) != NULL
);
288 wxVERIFY( (*m_ppQueue
)->create(m_ppQueue
, 0, 512) == S_OK
); //Param 2, flags, none yet
292 bool wxHIDDevice::IsActive(int nIndex
)
294 wxASSERT(m_pCookies
[nIndex
] != NULL
);
295 IOHIDEventStruct Event
;
296 (*m_ppDevice
)->getElementValue(m_ppDevice
, m_pCookies
[nIndex
], &Event
);
297 return !!Event
.value
;
300 bool wxHIDDevice::HasElement(int nIndex
)
302 return m_pCookies
[nIndex
] != NULL
;
305 wxHIDDevice::~wxHIDDevice()
307 if (m_ppDevice
!= NULL
)
309 if (m_ppQueue
!= NULL
)
311 (*m_ppQueue
)->stop(m_ppQueue
);
312 (*m_ppQueue
)->dispose(m_ppQueue
);
313 (*m_ppQueue
)->Release(m_ppQueue
);
315 (*m_ppDevice
)->close(m_ppDevice
);
316 (*m_ppDevice
)->Release(m_ppDevice
);
317 mach_port_deallocate(mach_task_self(), m_pPort
);
320 if (m_pCookies
!= NULL
)
322 delete [] m_pCookies
;
326 // ---------------------------------------------------------------------------
328 // ---------------------------------------------------------------------------
339 bool wxHIDKeyboard::Create()
341 return wxHIDDevice::Create(kHIDPage_GenericDesktop
, kHIDUsage_GD_Keyboard
);
344 void wxHIDKeyboard::BuildCookies(wxCFArray
& Array
)
346 Array
= CFDictionaryGetValue((CFDictionaryRef
)Array
[0], CFSTR(kIOHIDElementKey
));
350 for (i
= 0; i
< Array
.GetCount(); ++i
)
353 (CFNumberRef
) CFDictionaryGetValue((CFDictionaryRef
) Array
[i
], CFSTR(kIOHIDElementUsageKey
)),
354 kCFNumberLongType
, &nUsage
);
356 if (nUsage
>= kHIDUsage_KeyboardA
&& nUsage
<= kHIDUsage_KeyboardZ
)
357 AddCookie(Array
[i
], 'A' + (nUsage
- kHIDUsage_KeyboardA
) );
358 else if (nUsage
>= kHIDUsage_Keyboard1
&& nUsage
<= kHIDUsage_Keyboard9
)
359 AddCookie(Array
[i
], '1' + (nUsage
- kHIDUsage_Keyboard1
) );
360 else if (nUsage
>= kHIDUsage_KeyboardF1
&& nUsage
<= kHIDUsage_KeyboardF12
)
361 AddCookie(Array
[i
], WXK_F1
+ (nUsage
- kHIDUsage_KeyboardF1
) );
362 else if (nUsage
>= kHIDUsage_KeyboardF13
&& nUsage
<= kHIDUsage_KeyboardF24
)
363 AddCookie(Array
[i
], WXK_F13
+ (nUsage
- kHIDUsage_KeyboardF13
) );
364 else if (nUsage
>= kHIDUsage_Keypad1
&& nUsage
<= kHIDUsage_Keypad9
)
365 AddCookie(Array
[i
], WXK_NUMPAD1
+ (nUsage
- kHIDUsage_Keypad1
) );
368 //0's (wx & ascii go 0-9, but HID goes 1-0)
369 case kHIDUsage_Keyboard0
:
370 AddCookie(Array
[i
],'0');
372 case kHIDUsage_Keypad0
:
373 AddCookie(Array
[i
],WXK_NUMPAD0
);
377 case kHIDUsage_KeyboardReturnOrEnter
:
378 AddCookie(Array
[i
], WXK_RETURN
);
380 case kHIDUsage_KeyboardEscape
:
381 AddCookie(Array
[i
], WXK_ESCAPE
);
383 case kHIDUsage_KeyboardDeleteOrBackspace
:
384 AddCookie(Array
[i
], WXK_BACK
);
386 case kHIDUsage_KeyboardTab
:
387 AddCookie(Array
[i
], WXK_TAB
);
389 case kHIDUsage_KeyboardSpacebar
:
390 AddCookie(Array
[i
], WXK_SPACE
);
392 case kHIDUsage_KeyboardPageUp
:
393 AddCookie(Array
[i
], WXK_PRIOR
);
395 case kHIDUsage_KeyboardEnd
:
396 AddCookie(Array
[i
], WXK_END
);
398 case kHIDUsage_KeyboardPageDown
:
399 AddCookie(Array
[i
], WXK_NEXT
);
401 case kHIDUsage_KeyboardRightArrow
:
402 AddCookie(Array
[i
], WXK_RIGHT
);
404 case kHIDUsage_KeyboardLeftArrow
:
405 AddCookie(Array
[i
], WXK_LEFT
);
407 case kHIDUsage_KeyboardDownArrow
:
408 AddCookie(Array
[i
], WXK_DOWN
);
410 case kHIDUsage_KeyboardUpArrow
:
411 AddCookie(Array
[i
], WXK_UP
);
415 case kHIDUsage_KeyboardCapsLock
:
416 AddCookie(Array
[i
],WXK_CAPITAL
);
418 case kHIDUsage_KeypadNumLock
:
419 AddCookie(Array
[i
],WXK_NUMLOCK
);
421 case kHIDUsage_KeyboardScrollLock
:
422 AddCookie(Array
[i
],WXK_SCROLL
);
425 //Menu keys, Shift, other specials
426 case kHIDUsage_KeyboardLeftControl
:
427 AddCookie(Array
[i
],WXK_CONTROL
);
429 case kHIDUsage_KeyboardLeftShift
:
430 AddCookie(Array
[i
],WXK_SHIFT
);
432 case kHIDUsage_KeyboardLeftAlt
:
433 AddCookie(Array
[i
],WXK_ALT
);
435 case kHIDUsage_KeyboardLeftGUI
:
436 AddCookie(Array
[i
],WXK_MENU
);
438 case kHIDUsage_KeyboardRightControl
:
439 AddCookie(Array
[i
],WXK_RCONTROL
);
441 case kHIDUsage_KeyboardRightShift
:
442 AddCookie(Array
[i
],WXK_RSHIFT
);
444 case kHIDUsage_KeyboardRightAlt
:
445 AddCookie(Array
[i
],WXK_RALT
);
447 case kHIDUsage_KeyboardRightGUI
:
448 AddCookie(Array
[i
],WXK_RMENU
);
453 //not in wx keycodes - do nothing....
463 #include "wx/utils.h"
464 #include "wx/module.h"
466 class wxHIDModule
: public wxModule
468 DECLARE_DYNAMIC_CLASS(wxHIDModule
)
471 static wxHIDKeyboard
* sm_keyboard
;
473 virtual bool OnInit()
478 virtual void OnExit()
485 IMPLEMENT_DYNAMIC_CLASS(wxHIDModule
, wxModule
)
487 wxHIDKeyboard
* wxHIDModule::sm_keyboard
;
489 bool wxGetKeyState (wxKeyCode key
)
491 wxASSERT_MSG(key
!= WXK_LBUTTON
&& key
!= WXK_RBUTTON
&& key
!=
492 WXK_MBUTTON
, wxT("can't use wxGetKeyState() for mouse buttons"));
494 if (!wxHIDModule::sm_keyboard
)
496 wxHIDModule::sm_keyboard
= new wxHIDKeyboard();
497 bool bOK
= wxHIDModule::sm_keyboard
->Create();
501 delete wxHIDModule::sm_keyboard
;
502 wxHIDModule::sm_keyboard
= NULL
;
507 return wxHIDModule::sm_keyboard
->IsActive(key
);