--- /dev/null
+#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
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
// KeyMapByteArray keymap;
// GetKeys((BigEndianLong*)keymap);
// return !!(BitTst(keymap, (sizeof(KeyMapByteArray)*8) - iKey));
+//#endif
}
#if !TARGET_CARBON
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
// KeyMapByteArray keymap;
// GetKeys((BigEndianLong*)keymap);
// return !!(BitTst(keymap, (sizeof(KeyMapByteArray)*8) - iKey));
+//#endif
}
#if !TARGET_CARBON
--- /dev/null
+#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
--- /dev/null
+#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