]> git.saurik.com Git - wxWidgets.git/blame - src/mac/corefoundation/hid.cpp
default implementations for Replace and Remove
[wxWidgets.git] / src / mac / corefoundation / hid.cpp
CommitLineData
ec8bd392
RN
1/////////////////////////////////////////////////////////////////////////////
2// Name: hid.cpp
3// Purpose: DARWIN HID layer for WX Implementation
4// Author: Ryan Norton
5// Modified by:
6// Created: 11/11/2003
7// RCS-ID: $Id$
8// Copyright: (c) Ryan Norton
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
1553abf4
RN
12// ===========================================================================
13// declarations
14// ===========================================================================
15
16// ---------------------------------------------------------------------------
17// headers
18// ---------------------------------------------------------------------------
19
1553abf4
RN
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
ec8bd392
RN
27//DARWIN _ONLY_
28#ifdef __DARWIN__
29
4cb1d3da 30#include "wx/mac/corefoundation/hid.h"
ec8bd392
RN
31#include "wx/string.h"
32#include "wx/log.h"
65442ab6 33#include "wx/mac/corefoundation/cfstring.h"
7f71c4c8 34
1553abf4
RN
35
36// ---------------------------------------------------------------------------
37// assertion macros
38// ---------------------------------------------------------------------------
39
7f71c4c8
RN
40#define wxFORCECHECK_MSG(arg, msg) \
41{\
26dfc728
VZ
42 if (arg) \
43 {\
44 wxLogSysError(wxString::Format(wxT("Message:%s\nHID: %s failed!"), wxT(msg), wxT(#arg)));\
45 return false;\
46 }\
7f71c4c8
RN
47}
48#define wxIOCHECK(arg, msg) wxFORCECHECK_MSG(arg != kIOReturnSuccess, msg)
49#define wxKERNCHECK(arg, msg) wxFORCECHECK_MSG(arg != KERN_SUCCESS, msg)
50#define wxSCHECK(arg, msg) wxFORCECHECK_MSG(arg != S_OK, msg)
51
ec8bd392 52/*
7f71c4c8
RN
53void CFShowTypeIDDescription(CFTypeRef pData)
54{
26dfc728
VZ
55 if(!pData)
56 {
57 wxASSERT(false);
58 return;
59 }
60
61 wxMessageBox(
62 CFStringGetCStringPtr(
63 CFCopyTypeIDDescription(CFGetTypeID(pData)),CFStringGetSystemEncoding()
64 )
65 );
7f71c4c8 66}
ec8bd392 67*/
7f71c4c8
RN
68
69// ============================================================================
70// implementation
71// ============================================================================
72
1553abf4
RN
73// ---------------------------------------------------------------------------
74// wxHIDDevice
75// ---------------------------------------------------------------------------
7f71c4c8 76
4cb1d3da 77bool wxHIDDevice::Create (int nClass, int nType, int nDev)
7f71c4c8 78{
26dfc728
VZ
79 //Create the mach port
80 wxIOCHECK(IOMasterPort(bootstrap_port, &m_pPort), "Could not create mach port");
81
82 //Dictionary that will hold first
83 //the matching dictionary for determining which kind of devices we want,
84 //then later some registry properties from an iterator (see below)
a8ee8060 85 //
26dfc728
VZ
86 //The call to IOServiceMatching filters down the
87 //the services we want to hid services (and also eats the
88 //dictionary up for us (consumes one reference))
a8ee8060
VZ
89 CFMutableDictionaryRef pDictionary = IOServiceMatching(kIOHIDDeviceKey);
90 wxCHECK_MSG( pDictionary, false,
91 _T("IOServiceMatching(kIOHIDDeviceKey) failed") );
92
93 wxASSERT( pDictionary );
26dfc728
VZ
94
95 //Here we'll filter down the services to what we want
96 if (nType != -1)
97 {
98 CFNumberRef pType = CFNumberCreate(kCFAllocatorDefault,
99 kCFNumberIntType, &nType);
100 CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsageKey), pType);
101 CFRelease(pType);
102 }
103 if (nClass != -1)
104 {
105 CFNumberRef pClass = CFNumberCreate(kCFAllocatorDefault,
106 kCFNumberIntType, &nClass);
107 CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsagePageKey), pClass);
108 CFRelease(pClass);
109 }
110
111 //Now get the maching services
112 io_iterator_t pIterator;
113 wxIOCHECK(IOServiceGetMatchingServices(m_pPort, pDictionary, &pIterator), "No Matching HID Services");
ce0d1032
SC
114 if(pIterator == 0)
115 return false; // No devices found
26dfc728
VZ
116
117 //Now we iterate through them
118 io_object_t pObject;
119 while ( (pObject = IOIteratorNext(pIterator)) != 0)
120 {
4cb1d3da
RN
121 if(--nDev != 0)
122 continue;
7f71c4c8 123
a8ee8060
VZ
124 if ( IORegistryEntryCreateCFProperties
125 (
126 pObject,
127 &pDictionary,
128 kCFAllocatorDefault,
129 kNilOptions
130 ) != KERN_SUCCESS )
131 {
132 wxLogDebug(_T("IORegistryEntryCreateCFProperties failed"));
133 }
26dfc728
VZ
134
135 //Just for sanity :)
136 wxASSERT(CFGetTypeID(CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductKey))) == CFStringGetTypeID());
137
65442ab6
RN
138/*
139 kIOHIDTransportKey;
140 kIOHIDVendorIDKey;
141 kIOHIDProductIDKey;
142 kIOHIDVersionNumberKey;
143 kIOHIDManufacturerKey;
144 kIOHIDSerialNumberKey;
145 if !kIOHIDLocationIDKey
146 kUSBDevicePropertyLocationID
147 kIOHIDPrimaryUsageKey
148kIOHIDPrimaryUsagePageKey
149idProduct
150idVendor
151USB Product Name
152*/
26dfc728
VZ
153 //Get [product] name
154 m_szProductName = wxMacCFStringHolder( (CFStringRef) CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductKey)), false ).AsString();
155
2ff29ddf 156 CFNumberRef nref = (CFNumberRef) CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductIDKey));
26dfc728 157
2ff29ddf
RN
158 if (nref)
159 CFNumberGetValue(
26dfc728
VZ
160 nref,
161 kCFNumberIntType,
65442ab6 162 &m_nProductId
26dfc728 163 );
65442ab6 164
2ff29ddf
RN
165 nref = (CFNumberRef) CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDVendorIDKey));
166 if (nref)
26dfc728
VZ
167 CFNumberGetValue(
168 nref,
169 kCFNumberIntType,
65442ab6 170 &m_nManufacturerId
26dfc728
VZ
171 );
172
173 //Create the interface (good grief - long function names!)
174 SInt32 nScore;
175 IOCFPlugInInterface** ppPlugin;
176 wxIOCHECK(IOCreatePlugInInterfaceForService(pObject, kIOHIDDeviceUserClientTypeID,
177 kIOCFPlugInInterfaceID, &ppPlugin, &nScore), "");
178
179 //Now, the final thing we can check before we fall back to asserts
180 //(because the dtor only checks if the device is ok, so if anything
181 //fails from now on the dtor will delete the device anyway, so we can't break from this).
182
183 //Get the HID interface from the plugin to the mach port
184 wxSCHECK((*ppPlugin)->QueryInterface(ppPlugin,
185 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (void**) &m_ppDevice), "");
186
187 //release the plugin
188 (*ppPlugin)->Release(ppPlugin);
189
190 //open the HID interface...
a8ee8060
VZ
191 if ( (*m_ppDevice)->open(m_ppDevice, 0) != S_OK )
192 wxLogDebug(_T("HID device: open failed"));
26dfc728
VZ
193
194 //
195 //Now the hard part - in order to scan things we need "cookies" -
196 //
197 wxCFArray CookieArray = CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDElementKey));
198 BuildCookies(CookieArray);
199
200 //cleanup
201 CFRelease(pDictionary);
202 IOObjectRelease(pObject);
203 break;
204 }
205 //iterator cleanup
206 IOObjectRelease(pIterator);
207
208 return true;
7f71c4c8 209}//end Create()
26dfc728 210
4cb1d3da
RN
211int wxHIDDevice::GetCount (int nClass, int nType)
212{
26dfc728
VZ
213 mach_port_t m_pPort;
214
215 //Create the mach port
216 wxIOCHECK(IOMasterPort(bootstrap_port, &m_pPort), "Could not create mach port");
217
218 //Dictionary that will hold first
219 //the matching dictionary for determining which kind of devices we want,
220 //then later some registry properties from an iterator (see below)
a8ee8060
VZ
221 CFMutableDictionaryRef pDictionary = IOServiceMatching(kIOHIDDeviceKey);
222 wxCHECK_MSG( pDictionary, 0,
223 _T("IOServiceMatching(kIOHIDDeviceKey) failed") );
26dfc728
VZ
224
225 //Here we'll filter down the services to what we want
226 if (nType != -1)
227 {
228 CFNumberRef pType = CFNumberCreate(kCFAllocatorDefault,
229 kCFNumberIntType, &nType);
230 CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsageKey), pType);
231 CFRelease(pType);
232 }
233 if (nClass != -1)
234 {
235 CFNumberRef pClass = CFNumberCreate(kCFAllocatorDefault,
236 kCFNumberIntType, &nClass);
237 CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsagePageKey), pClass);
238 CFRelease(pClass);
239 }
240
241 //Now get the maching services
242 io_iterator_t pIterator;
243 wxIOCHECK(IOServiceGetMatchingServices(m_pPort, pDictionary, &pIterator), "No Matching HID Services");
244
a8ee8060 245 if ( !pIterator )
65442ab6 246 return 0;
4cb1d3da 247
26dfc728
VZ
248 //Now we iterate through them
249 io_object_t pObject;
250
4cb1d3da 251 int nCount = 0;
26dfc728
VZ
252
253 while ( (pObject = IOIteratorNext(pIterator)) != 0)
4cb1d3da 254 ++nCount;
26dfc728 255
4cb1d3da 256 //iterator cleanup
26dfc728
VZ
257 IOObjectRelease(pIterator);
258
259 return nCount;
4cb1d3da
RN
260}//end Create()
261
262void wxHIDDevice::AddCookie(CFTypeRef Data, int i)
7f71c4c8 263{
26dfc728
VZ
264 CFNumberGetValue(
265 (CFNumberRef) CFDictionaryGetValue ( (CFDictionaryRef) Data
266 , CFSTR(kIOHIDElementCookieKey)
267 ),
268 kCFNumberIntType,
269 &m_pCookies[i]
270 );
7f71c4c8
RN
271}
272
4cb1d3da 273void wxHIDDevice::AddCookieInQueue(CFTypeRef Data, int i)
7f71c4c8 274{
a8ee8060 275 //3rd Param flags (none yet)
26dfc728 276 AddCookie(Data, i);
a8ee8060
VZ
277 if ( (*m_ppQueue)->addElement(m_ppQueue, m_pCookies[i], 0) != S_OK )
278 wxLogDebug(_T("HID device: adding element failed"));
7f71c4c8 279}
26dfc728 280
4cb1d3da 281void wxHIDDevice::InitCookies(size_t dwSize, bool bQueue)
7f71c4c8 282{
26dfc728
VZ
283 m_pCookies = new IOHIDElementCookie[dwSize];
284 if (bQueue)
285 {
286 wxASSERT( m_ppQueue == NULL);
a8ee8060
VZ
287 m_ppQueue = (*m_ppDevice)->allocQueue(m_ppDevice);
288 if ( !m_ppQueue )
289 {
290 wxLogDebug(_T("HID device: allocQueue failed"));
291 return;
292 }
293
294 //Param 2, flags, none yet
295 if ( (*m_ppQueue)->create(m_ppQueue, 0, 512) != S_OK )
296 {
297 wxLogDebug(_T("HID device: create failed"));
298 }
26dfc728 299 }
7f71c4c8
RN
300}
301
4cb1d3da 302bool wxHIDDevice::IsActive(int nIndex)
7f71c4c8 303{
26dfc728
VZ
304 wxASSERT(m_pCookies[nIndex] != NULL);
305 IOHIDEventStruct Event;
306 (*m_ppDevice)->getElementValue(m_ppDevice, m_pCookies[nIndex], &Event);
09d27083
RN
307/*
308 wxString ss;
309 ss << _T("[") << (int) m_pCookies[nIndex] << _T("] = ") << Event.value << _T(" SIZE:") << Event.longValueSize;
26dfc728 310
09d27083
RN
311 wxLogDebug(ss);
312*/
26dfc728 313 return !!Event.value;
7f71c4c8 314}
26dfc728 315
4cb1d3da
RN
316bool wxHIDDevice::HasElement(int nIndex)
317{
318 return m_pCookies[nIndex] != NULL;
319}
7f71c4c8
RN
320
321wxHIDDevice::~wxHIDDevice()
322{
26dfc728
VZ
323 if (m_ppDevice != NULL)
324 {
325 if (m_ppQueue != NULL)
326 {
327 (*m_ppQueue)->stop(m_ppQueue);
328 (*m_ppQueue)->dispose(m_ppQueue);
329 (*m_ppQueue)->Release(m_ppQueue);
330 }
331 (*m_ppDevice)->close(m_ppDevice);
332 (*m_ppDevice)->Release(m_ppDevice);
333 mach_port_deallocate(mach_task_self(), m_pPort);
334 }
335
336 if (m_pCookies != NULL)
337 {
338 delete [] m_pCookies;
339 }
7f71c4c8 340}
7f71c4c8 341
1553abf4
RN
342// ---------------------------------------------------------------------------
343// wxHIDKeyboard
344// ---------------------------------------------------------------------------
345
7f71c4c8
RN
346enum
347{
26dfc728
VZ
348 WXK_RSHIFT = 400,
349 WXK_RALT,
350 WXK_RCONTROL,
351 WXK_RMENU
352
7f71c4c8
RN
353};
354
355bool wxHIDKeyboard::Create()
356{
26dfc728 357 return wxHIDDevice::Create(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard);
7f71c4c8
RN
358}
359
360void wxHIDKeyboard::BuildCookies(wxCFArray& Array)
361{
26dfc728
VZ
362 Array = CFDictionaryGetValue((CFDictionaryRef)Array[0], CFSTR(kIOHIDElementKey));
363 InitCookies(500);
364 int i,
365 nUsage;
09d27083 366 bool bEOTriggered = false;
26dfc728
VZ
367 for (i = 0; i < Array.Count(); ++i)
368 {
369 CFNumberGetValue(
370 (CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) Array[i], CFSTR(kIOHIDElementUsageKey)),
371 kCFNumberLongType, &nUsage);
372
09d27083 373 //
26dfc728 374 // OK, this is strange - basically this kind of strange -
09d27083
RN
375 // Starting from 0xEO these elements (like shift) appear twice in
376 // the array! The ones at the end are bogus I guess - the funny part
377 // is that besides the fact that the ones at the front have a Unit
378 // and UnitExponent key with a value of 0 and a different cookie value,
26dfc728 379 // there is no discernable difference between the two...
09d27083
RN
380 //
381 // Will the real shift please stand up?
382 //
383 // Something to spend a support request on, if I had one, LOL.
384 //
385 if(nUsage == 0xE0)
386 {
387 if(bEOTriggered)
388 break;
389 bEOTriggered = true;
390 }
391/*
392 wxString msg;
393 int cookie;
26dfc728
VZ
394 CFNumberGetValue(
395 (CFNumberRef) CFDictionaryGetValue ( (CFDictionaryRef) Array[i]
396 , CFSTR(kIOHIDElementCookieKey)
397 ),
398 kCFNumberIntType,
399 &cookie
400 );
09d27083
RN
401
402 msg << wxT("KEY:") << nUsage << wxT("COOKIE:") << cookie;
26dfc728 403 wxLogDebug(msg);
09d27083
RN
404*/
405
26dfc728
VZ
406 if (nUsage >= kHIDUsage_KeyboardA && nUsage <= kHIDUsage_KeyboardZ)
407 AddCookie(Array[i], 'A' + (nUsage - kHIDUsage_KeyboardA) );
408 else if (nUsage >= kHIDUsage_Keyboard1 && nUsage <= kHIDUsage_Keyboard9)
409 AddCookie(Array[i], '1' + (nUsage - kHIDUsage_Keyboard1) );
410 else if (nUsage >= kHIDUsage_KeyboardF1 && nUsage <= kHIDUsage_KeyboardF12)
411 AddCookie(Array[i], WXK_F1 + (nUsage - kHIDUsage_KeyboardF1) );
412 else if (nUsage >= kHIDUsage_KeyboardF13 && nUsage <= kHIDUsage_KeyboardF24)
413 AddCookie(Array[i], WXK_F13 + (nUsage - kHIDUsage_KeyboardF13) );
414 else if (nUsage >= kHIDUsage_Keypad1 && nUsage <= kHIDUsage_Keypad9)
415 AddCookie(Array[i], WXK_NUMPAD1 + (nUsage - kHIDUsage_Keypad1) );
416 else switch (nUsage)
417 {
418 //0's (wx & ascii go 0-9, but HID goes 1-0)
419 case kHIDUsage_Keyboard0:
420 AddCookie(Array[i],'0');
421 break;
422 case kHIDUsage_Keypad0:
423 AddCookie(Array[i],WXK_NUMPAD0);
424 break;
425
426 //Basic
427 case kHIDUsage_KeyboardReturnOrEnter:
428 AddCookie(Array[i], WXK_RETURN);
429 break;
430 case kHIDUsage_KeyboardEscape:
431 AddCookie(Array[i], WXK_ESCAPE);
432 break;
433 case kHIDUsage_KeyboardDeleteOrBackspace:
434 AddCookie(Array[i], WXK_BACK);
435 break;
436 case kHIDUsage_KeyboardTab:
437 AddCookie(Array[i], WXK_TAB);
438 break;
439 case kHIDUsage_KeyboardSpacebar:
440 AddCookie(Array[i], WXK_SPACE);
441 break;
442 case kHIDUsage_KeyboardPageUp:
443 AddCookie(Array[i], WXK_PRIOR);
444 break;
445 case kHIDUsage_KeyboardEnd:
446 AddCookie(Array[i], WXK_END);
447 break;
448 case kHIDUsage_KeyboardPageDown:
449 AddCookie(Array[i], WXK_NEXT);
450 break;
451 case kHIDUsage_KeyboardRightArrow:
452 AddCookie(Array[i], WXK_RIGHT);
453 break;
454 case kHIDUsage_KeyboardLeftArrow:
455 AddCookie(Array[i], WXK_LEFT);
456 break;
457 case kHIDUsage_KeyboardDownArrow:
458 AddCookie(Array[i], WXK_DOWN);
459 break;
460 case kHIDUsage_KeyboardUpArrow:
461 AddCookie(Array[i], WXK_UP);
462 break;
463
464 //LEDS
465 case kHIDUsage_KeyboardCapsLock:
466 AddCookie(Array[i],WXK_CAPITAL);
467 break;
468 case kHIDUsage_KeypadNumLock:
469 AddCookie(Array[i],WXK_NUMLOCK);
470 break;
471 case kHIDUsage_KeyboardScrollLock:
472 AddCookie(Array[i],WXK_SCROLL);
473 break;
474
475 //Menu keys, Shift, other specials
476 case kHIDUsage_KeyboardLeftControl:
477 AddCookie(Array[i],WXK_CONTROL);
478 break;
479 case kHIDUsage_KeyboardLeftShift:
480 AddCookie(Array[i],WXK_SHIFT);
481 break;
482 case kHIDUsage_KeyboardLeftAlt:
483 AddCookie(Array[i],WXK_ALT);
484 break;
485 case kHIDUsage_KeyboardLeftGUI:
486 AddCookie(Array[i],WXK_MENU);
487 break;
488 case kHIDUsage_KeyboardRightControl:
489 AddCookie(Array[i],WXK_RCONTROL);
490 break;
491 case kHIDUsage_KeyboardRightShift:
492 AddCookie(Array[i],WXK_RSHIFT);
493 break;
494 case kHIDUsage_KeyboardRightAlt:
495 AddCookie(Array[i],WXK_RALT);
496 break;
497 case kHIDUsage_KeyboardRightGUI:
498 AddCookie(Array[i],WXK_RMENU);
499 break;
500
501 //Default
502 default:
503 //not in wx keycodes - do nothing....
504 break;
505 }
506 }
7f71c4c8 507}//end buildcookies
ec8bd392 508
4cb1d3da
RN
509//
510// wxGetKeyState
511//
512
513#include "wx/utils.h"
514#include "wx/module.h"
515
516class wxHIDModule : public wxModule
517{
518 DECLARE_DYNAMIC_CLASS(wxHIDModule)
26dfc728 519
4cb1d3da
RN
520 public:
521 static wxHIDKeyboard* sm_keyboard;
26dfc728 522
4cb1d3da
RN
523 virtual bool OnInit()
524 {
525 sm_keyboard = NULL;
526 return true;
527 }
528 virtual void OnExit()
529 {
530 if (sm_keyboard)
531 delete sm_keyboard;
532 }
533};
534
535IMPLEMENT_DYNAMIC_CLASS(wxHIDModule, wxModule)
536
537wxHIDKeyboard* wxHIDModule::sm_keyboard;
538
539bool wxGetKeyState (wxKeyCode key)
540{
44353523
VZ
541 wxASSERT_MSG(key != WXK_LBUTTON && key != WXK_RBUTTON && key !=
542 WXK_MBUTTON, wxT("can't use wxGetKeyState() for mouse buttons"));
543
4cb1d3da
RN
544 if (!wxHIDModule::sm_keyboard)
545 {
546 wxHIDModule::sm_keyboard = new wxHIDKeyboard();
547 bool bOK = wxHIDModule::sm_keyboard->Create();
548 wxASSERT(bOK);
549 if(!bOK)
550 {
551 delete wxHIDModule::sm_keyboard;
552 wxHIDModule::sm_keyboard = NULL;
553 return false;
554 }
555 }
26dfc728 556
09d27083
RN
557 switch(key)
558 {
559 case WXK_SHIFT:
560 return wxHIDModule::sm_keyboard->IsActive(WXK_SHIFT) ||
561 wxHIDModule::sm_keyboard->IsActive(WXK_RSHIFT);
562 break;
26dfc728 563 case WXK_ALT:
09d27083
RN
564 return wxHIDModule::sm_keyboard->IsActive(WXK_ALT) ||
565 wxHIDModule::sm_keyboard->IsActive(WXK_RALT);
566 break;
26dfc728 567 case WXK_CONTROL:
09d27083
RN
568 return wxHIDModule::sm_keyboard->IsActive(WXK_CONTROL) ||
569 wxHIDModule::sm_keyboard->IsActive(WXK_RCONTROL);
570 break;
26dfc728 571 case WXK_MENU:
09d27083
RN
572 return wxHIDModule::sm_keyboard->IsActive(WXK_MENU) ||
573 wxHIDModule::sm_keyboard->IsActive(WXK_RMENU);
574 break;
575 default:
576 return wxHIDModule::sm_keyboard->IsActive(key);
577 break;
578 }
4cb1d3da
RN
579}
580
ec8bd392 581#endif //__DARWIN__