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"
39 // ---------------------------------------------------------------------------
41 // ---------------------------------------------------------------------------
43 #define wxFORCECHECK_MSG(arg, msg) \
47 wxLogSysError(wxString::Format(wxT("Message:%s\nHID: %s failed!"), wxT(msg), wxT(#arg)));\
51 #define wxIOCHECK(arg, msg) wxFORCECHECK_MSG(arg != kIOReturnSuccess, msg)
52 #define wxKERNCHECK(arg, msg) wxFORCECHECK_MSG(arg != KERN_SUCCESS, msg)
53 #define wxSCHECK(arg, msg) wxFORCECHECK_MSG(arg != S_OK, msg)
56 # define wxVERIFY(arg) wxASSERT(arg)
58 # define wxVERIFY(arg) arg
62 void CFShowTypeIDDescription(CFTypeRef pData)
71 CFStringGetCStringPtr(
72 CFCopyTypeIDDescription(CFGetTypeID(pData)),CFStringGetSystemEncoding()
78 // ============================================================================
80 // ============================================================================
82 // ---------------------------------------------------------------------------
84 // ---------------------------------------------------------------------------
86 bool wxHIDDevice::Create (int nClass
, int nType
, int nDev
)
88 //Create the mach port
89 wxIOCHECK(IOMasterPort(bootstrap_port
, &m_pPort
), "Could not create mach port");
91 //Dictionary that will hold first
92 //the matching dictionary for determining which kind of devices we want,
93 //then later some registry properties from an iterator (see below)
94 CFMutableDictionaryRef pDictionary
;
97 //The call to IOServiceMatching filters down the
98 //the services we want to hid services (and also eats the
99 //dictionary up for us (consumes one reference))
100 wxVERIFY((pDictionary
= IOServiceMatching(kIOHIDDeviceKey
)) != NULL
);
102 //Here we'll filter down the services to what we want
105 CFNumberRef pType
= CFNumberCreate(kCFAllocatorDefault
,
106 kCFNumberIntType
, &nType
);
107 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsageKey
), pType
);
112 CFNumberRef pClass
= CFNumberCreate(kCFAllocatorDefault
,
113 kCFNumberIntType
, &nClass
);
114 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsagePageKey
), pClass
);
118 //Now get the maching services
119 io_iterator_t pIterator
;
120 wxIOCHECK(IOServiceGetMatchingServices(m_pPort
, pDictionary
, &pIterator
), "No Matching HID Services");
121 wxASSERT(pIterator
!= 0);
123 //Now we iterate through them
125 while ( (pObject
= IOIteratorNext(pIterator
)) != 0)
130 wxVERIFY(IORegistryEntryCreateCFProperties(pObject
, &pDictionary
,
131 kCFAllocatorDefault
, kNilOptions
) == KERN_SUCCESS
);
134 wxASSERT(CFGetTypeID(CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDProductKey
))) == CFStringGetTypeID());
137 m_szName
= CFStringGetCStringPtr (
138 (CFStringRef
) CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDProductKey
)),
139 CFStringGetSystemEncoding()
142 //Create the interface (good grief - long function names!)
144 IOCFPlugInInterface
** ppPlugin
;
145 wxIOCHECK(IOCreatePlugInInterfaceForService(pObject
, kIOHIDDeviceUserClientTypeID
,
146 kIOCFPlugInInterfaceID
, &ppPlugin
, &nScore
), "");
148 //Now, the final thing we can check before we fall back to asserts
149 //(because the dtor only checks if the device is ok, so if anything
150 //fails from now on the dtor will delete the device anyway, so we can't break from this).
152 //Get the HID interface from the plugin to the mach port
153 wxSCHECK((*ppPlugin
)->QueryInterface(ppPlugin
,
154 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID
), (void**) &m_ppDevice
), "");
157 (*ppPlugin
)->Release(ppPlugin
);
159 //open the HID interface...
160 wxVERIFY((*m_ppDevice
)->open(m_ppDevice
, 0) == S_OK
);
163 //Now the hard part - in order to scan things we need "cookies" -
165 wxCFArray CookieArray
= CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDElementKey
));
166 BuildCookies(CookieArray
);
167 if (m_ppQueue
!= NULL
)
168 wxVERIFY((*m_ppQueue
)->start(m_ppQueue
) == S_OK
);
171 CFRelease(pDictionary
);
172 IOObjectRelease(pObject
);
176 IOObjectRelease(pIterator
);
181 int wxHIDDevice::GetCount (int nClass
, int nType
)
185 //Create the mach port
186 wxIOCHECK(IOMasterPort(bootstrap_port
, &m_pPort
), "Could not create mach port");
188 //Dictionary that will hold first
189 //the matching dictionary for determining which kind of devices we want,
190 //then later some registry properties from an iterator (see below)
191 CFMutableDictionaryRef pDictionary
;
193 //Create a dictionary
194 //The call to IOServiceMatching filters down the
195 //the services we want to hid services (and also eats the
196 //dictionary up for us (consumes one reference))
197 wxVERIFY((pDictionary
= IOServiceMatching(kIOHIDDeviceKey
)) != NULL
);
199 //Here we'll filter down the services to what we want
202 CFNumberRef pType
= CFNumberCreate(kCFAllocatorDefault
,
203 kCFNumberIntType
, &nType
);
204 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsageKey
), pType
);
209 CFNumberRef pClass
= CFNumberCreate(kCFAllocatorDefault
,
210 kCFNumberIntType
, &nClass
);
211 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsagePageKey
), pClass
);
215 //Now get the maching services
216 io_iterator_t pIterator
;
217 wxIOCHECK(IOServiceGetMatchingServices(m_pPort
, pDictionary
, &pIterator
), "No Matching HID Services");
218 wxASSERT(pIterator
!= 0);
220 //Now we iterate through them
225 while ( (pObject
= IOIteratorNext(pIterator
)) != 0)
229 IOObjectRelease(pIterator
);
234 void wxHIDDevice::AddCookie(CFTypeRef Data
, int i
)
237 (CFNumberRef
) CFDictionaryGetValue ( (CFDictionaryRef
) Data
238 , CFSTR(kIOHIDElementCookieKey
)
245 void wxHIDDevice::AddCookieInQueue(CFTypeRef Data
, int i
)
248 wxVERIFY((*m_ppQueue
)->addElement(m_ppQueue
, m_pCookies
[i
], 0) == S_OK
);//3rd Param flags (none yet)
251 void wxHIDDevice::InitCookies(size_t dwSize
, bool bQueue
)
253 m_pCookies
= new IOHIDElementCookie
[dwSize
];
256 wxASSERT( m_ppQueue
== NULL
);
257 wxVERIFY( (m_ppQueue
= (*m_ppDevice
)->allocQueue(m_ppDevice
)) != NULL
);
258 wxVERIFY( (*m_ppQueue
)->create(m_ppQueue
, 0, 512) == S_OK
); //Param 2, flags, none yet
262 bool wxHIDDevice::IsActive(int nIndex
)
264 wxASSERT(m_pCookies
[nIndex
] != NULL
);
265 IOHIDEventStruct Event
;
266 (*m_ppDevice
)->getElementValue(m_ppDevice
, m_pCookies
[nIndex
], &Event
);
267 return !!Event
.value
;
270 bool wxHIDDevice::HasElement(int nIndex
)
272 return m_pCookies
[nIndex
] != NULL
;
275 wxHIDDevice::~wxHIDDevice()
277 if (m_ppDevice
!= NULL
)
279 if (m_ppQueue
!= NULL
)
281 (*m_ppQueue
)->stop(m_ppQueue
);
282 (*m_ppQueue
)->dispose(m_ppQueue
);
283 (*m_ppQueue
)->Release(m_ppQueue
);
285 (*m_ppDevice
)->close(m_ppDevice
);
286 (*m_ppDevice
)->Release(m_ppDevice
);
287 mach_port_deallocate(mach_task_self(), m_pPort
);
290 if (m_pCookies
!= NULL
)
292 delete [] m_pCookies
;
296 // ---------------------------------------------------------------------------
298 // ---------------------------------------------------------------------------
309 bool wxHIDKeyboard::Create()
311 return wxHIDDevice::Create(kHIDPage_GenericDesktop
, kHIDUsage_GD_Keyboard
);
314 void wxHIDKeyboard::BuildCookies(wxCFArray
& Array
)
316 Array
= CFDictionaryGetValue((CFDictionaryRef
)Array
[0], CFSTR(kIOHIDElementKey
));
320 for (i
= 0; i
< Array
.Count(); ++i
)
323 (CFNumberRef
) CFDictionaryGetValue((CFDictionaryRef
) Array
[i
], CFSTR(kIOHIDElementUsageKey
)),
324 kCFNumberLongType
, &nUsage
);
326 if (nUsage
>= kHIDUsage_KeyboardA
&& nUsage
<= kHIDUsage_KeyboardZ
)
327 AddCookie(Array
[i
], 'A' + (nUsage
- kHIDUsage_KeyboardA
) );
328 else if (nUsage
>= kHIDUsage_Keyboard1
&& nUsage
<= kHIDUsage_Keyboard9
)
329 AddCookie(Array
[i
], '1' + (nUsage
- kHIDUsage_Keyboard1
) );
330 else if (nUsage
>= kHIDUsage_KeyboardF1
&& nUsage
<= kHIDUsage_KeyboardF12
)
331 AddCookie(Array
[i
], WXK_F1
+ (nUsage
- kHIDUsage_KeyboardF1
) );
332 else if (nUsage
>= kHIDUsage_KeyboardF13
&& nUsage
<= kHIDUsage_KeyboardF24
)
333 AddCookie(Array
[i
], WXK_F13
+ (nUsage
- kHIDUsage_KeyboardF13
) );
334 else if (nUsage
>= kHIDUsage_Keypad1
&& nUsage
<= kHIDUsage_Keypad9
)
335 AddCookie(Array
[i
], WXK_NUMPAD1
+ (nUsage
- kHIDUsage_Keypad1
) );
338 //0's (wx & ascii go 0-9, but HID goes 1-0)
339 case kHIDUsage_Keyboard0
:
340 AddCookie(Array
[i
],'0');
342 case kHIDUsage_Keypad0
:
343 AddCookie(Array
[i
],WXK_NUMPAD0
);
347 case kHIDUsage_KeyboardReturnOrEnter
:
348 AddCookie(Array
[i
], WXK_RETURN
);
350 case kHIDUsage_KeyboardEscape
:
351 AddCookie(Array
[i
], WXK_ESCAPE
);
353 case kHIDUsage_KeyboardDeleteOrBackspace
:
354 AddCookie(Array
[i
], WXK_BACK
);
356 case kHIDUsage_KeyboardTab
:
357 AddCookie(Array
[i
], WXK_TAB
);
359 case kHIDUsage_KeyboardSpacebar
:
360 AddCookie(Array
[i
], WXK_SPACE
);
362 case kHIDUsage_KeyboardPageUp
:
363 AddCookie(Array
[i
], WXK_PRIOR
);
365 case kHIDUsage_KeyboardEnd
:
366 AddCookie(Array
[i
], WXK_END
);
368 case kHIDUsage_KeyboardPageDown
:
369 AddCookie(Array
[i
], WXK_NEXT
);
371 case kHIDUsage_KeyboardRightArrow
:
372 AddCookie(Array
[i
], WXK_RIGHT
);
374 case kHIDUsage_KeyboardLeftArrow
:
375 AddCookie(Array
[i
], WXK_LEFT
);
377 case kHIDUsage_KeyboardDownArrow
:
378 AddCookie(Array
[i
], WXK_DOWN
);
380 case kHIDUsage_KeyboardUpArrow
:
381 AddCookie(Array
[i
], WXK_UP
);
385 case kHIDUsage_KeyboardCapsLock
:
386 AddCookie(Array
[i
],WXK_CAPITAL
);
388 case kHIDUsage_KeypadNumLock
:
389 AddCookie(Array
[i
],WXK_NUMLOCK
);
391 case kHIDUsage_KeyboardScrollLock
:
392 AddCookie(Array
[i
],WXK_SCROLL
);
395 //Menu keys, Shift, other specials
396 case kHIDUsage_KeyboardLeftControl
:
397 AddCookie(Array
[i
],WXK_CONTROL
);
399 case kHIDUsage_KeyboardLeftShift
:
400 AddCookie(Array
[i
],WXK_SHIFT
);
402 case kHIDUsage_KeyboardLeftAlt
:
403 AddCookie(Array
[i
],WXK_ALT
);
405 case kHIDUsage_KeyboardLeftGUI
:
406 AddCookie(Array
[i
],WXK_MENU
);
408 case kHIDUsage_KeyboardRightControl
:
409 AddCookie(Array
[i
],WXK_RCONTROL
);
411 case kHIDUsage_KeyboardRightShift
:
412 AddCookie(Array
[i
],WXK_RSHIFT
);
414 case kHIDUsage_KeyboardRightAlt
:
415 AddCookie(Array
[i
],WXK_RALT
);
417 case kHIDUsage_KeyboardRightGUI
:
418 AddCookie(Array
[i
],WXK_RMENU
);
423 //not in wx keycodes - do nothing....
433 #include "wx/utils.h"
434 #include "wx/module.h"
436 class wxHIDModule
: public wxModule
438 DECLARE_DYNAMIC_CLASS(wxHIDModule
)
441 static wxHIDKeyboard
* sm_keyboard
;
443 virtual bool OnInit()
448 virtual void OnExit()
455 IMPLEMENT_DYNAMIC_CLASS(wxHIDModule
, wxModule
)
457 wxHIDKeyboard
* wxHIDModule::sm_keyboard
;
459 bool wxGetKeyState (wxKeyCode key
)
461 if (!wxHIDModule::sm_keyboard
)
463 wxHIDModule::sm_keyboard
= new wxHIDKeyboard();
464 bool bOK
= wxHIDModule::sm_keyboard
->Create();
468 delete wxHIDModule::sm_keyboard
;
469 wxHIDModule::sm_keyboard
= NULL
;
474 return wxHIDModule::sm_keyboard
->IsActive(key
);