AppleEmbeddedKeyboard.cpp [plain text]
#include <IOKit/IOLib.h>
#include "AppleEmbeddedKeyboard.h"
#include "AppleHIDUsageTables.h"
#include "IOHIDUsageTables.h"
#include "IOHIDKeyboard.h"
#include "IOLLEvent.h"
#define kFnFunctionUsageMapKey "FnFunctionUsageMap"
#define kFnKeyboardUsageMapKey "FnKeyboardUsageMap"
#define kNumLockKeyboardUsageMapKey "NumLockKeyboardUsageMap"
#define kKeyboardUsageMapKey "KeyboardUsageMap"
#define super IOHIDEventDriver
OSDefineMetaClassAndStructors( AppleEmbeddedKeyboard, IOHIDEventDriver )
bool AppleEmbeddedKeyboard::init(OSDictionary * properties)
{
if ( !super::init(properties) )
return false;
bzero(_secondaryKeys, sizeof(SecondaryKey)*255);
return true;
}
void AppleEmbeddedKeyboard::free()
{
if ( _keyboardMap )
_keyboardMap->release();
super::free();
}
bool AppleEmbeddedKeyboard::handleStart( IOService * provider )
{
if (!super::handleStart(provider))
return false;
findKeyboardRollOverElement(getReportElements());
parseSecondaryUsages();
_keyboardMap = OSDynamicCast(OSDictionary, copyProperty(kKeyboardUsageMapKey));
setProperty(kIOHIDFKeyModeKey, _fKeyMode, sizeof(_fKeyMode));
return true;
}
void AppleEmbeddedKeyboard::setElementValue (
UInt32 usagePage,
UInt32 usage,
UInt32 value )
{
if ((usagePage == kHIDPage_LEDs) && (usage == kHIDUsage_LED_NumLock))
_numLockDown = (value != 0);
super::setElementValue(usagePage, usage, value);
}
void AppleEmbeddedKeyboard::dispatchKeyboardEvent(
AbsoluteTime timeStamp,
UInt32 usagePage,
UInt32 usage,
UInt32 value,
IOOptionBits options)
{
filterKeyboardUsage(&usagePage, &usage, value);
if ( (( usagePage == kHIDPage_AppleVendorTopCase ) && ( usage == kHIDUsage_AV_TopCase_KeyboardFn )) ||
(( usagePage == kHIDPage_AppleVendorKeyboard ) && ( usage == kHIDUsage_AppleVendorKeyboard_Function )) )
{
if (_keyboardRollOverElement)
{
AbsoluteTime rolloverTS = _keyboardRollOverElement->getTimeStamp();
if ((CMP_ABSOLUTETIME(&rolloverTS, &timeStamp) == 0) &&
((_keyboardRollOverElement->getValue() && value && !_fnKeyDownPhysical) || (_fnKeyDownPhysical == value)))
return;
}
_fnKeyDownPhysical = (value != 0);
}
else if ( usagePage == kHIDPage_KeyboardOrKeypad )
{
if (!filterSecondaryFnFunctionUsage(&usagePage, &usage, (value!=0))
&& !filterSecondaryFnKeyboardUsage(&usagePage, &usage, (value!=0))
&& filterSecondaryNumLockKeyboardUsage(&usagePage, &usage, (value!=0)))
return;
}
super::dispatchKeyboardEvent(timeStamp, usagePage, usage, value, options);
#if !TARGET_OS_EMBEDDED
_fnKeyDownVirtual = _keyboardNub ? (_keyboardNub->eventFlags() & NX_SECONDARYFNMASK) : _fnKeyDownPhysical;
#else
_fnKeyDownVirtual = _fnKeyDownPhysical;
#endif
}
bool AppleEmbeddedKeyboard::filterSecondaryFnFunctionUsage(
UInt32 * usagePage,
UInt32 * usage,
bool down)
{
if (!(_secondaryKeys[*usage].bits & kSecondaryKeyFnFunction))
return false;
if (down && ( _fnKeyDownPhysical ^ _fKeyMode ))
return false;
if (!down && !(_secondaryKeys[*usage].swapping & kSecondaryKeyFnFunction))
return false;
#if !TARGET_OS_EMBEDDED
if ((*usagePage == kHIDPage_KeyboardOrKeypad) && (*usage == kHIDUsage_KeyboardF5)) {
UInt32 flags = _keyboardNub ? _keyboardNub->eventFlags() : 0;
if (flags & (NX_COMMANDMASK | NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK)) {
return false;
}
}
#endif
if (down)
_secondaryKeys[*usage].swapping |= kSecondaryKeyFnFunction;
else
_secondaryKeys[*usage].swapping = 0;
*usagePage = _secondaryKeys[*usage].fnFunctionUsagePage;
*usage = _secondaryKeys[*usage].fnFunctionUsage;
return true;
}
bool AppleEmbeddedKeyboard::filterSecondaryFnKeyboardUsage(
UInt32 * usagePage,
UInt32 * usage,
bool down)
{
if (!(_secondaryKeys[*usage].bits & kSecondaryKeyFnKeyboard))
return false;
if (down && !_fnKeyDownVirtual)
return false;
if (!down && !(_secondaryKeys[*usage].swapping & kSecondaryKeyFnKeyboard))
return false;
if (down)
_secondaryKeys[*usage].swapping |= kSecondaryKeyFnKeyboard;
else
_secondaryKeys[*usage].swapping = 0;
*usagePage = _secondaryKeys[*usage].fnKeyboardUsagePage;
*usage = _secondaryKeys[*usage].fnKeyboardUsage;
return false;
}
bool AppleEmbeddedKeyboard::filterSecondaryNumLockKeyboardUsage(
UInt32 * usagePage,
UInt32 * usage,
bool down)
{
if (down && !_numLockDown)
return false;
if (!down && !(_secondaryKeys[*usage].swapping & kSecondaryKeyNumLockKeyboard))
return false;
if (_secondaryKeys[*usage].bits & kSecondaryKeyNumLockKeyboard)
{
if (down)
_secondaryKeys[*usage].swapping |= kSecondaryKeyNumLockKeyboard;
else
_secondaryKeys[*usage].swapping = 0;
*usagePage = _secondaryKeys[*usage].numLockKeyboardUsagePage;
*usage = _secondaryKeys[*usage].numLockKeyboardUsage;
}
else if ( down )
return true;
return false;
}
bool AppleEmbeddedKeyboard::filterKeyboardUsage(UInt32 * usagePage,
UInt32 * usage,
bool down __unused)
{
char key[32];
bzero(key, sizeof(key));
snprintf(key, sizeof(key), "0x%04x%04x", (uint16_t)*usagePage, (uint16_t)*usage);
if ( _keyboardMap ) {
OSNumber * map = OSDynamicCast(OSNumber, _keyboardMap->getObject(key));
if ( map ) {
*usagePage = (map->unsigned32BitValue()>>16) & 0xffff;
*usage = map->unsigned32BitValue()&0xffff;
}
}
return false;
}
void AppleEmbeddedKeyboard::findKeyboardRollOverElement(OSArray * reportElements)
{
IOHIDElement * element;
UInt32 count;
if (!reportElements)
return;
count = reportElements->getCount();
for (UInt32 i=0; i<count; i++)
{
element = (IOHIDElement *) reportElements->getObject(i);
if (element && (element->getUsagePage() == kHIDPage_KeyboardOrKeypad ) &&
(element->getUsage() == kHIDUsage_KeyboardErrorRollOver))
{
_keyboardRollOverElement = element;
return;
}
}
}
void AppleEmbeddedKeyboard::parseSecondaryUsages()
{
OSString * mappingString;
char * str;
UInt32 index, value;
#define DECODE_MAP(type,key,bit) \
do { \
mappingString = OSDynamicCast(OSString,getProperty(key)); \
if (!mappingString) break; \
str = (char *)mappingString->getCStringNoCopy(); \
while ( str && (*str != '\0')) { \
index = strtoul(str, &str, 16) & 0xff; \
while ((*str!='\0')&&((*str < '0')||(*str > '9'))) { str ++; } \
value = strtoul(str, &str, 16); \
while ((*str!='\0')&&((*str < '0')||(*str > '9'))) { str ++; } \
_secondaryKeys[index].type##UsagePage = (value >> 16) & 0xffff; \
_secondaryKeys[index].type##Usage = value & 0xffff; \
_secondaryKeys[index].bits |= bit; \
} \
} while (0)
DECODE_MAP(numLockKeyboard, kNumLockKeyboardUsageMapKey, kSecondaryKeyNumLockKeyboard);
DECODE_MAP(fnKeyboard, kFnKeyboardUsageMapKey, kSecondaryKeyFnKeyboard);
DECODE_MAP(fnFunction, kFnFunctionUsageMapKey, kSecondaryKeyFnFunction);
if ( getProperty(kNumLockKeyboardUsageMapKey) ) {
_virtualMouseKeysSupport = TRUE;
for (index=0; index<255; index++) {
if ( ( _secondaryKeys[index].bits & kSecondaryKeyFnFunction ) &&
( _secondaryKeys[index].fnFunctionUsagePage == kHIDPage_KeyboardOrKeypad ) &&
( _secondaryKeys[index].fnFunctionUsage == kHIDUsage_KeyboardLockingNumLock ) ) {
_virtualMouseKeysSupport = FALSE;
break;
}
}
} else {
_virtualMouseKeysSupport = FALSE;
}
setProperty(kIOHIDMouseKeysEnablesVirtualNumPadKey, _virtualMouseKeysSupport);
}
IOReturn AppleEmbeddedKeyboard::setSystemProperties( OSDictionary * properties )
{
OSNumber * number;
OSString * string;
bool parseSecondaries = false;
if ((number = OSDynamicCast(OSNumber, properties->getObject(kIOHIDFKeyModeKey))))
{
_fKeyMode = number->unsigned32BitValue();
setProperty(kIOHIDFKeyModeKey, number);
}
if (_virtualMouseKeysSupport && ((number = OSDynamicCast(OSNumber, properties->getObject(kIOHIDMouseKeysOnKey)))))
{
_numLockDown = number->unsigned32BitValue();
}
if ((string = OSDynamicCast(OSString, properties->getObject(kFnFunctionUsageMapKey)))) {
setProperty(kFnFunctionUsageMapKey, string);
parseSecondaries = true;
}
if ((string = OSDynamicCast(OSString, properties->getObject(kFnKeyboardUsageMapKey)))) {
setProperty(kFnKeyboardUsageMapKey, string);
parseSecondaries = true;
}
if ((string = OSDynamicCast(OSString, properties->getObject(kNumLockKeyboardUsageMapKey)))) {
setProperty(kNumLockKeyboardUsageMapKey, string);
parseSecondaries = true;
}
if (parseSecondaries) {
parseSecondaryUsages();
}
return super::setSystemProperties(properties);
}