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();
156 (CFNumberRef
) CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDProductIDKey
)),
163 (CFNumberRef
) CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDVendorIDKey
)),
168 //Create the interface (good grief - long function names!)
170 IOCFPlugInInterface
** ppPlugin
;
171 wxIOCHECK(IOCreatePlugInInterfaceForService(pObject
, kIOHIDDeviceUserClientTypeID
,
172 kIOCFPlugInInterfaceID
, &ppPlugin
, &nScore
), "");
174 //Now, the final thing we can check before we fall back to asserts
175 //(because the dtor only checks if the device is ok, so if anything
176 //fails from now on the dtor will delete the device anyway, so we can't break from this).
178 //Get the HID interface from the plugin to the mach port
179 wxSCHECK((*ppPlugin
)->QueryInterface(ppPlugin
,
180 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID
), (void**) &m_ppDevice
), "");
183 (*ppPlugin
)->Release(ppPlugin
);
185 //open the HID interface...
186 wxVERIFY((*m_ppDevice
)->open(m_ppDevice
, 0) == S_OK
);
189 //Now the hard part - in order to scan things we need "cookies" -
191 wxCFArray CookieArray
= CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDElementKey
));
192 BuildCookies(CookieArray
);
195 CFRelease(pDictionary
);
196 IOObjectRelease(pObject
);
200 IOObjectRelease(pIterator
);
205 int wxHIDDevice::GetCount (int nClass
, int nType
)
209 //Create the mach port
210 wxIOCHECK(IOMasterPort(bootstrap_port
, &m_pPort
), "Could not create mach port");
212 //Dictionary that will hold first
213 //the matching dictionary for determining which kind of devices we want,
214 //then later some registry properties from an iterator (see below)
215 CFMutableDictionaryRef pDictionary
;
217 //Create a dictionary
218 //The call to IOServiceMatching filters down the
219 //the services we want to hid services (and also eats the
220 //dictionary up for us (consumes one reference))
221 wxVERIFY((pDictionary
= IOServiceMatching(kIOHIDDeviceKey
)) != NULL
);
223 //Here we'll filter down the services to what we want
226 CFNumberRef pType
= CFNumberCreate(kCFAllocatorDefault
,
227 kCFNumberIntType
, &nType
);
228 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsageKey
), pType
);
233 CFNumberRef pClass
= CFNumberCreate(kCFAllocatorDefault
,
234 kCFNumberIntType
, &nClass
);
235 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsagePageKey
), pClass
);
239 //Now get the maching services
240 io_iterator_t pIterator
;
241 wxIOCHECK(IOServiceGetMatchingServices(m_pPort
, pDictionary
, &pIterator
), "No Matching HID Services");
243 if(pIterator
== NULL
)
246 //Now we iterate through them
251 while ( (pObject
= IOIteratorNext(pIterator
)) != 0)
255 IOObjectRelease(pIterator
);
260 void wxHIDDevice::AddCookie(CFTypeRef Data
, int i
)
263 (CFNumberRef
) CFDictionaryGetValue ( (CFDictionaryRef
) Data
264 , CFSTR(kIOHIDElementCookieKey
)
271 void wxHIDDevice::AddCookieInQueue(CFTypeRef Data
, int i
)
274 wxVERIFY((*m_ppQueue
)->addElement(m_ppQueue
, m_pCookies
[i
], 0) == S_OK
);//3rd Param flags (none yet)
277 void wxHIDDevice::InitCookies(size_t dwSize
, bool bQueue
)
279 m_pCookies
= new IOHIDElementCookie
[dwSize
];
282 wxASSERT( m_ppQueue
== NULL
);
283 wxVERIFY( (m_ppQueue
= (*m_ppDevice
)->allocQueue(m_ppDevice
)) != NULL
);
284 wxVERIFY( (*m_ppQueue
)->create(m_ppQueue
, 0, 512) == S_OK
); //Param 2, flags, none yet
288 bool wxHIDDevice::IsActive(int nIndex
)
290 wxASSERT(m_pCookies
[nIndex
] != NULL
);
291 IOHIDEventStruct Event
;
292 (*m_ppDevice
)->getElementValue(m_ppDevice
, m_pCookies
[nIndex
], &Event
);
293 return !!Event
.value
;
296 bool wxHIDDevice::HasElement(int nIndex
)
298 return m_pCookies
[nIndex
] != NULL
;
301 wxHIDDevice::~wxHIDDevice()
303 if (m_ppDevice
!= NULL
)
305 if (m_ppQueue
!= NULL
)
307 (*m_ppQueue
)->stop(m_ppQueue
);
308 (*m_ppQueue
)->dispose(m_ppQueue
);
309 (*m_ppQueue
)->Release(m_ppQueue
);
311 (*m_ppDevice
)->close(m_ppDevice
);
312 (*m_ppDevice
)->Release(m_ppDevice
);
313 mach_port_deallocate(mach_task_self(), m_pPort
);
316 if (m_pCookies
!= NULL
)
318 delete [] m_pCookies
;
322 // ---------------------------------------------------------------------------
324 // ---------------------------------------------------------------------------
335 bool wxHIDKeyboard::Create()
337 return wxHIDDevice::Create(kHIDPage_GenericDesktop
, kHIDUsage_GD_Keyboard
);
340 void wxHIDKeyboard::BuildCookies(wxCFArray
& Array
)
342 Array
= CFDictionaryGetValue((CFDictionaryRef
)Array
[0], CFSTR(kIOHIDElementKey
));
346 for (i
= 0; i
< Array
.Count(); ++i
)
349 (CFNumberRef
) CFDictionaryGetValue((CFDictionaryRef
) Array
[i
], CFSTR(kIOHIDElementUsageKey
)),
350 kCFNumberLongType
, &nUsage
);
352 if (nUsage
>= kHIDUsage_KeyboardA
&& nUsage
<= kHIDUsage_KeyboardZ
)
353 AddCookie(Array
[i
], 'A' + (nUsage
- kHIDUsage_KeyboardA
) );
354 else if (nUsage
>= kHIDUsage_Keyboard1
&& nUsage
<= kHIDUsage_Keyboard9
)
355 AddCookie(Array
[i
], '1' + (nUsage
- kHIDUsage_Keyboard1
) );
356 else if (nUsage
>= kHIDUsage_KeyboardF1
&& nUsage
<= kHIDUsage_KeyboardF12
)
357 AddCookie(Array
[i
], WXK_F1
+ (nUsage
- kHIDUsage_KeyboardF1
) );
358 else if (nUsage
>= kHIDUsage_KeyboardF13
&& nUsage
<= kHIDUsage_KeyboardF24
)
359 AddCookie(Array
[i
], WXK_F13
+ (nUsage
- kHIDUsage_KeyboardF13
) );
360 else if (nUsage
>= kHIDUsage_Keypad1
&& nUsage
<= kHIDUsage_Keypad9
)
361 AddCookie(Array
[i
], WXK_NUMPAD1
+ (nUsage
- kHIDUsage_Keypad1
) );
364 //0's (wx & ascii go 0-9, but HID goes 1-0)
365 case kHIDUsage_Keyboard0
:
366 AddCookie(Array
[i
],'0');
368 case kHIDUsage_Keypad0
:
369 AddCookie(Array
[i
],WXK_NUMPAD0
);
373 case kHIDUsage_KeyboardReturnOrEnter
:
374 AddCookie(Array
[i
], WXK_RETURN
);
376 case kHIDUsage_KeyboardEscape
:
377 AddCookie(Array
[i
], WXK_ESCAPE
);
379 case kHIDUsage_KeyboardDeleteOrBackspace
:
380 AddCookie(Array
[i
], WXK_BACK
);
382 case kHIDUsage_KeyboardTab
:
383 AddCookie(Array
[i
], WXK_TAB
);
385 case kHIDUsage_KeyboardSpacebar
:
386 AddCookie(Array
[i
], WXK_SPACE
);
388 case kHIDUsage_KeyboardPageUp
:
389 AddCookie(Array
[i
], WXK_PRIOR
);
391 case kHIDUsage_KeyboardEnd
:
392 AddCookie(Array
[i
], WXK_END
);
394 case kHIDUsage_KeyboardPageDown
:
395 AddCookie(Array
[i
], WXK_NEXT
);
397 case kHIDUsage_KeyboardRightArrow
:
398 AddCookie(Array
[i
], WXK_RIGHT
);
400 case kHIDUsage_KeyboardLeftArrow
:
401 AddCookie(Array
[i
], WXK_LEFT
);
403 case kHIDUsage_KeyboardDownArrow
:
404 AddCookie(Array
[i
], WXK_DOWN
);
406 case kHIDUsage_KeyboardUpArrow
:
407 AddCookie(Array
[i
], WXK_UP
);
411 case kHIDUsage_KeyboardCapsLock
:
412 AddCookie(Array
[i
],WXK_CAPITAL
);
414 case kHIDUsage_KeypadNumLock
:
415 AddCookie(Array
[i
],WXK_NUMLOCK
);
417 case kHIDUsage_KeyboardScrollLock
:
418 AddCookie(Array
[i
],WXK_SCROLL
);
421 //Menu keys, Shift, other specials
422 case kHIDUsage_KeyboardLeftControl
:
423 AddCookie(Array
[i
],WXK_CONTROL
);
425 case kHIDUsage_KeyboardLeftShift
:
426 AddCookie(Array
[i
],WXK_SHIFT
);
428 case kHIDUsage_KeyboardLeftAlt
:
429 AddCookie(Array
[i
],WXK_ALT
);
431 case kHIDUsage_KeyboardLeftGUI
:
432 AddCookie(Array
[i
],WXK_MENU
);
434 case kHIDUsage_KeyboardRightControl
:
435 AddCookie(Array
[i
],WXK_RCONTROL
);
437 case kHIDUsage_KeyboardRightShift
:
438 AddCookie(Array
[i
],WXK_RSHIFT
);
440 case kHIDUsage_KeyboardRightAlt
:
441 AddCookie(Array
[i
],WXK_RALT
);
443 case kHIDUsage_KeyboardRightGUI
:
444 AddCookie(Array
[i
],WXK_RMENU
);
449 //not in wx keycodes - do nothing....
459 #include "wx/utils.h"
460 #include "wx/module.h"
462 class wxHIDModule
: public wxModule
464 DECLARE_DYNAMIC_CLASS(wxHIDModule
)
467 static wxHIDKeyboard
* sm_keyboard
;
469 virtual bool OnInit()
474 virtual void OnExit()
481 IMPLEMENT_DYNAMIC_CLASS(wxHIDModule
, wxModule
)
483 wxHIDKeyboard
* wxHIDModule::sm_keyboard
;
485 bool wxGetKeyState (wxKeyCode key
)
487 if (!wxHIDModule::sm_keyboard
)
489 wxHIDModule::sm_keyboard
= new wxHIDKeyboard();
490 bool bOK
= wxHIDModule::sm_keyboard
->Create();
494 delete wxHIDModule::sm_keyboard
;
495 wxHIDModule::sm_keyboard
= NULL
;
500 return wxHIDModule::sm_keyboard
->IsActive(key
);