]> git.saurik.com Git - wxWidgets.git/commitdiff
HID support (preliminary - not added to bakefiles yet)
authorRyan Norton <wxprojects@comcast.net>
Fri, 23 Jan 2004 09:44:05 +0000 (09:44 +0000)
committerRyan Norton <wxprojects@comcast.net>
Fri, 23 Jan 2004 09:44:05 +0000 (09:44 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@25335 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/mac/private/hid.h [new file with mode: 0644]
src/mac/app.cpp
src/mac/carbon/app.cpp
src/mac/carbon/hid.cpp [new file with mode: 0644]
src/mac/hid.cpp [new file with mode: 0644]

diff --git a/include/wx/mac/private/hid.h b/include/wx/mac/private/hid.h
new file mode 100644 (file)
index 0000000..2947ee3
--- /dev/null
@@ -0,0 +1,63 @@
+#include <wx/wx.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/hid/IOHIDLib.h>
+#include <IOKit/hid/IOHIDKeys.h>
+#include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
+
+#include <mach/mach.h>
+
+//Utility wrapper around CFArray
+class wxCFArray
+{
+public:
+       wxCFArray(CFTypeRef pData) : pArray((CFArrayRef) pData) {}
+       CFTypeRef operator [] (const int& nIndex) {return CFArrayGetValueAtIndex(pArray, nIndex); }
+       int Count() {return CFArrayGetCount(pArray);}
+private:
+       CFArrayRef pArray;
+};
+
+//
+//     A wrapper around OS X HID Manager procedures.
+//     The tutorial "Working With HID Class Device Interfaces" Is
+//     Quite good, as is the sample program associated with it 
+//  (Depite the author's protests!).
+class wxHIDDevice
+{
+public:
+       wxHIDDevice() : m_ppDevice(NULL), m_ppQueue(NULL), m_pCookies(NULL) {}
+       //kHIDPage_GenericDesktop
+       //kHIDUsage_GD_Joystick,kHIDUsage_GD_Mouse,kHIDUsage_GD_Keyboard
+       bool Create (const int& nClass = -1, const int& nType = -1);
+
+       inline void AddCookie(CFTypeRef Data, const int& i);
+       inline void AddCookieInQueue(CFTypeRef Data, const int& i);     
+       inline void InitCookies(const size_t& dwSize, bool bQueue = false);
+
+       //Must be implemented by derived classes
+       //builds the cookie array -
+       //first call InitCookies to initialize the cookie
+       //array, then AddCookie to add a cookie at a certain point in an array
+       virtual void BuildCookies(wxCFArray& Array) = 0;
+               
+       //checks to see whether the cookie at index nIndex is active (element value != 0)
+       bool IsActive(const int& nIndex);
+       
+       //closes the device and cleans the queue and cookies
+       virtual ~wxHIDDevice();
+private:
+       IOHIDDeviceInterface**  m_ppDevice; //this, essentially
+       IOHIDQueueInterface**   m_ppQueue;  //queue (if we want one)
+       IOHIDElementCookie*     m_pCookies; //cookies
+
+       const char*                     m_szName; //(product) name
+       mach_port_t                     m_pPort;
+};
+
+class wxHIDKeyboard : public wxHIDDevice
+{
+public:
+       bool Create();
+       virtual void BuildCookies(wxCFArray& Array);
+};
\ No newline at end of file
index f7e96bddfb3db11a931fec9ceb68aad8d7fd6605..a5f703819b6203f297d434c791e16f83d753f346 100644 (file)
@@ -1817,6 +1817,10 @@ int wxKeyCodeToMacModifier(wxKeyCode key)
 
 bool wxGetKeyState(wxKeyCode key) //virtual key code if < 10.2.x, else see below
 {
+//#ifdef __DARWIN__
+//     wxHIDKeyboard keyboard;
+//     return keyboard.IsActive(key);
+//#else
 // TODO:  Have it use HID Manager on OSX...
 //if OS X > 10.2 (i.e. 10.2.x)
 //a known apple bug prevents the system from determining led
@@ -1826,6 +1830,7 @@ bool wxGetKeyState(wxKeyCode key) //virtual key code if < 10.2.x, else see below
 //  KeyMapByteArray keymap; 
 //  GetKeys((BigEndianLong*)keymap);
 //  return !!(BitTst(keymap, (sizeof(KeyMapByteArray)*8) - iKey));
+//#endif
 }
 
 #if !TARGET_CARBON
index f7e96bddfb3db11a931fec9ceb68aad8d7fd6605..a5f703819b6203f297d434c791e16f83d753f346 100644 (file)
@@ -1817,6 +1817,10 @@ int wxKeyCodeToMacModifier(wxKeyCode key)
 
 bool wxGetKeyState(wxKeyCode key) //virtual key code if < 10.2.x, else see below
 {
+//#ifdef __DARWIN__
+//     wxHIDKeyboard keyboard;
+//     return keyboard.IsActive(key);
+//#else
 // TODO:  Have it use HID Manager on OSX...
 //if OS X > 10.2 (i.e. 10.2.x)
 //a known apple bug prevents the system from determining led
@@ -1826,6 +1830,7 @@ bool wxGetKeyState(wxKeyCode key) //virtual key code if < 10.2.x, else see below
 //  KeyMapByteArray keymap; 
 //  GetKeys((BigEndianLong*)keymap);
 //  return !!(BitTst(keymap, (sizeof(KeyMapByteArray)*8) - iKey));
+//#endif
 }
 
 #if !TARGET_CARBON
diff --git a/src/mac/carbon/hid.cpp b/src/mac/carbon/hid.cpp
new file mode 100644 (file)
index 0000000..f4ce8a1
--- /dev/null
@@ -0,0 +1,417 @@
+#include "hid.h"
+
+#define wxFORCECHECK_MSG(arg, msg)  \
+{\
+       if (arg) \
+       {\
+               wxLogSysError(wxString::Format(wxT("Message:%s\nHID: %s failed!"), wxT(msg), wxT(#arg)));\
+               return false;\
+       }\
+}
+#define wxIOCHECK(arg, msg)  wxFORCECHECK_MSG(arg != kIOReturnSuccess, msg)
+#define wxKERNCHECK(arg, msg) wxFORCECHECK_MSG(arg != KERN_SUCCESS, msg)
+#define wxSCHECK(arg, msg) wxFORCECHECK_MSG(arg != S_OK, msg)
+
+void CFShowTypeIDDescription(CFTypeRef pData)
+{
+       if(!pData)
+       {
+               wxMessageBox("AHHH!");
+               return;
+       }
+       
+       wxMessageBox(
+               CFStringGetCStringPtr(
+                       CFCopyTypeIDDescription(CFGetTypeID(pData)),CFStringGetSystemEncoding()
+                                                        )
+                               );      
+}
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+
+bool wxHIDDevice::Create (const int& nClass, const int& nType)
+{
+       //Create the mach port
+       wxIOCHECK(IOMasterPort(bootstrap_port, &m_pPort), "Could not create mach port");
+
+       //Dictionary that will hold first
+       //the matching dictionary for determining which kind of devices we want,
+       //then later some registry properties from an iterator (see below)
+       CFMutableDictionaryRef pDictionary;
+
+       //Create a dictionary
+       //The call to IOServiceMatching filters down the
+       //the services we want to hid services (and also eats the
+       //dictionary up for us (consumes one reference))
+       wxASSERT((pDictionary = IOServiceMatching(kIOHIDDeviceKey)) != NULL );
+
+       //Here we'll filter down the services to what we want
+       if (nType != -1)
+       {
+               CFNumberRef pType = CFNumberCreate(kCFAllocatorDefault,
+                                                                       kCFNumberIntType, &nType);
+               CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsageKey), pType);
+               CFRelease(pType);
+       }
+       if (nClass != -1)
+       {
+               CFNumberRef pClass = CFNumberCreate(kCFAllocatorDefault,
+                                                                       kCFNumberIntType, &nClass);
+               CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsagePageKey), pClass);
+               CFRelease(pClass);
+       }
+
+       //Now get the maching services
+       io_iterator_t pIterator;
+       wxIOCHECK(IOServiceGetMatchingServices(m_pPort, pDictionary, &pIterator), "No Matching HID Services");
+       wxASSERT(pIterator != NULL);
+
+       //Now we iterate through them
+       io_object_t pObject;
+       while ( (pObject = IOIteratorNext(pIterator)) != NULL)
+       {
+               wxASSERT(IORegistryEntryCreateCFProperties(pObject, &pDictionary,
+                                                                                       kCFAllocatorDefault, kNilOptions) == KERN_SUCCESS);
+
+               //Just for sanity :)
+               wxASSERT(CFGetTypeID(CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductKey))) == CFStringGetTypeID());
+                       
+               //Get [product] name
+               m_szName = CFStringGetCStringPtr        (
+                                               (CFStringRef) CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductKey)), 
+                                               CFStringGetSystemEncoding()
+                                                                               );
+
+               //
+               //Now the hard part - in order to scan things we need "cookies" -
+               //
+               wxCFArray CookieArray = CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDElementKey));
+               BuildCookies(CookieArray);
+               if (m_ppQueue != NULL)
+                       wxASSERT((*m_ppQueue)->start(m_ppQueue) == S_OK);
+
+               //Create the interface (good grief - long function names!)
+               SInt32 nScore;
+               IOCFPlugInInterface** ppPlugin;
+               wxIOCHECK(IOCreatePlugInInterfaceForService(pObject, kIOHIDDeviceUserClientTypeID,
+                                                                                       kIOCFPlugInInterfaceID, &ppPlugin, &nScore), "");
+                                                                                          
+               //Now, the final thing we can check before we fall back to asserts
+               //(because the dtor only checks if the device is ok, so if anything
+               //fails from now on the dtor will delete the device anyway, so we can't break from this).
+                       
+               //Get the HID interface from the plugin to the mach port
+               wxSCHECK((*ppPlugin)->QueryInterface(ppPlugin,
+                                                       CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (void**) &m_ppDevice), "");
+                                                       
+               //release the plugin
+               (*ppPlugin)->Release(ppPlugin);
+               
+               //open the HID interface...
+               wxASSERT((*m_ppDevice)->open(m_ppDevice, 0) == S_OK);
+               
+               //cleanup
+               CFRelease(pDictionary);
+               IOObjectRelease(pObject);
+               break;
+       }
+       //iterator cleanup
+       IOObjectRelease(pIterator);
+               
+       return true;
+}//end Create()
+       
+void wxHIDDevice::AddCookie(CFTypeRef Data, const int& i)
+{
+       CFNumberGetValue(
+                               (CFNumberRef) CFDictionaryGetValue      ( (CFDictionaryRef) Data
+                                                                               , CFSTR(kIOHIDElementCookieKey)
+                                                                               ),      
+                               kCFNumberIntType,
+                               &m_pCookies[i]
+                               );
+}
+
+void wxHIDDevice::AddCookieInQueue(CFTypeRef Data, const int& i)
+{
+       AddCookie(Data, i);
+       wxASSERT((*m_ppQueue)->addElement(m_ppQueue, m_pCookies[i], 0) == S_OK);//3rd Param flags (none yet)
+}
+       
+void wxHIDDevice::InitCookies(const size_t& dwSize, bool bQueue)
+{
+       m_pCookies = new IOHIDElementCookie[dwSize];
+       if (bQueue)
+       {
+               wxASSERT( m_ppQueue != NULL);
+               wxASSERT(  (m_ppQueue = (*m_ppDevice)->allocQueue(m_ppDevice)) != NULL);
+               wxASSERT(  (*m_ppQueue)->create(m_ppQueue, 0, 512) == S_OK); //Param 2, flags, none yet
+       }               
+}
+
+bool wxHIDDevice::IsActive(const int& nIndex)
+{
+       wxASSERT(m_pCookies[nIndex] != NULL);
+       IOHIDEventStruct Event;
+       (*m_ppDevice)->getElementValue(m_ppDevice, m_pCookies[nIndex], &Event);
+       return !!Event.value;
+}
+       
+
+wxHIDDevice::~wxHIDDevice()
+{
+       if (m_ppDevice != NULL)
+       {
+               (*m_ppDevice)->close(m_ppDevice);
+               (*m_ppDevice)->Release(m_ppDevice);
+               mach_port_deallocate(mach_task_self(), m_pPort);
+       }
+       
+       if (m_pCookies != NULL)
+       {
+               delete [] m_pCookies;
+               if (m_ppQueue != NULL)
+               {
+                       (*m_ppQueue)->stop(m_ppQueue);
+                       (*m_ppQueue)->dispose(m_ppQueue);
+                       (*m_ppQueue)->Release(m_ppQueue);
+               }
+       }
+}
+/*
+enum
+{
+       kHIDUsage_KeyboardHyphen        = 0x2D, 
+       kHIDUsage_KeyboardEqualSign     = 0x2E, 
+       kHIDUsage_KeyboardOpenBracket   = 0x2F, 
+       kHIDUsage_KeyboardCloseBracket  = 0x30,
+       kHIDUsage_KeyboardBackslash     = 0x31, //* \ or | *
+       kHIDUsage_KeyboardNonUSPound    = 0x32, /* Non-US # or _ *
+       kHIDUsage_KeyboardSemicolon     = 0x33, /* ; or : *
+       kHIDUsage_KeyboardQuote = 0x34, /* ' or " *
+       kHIDUsage_KeyboardGraveAccentAndTilde   = 0x35, /* Grave Accent and Tilde *
+       kHIDUsage_KeyboardComma = 0x36, /* , or < *
+       kHIDUsage_KeyboardPeriod        = 0x37, /* . or > *
+       kHIDUsage_KeyboardSlash = 0x38, /* / or ? *
+       kHIDUsage_KeyboardCapsLock      = 0x39, /* Caps Lock *
+
+       kHIDUsage_KeyboardPrintScreen   = 0x46, /* Print Screen *
+       kHIDUsage_KeyboardScrollLock    = 0x47, /* Scroll Lock *
+       kHIDUsage_KeyboardPause = 0x48, /* Pause *
+       kHIDUsage_KeyboardInsert        = 0x49, /* Insert *
+       kHIDUsage_KeyboardHome  = 0x4A, /* Home *
+       kHIDUsage_KeyboardDeleteForward = 0x4C, /* Delete Forward *
+
+       kHIDUsage_KeyboardUpArrow
+       kHIDUsage_KeypadNumLock
+       kHIDUsage_KeypadSlash
+       kHIDUsage_KeypadAsterisk
+       kHIDUsage_KeypadHyphen
+       kHIDUsage_KeypadPlus
+       kHIDUsage_KeypadEnter
+       kHIDUsage_KeypadPeriod
+       kHIDUsage_KeyboardNonUSBackslash
+       kHIDUsage_KeyboardApplication
+       kHIDUsage_KeyboardPower
+       kHIDUsage_KeypadEqualSign
+};
+/*
+       enum wxKeyCode
+       {
+
+               WXK_START   = 300,
+               WXK_LBUTTON,
+               WXK_RBUTTON,
+               WXK_CANCEL,
+               WXK_MBUTTON,
+               WXK_CLEAR,
+               WXK_SHIFT,
+               WXK_ALT,
+               WXK_CONTROL,
+               WXK_MENU,
+               WXK_PAUSE,
+               WXK_PRIOR,  *  Page up *
+               WXK_NEXT,   *  Page down *
+               WXK_END,
+               WXK_HOME,
+               WXK_LEFT,
+               WXK_UP,
+               WXK_RIGHT,
+               WXK_DOWN,
+               WXK_SELECT,
+               WXK_PRINT,
+               WXK_EXECUTE,
+               WXK_SNAPSHOT,
+               WXK_INSERT,
+               WXK_HELP,
+               WXK_MULTIPLY,
+               WXK_ADD,
+               WXK_SEPARATOR,
+               WXK_SUBTRACT,
+               WXK_DECIMAL,
+               WXK_DIVIDE,
+               WXK_PAGEUP,
+               WXK_PAGEDOWN,
+
+               WXK_NUMPAD_SPACE,
+               WXK_NUMPAD_TAB,
+               WXK_NUMPAD_ENTER,
+               WXK_NUMPAD_HOME,
+               WXK_NUMPAD_LEFT,
+               WXK_NUMPAD_UP,
+               WXK_NUMPAD_RIGHT,
+               WXK_NUMPAD_DOWN,
+               WXK_NUMPAD_PRIOR,
+               WXK_NUMPAD_PAGEUP,
+               WXK_NUMPAD_NEXT,
+               WXK_NUMPAD_PAGEDOWN,
+               WXK_NUMPAD_END,
+               WXK_NUMPAD_BEGIN,
+               WXK_NUMPAD_INSERT,
+               WXK_NUMPAD_DELETE,
+               WXK_NUMPAD_EQUAL,
+               WXK_NUMPAD_MULTIPLY,
+               WXK_NUMPAD_ADD,
+               WXK_NUMPAD_SEPARATOR,
+               WXK_NUMPAD_SUBTRACT,
+               WXK_NUMPAD_DECIMAL,
+               WXK_NUMPAD_DIVIDE,
+
+               WXK_WINDOWS_LEFT,
+               WXK_WINDOWS_RIGHT,
+               WXK_WINDOWS_MENU ,
+               WXK_COMMAND
+       };
+
+ */
+enum
+{
+       WXK_RSHIFT = 400,
+       WXK_RALT,
+       WXK_RCONTROL,
+       WXK_RMENU
+       
+};
+
+bool wxHIDKeyboard::Create()
+{
+       return wxHIDDevice::Create(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard);
+}
+
+void wxHIDKeyboard::BuildCookies(wxCFArray& Array)
+{
+       Array = CFDictionaryGetValue((CFDictionaryRef)Array[0], CFSTR(kIOHIDElementKey));
+       InitCookies(500);
+       int i,
+               nUsage;
+       for (i = 0; i < Array.Count(); ++i)
+       {
+               CFNumberGetValue(
+                       (CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) Array[i], CFSTR(kIOHIDElementUsageKey)), 
+                               kCFNumberLongType, &nUsage);
+                       
+               if (nUsage >= kHIDUsage_KeyboardA && nUsage <= kHIDUsage_KeyboardZ)
+                       AddCookie(Array[i], 'A' + (nUsage - kHIDUsage_KeyboardA) );
+               else if (nUsage >= kHIDUsage_Keyboard1 && nUsage <= kHIDUsage_Keyboard9)
+                       AddCookie(Array[i], '1' + (nUsage - kHIDUsage_Keyboard1) );
+               else if (nUsage >= kHIDUsage_KeyboardF1 && nUsage <= kHIDUsage_KeyboardF12)
+                       AddCookie(Array[i], WXK_F1 + (nUsage - kHIDUsage_KeyboardF1) );
+               else if (nUsage >= kHIDUsage_KeyboardF13 && nUsage <= kHIDUsage_KeyboardF24)
+                       AddCookie(Array[i], WXK_F13 + (nUsage - kHIDUsage_KeyboardF13) );
+               else if (nUsage >= kHIDUsage_Keypad1 && nUsage <= kHIDUsage_Keypad9)
+                       AddCookie(Array[i], WXK_NUMPAD1 + (nUsage - kHIDUsage_Keypad1) );
+               else switch (nUsage)
+               {
+                       //0's (wx & ascii go 0-9, but HID goes 1-0)
+                       case kHIDUsage_Keyboard0:
+                               AddCookie(Array[i],'0');
+                               break;
+                       case kHIDUsage_Keypad0:
+                               AddCookie(Array[i],WXK_NUMPAD0);
+                               break;
+                               
+                       //Basic
+                       case kHIDUsage_KeyboardReturnOrEnter:
+                               AddCookie(Array[i], WXK_RETURN);
+                               break;
+                       case kHIDUsage_KeyboardEscape:
+                               AddCookie(Array[i], WXK_ESCAPE);
+                               break;
+                       case kHIDUsage_KeyboardDeleteOrBackspace:
+                               AddCookie(Array[i], WXK_BACK);
+                               break;
+                       case kHIDUsage_KeyboardTab:
+                               AddCookie(Array[i], WXK_TAB);
+                               break;
+                       case kHIDUsage_KeyboardSpacebar:
+                               AddCookie(Array[i], WXK_SPACE);
+                               break;
+                       case kHIDUsage_KeyboardPageUp:
+                               AddCookie(Array[i], WXK_PRIOR);
+                               break;
+                       case kHIDUsage_KeyboardEnd:
+                               AddCookie(Array[i], WXK_END);
+                               break;
+                       case kHIDUsage_KeyboardPageDown:
+                               AddCookie(Array[i], WXK_NEXT);
+                               break;
+                       case kHIDUsage_KeyboardRightArrow:
+                               AddCookie(Array[i], WXK_RIGHT);
+                               break;
+                       case kHIDUsage_KeyboardLeftArrow:
+                               AddCookie(Array[i], WXK_LEFT);
+                               break;
+                       case kHIDUsage_KeyboardDownArrow:
+                               AddCookie(Array[i], WXK_DOWN);
+                               break;
+                       case kHIDUsage_KeyboardUpArrow:
+                               AddCookie(Array[i], WXK_UP);
+                               break;
+                                               
+                       //LEDS
+                       case kHIDUsage_KeyboardCapsLock:
+                               AddCookie(Array[i],WXK_CAPITAL);
+                               break;
+                       case kHIDUsage_KeypadNumLock:
+                               AddCookie(Array[i],WXK_NUMLOCK);
+                               break;
+                       case kHIDUsage_KeyboardScrollLock:
+                               AddCookie(Array[i],WXK_SCROLL);
+                               break;
+                                       
+                       //Menu keys, Shift, other specials
+                       case kHIDUsage_KeyboardLeftControl:
+                               AddCookie(Array[i],WXK_CONTROL);
+                               break;
+                       case kHIDUsage_KeyboardLeftShift:
+                               AddCookie(Array[i],WXK_SHIFT);
+                               break;
+                       case kHIDUsage_KeyboardLeftAlt:
+                               AddCookie(Array[i],WXK_ALT);
+                               break;
+                       case kHIDUsage_KeyboardLeftGUI:
+                               AddCookie(Array[i],WXK_MENU);
+                               break;
+                       case kHIDUsage_KeyboardRightControl:
+                               AddCookie(Array[i],WXK_RCONTROL);
+                               break;
+                       case kHIDUsage_KeyboardRightShift:
+                               AddCookie(Array[i],WXK_RSHIFT);
+                               break;
+                       case kHIDUsage_KeyboardRightAlt:
+                               AddCookie(Array[i],WXK_RALT);
+                               break;
+                       case kHIDUsage_KeyboardRightGUI:
+                               AddCookie(Array[i],WXK_RMENU);
+                               break;
+                                               
+                       //Default       
+                       default:
+                       //not in wx keycodes - do nothing....
+                       break;
+               }
+       }
+}//end buildcookies
diff --git a/src/mac/hid.cpp b/src/mac/hid.cpp
new file mode 100644 (file)
index 0000000..f4ce8a1
--- /dev/null
@@ -0,0 +1,417 @@
+#include "hid.h"
+
+#define wxFORCECHECK_MSG(arg, msg)  \
+{\
+       if (arg) \
+       {\
+               wxLogSysError(wxString::Format(wxT("Message:%s\nHID: %s failed!"), wxT(msg), wxT(#arg)));\
+               return false;\
+       }\
+}
+#define wxIOCHECK(arg, msg)  wxFORCECHECK_MSG(arg != kIOReturnSuccess, msg)
+#define wxKERNCHECK(arg, msg) wxFORCECHECK_MSG(arg != KERN_SUCCESS, msg)
+#define wxSCHECK(arg, msg) wxFORCECHECK_MSG(arg != S_OK, msg)
+
+void CFShowTypeIDDescription(CFTypeRef pData)
+{
+       if(!pData)
+       {
+               wxMessageBox("AHHH!");
+               return;
+       }
+       
+       wxMessageBox(
+               CFStringGetCStringPtr(
+                       CFCopyTypeIDDescription(CFGetTypeID(pData)),CFStringGetSystemEncoding()
+                                                        )
+                               );      
+}
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+
+bool wxHIDDevice::Create (const int& nClass, const int& nType)
+{
+       //Create the mach port
+       wxIOCHECK(IOMasterPort(bootstrap_port, &m_pPort), "Could not create mach port");
+
+       //Dictionary that will hold first
+       //the matching dictionary for determining which kind of devices we want,
+       //then later some registry properties from an iterator (see below)
+       CFMutableDictionaryRef pDictionary;
+
+       //Create a dictionary
+       //The call to IOServiceMatching filters down the
+       //the services we want to hid services (and also eats the
+       //dictionary up for us (consumes one reference))
+       wxASSERT((pDictionary = IOServiceMatching(kIOHIDDeviceKey)) != NULL );
+
+       //Here we'll filter down the services to what we want
+       if (nType != -1)
+       {
+               CFNumberRef pType = CFNumberCreate(kCFAllocatorDefault,
+                                                                       kCFNumberIntType, &nType);
+               CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsageKey), pType);
+               CFRelease(pType);
+       }
+       if (nClass != -1)
+       {
+               CFNumberRef pClass = CFNumberCreate(kCFAllocatorDefault,
+                                                                       kCFNumberIntType, &nClass);
+               CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsagePageKey), pClass);
+               CFRelease(pClass);
+       }
+
+       //Now get the maching services
+       io_iterator_t pIterator;
+       wxIOCHECK(IOServiceGetMatchingServices(m_pPort, pDictionary, &pIterator), "No Matching HID Services");
+       wxASSERT(pIterator != NULL);
+
+       //Now we iterate through them
+       io_object_t pObject;
+       while ( (pObject = IOIteratorNext(pIterator)) != NULL)
+       {
+               wxASSERT(IORegistryEntryCreateCFProperties(pObject, &pDictionary,
+                                                                                       kCFAllocatorDefault, kNilOptions) == KERN_SUCCESS);
+
+               //Just for sanity :)
+               wxASSERT(CFGetTypeID(CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductKey))) == CFStringGetTypeID());
+                       
+               //Get [product] name
+               m_szName = CFStringGetCStringPtr        (
+                                               (CFStringRef) CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductKey)), 
+                                               CFStringGetSystemEncoding()
+                                                                               );
+
+               //
+               //Now the hard part - in order to scan things we need "cookies" -
+               //
+               wxCFArray CookieArray = CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDElementKey));
+               BuildCookies(CookieArray);
+               if (m_ppQueue != NULL)
+                       wxASSERT((*m_ppQueue)->start(m_ppQueue) == S_OK);
+
+               //Create the interface (good grief - long function names!)
+               SInt32 nScore;
+               IOCFPlugInInterface** ppPlugin;
+               wxIOCHECK(IOCreatePlugInInterfaceForService(pObject, kIOHIDDeviceUserClientTypeID,
+                                                                                       kIOCFPlugInInterfaceID, &ppPlugin, &nScore), "");
+                                                                                          
+               //Now, the final thing we can check before we fall back to asserts
+               //(because the dtor only checks if the device is ok, so if anything
+               //fails from now on the dtor will delete the device anyway, so we can't break from this).
+                       
+               //Get the HID interface from the plugin to the mach port
+               wxSCHECK((*ppPlugin)->QueryInterface(ppPlugin,
+                                                       CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (void**) &m_ppDevice), "");
+                                                       
+               //release the plugin
+               (*ppPlugin)->Release(ppPlugin);
+               
+               //open the HID interface...
+               wxASSERT((*m_ppDevice)->open(m_ppDevice, 0) == S_OK);
+               
+               //cleanup
+               CFRelease(pDictionary);
+               IOObjectRelease(pObject);
+               break;
+       }
+       //iterator cleanup
+       IOObjectRelease(pIterator);
+               
+       return true;
+}//end Create()
+       
+void wxHIDDevice::AddCookie(CFTypeRef Data, const int& i)
+{
+       CFNumberGetValue(
+                               (CFNumberRef) CFDictionaryGetValue      ( (CFDictionaryRef) Data
+                                                                               , CFSTR(kIOHIDElementCookieKey)
+                                                                               ),      
+                               kCFNumberIntType,
+                               &m_pCookies[i]
+                               );
+}
+
+void wxHIDDevice::AddCookieInQueue(CFTypeRef Data, const int& i)
+{
+       AddCookie(Data, i);
+       wxASSERT((*m_ppQueue)->addElement(m_ppQueue, m_pCookies[i], 0) == S_OK);//3rd Param flags (none yet)
+}
+       
+void wxHIDDevice::InitCookies(const size_t& dwSize, bool bQueue)
+{
+       m_pCookies = new IOHIDElementCookie[dwSize];
+       if (bQueue)
+       {
+               wxASSERT( m_ppQueue != NULL);
+               wxASSERT(  (m_ppQueue = (*m_ppDevice)->allocQueue(m_ppDevice)) != NULL);
+               wxASSERT(  (*m_ppQueue)->create(m_ppQueue, 0, 512) == S_OK); //Param 2, flags, none yet
+       }               
+}
+
+bool wxHIDDevice::IsActive(const int& nIndex)
+{
+       wxASSERT(m_pCookies[nIndex] != NULL);
+       IOHIDEventStruct Event;
+       (*m_ppDevice)->getElementValue(m_ppDevice, m_pCookies[nIndex], &Event);
+       return !!Event.value;
+}
+       
+
+wxHIDDevice::~wxHIDDevice()
+{
+       if (m_ppDevice != NULL)
+       {
+               (*m_ppDevice)->close(m_ppDevice);
+               (*m_ppDevice)->Release(m_ppDevice);
+               mach_port_deallocate(mach_task_self(), m_pPort);
+       }
+       
+       if (m_pCookies != NULL)
+       {
+               delete [] m_pCookies;
+               if (m_ppQueue != NULL)
+               {
+                       (*m_ppQueue)->stop(m_ppQueue);
+                       (*m_ppQueue)->dispose(m_ppQueue);
+                       (*m_ppQueue)->Release(m_ppQueue);
+               }
+       }
+}
+/*
+enum
+{
+       kHIDUsage_KeyboardHyphen        = 0x2D, 
+       kHIDUsage_KeyboardEqualSign     = 0x2E, 
+       kHIDUsage_KeyboardOpenBracket   = 0x2F, 
+       kHIDUsage_KeyboardCloseBracket  = 0x30,
+       kHIDUsage_KeyboardBackslash     = 0x31, //* \ or | *
+       kHIDUsage_KeyboardNonUSPound    = 0x32, /* Non-US # or _ *
+       kHIDUsage_KeyboardSemicolon     = 0x33, /* ; or : *
+       kHIDUsage_KeyboardQuote = 0x34, /* ' or " *
+       kHIDUsage_KeyboardGraveAccentAndTilde   = 0x35, /* Grave Accent and Tilde *
+       kHIDUsage_KeyboardComma = 0x36, /* , or < *
+       kHIDUsage_KeyboardPeriod        = 0x37, /* . or > *
+       kHIDUsage_KeyboardSlash = 0x38, /* / or ? *
+       kHIDUsage_KeyboardCapsLock      = 0x39, /* Caps Lock *
+
+       kHIDUsage_KeyboardPrintScreen   = 0x46, /* Print Screen *
+       kHIDUsage_KeyboardScrollLock    = 0x47, /* Scroll Lock *
+       kHIDUsage_KeyboardPause = 0x48, /* Pause *
+       kHIDUsage_KeyboardInsert        = 0x49, /* Insert *
+       kHIDUsage_KeyboardHome  = 0x4A, /* Home *
+       kHIDUsage_KeyboardDeleteForward = 0x4C, /* Delete Forward *
+
+       kHIDUsage_KeyboardUpArrow
+       kHIDUsage_KeypadNumLock
+       kHIDUsage_KeypadSlash
+       kHIDUsage_KeypadAsterisk
+       kHIDUsage_KeypadHyphen
+       kHIDUsage_KeypadPlus
+       kHIDUsage_KeypadEnter
+       kHIDUsage_KeypadPeriod
+       kHIDUsage_KeyboardNonUSBackslash
+       kHIDUsage_KeyboardApplication
+       kHIDUsage_KeyboardPower
+       kHIDUsage_KeypadEqualSign
+};
+/*
+       enum wxKeyCode
+       {
+
+               WXK_START   = 300,
+               WXK_LBUTTON,
+               WXK_RBUTTON,
+               WXK_CANCEL,
+               WXK_MBUTTON,
+               WXK_CLEAR,
+               WXK_SHIFT,
+               WXK_ALT,
+               WXK_CONTROL,
+               WXK_MENU,
+               WXK_PAUSE,
+               WXK_PRIOR,  *  Page up *
+               WXK_NEXT,   *  Page down *
+               WXK_END,
+               WXK_HOME,
+               WXK_LEFT,
+               WXK_UP,
+               WXK_RIGHT,
+               WXK_DOWN,
+               WXK_SELECT,
+               WXK_PRINT,
+               WXK_EXECUTE,
+               WXK_SNAPSHOT,
+               WXK_INSERT,
+               WXK_HELP,
+               WXK_MULTIPLY,
+               WXK_ADD,
+               WXK_SEPARATOR,
+               WXK_SUBTRACT,
+               WXK_DECIMAL,
+               WXK_DIVIDE,
+               WXK_PAGEUP,
+               WXK_PAGEDOWN,
+
+               WXK_NUMPAD_SPACE,
+               WXK_NUMPAD_TAB,
+               WXK_NUMPAD_ENTER,
+               WXK_NUMPAD_HOME,
+               WXK_NUMPAD_LEFT,
+               WXK_NUMPAD_UP,
+               WXK_NUMPAD_RIGHT,
+               WXK_NUMPAD_DOWN,
+               WXK_NUMPAD_PRIOR,
+               WXK_NUMPAD_PAGEUP,
+               WXK_NUMPAD_NEXT,
+               WXK_NUMPAD_PAGEDOWN,
+               WXK_NUMPAD_END,
+               WXK_NUMPAD_BEGIN,
+               WXK_NUMPAD_INSERT,
+               WXK_NUMPAD_DELETE,
+               WXK_NUMPAD_EQUAL,
+               WXK_NUMPAD_MULTIPLY,
+               WXK_NUMPAD_ADD,
+               WXK_NUMPAD_SEPARATOR,
+               WXK_NUMPAD_SUBTRACT,
+               WXK_NUMPAD_DECIMAL,
+               WXK_NUMPAD_DIVIDE,
+
+               WXK_WINDOWS_LEFT,
+               WXK_WINDOWS_RIGHT,
+               WXK_WINDOWS_MENU ,
+               WXK_COMMAND
+       };
+
+ */
+enum
+{
+       WXK_RSHIFT = 400,
+       WXK_RALT,
+       WXK_RCONTROL,
+       WXK_RMENU
+       
+};
+
+bool wxHIDKeyboard::Create()
+{
+       return wxHIDDevice::Create(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard);
+}
+
+void wxHIDKeyboard::BuildCookies(wxCFArray& Array)
+{
+       Array = CFDictionaryGetValue((CFDictionaryRef)Array[0], CFSTR(kIOHIDElementKey));
+       InitCookies(500);
+       int i,
+               nUsage;
+       for (i = 0; i < Array.Count(); ++i)
+       {
+               CFNumberGetValue(
+                       (CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) Array[i], CFSTR(kIOHIDElementUsageKey)), 
+                               kCFNumberLongType, &nUsage);
+                       
+               if (nUsage >= kHIDUsage_KeyboardA && nUsage <= kHIDUsage_KeyboardZ)
+                       AddCookie(Array[i], 'A' + (nUsage - kHIDUsage_KeyboardA) );
+               else if (nUsage >= kHIDUsage_Keyboard1 && nUsage <= kHIDUsage_Keyboard9)
+                       AddCookie(Array[i], '1' + (nUsage - kHIDUsage_Keyboard1) );
+               else if (nUsage >= kHIDUsage_KeyboardF1 && nUsage <= kHIDUsage_KeyboardF12)
+                       AddCookie(Array[i], WXK_F1 + (nUsage - kHIDUsage_KeyboardF1) );
+               else if (nUsage >= kHIDUsage_KeyboardF13 && nUsage <= kHIDUsage_KeyboardF24)
+                       AddCookie(Array[i], WXK_F13 + (nUsage - kHIDUsage_KeyboardF13) );
+               else if (nUsage >= kHIDUsage_Keypad1 && nUsage <= kHIDUsage_Keypad9)
+                       AddCookie(Array[i], WXK_NUMPAD1 + (nUsage - kHIDUsage_Keypad1) );
+               else switch (nUsage)
+               {
+                       //0's (wx & ascii go 0-9, but HID goes 1-0)
+                       case kHIDUsage_Keyboard0:
+                               AddCookie(Array[i],'0');
+                               break;
+                       case kHIDUsage_Keypad0:
+                               AddCookie(Array[i],WXK_NUMPAD0);
+                               break;
+                               
+                       //Basic
+                       case kHIDUsage_KeyboardReturnOrEnter:
+                               AddCookie(Array[i], WXK_RETURN);
+                               break;
+                       case kHIDUsage_KeyboardEscape:
+                               AddCookie(Array[i], WXK_ESCAPE);
+                               break;
+                       case kHIDUsage_KeyboardDeleteOrBackspace:
+                               AddCookie(Array[i], WXK_BACK);
+                               break;
+                       case kHIDUsage_KeyboardTab:
+                               AddCookie(Array[i], WXK_TAB);
+                               break;
+                       case kHIDUsage_KeyboardSpacebar:
+                               AddCookie(Array[i], WXK_SPACE);
+                               break;
+                       case kHIDUsage_KeyboardPageUp:
+                               AddCookie(Array[i], WXK_PRIOR);
+                               break;
+                       case kHIDUsage_KeyboardEnd:
+                               AddCookie(Array[i], WXK_END);
+                               break;
+                       case kHIDUsage_KeyboardPageDown:
+                               AddCookie(Array[i], WXK_NEXT);
+                               break;
+                       case kHIDUsage_KeyboardRightArrow:
+                               AddCookie(Array[i], WXK_RIGHT);
+                               break;
+                       case kHIDUsage_KeyboardLeftArrow:
+                               AddCookie(Array[i], WXK_LEFT);
+                               break;
+                       case kHIDUsage_KeyboardDownArrow:
+                               AddCookie(Array[i], WXK_DOWN);
+                               break;
+                       case kHIDUsage_KeyboardUpArrow:
+                               AddCookie(Array[i], WXK_UP);
+                               break;
+                                               
+                       //LEDS
+                       case kHIDUsage_KeyboardCapsLock:
+                               AddCookie(Array[i],WXK_CAPITAL);
+                               break;
+                       case kHIDUsage_KeypadNumLock:
+                               AddCookie(Array[i],WXK_NUMLOCK);
+                               break;
+                       case kHIDUsage_KeyboardScrollLock:
+                               AddCookie(Array[i],WXK_SCROLL);
+                               break;
+                                       
+                       //Menu keys, Shift, other specials
+                       case kHIDUsage_KeyboardLeftControl:
+                               AddCookie(Array[i],WXK_CONTROL);
+                               break;
+                       case kHIDUsage_KeyboardLeftShift:
+                               AddCookie(Array[i],WXK_SHIFT);
+                               break;
+                       case kHIDUsage_KeyboardLeftAlt:
+                               AddCookie(Array[i],WXK_ALT);
+                               break;
+                       case kHIDUsage_KeyboardLeftGUI:
+                               AddCookie(Array[i],WXK_MENU);
+                               break;
+                       case kHIDUsage_KeyboardRightControl:
+                               AddCookie(Array[i],WXK_RCONTROL);
+                               break;
+                       case kHIDUsage_KeyboardRightShift:
+                               AddCookie(Array[i],WXK_RSHIFT);
+                               break;
+                       case kHIDUsage_KeyboardRightAlt:
+                               AddCookie(Array[i],WXK_RALT);
+                               break;
+                       case kHIDUsage_KeyboardRightGUI:
+                               AddCookie(Array[i],WXK_RMENU);
+                               break;
+                                               
+                       //Default       
+                       default:
+                       //not in wx keycodes - do nothing....
+                       break;
+               }
+       }
+}//end buildcookies