#include <IOKit/IOLib.h>
#include <IOKit/hidsystem/IOHIKeyboardMapper.h>
#include <IOKit/hidsystem/IOLLEvent.h>
#include <IOKit/hidsystem/IOHIDParameter.h>
#include "IOHIDSystem.h"
#include "IOHIKeyboard.h"
#include "IOHIDKeyboardDevice.h"
struct KeyboardReserved
{
IOHIKeyboard * service;
thread_call_t repeat_thread_call;
bool dispatchEventCalled;
bool isSeized;
bool repeatMode;
IOService * openClient;
IOHIDKeyboardDevice * keyboardNub;
};
static OSArray *gKeyboardReservedArray = OSArray::withCapacity(4);
static KeyboardReserved * GetKeyboardReservedStructEventForService(IOHIKeyboard *service, UInt32 * index = 0)
{
KeyboardReserved * retVal = 0;
OSData * data = 0;
UInt32 count = 0;
UInt32 i = 0;
if (gKeyboardReservedArray)
{
count = gKeyboardReservedArray->getCount();
for(i=0; i<count; i++)
{
if ( (data = (OSData *)gKeyboardReservedArray->getObject(i)) &&
(retVal = (KeyboardReserved *)data->getBytesNoCopy()) &&
(retVal->service == service) )
{
if ( index ) *index = i;
return retVal;
}
}
}
return NULL;
}
static void AppendNewKeyboardReservedStructForService(IOHIKeyboard *service)
{
KeyboardReserved temp;
OSData * data = 0;
if (gKeyboardReservedArray)
{
bzero(&temp, sizeof(KeyboardReserved));
temp.repeatMode = true;
temp.service = service;
data = OSData::withBytes(&temp, sizeof(KeyboardReserved));
gKeyboardReservedArray->setObject(data);
data->release();
}
}
static void RemoveKeyboardReservedStructForService(IOHIKeyboard *service)
{
UInt32 index = 0;
if (gKeyboardReservedArray && GetKeyboardReservedStructEventForService(service, &index) )
{
gKeyboardReservedArray->removeObject(index);
}
}
#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 && 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 = NULL;
OSNumber * number = NULL;
IOReturn err = kIOReturnSuccess;
IOReturn err2 = kIOReturnSuccess;
unsigned char * map = NULL;
IOHIKeyboardMapper * oldMap = NULL;
bool updated = false;
UInt64 nano;
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;
}
}
if (_keyMap)
err2 = _keyMap->setParamProperties(dict);
IOLockUnlock( _deviceLock);
if( updated )
updateProperties();
if (err == kIOReturnSuccess)
err = err2;
return( err );
}
IOReturn IOHIKeyboard::setProperties( OSObject * properties )
{
OSDictionary * propertyDict = OSDynamicCast(OSDictionary, properties);
OSNumber * subinterfaceID = 0;
if ( !propertyDict )
return kIOReturnError;
if ( subinterfaceID = OSDynamicCast(OSNumber, propertyDict->getObject(kIOHIDSubinterfaceIDKey)) )
{
_deviceType = subinterfaceID->unsigned32BitValue();
updateProperties();
}
return kIOReturnSuccess;
}
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();
_interfaceType = interfaceID();
_deviceType = deviceType();
_guid = getGUID();
if (getProperty("HIDKeyboardKeysDefined"))
{
KeyboardReserved * reservedStruct = GetKeyboardReservedStructEventForService(this);
if ( reservedStruct && !reservedStruct->keyboardNub)
reservedStruct->keyboardNub = IOHIDKeyboardDevice::newKeyboardDeviceAndStart(this);
}
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)
{
KeyboardReserved *tempReservedStruct;
if ( _isRepeat == false ) {
tempReservedStruct = GetKeyboardReservedStructEventForService(this);
if ((eventType == NX_KEYDOWN) &&
(tempReservedStruct && (tempReservedStruct->repeatMode == true))) {
_downRepeatTime = _initialKeyRepeat; _codeToRepeat = keyCode;
scheduleAutoRepeat();
}
else if (((eventType == NX_KEYUP) && (_codeToRepeat == keyCode)) ||
(tempReservedStruct && (tempReservedStruct->repeatMode == false))) {
AbsoluteTime_to_scalar(&_downRepeatTime) = 0;
_codeToRepeat = (unsigned)-1;
scheduleAutoRepeat();
}
}
}
void IOHIKeyboard::setRepeatMode(bool repeat)
{
KeyboardReserved *tempReservedStruct = GetKeyboardReservedStructEventForService(this);
IOLockLock( _deviceLock);
if (tempReservedStruct)
{
tempReservedStruct->repeatMode = repeat;
}
IOLockUnlock( _deviceLock);
}
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 != ((unsigned)-1))
{
AbsoluteTime ts;
clock_get_uptime(&ts);
dispatchKeyboardEvent(_codeToRepeat, false, ts);
}
_updateEventFlags(this, 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:
case kIOHIDSystem508SpecialKeyDownMessage:
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);
}