#include <AssertMacros.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOLocks.h>
#include <IOKit/hidsystem/IOHIKeyboardMapper.h>
#include <IOKit/hidsystem/IOLLEvent.h>
#include <IOKit/hidsystem/IOHIDParameter.h>
#include "IOKit/hidsystem/IOHIDSystem.h"
#include "IOKit/hidsystem/IOHIKeyboard.h"
#include "IOHIDKeyboardDevice.h"
#include "IOHIDFamilyTrace.h"
#include "IOHIDSecurePromptClient.h"
#include "ev_private.h"
struct KeyboardReserved
{
IOHIKeyboard * service;
thread_call_t repeat_thread_call;
bool dispatchEventCalled;
bool isSeized;
bool repeatMode;
bool hasSecurePrompt;
IOService * openClient;
IOHIDKeyboardDevice * keyboardNub;
};
static OSArray *gKeyboardReservedArray = OSArray::withCapacity(4);
IOLock *gKeyboardReservedArrayLock = IOLockAlloc();
static KeyboardReserved * GetKeyboardReservedStructEventForService(IOHIKeyboard *service, UInt32 * index = 0)
{
KeyboardReserved * retVal = 0;
if (gKeyboardReservedArray) {
OSCollectionIterator * iterator = 0;
iterator = OSCollectionIterator::withCollection(gKeyboardReservedArray);
if (iterator) {
bool done = false;
while (!done) {
OSObject * obj = 0;
IOLockLock(gKeyboardReservedArrayLock);
while (!done && (NULL != (obj = iterator->getNextObject()))) {
obj->retain();
IOLockUnlock(gKeyboardReservedArrayLock);
OSData * data = OSDynamicCast(OSData, obj);
if (data) {
retVal = (KeyboardReserved *)data->getBytesNoCopy();
if (retVal && (retVal->service == service)) {
if (index)
*index = gKeyboardReservedArray->getNextIndexOfObject(obj, 0);
done = true;
}
else {
retVal = 0;
}
}
IOLockLock(gKeyboardReservedArrayLock);
}
IOLockUnlock(gKeyboardReservedArrayLock);
if (iterator->isValid()) {
done = true;
}
else {
iterator->reset();
}
}
iterator->release();
}
}
return retVal;
}
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));
IOLockLock(gKeyboardReservedArrayLock);
gKeyboardReservedArray->setObject(data);
IOLockUnlock(gKeyboardReservedArrayLock);
data->release();
}
}
static void RemoveKeyboardReservedStructForService(IOHIKeyboard *service)
{
UInt32 index = 0;
if (gKeyboardReservedArray && GetKeyboardReservedStructEventForService(service, &index) )
{
IOLockLock(gKeyboardReservedArrayLock);
gKeyboardReservedArray->removeObject(index);
IOLockUnlock(gKeyboardReservedArrayLock);
}
}
#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);
return true;
}
bool IOHIKeyboard::start(IOService * provider)
{
if (!super::start(provider)) return false;
AppendNewKeyboardReservedStructForService(this);
KeyboardReserved * tempReservedStruct = GetKeyboardReservedStructEventForService(this);
if (tempReservedStruct)
{
tempReservedStruct->repeat_thread_call = thread_call_allocate(_autoRepeat, this);
}
registerService(kIOServiceAsynchronous);
return true;
}
void IOHIKeyboard::stop(IOService * provider)
{
super::stop(provider);
KeyboardReserved *tempReservedStruct = GetKeyboardReservedStructEventForService(this);
if (tempReservedStruct) {
thread_call_cancel(tempReservedStruct->repeat_thread_call);
thread_call_free(tempReservedStruct->repeat_thread_call);
tempReservedStruct->repeat_thread_call = NULL;
if ( tempReservedStruct->keyboardNub )
tempReservedStruct->keyboardNub->release();
tempReservedStruct->keyboardNub = NULL;
if ( tempReservedStruct->hasSecurePrompt )
tempReservedStruct->hasSecurePrompt = false;
RemoveKeyboardReservedStructForService(this);
}
}
void IOHIKeyboard::free()
{
IOLock * lock = NULL;
if ( _deviceLock )
{
lock = _deviceLock;
IOLockLock( lock);
_deviceLock = NULL;
}
if ( _keyMap ) {
_keyMap->release();
_keyMap = 0;
}
if( _keyState )
IOFree( _keyState, _keyStateSize);
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 (NULL != (number = OSDynamicCast(OSNumber, dict->getObject(kIOHIDSubinterfaceIDKey))))
{
if (!OSDynamicCast(OSNumber, getProperty(kIOHIDOriginalSubinterfaceIDKey))) {
OSNumber *original = (OSNumber*)copyProperty(kIOHIDSubinterfaceIDKey);
if (OSDynamicCast(OSNumber, original)) {
setProperty(kIOHIDOriginalSubinterfaceIDKey, original);
}
OSSafeReleaseNULL(original);
}
_deviceType = number->unsigned32BitValue();
updated = true;
}
if (_keyMap)
err2 = _keyMap->setParamProperties(dict);
IOLockUnlock( _deviceLock);
if( updated )
updateProperties();
if (err == kIOReturnSuccess)
err = err2;
return( err == kIOReturnSuccess ) ? super::setParamProperties(dict) : err;
}
IOReturn IOHIKeyboard::setProperties( OSObject * properties )
{
return super::setProperties(properties);
}
bool IOHIKeyboard::resetKeyboard()
{
const unsigned char *defaultKeymap;
UInt32 defaultKeymapLength;
IOLockLock( _deviceLock);
if ( _keyMap ) {
_keyMap->release();
_keyMap = 0;
}
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) {
IOHID_DEBUG(kIOHIDDebugCode_KeyboardCapsThreadTrigger, this, __OSAbsoluteTime(deadline), tempReservedStruct->repeat_thread_call, 0);
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;
IOHID_DEBUG(kIOHIDDebugCode_KeyboardCapsThreadActive, self, self ? self->_codeToRepeat : 0, 0, 0);
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 (postSecureKey(_codeToRepeat, true)) {
}
else 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);
bool relock = false;
if (tempReservedStruct && tempReservedStruct->dispatchEventCalled)
{
relock = true;
IOLockUnlock(_deviceLock);
}
UInt16 usage = 0;
UInt16 usagePage = 0;
unsigned modifiedOrigCharCode = origCharCode;
unsigned modifiedOrigCharSet = origCharSet;
unsigned modifiedFlags = flags;
if ((origCharCode < 0xffff) && (origCharSet < 0xffff)) {
getLastPageAndUsage(usagePage, usage);
if (usage || usagePage) {
modifiedOrigCharCode |= usage << 16;
modifiedOrigCharSet |= usagePage << 16;
modifiedFlags |= NX_HIGHCODE_ENCODING_MASK;
}
}
else {
IOLog("IOHIKeyboard::keyboardEvent original code/set unusually large %02x:%02x\n", origCharCode, origCharSet);
}
_keyboardEvent( this,
eventType,
modifiedFlags,
keyCode,
charCode,
charSet,
modifiedOrigCharCode,
modifiedOrigCharSet,
_deviceType,
_isRepeat,
_lastEventTime);
if (relock)
{
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);
bool relock = false;
if (tempReservedStruct && tempReservedStruct->dispatchEventCalled)
{
relock = true;
IOLockUnlock(_deviceLock);
}
_keyboardSpecialEvent(this,
eventType,
flags,
keyCode,
flavor,
_guid,
_isRepeat,
_lastEventTime);
if (relock)
{
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);
bool relock = false;
if (tempReservedStruct && tempReservedStruct->dispatchEventCalled)
{
relock = true;
IOLockUnlock(_deviceLock);
}
_updateEventFlags(this, flags);
if (relock)
{
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 (postSecureKey(keyCode, goingDown)) {
IOLockUnlock( _deviceLock);
return;
}
if (tempReservedStruct)
{
if (tempReservedStruct->keyboardNub)
{
tempReservedStruct->keyboardNub->postKeyboardEvent(keyCode, goingDown);
}
if (tempReservedStruct->isSeized)
{
IOLockUnlock( _deviceLock);
return;
}
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( NX_NUMKEYCODES );
}
bool IOHIKeyboard:: doesKeyLock ( unsigned key __unused)
{
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)
{
AbsoluteTime ts;
clock_get_uptime(&ts);
if (_codeToRepeat != ((unsigned)-1))
dispatchKeyboardEvent(_codeToRepeat, false, ts);
UInt32 i, maxKeys = maxKeyCodes();
for (i=0; i<maxKeys; i++)
if ( EVK_IS_KEYDOWN(i,_keyState) )
dispatchKeyboardEvent(i, false, ts);
_updateEventFlags(this, 0);
_keyboardSpecialEvent( this,
NX_SYSDEFINED,
0,
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;
case IOHIDSecurePromptClient::gatheringMessage:
{
if (argument) {
AbsoluteTime ts;
clock_get_uptime(&ts);
if (_codeToRepeat != ((unsigned)-1))
dispatchKeyboardEvent(_codeToRepeat, false, ts);
UInt32 i, maxKeys = maxKeyCodes();
for (i=0; i<maxKeys; i++)
if ( EVK_IS_KEYDOWN(i,_keyState) )
dispatchKeyboardEvent(i, false, ts);
_updateEventFlags(this, 0);
_keyboardSpecialEvent( this,
NX_SYSDEFINED,
0,
NX_NOSPECIALKEY,
NX_SUBTYPE_STICKYKEYS_RELEASE,
_guid,
0,
_lastEventTime);
if (provider) {
OSIterator *itr = getClientIterator();
if (itr) {
IOHIDSecurePromptClient *client = NULL;
do {
client = IOHIDSecurePromptClient::nextForIterator(itr);
if (client && (client != provider) && client->gathering()) {
client->setGathering(0);
}
}
while(client);
itr->release();
}
}
}
}
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)
{
if (!self || !self->_keyboardEventAction || !self->_keyboardEventTarget) {
}
else {
KeyboardEventCallback keCallback = (KeyboardEventCallback)self->_keyboardEventAction;
(*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)
{
if (!self || !self->_keyboardSpecialEventAction || !self->_keyboardEventTarget) {
}
else {
KeyboardSpecialEventCallback kseCallback = (KeyboardSpecialEventCallback)self->_keyboardSpecialEventAction;
(*kseCallback)(self->_keyboardEventTarget,
eventType,
flags,
key,
flavor,
guid,
repeat,
ts,
self,
0);
}
}
void IOHIKeyboard::_updateEventFlags( IOHIKeyboard * self,
unsigned flags)
{
if (!self || !self->_keyboardSpecialEventAction || !self->_keyboardEventTarget) {
}
else {
UpdateEventFlagsCallback uefCallback = (UpdateEventFlagsCallback)self->_updateEventFlagsAction;
(*uefCallback)(self->_updateEventFlagsTarget,
flags,
self,
0);
}
}
IOReturn IOHIKeyboard::newUserClient(task_t owningTask,
void * security_id,
UInt32 type,
OSDictionary * properties,
IOUserClient ** handler )
{
if ( type == IOHIDSecurePromptClient::clientID )
return kIOReturnUnsupported;
return super::newUserClient( owningTask, security_id, type, properties, handler );
}
static bool IOHIKeyboard_attachSecurePromptClient_Callback(void * target,
void * refCon __unused,
IOService * newService,
IONotifier * notifier __unused )
{
IOHIDSecurePromptClient *client = (IOHIDSecurePromptClient*)target;
IOHIKeyboard *keyboard = OSDynamicCast(IOHIKeyboard, newService);
require(client, improper_call);
require(keyboard, improper_call);
require(!client->dead(), invalid_client);
return client->attach(keyboard);
invalid_client:
improper_call:
return false;
}
IOReturn IOHIKeyboard::newUserClientGated(task_t owningTask,
void * security_id,
OSDictionary * properties,
IOUserClient ** handler )
{
IOHIDSecurePromptClient * client = new IOHIDSecurePromptClient;
if ( !client->initWithTask( owningTask, security_id, 0, properties ) ) {
client->release();
return kIOReturnBadArgument;
}
if ( !client->start( this ) ) {
client->detach( this );
client->release();
return kIOReturnInternalError;
}
*handler = client;
OSDictionary *match = IOService::serviceMatching(kIOHIKeyboardClass);
IONotifier *notifier = IOService::addMatchingNotification(gIOPublishNotification,
match,
IOHIKeyboard_attachSecurePromptClient_Callback,
client);
client->setNotifier(notifier);
match->release();
notifier->release();
return kIOReturnSuccess;
}
bool IOHIKeyboard::
postSecureKey(UInt8 key, bool down)
{
KeyboardReserved *reservedStruct = GetKeyboardReservedStructEventForService(this);
bool posted = false;
if (reservedStruct && reservedStruct->hasSecurePrompt) {
IOHIDSecurePromptClient *client = NULL;
OSIterator *itr = getClientIterator();
if (itr) {
do {
client = IOHIDSecurePromptClient::nextForIterator(itr);
if (client && client->gathering()) {
IOReturn result = client->postKey(key, down);
client = NULL;
if (result == kIOReturnSuccess) {
posted = true;
}
}
}
while(client);
itr->release();
}
}
return posted;
}
bool IOHIKeyboard::
attachToChild(IORegistryEntry * child,
const IORegistryPlane * plane )
{
IOHIDSecurePromptClient *secureClient = OSDynamicCast(IOHIDSecurePromptClient, child);
if (secureClient) {
KeyboardReserved *reservedStruct = GetKeyboardReservedStructEventForService(this);
if (reservedStruct) {
reservedStruct->hasSecurePrompt = true;
}
}
return super::attachToChild(child, plane);
}
void IOHIKeyboard::
detachFromChild(IORegistryEntry * child,
const IORegistryPlane * plane )
{
IOHIDSecurePromptClient *secureClient = OSDynamicCast(IOHIDSecurePromptClient, child);
super::detachFromChild(child, plane);
if (secureClient) {
KeyboardReserved *reservedStruct = GetKeyboardReservedStructEventForService(this);
if (reservedStruct && reservedStruct->hasSecurePrompt) {
OSIterator *itr = getClientIterator();
if (itr) {
if (NULL == IOHIDSecurePromptClient::nextForIterator(itr)) {
reservedStruct->hasSecurePrompt = false;
}
itr->release();
}
}
}
}
void IOHIKeyboard::clearLastPageAndUsage()
{
if (!_lastUsagePage && !_lastUsage)
IOLog("IOHIKeyboard::clearLastPageAndUsage called when not set %02x:%02x\n", _lastUsagePage, _lastUsage);
_lastUsagePage = 0;
_lastUsage = 0;
}
void IOHIKeyboard::setLastPageAndUsage(UInt16 usagePage, UInt16 usage)
{
if (_lastUsagePage || _lastUsage)
IOLog("IOHIKeyboard::setLastPageAndUsage called when already set %02x:%02x\n", _lastUsagePage, _lastUsage);
_lastUsagePage = usagePage;
_lastUsage = usage;
}
void IOHIKeyboard::getLastPageAndUsage(UInt16 &usagePage, UInt16 &usage)
{
usagePage = _lastUsagePage;
usage = _lastUsage;
}