Added support for several connected keyboards in HIDInputManager
This commit is contained in:
parent
b5008ba01b
commit
5fbf147cc0
@ -36,6 +36,7 @@
|
|||||||
#include <Carbon/Carbon.h>
|
#include <Carbon/Carbon.h>
|
||||||
#include <IOKit/hid/IOHIDManager.h>
|
#include <IOKit/hid/IOHIDManager.h>
|
||||||
#include <IOKit/hid/IOHIDDevice.h>
|
#include <IOKit/hid/IOHIDDevice.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
@ -126,6 +127,27 @@ private :
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void InitializeKeyboard();
|
void InitializeKeyboard();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Load the given keyboard into myKeys
|
||||||
|
///
|
||||||
|
/// If the given keyboard has no key this function simply
|
||||||
|
/// returns. FreeUp is _not_ called because this is not fatal.
|
||||||
|
///
|
||||||
|
/// \param keyboard Keyboard to load
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void LoadKeyboard(IOHIDDeviceRef keyboard);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Load the given key into myKeys
|
||||||
|
///
|
||||||
|
/// FreeUp is _not_ called by this function.
|
||||||
|
///
|
||||||
|
/// \param key Key to load
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void LoadKey(IOHIDElementRef key);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Release all resources
|
/// \brief Release all resources
|
||||||
///
|
///
|
||||||
@ -146,13 +168,25 @@ private :
|
|||||||
static CFDictionaryRef CopyDevicesMaskForManager(UInt32 page, UInt32 usage);
|
static CFDictionaryRef CopyDevicesMaskForManager(UInt32 page, UInt32 usage);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Converte a HID key usage to it's conrresponding virtual code
|
/// \brief Filter the devices and return them.
|
||||||
|
///
|
||||||
|
/// If something went wrong FreeUp is called
|
||||||
|
///
|
||||||
|
/// \param page HID page like kHIDPage_GenericDesktop
|
||||||
|
/// \param usage HID usage page like kHIDUsage_GD_Keyboard or kHIDUsage_GD_Mouse
|
||||||
|
/// \return a retained CFSetRef of IOHIDDeviceRef or NULL
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
CFSetRef CopyDevices(UInt32 page, UInt32 usage);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Converte a HID key usage to its corresponding virtual code
|
||||||
///
|
///
|
||||||
/// See IOHIDUsageTables.h
|
/// See IOHIDUsageTables.h
|
||||||
///
|
///
|
||||||
/// \param usage Any kHIDUsage_Keyboard* usage
|
/// \param usage Any kHIDUsage_Keyboard* usage
|
||||||
/// \return the virtual code associate to the given HID key usage
|
/// \return the virtual code associate with the given HID key usage
|
||||||
/// or 0xff if it is associate to no virtual code
|
/// or 0xff if it is associate with no virtual code
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
static UInt8 UsageToVirtualCode(UInt32 usage);
|
static UInt8 UsageToVirtualCode(UInt32 usage);
|
||||||
@ -166,9 +200,18 @@ private :
|
|||||||
CFDataRef myLayoutData; ///< CFData containing the layout
|
CFDataRef myLayoutData; ///< CFData containing the layout
|
||||||
UCKeyboardLayout* myLayout; ///< Current Keyboard Layout
|
UCKeyboardLayout* myLayout; ///< Current Keyboard Layout
|
||||||
IOHIDManagerRef myManager; ///< HID Manager
|
IOHIDManagerRef myManager; ///< HID Manager
|
||||||
IOHIDElementRef myKeys[Keyboard::KeyCount]; ///< All the keys on the current keyboard
|
|
||||||
/* myKeys index correspond to sf::Keyboard::Key enum */
|
typedef std::vector<IOHIDElementRef> IOHIDElements;
|
||||||
/* if no key is assigned to a key XYZ then myKeys[XYZ] = 0 */
|
IOHIDElements myKeys[Keyboard::KeyCount]; ///< All the keys on the current keyboard
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// myKeys' index corresponds to sf::Keyboard::Key enum.
|
||||||
|
/// if no key is assigned with key XYZ then myKeys[XYZ].size() == 0.
|
||||||
|
/// if there are several keyboards connected and several HID keys associate
|
||||||
|
/// with the same sf::Keyboard::Key then myKeys[XYZ] contains all these
|
||||||
|
/// HID keys.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace priv
|
} // namespace priv
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#include <SFML/Window/OSX/HIDInputManager.hpp>
|
#include <SFML/Window/OSX/HIDInputManager.hpp>
|
||||||
#include <SFML/System/Err.hpp>
|
#include <SFML/System/Err.hpp>
|
||||||
#include <algorithm>
|
|
||||||
#include <AppKit/AppKit.h>
|
#include <AppKit/AppKit.h>
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
@ -51,48 +50,42 @@ bool HIDInputManager::IsKeyPressed(Keyboard::Key key)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Have we an associate IOHIDElementRef to that key ?
|
// state = true if at least one corresponding HID key is pressed
|
||||||
if (myKeys[key] == 0) { // No
|
bool state = false;
|
||||||
|
|
||||||
sf::Err() << key
|
for (IOHIDElements::iterator it = myKeys[key].begin(); it != myKeys[key].end(); ++it) {
|
||||||
<< " is not associate to any IOHIDElementRef."
|
|
||||||
<< std::endl;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
} else { // Yes
|
|
||||||
|
|
||||||
IOHIDValueRef value = 0;
|
IOHIDValueRef value = 0;
|
||||||
|
|
||||||
IOHIDDeviceRef device = IOHIDElementGetDevice(myKeys[key]);
|
IOHIDDeviceRef device = IOHIDElementGetDevice(*it);
|
||||||
IOHIDDeviceGetValue(device, myKeys[key], &value);
|
IOHIDDeviceGetValue(device, *it, &value);
|
||||||
|
|
||||||
if (!value) {
|
if (!value) {
|
||||||
|
|
||||||
// This means some kind of error / deconnection so we remove this
|
// This means some kind of error / deconnection so we remove this
|
||||||
// element from our keys
|
// element from our keys
|
||||||
|
|
||||||
CFRelease(myKeys[key]);
|
CFRelease(*it);
|
||||||
myKeys[key] = 0;
|
it = myKeys[key].erase(it);
|
||||||
|
|
||||||
sf::Err() << key
|
sf::Err() << key
|
||||||
<< " is dead (cannot access its value)."
|
<< " is dead (cannot access its value)."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
} else if (IOHIDValueGetIntegerValue(value) == 1) {
|
} else if (IOHIDValueGetIntegerValue(value) == 1) {
|
||||||
|
|
||||||
// This means the key is pressed
|
// This means the key is pressed
|
||||||
return true;
|
state = true;
|
||||||
|
break; // Stop here.
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// This means the key is released
|
// This means the key is released
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -116,9 +109,6 @@ HIDInputManager::HIDInputManager()
|
|||||||
, myLayout(0)
|
, myLayout(0)
|
||||||
, myManager(0)
|
, myManager(0)
|
||||||
{
|
{
|
||||||
// And initialize myKeys with 0s.
|
|
||||||
std::fill(myKeys, myKeys + Keyboard::KeyCount, (IOHIDElementRef)0);
|
|
||||||
|
|
||||||
// Get the current keyboard layout
|
// Get the current keyboard layout
|
||||||
TISInputSourceRef tis = TISCopyCurrentKeyboardLayoutInputSource();
|
TISInputSourceRef tis = TISCopyCurrentKeyboardLayoutInputSource();
|
||||||
myLayoutData = (CFDataRef)TISGetInputSourceProperty(tis,
|
myLayoutData = (CFDataRef)TISGetInputSourceProperty(tis,
|
||||||
@ -172,50 +162,45 @@ void HIDInputManager::InitializeKeyboard()
|
|||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// The purpose of this function is to initalize myKeys so we can get
|
// The purpose of this function is to initalize myKeys so we can get
|
||||||
// the associate IOHIDElementRef of a sf::Keyboard::Key in constant time.
|
// the associate IOHIDElementRef with a sf::Keyboard::Key in ~constant~ time.
|
||||||
|
|
||||||
|
// Get only keyboards
|
||||||
// Filter and keep only the keyboards
|
CFSetRef keyboards = CopyDevices(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard);
|
||||||
CFDictionaryRef mask = CopyDevicesMaskForManager(kHIDPage_GenericDesktop,
|
|
||||||
kHIDUsage_GD_Keyboard);
|
|
||||||
|
|
||||||
IOHIDManagerSetDeviceMatching(myManager, mask);
|
|
||||||
|
|
||||||
CFRelease(mask);
|
|
||||||
mask = 0;
|
|
||||||
|
|
||||||
CFSetRef keyboards = IOHIDManagerCopyDevices(myManager);
|
|
||||||
if (keyboards == NULL) {
|
if (keyboards == NULL) {
|
||||||
sf::Err() << "Cannot find any keyboard (1)" << std::endl;
|
|
||||||
FreeUp();
|
// FreeUp was already called
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is there at least one keyboard ?
|
CFIndex keyboardCount = CFSetGetCount(keyboards); // >= 1 (asserted by CopyDevices)
|
||||||
CFIndex keyboardCount = CFSetGetCount(keyboards);
|
|
||||||
if (keyboardCount < 1) {
|
|
||||||
sf::Err() << "Cannot find any keyboard (2)" << std::endl;
|
|
||||||
CFRelease(keyboards);
|
|
||||||
FreeUp();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the first keyboard
|
// Get an iterable array
|
||||||
CFTypeRef devicesArray[keyboardCount];
|
CFTypeRef devicesArray[keyboardCount];
|
||||||
CFSetGetValues(keyboards, devicesArray);
|
CFSetGetValues(keyboards, devicesArray);
|
||||||
|
|
||||||
IOHIDDeviceRef keyboard = (IOHIDDeviceRef)devicesArray[0];
|
for (CFIndex i = 0; i < keyboardCount; ++i) {
|
||||||
|
|
||||||
CFArrayRef keys = IOHIDDeviceCopyMatchingElements(keyboard,
|
IOHIDDeviceRef keyboard = (IOHIDDeviceRef)devicesArray[i];
|
||||||
NULL,
|
|
||||||
kIOHIDOptionsTypeNone);
|
LoadKeyboard(keyboard);
|
||||||
|
}
|
||||||
|
|
||||||
// Release unused stuff
|
// Release unused stuff
|
||||||
CFRelease(keyboards);
|
CFRelease(keyboards);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// At this point myKeys is filled with as many IOHIDElementRef as possible
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void HIDInputManager::LoadKeyboard(IOHIDDeviceRef keyboard)
|
||||||
|
{
|
||||||
|
CFArrayRef keys = IOHIDDeviceCopyMatchingElements(keyboard,
|
||||||
|
NULL,
|
||||||
|
kIOHIDOptionsTypeNone);
|
||||||
if (keys == NULL) {
|
if (keys == NULL) {
|
||||||
sf::Err() << "We got a keyboard without any keys (1)" << std::endl;
|
sf::Err() << "We got a keyboard without any keys (1)" << std::endl;
|
||||||
FreeUp();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,12 +210,12 @@ void HIDInputManager::InitializeKeyboard()
|
|||||||
if (keysCount == 0) {
|
if (keysCount == 0) {
|
||||||
sf::Err() << "We got a keyboard without any keys (2)" << std::endl;
|
sf::Err() << "We got a keyboard without any keys (2)" << std::endl;
|
||||||
CFRelease(keys);
|
CFRelease(keys);
|
||||||
FreeUp();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go through all connected elements.
|
// Go through all connected elements.
|
||||||
for (int i = 0; i < keysCount; ++i) {
|
for (CFIndex i = 0; i < keysCount; ++i) {
|
||||||
|
|
||||||
IOHIDElementRef aKey = (IOHIDElementRef) CFArrayGetValueAtIndex(keys, i);
|
IOHIDElementRef aKey = (IOHIDElementRef) CFArrayGetValueAtIndex(keys, i);
|
||||||
|
|
||||||
// Skip non-matching keys elements
|
// Skip non-matching keys elements
|
||||||
@ -238,12 +223,24 @@ void HIDInputManager::InitializeKeyboard()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LoadKey(aKey);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release unused stuff
|
||||||
|
CFRelease(keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void HIDInputManager::LoadKey(IOHIDElementRef key)
|
||||||
|
{
|
||||||
// Get its virtual code
|
// Get its virtual code
|
||||||
UInt32 usageCode = IOHIDElementGetUsage(aKey);
|
UInt32 usageCode = IOHIDElementGetUsage(key);
|
||||||
UInt8 virtualCode = UsageToVirtualCode(usageCode);
|
UInt8 virtualCode = UsageToVirtualCode(usageCode);
|
||||||
|
|
||||||
if (virtualCode == 0xff) {
|
if (virtualCode == 0xff) {
|
||||||
continue; // no corresponding virtual code -> skip
|
return; // no corresponding virtual code -> skip
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now translate the virtual code to unicode according to
|
// Now translate the virtual code to unicode according to
|
||||||
@ -272,16 +269,16 @@ void HIDInputManager::InitializeKeyboard()
|
|||||||
// Translation went fine
|
// Translation went fine
|
||||||
|
|
||||||
// The corresponding SFML key code
|
// The corresponding SFML key code
|
||||||
Keyboard::Key code = Keyboard::KeyCount;
|
Keyboard::Key code = Keyboard::KeyCount; // KeyCound means 'none'
|
||||||
|
|
||||||
// First we look if the key down is from a list of caracter
|
// First we look if the key down is from a list of characters
|
||||||
// that depend on keyboard localization.
|
// that depend on keyboard localization
|
||||||
if (actualStringLength > 0) {
|
if (actualStringLength > 0) {
|
||||||
code = LocalizedKeys(unicodeString[0]);
|
code = LocalizedKeys(unicodeString[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The key is not a localized one, so we try to find a corresponding
|
// The key is not a localized one so we try to find a
|
||||||
// code through virtual key code.
|
// corresponding code through virtual key code
|
||||||
if (code == Keyboard::KeyCount) {
|
if (code == Keyboard::KeyCount) {
|
||||||
code = NonLocalizedKeys(virtualCode);
|
code = NonLocalizedKeys(virtualCode);
|
||||||
}
|
}
|
||||||
@ -289,39 +286,13 @@ void HIDInputManager::InitializeKeyboard()
|
|||||||
// A code was found, wonderful!
|
// A code was found, wonderful!
|
||||||
if (code != Keyboard::KeyCount) {
|
if (code != Keyboard::KeyCount) {
|
||||||
|
|
||||||
// Last step : verify that the key was not found twice or more
|
|
||||||
|
|
||||||
// Some keys (modifiers) appears to be twice on my keyboard
|
|
||||||
// I've no idea why
|
|
||||||
// if (myKeys[code] != 0) {
|
|
||||||
// UInt32 firstUsageCode = IOHIDElementGetUsage(myKeys[code]);
|
|
||||||
// sf::Err() << "The current keyboard has several times the "
|
|
||||||
// << "same keys. Only the first one is considered "
|
|
||||||
// << "as valid. sf::Keyboard::Key is "
|
|
||||||
// << code
|
|
||||||
// << ", virtual key code is 0x"
|
|
||||||
// << std::hex
|
|
||||||
// << (UInt32)virtualCode
|
|
||||||
// << " and HID usage code is 0x"
|
|
||||||
// << usageCode
|
|
||||||
// << ". First HID usage code is 0x"
|
|
||||||
// << firstUsageCode
|
|
||||||
// << std::dec
|
|
||||||
// << "."
|
|
||||||
// << std::endl;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (myKeys[code] == 0) {
|
|
||||||
|
|
||||||
// Ok, everything went fine. Now we have a unique
|
// Ok, everything went fine. Now we have a unique
|
||||||
// corresponding sf::Keyboard::Key to one IOHIDElementRef.
|
// corresponding sf::Keyboard::Key to one IOHIDElementRef
|
||||||
|
|
||||||
myKeys[code] = aKey;
|
myKeys[code].push_back(key);
|
||||||
|
|
||||||
// And don't forget to keep the reference alive for our usage
|
// And don't forget to keep the reference alive for our usage
|
||||||
CFRetain(myKeys[code]);
|
CFRetain(myKeys[code].back());
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,7 +309,7 @@ void HIDInputManager::InitializeKeyboard()
|
|||||||
// 0x51 | 0x67 | Keypad Equal
|
// 0x51 | 0x67 | Keypad Equal
|
||||||
// 0x4c | 0x77 | Select
|
// 0x4c | 0x77 | Select
|
||||||
|
|
||||||
// else { // The key is unknown.
|
//if (code == Keyboard::KeyCount) { // The key is unknown.
|
||||||
// sf::Err() << "This is an unknow key. Virtual key code is 0x"
|
// sf::Err() << "This is an unknow key. Virtual key code is 0x"
|
||||||
// << std::hex
|
// << std::hex
|
||||||
// << (UInt32)virtualCode
|
// << (UInt32)virtualCode
|
||||||
@ -350,19 +321,12 @@ void HIDInputManager::InitializeKeyboard()
|
|||||||
//}
|
//}
|
||||||
|
|
||||||
} /* if (error == noErr) */
|
} /* if (error == noErr) */
|
||||||
|
|
||||||
else {
|
else {
|
||||||
|
|
||||||
sf::Err() << "Cannot translate the virtual key code, error : "
|
sf::Err() << "Cannot translate the virtual key code, error : "
|
||||||
<< error
|
<< error
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* for (int i = 0; i < keysCount; ++i) */
|
|
||||||
|
|
||||||
CFRelease(keys);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// At this point myKeys is filled with as many IOHIDElementRef as possible
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -376,9 +340,10 @@ void HIDInputManager::FreeUp()
|
|||||||
if (myManager != 0) CFRelease(myManager);
|
if (myManager != 0) CFRelease(myManager);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < Keyboard::KeyCount; ++i) {
|
for (unsigned int i = 0; i < Keyboard::KeyCount; ++i) {
|
||||||
if (myKeys[i] != 0) {
|
for (IOHIDElements::iterator it = myKeys[i].begin(); it != myKeys[i].end(); ++it) {
|
||||||
CFRelease(myKeys[i]);
|
CFRelease(*it);
|
||||||
}
|
}
|
||||||
|
myKeys[i].clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,11 +370,42 @@ CFDictionaryRef HIDInputManager::CopyDevicesMaskForManager(UInt32 page, UInt32 u
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
CFSetRef HIDInputManager::CopyDevices(UInt32 page, UInt32 usage)
|
||||||
|
{
|
||||||
|
// Filter and keep only the requested devices
|
||||||
|
CFDictionaryRef mask = CopyDevicesMaskForManager(page, usage);
|
||||||
|
|
||||||
|
IOHIDManagerSetDeviceMatching(myManager, mask);
|
||||||
|
|
||||||
|
CFRelease(mask);
|
||||||
|
mask = 0;
|
||||||
|
|
||||||
|
CFSetRef devices = IOHIDManagerCopyDevices(myManager);
|
||||||
|
if (devices == NULL) {
|
||||||
|
sf::Err() << "Cannot find any devices." << std::endl;
|
||||||
|
FreeUp();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is there at least one keyboard ?
|
||||||
|
CFIndex deviceCount = CFSetGetCount(devices);
|
||||||
|
if (deviceCount < 1) {
|
||||||
|
sf::Err() << "Found no device." << std::endl;
|
||||||
|
CFRelease(devices);
|
||||||
|
FreeUp();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
UInt8 HIDInputManager::UsageToVirtualCode(UInt32 usage)
|
UInt8 HIDInputManager::UsageToVirtualCode(UInt32 usage)
|
||||||
{
|
{
|
||||||
// Some usage key doesn't have any corresponding virtual code or it was not
|
// Some usage key doesn't have any corresponding virtual
|
||||||
// found.
|
// code or it was not found (return 0xff).
|
||||||
switch (usage) {
|
switch (usage) {
|
||||||
case kHIDUsage_KeyboardErrorRollOver: return 0xff;
|
case kHIDUsage_KeyboardErrorRollOver: return 0xff;
|
||||||
case kHIDUsage_KeyboardPOSTFail: return 0xff;
|
case kHIDUsage_KeyboardPOSTFail: return 0xff;
|
||||||
|
Loading…
Reference in New Issue
Block a user