#include <IOKit/IOLib.h>
#include <IOKit/hidsystem/IOHIKeyboard.h>
#include <IOKit/hidsystem/IOHIKeyboardMapper.h>
#include <IOKit/hidsystem/IOLLEvent.h>
#include <IOKit/hidsystem/IOHIDParameter.h>
#include "IOHIDSystem.h"
#include "IOHIDKeyboardDevice.h"
struct KeyboardReserved
{
thread_call_t repeat_thread_call;
bool dispatchEventCalled;
bool isSeized;
IOService * openClient;
IOHIDKeyboardDevice * keyboardNub;
};
static OSDictionary *gKeyboardReservedDictionary = OSDictionary::withCapacity(4);
static OSSymbol * GetKeyForService(OSObject * newService)
{
char key[9];
sprintf(key, "%x", (UInt32)newService);
return OSSymbol::withCString(key);
}
static KeyboardReserved * GetKeyboardReservedStructEventForService(OSObject *service)
{
KeyboardReserved * retVal = 0;
OSSymbol * key = 0;
OSData * data = 0;
if (gKeyboardReservedDictionary && (key = GetKeyForService(service)))
{
if (data = gKeyboardReservedDictionary->getObject(key))
{
retVal = (KeyboardReserved *)data->getBytesNoCopy();
}
key->release();
}
return retVal;
}
static void AppendNewKeyboardReservedStructForService(OSObject *service)
{
KeyboardReserved temp;
OSSymbol * key = 0;
OSData * data = 0;
if (gKeyboardReservedDictionary && (key = GetKeyForService(service)))
{
bzero(&temp, sizeof(KeyboardReserved));
data = OSData::withBytes(&temp, sizeof(KeyboardReserved));
gKeyboardReservedDictionary->setObject(key, data);
data->release();
key->release();
}
}
static void RemoveKeyboardReservedStructForService(OSObject *service)
{
OSSymbol * key = 0;
if (gKeyboardReservedDictionary && (key = GetKeyForService(service)))
{
gKeyboardReservedDictionary->removeObject(key);
key->release();
}
}
#define super IOHIDevice
OSDefineMetaClassAndStructors(IOHIKeyboard, IOHIDevice);
bool IOHIKeyboard::init(OSDictionary * properties)
{
if (!super::init(properties)) return false;
_deviceLock = IOLockAlloc();
_keyMap = 0;
_keyStateSize = 4*((maxKeyCodes()+(EVK_BITS_PER_UNIT-1))/EVK_BITS_PER_UNIT);
_keyState = (UInt32 *) IOMalloc(_keyStateSize);
_codeToRepeat = (unsigned)-1;
_keyboardEventTarget = 0;
_keyboardEventAction = 0;
_keyboardSpecialEventTarget = 0;
_keyboardSpecialEventAction = 0;
_updateEventFlagsTarget = 0;
_updateEventFlagsAction = 0;
if (!_deviceLock || !_keyState) return false;
bzero(_keyState, _keyStateSize);
AppendNewKeyboardReservedStructForService(this);
KeyboardReserved * tempReservedStruct = GetKeyboardReservedStructEventForService(this);
if (tempReservedStruct)
{
tempReservedStruct->repeat_thread_call = thread_call_allocate(_autoRepeat, this);
}
return true;
}
bool IOHIKeyboard::start(IOService * provider)
{
if (!super::start(provider)) return false;
registerService();
return true;
}
void IOHIKeyboard::stop(IOService * provider)
{
KeyboardReserved *tempReservedStruct = GetKeyboardReservedStructEventForService(this);
if (tempReservedStruct) {
if (tempReservedStruct->keyboardNub) {
tempReservedStruct->keyboardNub->stop(this);
tempReservedStruct->keyboardNub->detach(this);
tempReservedStruct->keyboardNub->release();
tempReservedStruct->keyboardNub = 0;
}
}
super::stop(provider);
}
void IOHIKeyboard::free()
{
IOLock * lock = NULL;
if ( _deviceLock )
{
lock = _deviceLock;
IOLockLock( lock);
_deviceLock = NULL;
}
if ( _keyMap ) {
_keyMap->release();
}
if( _keyState )
IOFree( _keyState, _keyStateSize);
KeyboardReserved *tempReservedStruct = GetKeyboardReservedStructEventForService(this);
if (tempReservedStruct) {
thread_call_free(tempReservedStruct->repeat_thread_call);
RemoveKeyboardReservedStructForService(this);
}
if ( lock )
{
IOLockUnlock( lock);
IOLockFree( lock);
}
super::free();
}
IOHIDKind IOHIKeyboard::hidKind()
{
return kHIKeyboardDevice;
}
bool IOHIKeyboard::updateProperties( void )
{
bool ok;
ok = setProperty( kIOHIDKeyMappingKey, _keyMap );
return( ok & super::updateProperties() );
}
IOReturn IOHIKeyboard::setParamProperties( OSDictionary * dict )
{
OSData * data;
OSNumber * number;
IOReturn err = kIOReturnSuccess, err2;
unsigned char * map;
IOHIKeyboardMapper * oldMap;
bool updated = false;
UInt64 nano;
UInt32 value;
if( dict->getObject(kIOHIDResetKeyboardKey))
resetKeyboard();
IOLockLock( _deviceLock);
if ((number = OSDynamicCast(OSNumber,
dict->getObject(kIOHIDKeyRepeatKey))) ||
(data = OSDynamicCast(OSData,
dict->getObject(kIOHIDKeyRepeatKey))))
{
nano = (number) ? number->unsigned64BitValue() : *((UInt64 *) (data->getBytesNoCopy()));
if( nano < EV_MINKEYREPEAT)
nano = EV_MINKEYREPEAT;
nanoseconds_to_absolutetime(nano, &_keyRepeat);
updated = true;
}
if ((number = OSDynamicCast(OSNumber,
dict->getObject(kIOHIDInitialKeyRepeatKey))) ||
(data = OSDynamicCast(OSData,
dict->getObject(kIOHIDInitialKeyRepeatKey))))
{
nano = (number) ? number->unsigned64BitValue() : *((UInt64 *) (data->getBytesNoCopy()));
if( nano < EV_MINKEYREPEAT)
nano = EV_MINKEYREPEAT;
nanoseconds_to_absolutetime(nano, &_initialKeyRepeat);
updated = true;
}
if( (data = OSDynamicCast( OSData, dict->getObject(kIOHIDKeyMappingKey))))
{
map = (unsigned char *)IOMalloc( data->getLength() );
bcopy( data->getBytesNoCopy(), map, data->getLength() );
oldMap = _keyMap;
_keyMap = IOHIKeyboardMapper::keyboardMapper(this, map, data->getLength(), true);
if (_keyMap)
{
_keyMap->setKeyboardTarget((IOService *) _keyboardEventTarget);
if (oldMap)
oldMap->release();
updated = true;
}
else
{
_keyMap = oldMap;
err = kIOReturnBadArgument;
}
}
IOLockUnlock( _deviceLock);
if (_keyMap)
err2 = _keyMap->setParamProperties(dict);
if( updated )
updateProperties();
if (err == kIOReturnSuccess)
err = err2;
return( err );
}
bool IOHIKeyboard::resetKeyboard()
{
const unsigned char *defaultKeymap;
UInt32 defaultKeymapLength;
IOLockLock( _deviceLock);
if ( _keyMap )
_keyMap->release();
defaultKeymap = defaultKeymapOfLength(&defaultKeymapLength);
_keyMap = IOHIKeyboardMapper::keyboardMapper( this,
defaultKeymap,
defaultKeymapLength,
false );
if (_keyMap)
{
_keyMap->setKeyboardTarget((IOService *) _keyboardEventTarget);
clock_interval_to_absolutetime_interval( EV_DEFAULTKEYREPEAT,
kNanosecondScale, &_keyRepeat);
clock_interval_to_absolutetime_interval( EV_DEFAULTINITIALREPEAT,
kNanosecondScale, &_initialKeyRepeat);
}
updateProperties();
if (getProperty("HIDKeyboardKeysDefined"))
{
IOHIDKeyboardDevice * hidKeyboardNub = 0;
KeyboardReserved *tempReservedStruct = GetKeyboardReservedStructEventForService(this);
if (tempReservedStruct) {
hidKeyboardNub = tempReservedStruct->keyboardNub;
if (!hidKeyboardNub)
{
hidKeyboardNub = IOHIDKeyboardDevice::newKeyboardDevice(this);
if (hidKeyboardNub &&
(!hidKeyboardNub->attach(this) ||
!hidKeyboardNub->start(this)))
{
hidKeyboardNub->release();
hidKeyboardNub = 0;
}
tempReservedStruct->keyboardNub = hidKeyboardNub;
}
}
}
_interfaceType = interfaceID();
_deviceType = deviceType();
_guid = getGUID();
IOLockUnlock( _deviceLock);
return (_keyMap) ? true : false;
}
void IOHIKeyboard::scheduleAutoRepeat()
{
KeyboardReserved *tempReservedStruct = GetKeyboardReservedStructEventForService(this);
if ( _calloutPending == true )
{
if (tempReservedStruct) {
thread_call_cancel(tempReservedStruct->repeat_thread_call);
}
_calloutPending = false;
}
if ( AbsoluteTime_to_scalar(&_downRepeatTime) )
{
AbsoluteTime deadline;
clock_absolutetime_interval_to_deadline(_downRepeatTime, &deadline);
if (tempReservedStruct) {
thread_call_enter_delayed(tempReservedStruct->repeat_thread_call, deadline);
}
_calloutPending = true;
}
}
void IOHIKeyboard::_autoRepeat(thread_call_param_t arg,
thread_call_param_t)
{
IOHIKeyboard *self = (IOHIKeyboard *) arg;
self->autoRepeat();
}
void IOHIKeyboard::autoRepeat()
{
KeyboardReserved *tempReservedStruct = GetKeyboardReservedStructEventForService(this);
IOLockLock( _deviceLock);
if (( _calloutPending == false ) ||
((tempReservedStruct) && tempReservedStruct->dispatchEventCalled ))
{
IOLockUnlock( _deviceLock);
return;
}
_calloutPending = false;
_isRepeat = true;
if (tempReservedStruct) tempReservedStruct->dispatchEventCalled = true;
if ( AbsoluteTime_to_scalar(&_downRepeatTime) )
{
if (_keyMap) _keyMap->translateKeyCode(_codeToRepeat,
true,
_keyState);
_downRepeatTime = _keyRepeat;
}
if (tempReservedStruct) tempReservedStruct->dispatchEventCalled = false;
_isRepeat = false;
scheduleAutoRepeat();
IOLockUnlock( _deviceLock);
}
void IOHIKeyboard::setRepeat(unsigned eventType, unsigned keyCode)
{
if ( _isRepeat == false ) {
if (eventType == NX_KEYDOWN) {
_downRepeatTime = _initialKeyRepeat; _codeToRepeat = keyCode;
scheduleAutoRepeat();
}
else if (eventType == NX_KEYUP) {
if (_codeToRepeat == keyCode)
{
AbsoluteTime_to_scalar(&_downRepeatTime) = 0;
_codeToRepeat = (unsigned)-1;
scheduleAutoRepeat();
}
}
}
}
void IOHIKeyboard::keyboardEvent(unsigned eventType,
unsigned flags,
unsigned keyCode,
unsigned charCode,
unsigned charSet,
unsigned origCharCode,
unsigned origCharSet)
{
KeyboardReserved *tempReservedStruct = GetKeyboardReservedStructEventForService(this);
if (tempReservedStruct && tempReservedStruct->dispatchEventCalled)
{
IOLockUnlock(_deviceLock);
}
_keyboardEvent( this,
eventType,
flags,
keyCode,
charCode,
charSet,
origCharCode,
origCharSet,
_deviceType,
_isRepeat,
_lastEventTime);
if (tempReservedStruct && tempReservedStruct->dispatchEventCalled)
{
IOLockLock(_deviceLock);
}
if( keyCode == _keyMap->getParsedSpecialKey(NX_KEYTYPE_CAPS_LOCK) ||
keyCode == _keyMap->getParsedSpecialKey(NX_KEYTYPE_NUM_LOCK) ||
keyCode == _keyMap->getParsedSpecialKey(NX_POWER_KEY) ||
keyCode == _keyMap->getParsedSpecialKey(NX_KEYTYPE_MUTE) ||
keyCode == _keyMap->getParsedSpecialKey(NX_KEYTYPE_PLAY) ||
keyCode == _keyMap->getParsedSpecialKey(NX_KEYTYPE_EJECT) ||
keyCode == _keyMap->getParsedSpecialKey(NX_KEYTYPE_VIDMIRROR) ||
keyCode == _keyMap->getParsedSpecialKey(NX_KEYTYPE_ILLUMINATION_TOGGLE))
{
if (_interfaceType == NX_EVS_DEVICE_INTERFACE_ADB)
{
return;
}
}
setRepeat(eventType, keyCode);
}
void IOHIKeyboard::keyboardSpecialEvent(unsigned eventType,
unsigned flags,
unsigned keyCode,
unsigned flavor)
{
KeyboardReserved *tempReservedStruct = GetKeyboardReservedStructEventForService(this);
if (tempReservedStruct && tempReservedStruct->dispatchEventCalled)
{
IOLockUnlock(_deviceLock);
}
_keyboardSpecialEvent(this,
eventType,
flags,
keyCode,
flavor,
_guid,
_isRepeat,
_lastEventTime);
if (tempReservedStruct && tempReservedStruct->dispatchEventCalled)
{
IOLockLock(_deviceLock);
}
if( keyCode == _keyMap->getParsedSpecialKey(NX_KEYTYPE_CAPS_LOCK) ||
keyCode == _keyMap->getParsedSpecialKey(NX_KEYTYPE_NUM_LOCK) ||
keyCode == _keyMap->getParsedSpecialKey(NX_POWER_KEY) ||
keyCode == _keyMap->getParsedSpecialKey(NX_KEYTYPE_MUTE) ||
keyCode == _keyMap->getParsedSpecialKey(NX_KEYTYPE_PLAY) ||
keyCode == _keyMap->getParsedSpecialKey(NX_KEYTYPE_EJECT) ||
keyCode == _keyMap->getParsedSpecialKey(NX_KEYTYPE_VIDMIRROR) ||
keyCode == _keyMap->getParsedSpecialKey(NX_KEYTYPE_ILLUMINATION_TOGGLE))
{
return;
}
setRepeat(eventType, keyCode);
}
void IOHIKeyboard::updateEventFlags(unsigned flags)
{
KeyboardReserved *tempReservedStruct = GetKeyboardReservedStructEventForService(this);
if (tempReservedStruct && tempReservedStruct->dispatchEventCalled)
{
IOLockUnlock(_deviceLock);
}
_updateEventFlags(this, flags);
if (tempReservedStruct && tempReservedStruct->dispatchEventCalled)
{
IOLockLock(_deviceLock);
}
}
unsigned IOHIKeyboard::eventFlags()
{
return _eventFlags;
}
unsigned IOHIKeyboard::deviceFlags()
{
return _eventFlags;
}
void IOHIKeyboard::setDeviceFlags(unsigned flags)
{
if (_eventFlags != flags) {
_eventFlags = flags;
AbsoluteTime_to_scalar(&_downRepeatTime) = 0;
_codeToRepeat = (unsigned)-1;
scheduleAutoRepeat();
}
}
bool IOHIKeyboard::alphaLock()
{
return _alphaLock;
}
void IOHIKeyboard::setAlphaLock(bool val)
{
_alphaLock = val;
setAlphaLockFeedback(val);
KeyboardReserved *tempReservedStruct = GetKeyboardReservedStructEventForService(this);
if (tempReservedStruct && tempReservedStruct->keyboardNub )
tempReservedStruct->keyboardNub->setCapsLockLEDElement(val);
}
bool IOHIKeyboard::numLock()
{
return _numLock;
}
void IOHIKeyboard::setNumLock(bool val)
{
_numLock = val;
setNumLockFeedback(val);
KeyboardReserved *tempReservedStruct = GetKeyboardReservedStructEventForService(this);
if (tempReservedStruct && tempReservedStruct->keyboardNub )
tempReservedStruct->keyboardNub->setNumLockLEDElement(val);
}
bool IOHIKeyboard::charKeyActive()
{
return _charKeyActive;
}
void IOHIKeyboard::setCharKeyActive(bool val)
{
_charKeyActive = val;
}
void IOHIKeyboard::dispatchKeyboardEvent(unsigned int keyCode,
bool goingDown,
AbsoluteTime time)
{
IOHIKeyboardMapper * theKeyMap;
KeyboardReserved *tempReservedStruct = GetKeyboardReservedStructEventForService(this);
IOLockLock( _deviceLock);
_lastEventTime = time;
if (tempReservedStruct)
{
if (tempReservedStruct->keyboardNub )
{
tempReservedStruct->keyboardNub->postKeyboardEvent(keyCode, goingDown);
}
if (tempReservedStruct->isSeized)
{
IOLockUnlock( _deviceLock);
return;
}
}
if (tempReservedStruct) tempReservedStruct->dispatchEventCalled = true;
if (_keyMap) _keyMap->translateKeyCode(keyCode,
goingDown,
_keyState);
theKeyMap = _keyMap;
if (tempReservedStruct) tempReservedStruct->dispatchEventCalled = false;
IOLockUnlock( _deviceLock);
if (theKeyMap)
{
theKeyMap->retain();
theKeyMap->keyEventPostProcess();
theKeyMap->release();
}
}
const unsigned char * IOHIKeyboard::defaultKeymapOfLength(UInt32 * length)
{
*length = 0;
return NULL;
}
void IOHIKeyboard::setAlphaLockFeedback(bool )
{
return;
}
void IOHIKeyboard::setNumLockFeedback(bool )
{
return;
}
UInt32 IOHIKeyboard::maxKeyCodes()
{
return( 0x80);
}
bool IOHIKeyboard:: doesKeyLock ( unsigned key)
{
return false;
}
unsigned IOHIKeyboard:: getLEDStatus ()
{
return 0;
}
bool IOHIKeyboard::open(IOService * client,
IOOptionBits options,
KeyboardEventAction keAction,
KeyboardSpecialEventAction kseAction,
UpdateEventFlagsAction uefAction)
{
if ( (!_keyMap) && (!resetKeyboard())) return false;
if (client == this) {
KeyboardReserved *tempReservedStruct;
tempReservedStruct = GetKeyboardReservedStructEventForService(this);
return super::open((tempReservedStruct) ? tempReservedStruct->openClient : 0, options);
}
return open(client,
options,
0,
(KeyboardEventCallback)keAction,
(KeyboardSpecialEventCallback)kseAction,
(UpdateEventFlagsCallback)uefAction);
}
bool IOHIKeyboard::open(
IOService * client,
IOOptionBits options,
void * ,
KeyboardEventCallback keCallback,
KeyboardSpecialEventCallback kseCallback,
UpdateEventFlagsCallback uefCallback)
{
if (client == this) return true;
KeyboardReserved *tempReservedStruct;
tempReservedStruct = GetKeyboardReservedStructEventForService(this);
if (tempReservedStruct) tempReservedStruct->openClient = client;
bool returnValue = open(this, options,
(KeyboardEventAction)_keyboardEvent,
(KeyboardSpecialEventAction)_keyboardSpecialEvent,
(UpdateEventFlagsAction)_updateEventFlags);
if (!returnValue)
return false;
if (_keyMap)
_keyMap->setKeyboardTarget(client);
_keyboardEventTarget = client;
_keyboardEventAction = (KeyboardEventAction)keCallback;
_keyboardSpecialEventTarget = client;
_keyboardSpecialEventAction = (KeyboardSpecialEventAction)kseCallback;
_updateEventFlagsTarget = client;
_updateEventFlagsAction = (UpdateEventFlagsAction)uefCallback;
return true;
}
void IOHIKeyboard::close(IOService * client, IOOptionBits)
{
if (_codeToRepeat != -1)
{
AbsoluteTime ts;
clock_get_uptime(&ts);
dispatchKeyboardEvent(_codeToRepeat, false, ts);
}
setAlphaLock(false);
_updateEventFlags(this, 0);
_eventFlags = 0;
_keyboardSpecialEvent( this,
NX_SYSDEFINED,
_eventFlags,
NX_NOSPECIALKEY,
NX_SUBTYPE_STICKYKEYS_RELEASE,
_guid,
0,
_lastEventTime);
bzero(_keyState, _keyStateSize);
_keyboardEventAction = NULL;
_keyboardEventTarget = 0;
_keyboardSpecialEventAction = NULL;
_keyboardSpecialEventTarget = 0;
_updateEventFlagsAction = NULL;
_updateEventFlagsTarget = 0;
super::close(client);
}
IOReturn IOHIKeyboard::message( UInt32 type, IOService * provider,
void * argument)
{
IOReturn ret = kIOReturnSuccess;
switch(type)
{
case kIOHIDSystem508MouseClickMessage:
if (_keyMap)
ret = _keyMap->message(type, this);
break;
case kIOHIDSystemDeviceSeizeRequestMessage:
if (OSDynamicCast(IOHIDDevice, provider))
{
KeyboardReserved *tempReservedStruct = GetKeyboardReservedStructEventForService(this);
if (tempReservedStruct) {
tempReservedStruct->isSeized = (bool)argument;
}
}
break;
default:
ret = super::message(type, provider, argument);
break;
}
return ret;
}
void IOHIKeyboard::_keyboardEvent( IOHIKeyboard * self,
unsigned eventType,
unsigned flags,
unsigned key,
unsigned charCode,
unsigned charSet,
unsigned origCharCode,
unsigned origCharSet,
unsigned keyboardType,
bool repeat,
AbsoluteTime ts)
{
KeyboardEventCallback keCallback;
keCallback = (KeyboardEventCallback)self->_keyboardEventAction;
if ( !keCallback )
return;
(*keCallback)( self->_keyboardEventTarget,
eventType,
flags,
key,
charCode,
charSet,
origCharCode,
origCharSet,
keyboardType,
repeat,
ts,
self,
0);
}
void IOHIKeyboard::_keyboardSpecialEvent(
IOHIKeyboard * self,
unsigned eventType,
unsigned flags,
unsigned key,
unsigned flavor,
UInt64 guid,
bool repeat,
AbsoluteTime ts)
{
KeyboardSpecialEventCallback kseCallback;
kseCallback = (KeyboardSpecialEventCallback)self->_keyboardSpecialEventAction;
if ( !kseCallback )
return;
(*kseCallback)( self->_keyboardEventTarget,
eventType,
flags,
key,
flavor,
guid,
repeat,
ts,
self,
0);
}
void IOHIKeyboard::_updateEventFlags( IOHIKeyboard * self,
unsigned flags)
{
UpdateEventFlagsCallback uefCallback;
uefCallback = (UpdateEventFlagsCallback)self->_updateEventFlagsAction;
if ( !uefCallback )
return;
(*uefCallback)( self->_updateEventFlagsTarget,
flags,
self,
0);
}