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 wxVERIFY(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
262 WXK_PRIOR, * Page up *
263 WXK_NEXT, * Page down *
304 WXK_NUMPAD_SEPARATOR,
325 bool wxHIDKeyboard::Create()
327 return wxHIDDevice::Create(kHIDPage_GenericDesktop
, kHIDUsage_GD_Keyboard
);
330 void wxHIDKeyboard::BuildCookies(wxCFArray
& Array
)
332 Array
= CFDictionaryGetValue((CFDictionaryRef
)Array
[0], CFSTR(kIOHIDElementKey
));
336 for (i
= 0; i
< Array
.Count(); ++i
)
339 (CFNumberRef
) CFDictionaryGetValue((CFDictionaryRef
) Array
[i
], CFSTR(kIOHIDElementUsageKey
)),
340 kCFNumberLongType
, &nUsage
);
342 if (nUsage
>= kHIDUsage_KeyboardA
&& nUsage
<= kHIDUsage_KeyboardZ
)
343 AddCookie(Array
[i
], 'A' + (nUsage
- kHIDUsage_KeyboardA
) );
344 else if (nUsage
>= kHIDUsage_Keyboard1
&& nUsage
<= kHIDUsage_Keyboard9
)
345 AddCookie(Array
[i
], '1' + (nUsage
- kHIDUsage_Keyboard1
) );
346 else if (nUsage
>= kHIDUsage_KeyboardF1
&& nUsage
<= kHIDUsage_KeyboardF12
)
347 AddCookie(Array
[i
], WXK_F1
+ (nUsage
- kHIDUsage_KeyboardF1
) );
348 else if (nUsage
>= kHIDUsage_KeyboardF13
&& nUsage
<= kHIDUsage_KeyboardF24
)
349 AddCookie(Array
[i
], WXK_F13
+ (nUsage
- kHIDUsage_KeyboardF13
) );
350 else if (nUsage
>= kHIDUsage_Keypad1
&& nUsage
<= kHIDUsage_Keypad9
)
351 AddCookie(Array
[i
], WXK_NUMPAD1
+ (nUsage
- kHIDUsage_Keypad1
) );
354 //0's (wx & ascii go 0-9, but HID goes 1-0)
355 case kHIDUsage_Keyboard0
:
356 AddCookie(Array
[i
],'0');
358 case kHIDUsage_Keypad0
:
359 AddCookie(Array
[i
],WXK_NUMPAD0
);
363 case kHIDUsage_KeyboardReturnOrEnter
:
364 AddCookie(Array
[i
], WXK_RETURN
);
366 case kHIDUsage_KeyboardEscape
:
367 AddCookie(Array
[i
], WXK_ESCAPE
);
369 case kHIDUsage_KeyboardDeleteOrBackspace
:
370 AddCookie(Array
[i
], WXK_BACK
);
372 case kHIDUsage_KeyboardTab
:
373 AddCookie(Array
[i
], WXK_TAB
);
375 case kHIDUsage_KeyboardSpacebar
:
376 AddCookie(Array
[i
], WXK_SPACE
);
378 case kHIDUsage_KeyboardPageUp
:
379 AddCookie(Array
[i
], WXK_PRIOR
);
381 case kHIDUsage_KeyboardEnd
:
382 AddCookie(Array
[i
], WXK_END
);
384 case kHIDUsage_KeyboardPageDown
:
385 AddCookie(Array
[i
], WXK_NEXT
);
387 case kHIDUsage_KeyboardRightArrow
:
388 AddCookie(Array
[i
], WXK_RIGHT
);
390 case kHIDUsage_KeyboardLeftArrow
:
391 AddCookie(Array
[i
], WXK_LEFT
);
393 case kHIDUsage_KeyboardDownArrow
:
394 AddCookie(Array
[i
], WXK_DOWN
);
396 case kHIDUsage_KeyboardUpArrow
:
397 AddCookie(Array
[i
], WXK_UP
);
401 case kHIDUsage_KeyboardCapsLock
:
402 AddCookie(Array
[i
],WXK_CAPITAL
);
404 case kHIDUsage_KeypadNumLock
:
405 AddCookie(Array
[i
],WXK_NUMLOCK
);
407 case kHIDUsage_KeyboardScrollLock
:
408 AddCookie(Array
[i
],WXK_SCROLL
);
411 //Menu keys, Shift, other specials
412 case kHIDUsage_KeyboardLeftControl
:
413 AddCookie(Array
[i
],WXK_CONTROL
);
415 case kHIDUsage_KeyboardLeftShift
:
416 AddCookie(Array
[i
],WXK_SHIFT
);
418 case kHIDUsage_KeyboardLeftAlt
:
419 AddCookie(Array
[i
],WXK_ALT
);
421 case kHIDUsage_KeyboardLeftGUI
:
422 AddCookie(Array
[i
],WXK_MENU
);
424 case kHIDUsage_KeyboardRightControl
:
425 AddCookie(Array
[i
],WXK_RCONTROL
);
427 case kHIDUsage_KeyboardRightShift
:
428 AddCookie(Array
[i
],WXK_RSHIFT
);
430 case kHIDUsage_KeyboardRightAlt
:
431 AddCookie(Array
[i
],WXK_RALT
);
433 case kHIDUsage_KeyboardRightGUI
:
434 AddCookie(Array
[i
],WXK_RMENU
);
439 //not in wx keycodes - do nothing....