1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: DARWIN HID layer for WX Implementation
8 // Copyright: (c) Ryan Norton
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
17 #include "wx/mac/carbon/private/hid.h"
18 #include "wx/string.h"
21 #define wxFORCECHECK_MSG(arg, msg) \
25 wxLogSysError(wxString::Format(wxT("Message:%s\nHID: %s failed!"), wxT(msg), wxT(#arg)));\
29 #define wxIOCHECK(arg, msg) wxFORCECHECK_MSG(arg != kIOReturnSuccess, msg)
30 #define wxKERNCHECK(arg, msg) wxFORCECHECK_MSG(arg != KERN_SUCCESS, msg)
31 #define wxSCHECK(arg, msg) wxFORCECHECK_MSG(arg != S_OK, msg)
34 # define wxVERIFY(arg) wxASSERT(arg)
36 # define wxVERIFY(arg) arg
40 void CFShowTypeIDDescription(CFTypeRef pData)
49 CFStringGetCStringPtr(
50 CFCopyTypeIDDescription(CFGetTypeID(pData)),CFStringGetSystemEncoding()
56 // ============================================================================
58 // ============================================================================
61 bool wxHIDDevice::Create (const int& nClass
, const int& nType
)
63 //Create the mach port
64 wxIOCHECK(IOMasterPort(bootstrap_port
, &m_pPort
), "Could not create mach port");
66 //Dictionary that will hold first
67 //the matching dictionary for determining which kind of devices we want,
68 //then later some registry properties from an iterator (see below)
69 CFMutableDictionaryRef pDictionary
;
72 //The call to IOServiceMatching filters down the
73 //the services we want to hid services (and also eats the
74 //dictionary up for us (consumes one reference))
75 wxVERIFY((pDictionary
= IOServiceMatching(kIOHIDDeviceKey
)) != NULL
);
77 //Here we'll filter down the services to what we want
80 CFNumberRef pType
= CFNumberCreate(kCFAllocatorDefault
,
81 kCFNumberIntType
, &nType
);
82 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsageKey
), pType
);
87 CFNumberRef pClass
= CFNumberCreate(kCFAllocatorDefault
,
88 kCFNumberIntType
, &nClass
);
89 CFDictionarySetValue(pDictionary
, CFSTR(kIOHIDPrimaryUsagePageKey
), pClass
);
93 //Now get the maching services
94 io_iterator_t pIterator
;
95 wxIOCHECK(IOServiceGetMatchingServices(m_pPort
, pDictionary
, &pIterator
), "No Matching HID Services");
96 wxASSERT(pIterator
!= NULL
);
98 //Now we iterate through them
100 while ( (pObject
= IOIteratorNext(pIterator
)) != NULL
)
102 wxVERIFY(IORegistryEntryCreateCFProperties(pObject
, &pDictionary
,
103 kCFAllocatorDefault
, kNilOptions
) == KERN_SUCCESS
);
106 wxASSERT(CFGetTypeID(CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDProductKey
))) == CFStringGetTypeID());
109 m_szName
= CFStringGetCStringPtr (
110 (CFStringRef
) CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDProductKey
)),
111 CFStringGetSystemEncoding()
115 //Now the hard part - in order to scan things we need "cookies" -
117 wxCFArray CookieArray
= CFDictionaryGetValue(pDictionary
, CFSTR(kIOHIDElementKey
));
118 BuildCookies(CookieArray
);
119 if (m_ppQueue
!= NULL
)
120 wxVERIFY((*m_ppQueue
)->start(m_ppQueue
) == S_OK
);
122 //Create the interface (good grief - long function names!)
124 IOCFPlugInInterface
** ppPlugin
;
125 wxIOCHECK(IOCreatePlugInInterfaceForService(pObject
, kIOHIDDeviceUserClientTypeID
,
126 kIOCFPlugInInterfaceID
, &ppPlugin
, &nScore
), "");
128 //Now, the final thing we can check before we fall back to asserts
129 //(because the dtor only checks if the device is ok, so if anything
130 //fails from now on the dtor will delete the device anyway, so we can't break from this).
132 //Get the HID interface from the plugin to the mach port
133 wxSCHECK((*ppPlugin
)->QueryInterface(ppPlugin
,
134 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID
), (void**) &m_ppDevice
), "");
137 (*ppPlugin
)->Release(ppPlugin
);
139 //open the HID interface...
140 wxVERIFY((*m_ppDevice
)->open(m_ppDevice
, 0) == S_OK
);
143 CFRelease(pDictionary
);
144 IOObjectRelease(pObject
);
148 IOObjectRelease(pIterator
);
153 void wxHIDDevice::AddCookie(CFTypeRef Data
, const int& i
)
156 (CFNumberRef
) CFDictionaryGetValue ( (CFDictionaryRef
) Data
157 , CFSTR(kIOHIDElementCookieKey
)
164 void wxHIDDevice::AddCookieInQueue(CFTypeRef Data
, const int& i
)
167 wxVERIFY((*m_ppQueue
)->addElement(m_ppQueue
, m_pCookies
[i
], 0) == S_OK
);//3rd Param flags (none yet)
170 void wxHIDDevice::InitCookies(const size_t& dwSize
, bool bQueue
)
172 m_pCookies
= new IOHIDElementCookie
[dwSize
];
175 wxASSERT( m_ppQueue
!= NULL
);
176 wxVERIFY( (m_ppQueue
= (*m_ppDevice
)->allocQueue(m_ppDevice
)) != NULL
);
177 wxVERIFY( (*m_ppQueue
)->create(m_ppQueue
, 0, 512) == S_OK
); //Param 2, flags, none yet
181 bool wxHIDDevice::IsActive(const int& nIndex
)
183 wxASSERT(m_pCookies
[nIndex
] != NULL
);
184 IOHIDEventStruct Event
;
185 (*m_ppDevice
)->getElementValue(m_ppDevice
, m_pCookies
[nIndex
], &Event
);
186 return !!Event
.value
;
190 wxHIDDevice::~wxHIDDevice()
192 if (m_ppDevice
!= NULL
)
194 (*m_ppDevice
)->close(m_ppDevice
);
195 (*m_ppDevice
)->Release(m_ppDevice
);
196 mach_port_deallocate(mach_task_self(), m_pPort
);
199 if (m_pCookies
!= NULL
)
201 delete [] m_pCookies
;
202 if (m_ppQueue
!= NULL
)
204 (*m_ppQueue
)->stop(m_ppQueue
);
205 (*m_ppQueue
)->dispose(m_ppQueue
);
206 (*m_ppQueue
)->Release(m_ppQueue
);
213 kHIDUsage_KeyboardHyphen = 0x2D,
214 kHIDUsage_KeyboardEqualSign = 0x2E,
215 kHIDUsage_KeyboardOpenBracket = 0x2F,
216 kHIDUsage_KeyboardCloseBracket = 0x30,
217 kHIDUsage_KeyboardBackslash = 0x31, // \ or | *
218 kHIDUsage_KeyboardNonUSPound = 0x32, / Non-US # or _ *
219 kHIDUsage_KeyboardSemicolon = 0x33, / ; or : *
220 kHIDUsage_KeyboardQuote = 0x34, / ' or " *
221 kHIDUsage_KeyboardGraveAccentAndTilde = 0x35, / Grave Accent and Tilde *
222 kHIDUsage_KeyboardComma = 0x36, / , or < *
223 kHIDUsage_KeyboardPeriod = 0x37, / . or > *
224 kHIDUsage_KeyboardSlash = 0x38, / / or ? *
225 kHIDUsage_KeyboardCapsLock = 0x39, / Caps Lock *
227 kHIDUsage_KeyboardPrintScreen = 0x46, / Print Screen *
228 kHIDUsage_KeyboardScrollLock = 0x47, / Scroll Lock *
229 kHIDUsage_KeyboardPause = 0x48, / Pause *
230 kHIDUsage_KeyboardInsert = 0x49, / Insert *
231 kHIDUsage_KeyboardHome = 0x4A, / Home *
232 kHIDUsage_KeyboardDeleteForward = 0x4C, / Delete Forward *
234 kHIDUsage_KeyboardUpArrow
235 kHIDUsage_KeypadNumLock
236 kHIDUsage_KeypadSlash
237 kHIDUsage_KeypadAsterisk
238 kHIDUsage_KeypadHyphen
240 kHIDUsage_KeypadEnter
241 kHIDUsage_KeypadPeriod
242 kHIDUsage_KeyboardNonUSBackslash
243 kHIDUsage_KeyboardApplication
244 kHIDUsage_KeyboardPower
245 kHIDUsage_KeypadEqualSign
261 WXK_PRIOR, * Page up *
262 WXK_NEXT, * Page down *
303 WXK_NUMPAD_SEPARATOR,
324 bool wxHIDKeyboard::Create()
326 return wxHIDDevice::Create(kHIDPage_GenericDesktop
, kHIDUsage_GD_Keyboard
);
329 void wxHIDKeyboard::BuildCookies(wxCFArray
& Array
)
331 Array
= CFDictionaryGetValue((CFDictionaryRef
)Array
[0], CFSTR(kIOHIDElementKey
));
335 for (i
= 0; i
< Array
.Count(); ++i
)
338 (CFNumberRef
) CFDictionaryGetValue((CFDictionaryRef
) Array
[i
], CFSTR(kIOHIDElementUsageKey
)),
339 kCFNumberLongType
, &nUsage
);
341 if (nUsage
>= kHIDUsage_KeyboardA
&& nUsage
<= kHIDUsage_KeyboardZ
)
342 AddCookie(Array
[i
], 'A' + (nUsage
- kHIDUsage_KeyboardA
) );
343 else if (nUsage
>= kHIDUsage_Keyboard1
&& nUsage
<= kHIDUsage_Keyboard9
)
344 AddCookie(Array
[i
], '1' + (nUsage
- kHIDUsage_Keyboard1
) );
345 else if (nUsage
>= kHIDUsage_KeyboardF1
&& nUsage
<= kHIDUsage_KeyboardF12
)
346 AddCookie(Array
[i
], WXK_F1
+ (nUsage
- kHIDUsage_KeyboardF1
) );
347 else if (nUsage
>= kHIDUsage_KeyboardF13
&& nUsage
<= kHIDUsage_KeyboardF24
)
348 AddCookie(Array
[i
], WXK_F13
+ (nUsage
- kHIDUsage_KeyboardF13
) );
349 else if (nUsage
>= kHIDUsage_Keypad1
&& nUsage
<= kHIDUsage_Keypad9
)
350 AddCookie(Array
[i
], WXK_NUMPAD1
+ (nUsage
- kHIDUsage_Keypad1
) );
353 //0's (wx & ascii go 0-9, but HID goes 1-0)
354 case kHIDUsage_Keyboard0
:
355 AddCookie(Array
[i
],'0');
357 case kHIDUsage_Keypad0
:
358 AddCookie(Array
[i
],WXK_NUMPAD0
);
362 case kHIDUsage_KeyboardReturnOrEnter
:
363 AddCookie(Array
[i
], WXK_RETURN
);
365 case kHIDUsage_KeyboardEscape
:
366 AddCookie(Array
[i
], WXK_ESCAPE
);
368 case kHIDUsage_KeyboardDeleteOrBackspace
:
369 AddCookie(Array
[i
], WXK_BACK
);
371 case kHIDUsage_KeyboardTab
:
372 AddCookie(Array
[i
], WXK_TAB
);
374 case kHIDUsage_KeyboardSpacebar
:
375 AddCookie(Array
[i
], WXK_SPACE
);
377 case kHIDUsage_KeyboardPageUp
:
378 AddCookie(Array
[i
], WXK_PRIOR
);
380 case kHIDUsage_KeyboardEnd
:
381 AddCookie(Array
[i
], WXK_END
);
383 case kHIDUsage_KeyboardPageDown
:
384 AddCookie(Array
[i
], WXK_NEXT
);
386 case kHIDUsage_KeyboardRightArrow
:
387 AddCookie(Array
[i
], WXK_RIGHT
);
389 case kHIDUsage_KeyboardLeftArrow
:
390 AddCookie(Array
[i
], WXK_LEFT
);
392 case kHIDUsage_KeyboardDownArrow
:
393 AddCookie(Array
[i
], WXK_DOWN
);
395 case kHIDUsage_KeyboardUpArrow
:
396 AddCookie(Array
[i
], WXK_UP
);
400 case kHIDUsage_KeyboardCapsLock
:
401 AddCookie(Array
[i
],WXK_CAPITAL
);
403 case kHIDUsage_KeypadNumLock
:
404 AddCookie(Array
[i
],WXK_NUMLOCK
);
406 case kHIDUsage_KeyboardScrollLock
:
407 AddCookie(Array
[i
],WXK_SCROLL
);
410 //Menu keys, Shift, other specials
411 case kHIDUsage_KeyboardLeftControl
:
412 AddCookie(Array
[i
],WXK_CONTROL
);
414 case kHIDUsage_KeyboardLeftShift
:
415 AddCookie(Array
[i
],WXK_SHIFT
);
417 case kHIDUsage_KeyboardLeftAlt
:
418 AddCookie(Array
[i
],WXK_ALT
);
420 case kHIDUsage_KeyboardLeftGUI
:
421 AddCookie(Array
[i
],WXK_MENU
);
423 case kHIDUsage_KeyboardRightControl
:
424 AddCookie(Array
[i
],WXK_RCONTROL
);
426 case kHIDUsage_KeyboardRightShift
:
427 AddCookie(Array
[i
],WXK_RSHIFT
);
429 case kHIDUsage_KeyboardRightAlt
:
430 AddCookie(Array
[i
],WXK_RALT
);
432 case kHIDUsage_KeyboardRightGUI
:
433 AddCookie(Array
[i
],WXK_RMENU
);
438 //not in wx keycodes - do nothing....