1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/mac/corefoundation/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: hid.cpp 40943 2006-08-31 19:31:43Z ABX $
8 // Copyright:   (c) Ryan Norton
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11 
12 // ===========================================================================
13 // declarations
14 // ===========================================================================
15 
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19 
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22 
23 #ifdef __BORLANDC__
24     #pragma hdrstop
25 #endif
26 
27 //DARWIN _ONLY_
28 #ifdef __DARWIN__
29 
30 #include "wx/mac/corefoundation/hid.h"
31 
32 #ifndef WX_PRECOMP
33     #include "wx/dynarray.h"
34     #include "wx/string.h"
35     #include "wx/log.h"
36     #include "wx/utils.h"
37     #include "wx/module.h"
38 #endif
39 
40 #include "wx/mac/corefoundation/cfstring.h"
41 
42 // ============================================================================
43 // implementation
44 // ============================================================================
45 
46 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
47 //
48 // wxHIDDevice
49 //
50 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
51 
52 // ----------------------------------------------------------------------------
53 // wxHIDDevice::Create
54 //
55 //  nClass is the HID Page such as
56 //      kHIDPage_GenericDesktop
57 //  nType is the HID Usage such as
58 //      kHIDUsage_GD_Joystick,kHIDUsage_GD_Mouse,kHIDUsage_GD_Keyboard
59 //  nDev is the device number to use
60 //
61 // ----------------------------------------------------------------------------
Create(int nClass,int nType,int nDev)62 bool wxHIDDevice::Create (int nClass, int nType, int nDev)
63 {
64     //Create the mach port
65     if(IOMasterPort(bootstrap_port, &m_pPort) != kIOReturnSuccess)
66     {
67         wxLogSysError(wxT("Could not create mach port"));
68         return false;
69     }
70 
71     //Dictionary that will hold first
72     //the matching dictionary for determining which kind of devices we want,
73     //then later some registry properties from an iterator (see below)
74     //
75     //The call to IOServiceMatching filters down the
76     //the services we want to hid services (and also eats the
77     //dictionary up for us (consumes one reference))
78     CFMutableDictionaryRef pDictionary = IOServiceMatching(kIOHIDDeviceKey);
79     if(pDictionary == NULL)
80     {
81         wxLogSysError( _T("IOServiceMatching(kIOHIDDeviceKey) failed") );
82         return false;
83     }
84 
85     //Here we'll filter down the services to what we want
86     if (nType != -1)
87     {
88         CFNumberRef pType = CFNumberCreate(kCFAllocatorDefault,
89                                     kCFNumberIntType, &nType);
90         CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsageKey), pType);
91         CFRelease(pType);
92     }
93     if (nClass != -1)
94     {
95         CFNumberRef pClass = CFNumberCreate(kCFAllocatorDefault,
96                                     kCFNumberIntType, &nClass);
97         CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsagePageKey), pClass);
98         CFRelease(pClass);
99     }
100 
101     //Now get the maching services
102     io_iterator_t pIterator;
103     if( IOServiceGetMatchingServices(m_pPort,
104                         pDictionary, &pIterator) != kIOReturnSuccess )
105     {
106         wxLogSysError(_T("No Matching HID Services"));
107         return false;
108     }
109 
110     //Were there any devices matched?
111     if(pIterator == 0)
112         return false; // No devices found
113 
114     //Now we iterate through them
115     io_object_t pObject;
116     while ( (pObject = IOIteratorNext(pIterator)) != 0)
117     {
118         if(--nDev != 0)
119         {
120             IOObjectRelease(pObject);
121             continue;
122         }
123 
124         if ( IORegistryEntryCreateCFProperties
125              (
126                 pObject,
127                 &pDictionary,
128                 kCFAllocatorDefault,
129                 kNilOptions
130              ) != KERN_SUCCESS )
131         {
132             wxLogDebug(_T("IORegistryEntryCreateCFProperties failed"));
133         }
134 
135         //
136         // Now we get the attributes of each "product" in the iterator
137         //
138 
139         //Get [product] name
140         CFStringRef cfsProduct = (CFStringRef)
141             CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductKey));
142         m_szProductName =
143             wxMacCFStringHolder( cfsProduct,
144                                     false
145                                ).AsString();
146 
147         //Get the Product ID Key
148         CFNumberRef cfnProductId = (CFNumberRef)
149             CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductIDKey));
150         if (cfnProductId)
151         {
152             CFNumberGetValue(cfnProductId, kCFNumberIntType, &m_nProductId);
153         }
154 
155         //Get the Vendor ID Key
156         CFNumberRef cfnVendorId = (CFNumberRef)
157             CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDVendorIDKey));
158         if (cfnVendorId)
159         {
160             CFNumberGetValue(cfnVendorId, kCFNumberIntType, &m_nManufacturerId);
161         }
162 
163         //
164         // End attribute getting
165         //
166 
167         //Create the interface (good grief - long function names!)
168         SInt32 nScore;
169         IOCFPlugInInterface** ppPlugin;
170         if(IOCreatePlugInInterfaceForService(pObject,
171                                              kIOHIDDeviceUserClientTypeID,
172                                              kIOCFPlugInInterfaceID, &ppPlugin,
173                                              &nScore) !=  kIOReturnSuccess)
174         {
175             wxLogSysError(wxT("Could not create HID Interface for product"));
176             return false;
177         }
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         if((*ppPlugin)->QueryInterface(ppPlugin,
185                                CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
186                                (void**) &m_ppDevice) != S_OK)
187         {
188             wxLogSysError(wxT("Could not get device interface from HID interface"));
189             return false;
190         }
191 
192         //release the plugin
193         (*ppPlugin)->Release(ppPlugin);
194 
195         //open the HID interface...
196         if ( (*m_ppDevice)->open(m_ppDevice, 0) != S_OK )
197             wxLogDebug(_T("HID device: open failed"));
198 
199         //
200         //Now the hard part - in order to scan things we need "cookies"
201         //
202         CFArrayRef cfaCookies = (CFArrayRef)CFDictionaryGetValue(pDictionary,
203                                  CFSTR(kIOHIDElementKey));
204         BuildCookies(cfaCookies);
205 
206         //cleanup
207         CFRelease(pDictionary);
208         IOObjectRelease(pObject);
209 
210         //iterator cleanup
211         IOObjectRelease(pIterator);
212 
213         return true;
214     }
215 
216     //iterator cleanup
217     IOObjectRelease(pIterator);
218 
219     return false; //no device
220 }//end Create()
221 
222 // ----------------------------------------------------------------------------
223 // wxHIDDevice::GetCount [static]
224 //
225 //  Obtains the number of devices on a system for a given HID Page (nClass)
226 // and HID Usage (nType).
227 // ----------------------------------------------------------------------------
GetCount(int nClass,int nType)228 size_t wxHIDDevice::GetCount (int nClass, int nType)
229 {
230     //Create the mach port
231     mach_port_t             pPort;
232     if(IOMasterPort(bootstrap_port, &pPort) != kIOReturnSuccess)
233     {
234         wxLogSysError(wxT("Could not create mach port"));
235         return false;
236     }
237 
238     //Dictionary that will hold first
239     //the matching dictionary for determining which kind of devices we want,
240     //then later some registry properties from an iterator (see below)
241     CFMutableDictionaryRef pDictionary = IOServiceMatching(kIOHIDDeviceKey);
242     if(pDictionary == NULL)
243     {
244         wxLogSysError( _T("IOServiceMatching(kIOHIDDeviceKey) failed") );
245         return false;
246     }
247 
248     //Here we'll filter down the services to what we want
249     if (nType != -1)
250     {
251         CFNumberRef pType = CFNumberCreate(kCFAllocatorDefault,
252                                     kCFNumberIntType, &nType);
253         CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsageKey), pType);
254         CFRelease(pType);
255     }
256     if (nClass != -1)
257     {
258         CFNumberRef pClass = CFNumberCreate(kCFAllocatorDefault,
259                                     kCFNumberIntType, &nClass);
260         CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsagePageKey), pClass);
261         CFRelease(pClass);
262     }
263 
264     //Now get the maching services
265     io_iterator_t pIterator;
266     if( IOServiceGetMatchingServices(pPort,
267                                      pDictionary, &pIterator) != kIOReturnSuccess )
268     {
269         wxLogSysError(_T("No Matching HID Services"));
270         return false;
271     }
272 
273     //If the iterator doesn't exist there are no devices :)
274     if ( !pIterator )
275         return 0;
276 
277     //Now we iterate through them
278     size_t nCount = 0;
279     io_object_t pObject;
280     while ( (pObject = IOIteratorNext(pIterator)) != 0)
281     {
282         ++nCount;
283         IOObjectRelease(pObject);
284     }
285 
286     //cleanup
287     IOObjectRelease(pIterator);
288     mach_port_deallocate(mach_task_self(), pPort);
289 
290     return nCount;
291 }//end Create()
292 
293 // ----------------------------------------------------------------------------
294 // wxHIDDevice::AddCookie
295 //
296 // Adds a cookie to the internal cookie array from a CFType
297 // ----------------------------------------------------------------------------
AddCookie(CFTypeRef Data,int i)298 void wxHIDDevice::AddCookie(CFTypeRef Data, int i)
299 {
300     CFNumberGetValue(
301                 (CFNumberRef) CFDictionaryGetValue    ( (CFDictionaryRef) Data
302                                         , CFSTR(kIOHIDElementCookieKey)
303                                         ),
304                 kCFNumberIntType,
305                 &m_pCookies[i]
306                 );
307 }
308 
309 // ----------------------------------------------------------------------------
310 // wxHIDDevice::AddCookieInQueue
311 //
312 // Adds a cookie to the internal cookie array from a CFType and additionally
313 // adds it to the internal HID Queue
314 // ----------------------------------------------------------------------------
AddCookieInQueue(CFTypeRef Data,int i)315 void wxHIDDevice::AddCookieInQueue(CFTypeRef Data, int i)
316 {
317     //3rd Param flags (none yet)
318     AddCookie(Data, i);
319     if ( (*m_ppQueue)->addElement(m_ppQueue, m_pCookies[i], 0) != S_OK )
320         wxLogDebug(_T("HID device: adding element failed"));
321 }
322 
323 // ----------------------------------------------------------------------------
324 // wxHIDDevice::InitCookies
325 //
326 // Create the internal cookie array, optionally creating a HID Queue
327 // ----------------------------------------------------------------------------
InitCookies(size_t dwSize,bool bQueue)328 void wxHIDDevice::InitCookies(size_t dwSize, bool bQueue)
329 {
330     m_pCookies = new IOHIDElementCookie[dwSize];
331     if (bQueue)
332     {
333         wxASSERT( m_ppQueue == NULL);
334         m_ppQueue = (*m_ppDevice)->allocQueue(m_ppDevice);
335         if ( !m_ppQueue )
336         {
337             wxLogDebug(_T("HID device: allocQueue failed"));
338             return;
339         }
340 
341         //Param 2, flags, none yet
342         if ( (*m_ppQueue)->create(m_ppQueue, 0, 512) != S_OK )
343         {
344             wxLogDebug(_T("HID device: create failed"));
345         }
346     }
347 
348     //make sure that cookie array is clear
349     memset(m_pCookies, 0, sizeof(*m_pCookies) * dwSize);
350 }
351 
352 // ----------------------------------------------------------------------------
353 // wxHIDDevice::IsActive
354 //
355 // Returns true if a cookie of the device is active - for example if a key is
356 // held down, joystick button pressed, caps lock active, etc..
357 // ----------------------------------------------------------------------------
IsActive(int nIndex)358 bool wxHIDDevice::IsActive(int nIndex)
359 {
360     if(!HasElement(nIndex))
361     {
362         //cookie at index does not exist - getElementValue
363         //could return true which would be incorrect so we
364         //check here
365         return false;
366     }
367 
368     IOHIDEventStruct Event;
369     (*m_ppDevice)->getElementValue(m_ppDevice, m_pCookies[nIndex], &Event);
370     return !!Event.value;
371 }
372 
373 // ----------------------------------------------------------------------------
374 // wxHIDDevice::HasElement
375 //
376 // Returns true if the element in the internal cookie array exists
377 // ----------------------------------------------------------------------------
HasElement(int nIndex)378 bool wxHIDDevice::HasElement(int nIndex)
379 {
380     return m_pCookies[nIndex] != NULL;
381 }
382 
383 // ----------------------------------------------------------------------------
384 // wxHIDDevice Destructor
385 //
386 // Frees all memory and objects from the structure
387 // ----------------------------------------------------------------------------
~wxHIDDevice()388 wxHIDDevice::~wxHIDDevice()
389 {
390     if (m_ppDevice != NULL)
391     {
392         if (m_ppQueue != NULL)
393         {
394             (*m_ppQueue)->stop(m_ppQueue);
395             (*m_ppQueue)->dispose(m_ppQueue);
396             (*m_ppQueue)->Release(m_ppQueue);
397         }
398         (*m_ppDevice)->close(m_ppDevice);
399         (*m_ppDevice)->Release(m_ppDevice);
400         mach_port_deallocate(mach_task_self(), m_pPort);
401     }
402 
403     if (m_pCookies != NULL)
404     {
405         delete [] m_pCookies;
406     }
407 }
408 
409 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
410 //
411 // wxHIDKeyboard
412 //
413 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
414 
415 //There are no right shift, alt etc. in the wx headers yet so just sort
416 //of "define our own" for now
417 enum
418 {
419     WXK_RSHIFT = 400,
420     WXK_RALT,
421     WXK_RCONTROL,
422     WXK_RMENU
423 };
424 
425 // ----------------------------------------------------------------------------
426 // wxHIDKeyboard::GetCount [static]
427 //
428 // Get number of HID keyboards available
429 // ----------------------------------------------------------------------------
GetCount()430 int wxHIDKeyboard::GetCount()
431 {
432     return wxHIDDevice::GetCount(kHIDPage_GenericDesktop,
433                                kHIDUsage_GD_Keyboard);
434 }
435 
436 // ----------------------------------------------------------------------------
437 // wxHIDKeyboard::Create
438 //
439 // Create the HID Keyboard
440 // ----------------------------------------------------------------------------
Create(int nDev)441 bool wxHIDKeyboard::Create(int nDev /* = 1*/)
442 {
443     return wxHIDDevice::Create(kHIDPage_GenericDesktop,
444                                kHIDUsage_GD_Keyboard,
445                                nDev);
446 }
447 
448 // ----------------------------------------------------------------------------
449 // wxHIDKeyboard::AddCookie
450 //
451 // Overloaded version of wxHIDDevice::AddCookie that simply does not
452 // add a cookie if a duplicate is found
453 // ----------------------------------------------------------------------------
AddCookie(CFTypeRef Data,int i)454 void wxHIDKeyboard::AddCookie(CFTypeRef Data, int i)
455 {
456     if(!HasElement(i))
457         wxHIDDevice::AddCookie(Data, i);
458 }
459 
460 // ----------------------------------------------------------------------------
461 // wxHIDKeyboard::BuildCookies
462 //
463 // Callback from Create() to build the HID cookies for the internal cookie
464 // array
465 // ----------------------------------------------------------------------------
BuildCookies(CFArrayRef Array)466 void wxHIDKeyboard::BuildCookies(CFArrayRef Array)
467 {
468     //Create internal cookie array
469     InitCookies(500);
470 
471     //Begin recursing in array
472     DoBuildCookies(Array);
473 }
474 
DoBuildCookies(CFArrayRef Array)475 void wxHIDKeyboard::DoBuildCookies(CFArrayRef Array)
476 {
477     //Now go through each possible cookie
478     int i,
479         nUsage;
480 //    bool bEOTriggered = false;
481     for (i = 0; i < CFArrayGetCount(Array); ++i)
482     {
483         const void* ref = CFDictionaryGetValue(
484                 (CFDictionaryRef)CFArrayGetValueAtIndex(Array, i),
485                 CFSTR(kIOHIDElementKey)
486                                               );
487 
488         if (ref != NULL)
489         {
490             DoBuildCookies((CFArrayRef) ref);
491         }
492         else
493     {
494 
495             //
496             // Get the usage #
497             //
498         CFNumberGetValue(
499                 (CFNumberRef)
500                     CFDictionaryGetValue((CFDictionaryRef)
501                         CFArrayGetValueAtIndex(Array, i),
502                         CFSTR(kIOHIDElementUsageKey)
503                                         ),
504                               kCFNumberLongType,
505                               &nUsage);
506 
507             //
508             // Now translate the usage # into a wx keycode
509             //
510 
511         //
512         // OK, this is strange - basically this kind of strange -
513         // Starting from 0xEO these elements (like shift) appear twice in
514         // the array!  The ones at the end are bogus I guess - the funny part
515         // is that besides the fact that the ones at the front have a Unit
516         // and UnitExponent key with a value of 0 and a different cookie value,
517         // there is no discernable difference between the two...
518         //
519         // Will the real shift please stand up?
520         //
521         // Something to spend a support request on, if I had one, LOL.
522         //
523         //if(nUsage == 0xE0)
524         //{
525         //    if(bEOTriggered)
526         //       break;
527         //    bEOTriggered = true;
528         //}
529         //Instead of that though we now just don't add duplicate keys
530 
531         if (nUsage >= kHIDUsage_KeyboardA && nUsage <= kHIDUsage_KeyboardZ)
532             AddCookie(CFArrayGetValueAtIndex(Array, i), 'A' + (nUsage - kHIDUsage_KeyboardA) );
533         else if (nUsage >= kHIDUsage_Keyboard1 && nUsage <= kHIDUsage_Keyboard9)
534             AddCookie(CFArrayGetValueAtIndex(Array, i), '1' + (nUsage - kHIDUsage_Keyboard1) );
535         else if (nUsage >= kHIDUsage_KeyboardF1 && nUsage <= kHIDUsage_KeyboardF12)
536             AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_F1 + (nUsage - kHIDUsage_KeyboardF1) );
537         else if (nUsage >= kHIDUsage_KeyboardF13 && nUsage <= kHIDUsage_KeyboardF24)
538             AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_F13 + (nUsage - kHIDUsage_KeyboardF13) );
539         else if (nUsage >= kHIDUsage_Keypad1 && nUsage <= kHIDUsage_Keypad9)
540             AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_NUMPAD1 + (nUsage - kHIDUsage_Keypad1) );
541         else switch (nUsage)
542         {
543             //0's (wx & ascii go 0-9, but HID goes 1-0)
544             case kHIDUsage_Keyboard0:
545                 AddCookie(CFArrayGetValueAtIndex(Array, i), '0');
546                 break;
547             case kHIDUsage_Keypad0:
548                 AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_NUMPAD0);
549                 break;
550 
551             //Basic
552             case kHIDUsage_KeyboardReturnOrEnter:
553                 AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_RETURN);
554                 break;
555             case kHIDUsage_KeyboardEscape:
556                 AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_ESCAPE);
557                 break;
558             case kHIDUsage_KeyboardDeleteOrBackspace:
559                 AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_BACK);
560                 break;
561             case kHIDUsage_KeyboardTab:
562                 AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_TAB);
563                 break;
564             case kHIDUsage_KeyboardSpacebar:
565                 AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_SPACE);
566                 break;
567             case kHIDUsage_KeyboardPageUp:
568                 AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_PAGEUP);
569                 break;
570             case kHIDUsage_KeyboardEnd:
571                 AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_END);
572                 break;
573             case kHIDUsage_KeyboardPageDown:
574                 AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_PAGEDOWN);
575                 break;
576             case kHIDUsage_KeyboardRightArrow:
577                 AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_RIGHT);
578                 break;
579             case kHIDUsage_KeyboardLeftArrow:
580                 AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_LEFT);
581                 break;
582             case kHIDUsage_KeyboardDownArrow:
583                 AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_DOWN);
584                 break;
585             case kHIDUsage_KeyboardUpArrow:
586                 AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_UP);
587                 break;
588 
589             //LEDS
590             case kHIDUsage_KeyboardCapsLock:
591                 AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_CAPITAL);
592                 break;
593             case kHIDUsage_KeypadNumLock:
594                 AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_NUMLOCK);
595                 break;
596             case kHIDUsage_KeyboardScrollLock:
597                 AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_SCROLL);
598                 break;
599 
600             //Menu keys, Shift, other specials
601             case kHIDUsage_KeyboardLeftControl:
602                 AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_CONTROL);
603                 break;
604             case kHIDUsage_KeyboardLeftShift:
605                 AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_SHIFT);
606                 break;
607             case kHIDUsage_KeyboardLeftAlt:
608                 AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_ALT);
609                 break;
610             case kHIDUsage_KeyboardLeftGUI:
611                 AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_MENU);
612                 break;
613             case kHIDUsage_KeyboardRightControl:
614                 AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_RCONTROL);
615                 break;
616             case kHIDUsage_KeyboardRightShift:
617                 AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_RSHIFT);
618                 break;
619             case kHIDUsage_KeyboardRightAlt:
620                 AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_RALT);
621                 break;
622             case kHIDUsage_KeyboardRightGUI:
623                 AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_RMENU);
624                 break;
625 
626             //Default
627             default:
628             //not in wx keycodes - do nothing....
629             break;
630             } //end mightly long switch
631         } //end if the current element is not an array...
632     } //end for loop for Array
633 }//end buildcookies
634 
635 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
636 //
637 // wxHIDModule
638 //
639 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
640 
641 class wxHIDModule : public wxModule
642 {
643     DECLARE_DYNAMIC_CLASS(wxHIDModule)
644 
645     public:
646         static wxArrayPtrVoid sm_keyboards;
OnInit()647         virtual bool OnInit()
648         {
649             return true;
650         }
OnExit()651         virtual void OnExit()
652         {
653             for(size_t i = 0; i < sm_keyboards.GetCount(); ++i)
654                 delete (wxHIDKeyboard*) sm_keyboards[i];
655         }
656 };
657 
658 IMPLEMENT_DYNAMIC_CLASS(wxHIDModule, wxModule)
659 
660 wxArrayPtrVoid wxHIDModule::sm_keyboards;
661 
662 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
663 //
664 // wxGetKeyState()
665 //
666 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
667 
wxGetKeyState(wxKeyCode key)668 bool wxGetKeyState (wxKeyCode key)
669 {
670     wxASSERT_MSG(key != WXK_LBUTTON && key != WXK_RBUTTON && key !=
671         WXK_MBUTTON, wxT("can't use wxGetKeyState() for mouse buttons"));
672 
673     if (wxHIDModule::sm_keyboards.GetCount() == 0)
674     {
675         int nKeyboards = wxHIDKeyboard::GetCount();
676 
677         for(int i = 1; i <= nKeyboards; ++i)
678         {
679             wxHIDKeyboard* keyboard = new wxHIDKeyboard();
680             if(keyboard->Create(i))
681             {
682                 wxHIDModule::sm_keyboards.Add(keyboard);
683             }
684             else
685             {
686                 delete keyboard;
687                 break;
688             }
689         }
690 
691         wxASSERT_MSG(wxHIDModule::sm_keyboards.GetCount() != 0,
692                      wxT("No keyboards found!"));
693     }
694 
695     for(size_t i = 0; i < wxHIDModule::sm_keyboards.GetCount(); ++i)
696     {
697         wxHIDKeyboard* keyboard = (wxHIDKeyboard*)
698                                 wxHIDModule::sm_keyboards[i];
699 
700     switch(key)
701     {
702     case WXK_SHIFT:
703             if( keyboard->IsActive(WXK_SHIFT) ||
704                    keyboard->IsActive(WXK_RSHIFT) )
705             {
706                 return true;
707             }
708         break;
709     case WXK_ALT:
710             if( keyboard->IsActive(WXK_ALT) ||
711                    keyboard->IsActive(WXK_RALT) )
712             {
713                 return true;
714             }
715         break;
716     case WXK_CONTROL:
717             if( keyboard->IsActive(WXK_CONTROL) ||
718                    keyboard->IsActive(WXK_RCONTROL) )
719             {
720                 return true;
721             }
722         break;
723     case WXK_MENU:
724             if( keyboard->IsActive(WXK_MENU) ||
725                    keyboard->IsActive(WXK_RMENU) )
726             {
727                 return true;
728             }
729         break;
730     default:
731             if( keyboard->IsActive(key) )
732             {
733                 return true;
734             }
735         break;
736     }
737     }
738 
739     return false; //not down/error
740 }
741 
742 #endif //__DARWIN__
743