IOHIDKeyboardDevice.cpp [plain text]
#include <IOKit/IOLib.h>
#include "IOHIDKeyboardDevice.h"
typedef struct GenericLEDKeyboardDescriptor {
UInt8 devUsagePageOp;
UInt8 devUsagePageNum;
UInt8 devUsageOp;
UInt8 devUsageNum;
UInt8 appCollectionOp;
UInt8 appCollectionNum;
UInt8 modUsagePageOp;
UInt8 modUsagePageNum;
UInt8 modUsageMinOp;
UInt8 modUsageMinNum;
UInt8 modUsageMaxOp;
UInt8 modUsageMaxNum;
UInt8 modLogMinOp;
UInt8 modLogMinNum;
UInt8 modLogMaxOp;
UInt8 modLogMaxNum;
UInt8 modRptCountOp;
UInt8 modRptCountNum;
UInt8 modRptSizeOp;
UInt8 modRptSizeNum;
UInt8 modInputOp;
UInt8 modInputNum;
UInt8 rsrvCountOp;
UInt8 rsrvCountNum;
UInt8 rsrvSizeOp;
UInt8 rsrvSizeNum;
UInt8 rsrvInputOp;
UInt8 rsrvInputNum;
UInt8 ledRptCountOp;
UInt8 ledRptCountNum;
UInt8 ledRptSizeOp;
UInt8 ledRptSizeNum;
UInt8 ledUsagePageOp;
UInt8 ledUsagePageNum;
UInt8 ledUsageMinOp;
UInt8 ledUsageMinNum;
UInt8 ledUsageMaxOp;
UInt8 ledUsageMaxNum;
UInt8 ledInputOp;
UInt8 ledInputNum;
UInt8 fillRptCountOp;
UInt8 fillRptCountNum;
UInt8 fillRptSizeOp;
UInt8 fillRptSizeNum;
UInt8 fillInputOp;
UInt8 fillInputNum;
UInt8 keyRptCountOp;
UInt8 keyRptCountNum;
UInt8 keyRptSizeOp;
UInt8 keyRptSizeNum;
UInt8 keyLogMinOp;
UInt8 keyLogMinNum;
UInt8 keyLogMaxOp;
UInt16 keyLogMaxNum;
UInt8 keyUsagePageOp;
UInt8 keyUsagePageNum;
UInt8 keyUsageMinOp;
UInt8 keyUsageMinNum;
UInt8 keyUsageMaxOp;
UInt8 keyUsageMaxNum;
UInt8 keyInputOp;
UInt8 keyInputNum;
UInt8 appCollectionEnd;
} GenericLEDKeyboardDescriptor;
struct GenericKeyboardDescriptor {
UInt8 devUsagePageOp;
UInt8 devUsagePageNum;
UInt8 devUsageOp;
UInt8 devUsageNum;
UInt8 appCollectionOp;
UInt8 appCollectionNum;
UInt8 modUsagePageOp;
UInt8 modUsagePageNum;
UInt8 modUsageMinOp;
UInt8 modUsageMinNum;
UInt8 modUsageMaxOp;
UInt8 modUsageMaxNum;
UInt8 modLogMinOp;
UInt8 modLogMinNum;
UInt8 modLogMaxOp;
UInt8 modLogMaxNum;
UInt8 modRptCountOp;
UInt8 modRptCountNum;
UInt8 modRptSizeOp;
UInt8 modRptSizeNum;
UInt8 modInputOp;
UInt8 modInputNum;
UInt8 rsrvCountOp;
UInt8 rsrvCountNum;
UInt8 rsrvSizeOp;
UInt8 rsrvSizeNum;
UInt8 rsrvInputOp;
UInt8 rsrvInputNum;
UInt8 ledRptCountOp;
UInt8 ledRptCountNum;
UInt8 ledRptSizeOp;
UInt8 ledRptSizeNum;
UInt8 ledUsagePageOp;
UInt8 ledUsagePageNum;
UInt8 ledUsageMinOp;
UInt8 ledUsageMinNum;
UInt8 ledUsageMaxOp;
UInt8 ledUsageMaxNum;
UInt8 ledInputOp;
UInt8 ledInputNum;
UInt8 fillRptCountOp;
UInt8 fillRptCountNum;
UInt8 fillRptSizeOp;
UInt8 fillRptSizeNum;
UInt8 fillInputOp;
UInt8 fillInputNum;
UInt8 keyRptCountOp;
UInt8 keyRptCountNum;
UInt8 keyRptSizeOp;
UInt8 keyRptSizeNum;
UInt8 keyLogMinOp;
UInt8 keyLogMinNum;
UInt8 keyLogMaxOp;
UInt16 keyLogMaxNum;
UInt8 keyUsagePageOp;
UInt8 keyUsagePageNum;
UInt8 keyUsageMinOp;
UInt8 keyUsageMinNum;
UInt8 keyUsageMaxOp;
UInt8 keyUsageMaxNum;
UInt8 keyInputOp;
UInt8 keyInputNum;
UInt8 appCollectionEnd;
} GenericKeyboardDescriptor;
typedef struct GenericKeyboardRpt {
UInt8 modifiers;
UInt8 reserved;
UInt8 keys[6];
} GenericKeyboardRpt;
static UInt8 gGenLEDKeyboardDesc[] = {
0x05, 0x01,
0x09, 0x06,
0xA1, 0x01,
0x05, 0x07,
0x19, 0xe0,
0x29, 0xe7,
0x15, 0x00,
0x25, 0x01,
0x75, 0x01,
0x95, 0x08,
0x81, 0x02,
0x95, 0x01,
0x75, 0x08,
0x81, 0x01,
0x95, 0x02,
0x75, 0x01,
0x05, 0x08,
0x19, 0x01,
0x29, 0x02,
0x91, 0x02,
0x95, 0x01,
0x75, 0x06,
0x91, 0x01,
0x95, 0x06,
0x75, 0x08,
0x15, 0x00,
0x26, 0xff, 0x00,
0x05, 0x07,
0x19, 0x00,
0x29, 0xff,
0x81, 0x00,
0xC0
};
static UInt8 gGenKeyboardDesc[] = {
0x05, 0x01,
0x09, 0x06,
0xA1, 0x01,
0x05, 0x07,
0x19, 0xe0,
0x29, 0xe7,
0x15, 0x00,
0x25, 0x01,
0x75, 0x01,
0x95, 0x08,
0x81, 0x02,
0x95, 0x01,
0x75, 0x08,
0x81, 0x01,
0x95, 0x06,
0x75, 0x08,
0x15, 0x00,
0x26, 0xff, 0x00,
0x05, 0x07,
0x19, 0x00,
0x29, 0xff,
0x81, 0x00,
0xC0
};
static unsigned char hid_adb_2_usb_keymap[] =
{
0x04, 0x16, 0x07, 0x09, 0x0b, 0x0a, 0x1d, 0x1b, 0x06, 0x19, 0x64, 0x05, 0x14, 0x1a, 0x08, 0x15, 0x1c, 0x17, 0x1e, 0x1f, 0x20, 0x21, 0x23, 0x22, 0x2e, 0x26, 0x24, 0x2d, 0x25, 0x27, 0x30, 0x12, 0x18, 0x2f, 0x0c, 0x13, 0x28, 0x0f, 0x0d, 0x34, 0x0e, 0x33, 0x31, 0x36, 0x38, 0x11, 0x10, 0x37, 0x2b, 0x2c, 0x35, 0x2a, 0x58, 0x29, 0xe7, 0xe3, 0xe1, 0x39, 0xe2, 0xe0, 0xe5, 0xe6, 0xe4, 0x00, 0x6c, 0x63, 0x00, 0x55, 0x6d, 0x57, 0x00, 0x53, 0x00, 0x00, 0x00, 0x54, 0x58, 0x00, 0x56, 0x6d, 0x6e, 0x67, 0x62, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x6f, 0x60, 0x61, 0x89, 0x87, 0x85, 0x3e, 0x3f, 0x40, 0x3c, 0x41, 0x42, 0x91, 0x44, 0x90, 0x68, 0x6b, 0x69, 0x0, 0x43, 0x65, 0x45, 0x0, 0x6a, 0x75, 0x4a, 0x4b, 0x4c, 0x3d, 0x4d, 0x3b, 0x4e, 0x3a, 0x50, 0x4f, 0x51, 0x52, 0x66, };
#define super IOHIDDeviceShim
OSDefineMetaClassAndStructors( IOHIDKeyboardDevice, super )
IOHIDKeyboardDevice *
IOHIDKeyboardDevice::newKeyboardDeviceAndStart(IOService * owner, UInt32 location)
{
IOService * provider = owner;
while (provider = provider->getProvider())
{
if(OSDynamicCast(IOHIDDevice, provider) || OSDynamicCast(IOHIDevice, provider))
return 0;
}
IOHIDKeyboardDevice * device = new IOHIDKeyboardDevice;
if (device)
{
if ( device->initWithLocation(location) && device->attach(owner) )
{
if (!device->start(owner))
{
device->detach(owner);
device->release();
device = 0;
}
}
else
{
device->release();
device = 0;
}
}
return device;
}
bool IOHIDKeyboardDevice::initWithLocation( UInt32 location )
{
if (!super::initWithLocation(location))
return false;
_report = 0;
_cachedLEDState = 0;
_inputReportOnly = true;
bcopy(hid_adb_2_usb_keymap, _adb2usb, sizeof(hid_adb_2_usb_keymap));
return true;
}
void IOHIDKeyboardDevice::free()
{
if (_report) _report->release();
super::free();
}
bool IOHIDKeyboardDevice::handleStart( IOService * provider )
{
if (!super::handleStart(provider))
return false;
if ( (_keyboard = OSDynamicCast(IOHIKeyboard, provider)) )
{
_inputReportOnly = ((transport() == kIOHIDTransportADB) && (_keyboard->deviceType() >= 0xc3));
_cachedLEDState = _keyboard->getLEDStatus() & 0x3;
}
_report = IOBufferMemoryDescriptor::withCapacity(
sizeof(GenericKeyboardRpt), kIODirectionNone, true);
bzero(_report->getBytesNoCopy(), sizeof(GenericKeyboardRpt));
return (_report) ? true : false;
}
IOReturn IOHIDKeyboardDevice::newReportDescriptor(
IOMemoryDescriptor ** descriptor ) const
{
void * desc;
UInt8 * descBytes;
UInt8 descSize;
if (!descriptor)
return kIOReturnBadArgument;
if (_inputReportOnly)
{
descSize = sizeof(GenericKeyboardDescriptor);
descBytes = gGenKeyboardDesc;
}
else
{
descSize = sizeof(GenericLEDKeyboardDescriptor);
descBytes = gGenLEDKeyboardDesc;
}
*descriptor = IOBufferMemoryDescriptor::withCapacity(
descSize,
kIODirectionNone,
true);
if (! *descriptor)
return kIOReturnNoMemory;
desc = ((IOBufferMemoryDescriptor *)(*descriptor))->getBytesNoCopy();
bcopy(descBytes, desc, descSize);
return kIOReturnSuccess;
}
IOReturn IOHIDKeyboardDevice::getReport( IOMemoryDescriptor * report,
IOHIDReportType reportType,
IOOptionBits options )
{
if (!report)
return kIOReturnError;
if ( reportType != kIOHIDReportTypeInput)
return kIOReturnUnsupported;
report->writeBytes(0, _report->getBytesNoCopy(), min(report->getLength(), _report->getLength()));
return kIOReturnSuccess;
}
IOReturn IOHIDKeyboardDevice::setReport(IOMemoryDescriptor * report,
IOHIDReportType reportType,
IOOptionBits options )
{
UInt8 ledState;
UInt8 mask;
if ((options & 0xff) || (_inputReportOnly) || !_keyboard)
return kIOReturnError;
report->readBytes( 0, (void *)&ledState, sizeof(UInt8) );
mask = (1 << (kHIDUsage_LED_NumLock - 1));
if ( (ledState & mask) && !(_cachedLEDState & mask) )
{
_keyboard->setNumLockFeedback(true);
}
else if ( !(ledState & mask) && (_cachedLEDState & mask) )
{
_keyboard->setNumLockFeedback(false);
}
mask = (1 << (kHIDUsage_LED_CapsLock - 1));
if ( (ledState & mask) && !(_cachedLEDState & mask) )
{
_keyboard->setAlphaLockFeedback(true);
}
else if ( !(ledState & mask) && (_cachedLEDState & mask) )
{
_keyboard->setAlphaLockFeedback(false);
}
_cachedLEDState = ledState;
return kIOReturnSuccess;
}
void IOHIDKeyboardDevice::setCapsLockLEDElement(bool state)
{
UInt8 mask = (1 << (kHIDUsage_LED_CapsLock-1));
if (_inputReportOnly)
return;
if (state)
_cachedLEDState |= mask;
else
_cachedLEDState &= ~mask;
*(UInt8 *)(_report->getBytesNoCopy()) = _cachedLEDState;
handleReport(_report, kIOHIDReportTypeOutput);
}
void IOHIDKeyboardDevice::setNumLockLEDElement(bool state)
{
UInt8 mask = (1 << (kHIDUsage_LED_NumLock-1));
if (_inputReportOnly)
return;
if (state)
_cachedLEDState |= mask;
else
_cachedLEDState &= ~mask;
*(UInt8 *)(_report->getBytesNoCopy()) = _cachedLEDState;
handleReport(_report, kIOHIDReportTypeOutput);
}
#define SET_MODIFIER_BIT(bitField, key, down) \
if (down) {bitField |= (1 << (key - 0xe0));} \
else {bitField &= ~(1 << (key - 0xe0));}
void IOHIDKeyboardDevice::postKeyboardEvent(UInt8 key, bool keyDown)
{
GenericKeyboardRpt *report = (GenericKeyboardRpt *)_report->getBytesNoCopy();
UInt8 usbKey;
if (!report)
return;
if (! (usbKey = _adb2usb[key]))
return;
if ((usbKey >= 0xe0) && (usbKey <= 0xe7))
{
SET_MODIFIER_BIT(report->modifiers, usbKey, keyDown);
}
else
{
for (int i=0; i<6; i++)
{
if (report->keys[i] == usbKey)
{
if (keyDown) return;
for (int j=i; j<5; j++)
report->keys[j] = report->keys[j+1];
report->keys[5] = 0;
break;
}
else if ((report->keys[i] == 0) && keyDown)
{
report->keys[i] = usbKey;
break;
}
}
}
handleReport(_report);
}
enum {
kUSB_LEFT_CONTROL_BIT = 0x01,
kUSB_LEFT_SHIFT_BIT = 0x02,
kUSB_LEFT_ALT_BIT = 0x04,
kUSB_LEFT_FLOWER_BIT = 0x08,
kUSB_RIGHT_CONTROL_BIT = 0x10,
kUSB_RIGHT_SHIFT_BIT = 0x20,
kUSB_RIGHT_ALT_BIT = 0x040,
kUSB_RIGHT_FLOWER_BIT = 0x80
};
void IOHIDKeyboardDevice::postFlagKeyboardEvent(UInt32 flags)
{
GenericKeyboardRpt *report = (GenericKeyboardRpt *)_report->getBytesNoCopy();
UInt32 flagDelta = (flags ^ _lastFlags);
if (!flagDelta)
return;
report->modifiers = 0;
_lastFlags = flags;
if ( flagDelta & 0x0000ffff )
{
if( flags & NX_DEVICELSHIFTKEYMASK )
report->modifiers |= kUSB_LEFT_SHIFT_BIT;
if( flags & NX_DEVICELCTLKEYMASK )
report->modifiers |= kUSB_LEFT_CONTROL_BIT;
if( flags & NX_DEVICELALTKEYMASK )
report->modifiers |= kUSB_LEFT_ALT_BIT;
if( flags & NX_DEVICELCMDKEYMASK )
report->modifiers |= kUSB_LEFT_FLOWER_BIT;
if( flags & NX_DEVICERSHIFTKEYMASK )
report->modifiers |= kUSB_RIGHT_SHIFT_BIT;
if( flags & NX_DEVICERCTLKEYMASK )
report->modifiers |= kUSB_RIGHT_CONTROL_BIT;
if( flags & NX_DEVICERALTKEYMASK )
report->modifiers |= kUSB_RIGHT_ALT_BIT;
if( flags & NX_DEVICERCMDKEYMASK )
report->modifiers |= kUSB_RIGHT_FLOWER_BIT;
}
else if ( flagDelta & 0xffff0000 )
{
if( flags & NX_SHIFTMASK )
report->modifiers |= kUSB_LEFT_SHIFT_BIT;
if( flags & NX_CONTROLMASK )
report->modifiers |= kUSB_LEFT_CONTROL_BIT;
if( flags & NX_ALTERNATEMASK )
report->modifiers |= kUSB_LEFT_ALT_BIT;
if( flags & NX_COMMANDMASK )
report->modifiers |= kUSB_LEFT_FLOWER_BIT;
}
if ( flagDelta & NX_ALPHASHIFTMASK )
{
postKeyboardEvent(0x39, flags & NX_ALPHASHIFTMASK);
return;
}
handleReport(_report);
}
OSString * IOHIDKeyboardDevice::newProductString() const
{
OSString * string = 0;
if ( !(string = super::newProductString()) )
string = OSString::withCString("Virtual Keyboard");
return string;
}