#include <IOKit/IOKitKeys.h>
#include <IOKit/hidsystem/ev_keymap.h>
#include <IOKit/hidsystem/IOHIDShared.h>
#include <IOKit/hidsystem/IOHIDUsageTables.h>
#include "IOHIDElement.h"
#include "IOHIDConsumer.h"
#include "AppleHIDUsageTables.h"
#define super IOHIKeyboard
#define DEBUGGING_LEVEL 0
OSDefineMetaClassAndStructors( IOHIDConsumer, IOHIKeyboard )
IOHIDConsumer *
IOHIDConsumer::Consumer(bool isDispatcher)
{
IOHIDConsumer *consumer = new IOHIDConsumer;
if ((consumer == 0) || !consumer->init())
{
if (consumer) consumer->release();
return 0;
}
consumer->_isDispatcher = isDispatcher;
return consumer;
}
bool
IOHIDConsumer::init(OSDictionary *properties)
{
if (!super::init(properties)) return false;
_otherEventFlags = 0;
_otherCapsLockOn = FALSE;
_repeat = true;
setRepeatMode(_repeat);
return true;
}
bool IOHIDConsumer::start(IOService * provider)
{
setProperty(kIOHIDVirtualHIDevice, kOSBooleanTrue);
return super::start(provider);
}
void IOHIDConsumer::stop(IOService * provider)
{
OSSafeReleaseNULL(_keyboardNub);
super::stop(provider);
}
void IOHIDConsumer::dispatchConsumerEvent(
IOHIDKeyboard * sendingkeyboardNub,
AbsoluteTime timeStamp,
UInt32 usagePage,
UInt32 usage,
UInt32 value,
IOOptionBits options)
{
SInt32 keyCode = -1;
bool repeat = ((options & kHIDDispatchOptionKeyboardNoRepeat) == 0);
if (usagePage == kHIDPage_Consumer)
{
switch(usage)
{
case kHIDUsage_Csmr_Power:
case kHIDUsage_Csmr_Reset:
case kHIDUsage_Csmr_Sleep:
keyCode = NX_POWER_KEY;
break;
case kHIDUsage_Csmr_Play:
case kHIDUsage_Csmr_PlayOrPause:
case kHIDUsage_Csmr_PlayOrSkip:
keyCode = NX_KEYTYPE_PLAY;
break;
case kHIDUsage_Csmr_ScanNextTrack:
keyCode = NX_KEYTYPE_NEXT;
break;
case kHIDUsage_Csmr_ScanPreviousTrack:
keyCode = NX_KEYTYPE_PREVIOUS;
break;
case kHIDUsage_Csmr_FastForward:
keyCode = NX_KEYTYPE_FAST;
break;
case kHIDUsage_Csmr_Rewind:
keyCode = NX_KEYTYPE_REWIND;
break;
case kHIDUsage_Csmr_StopOrEject:
case kHIDUsage_Csmr_Eject:
keyCode = NX_KEYTYPE_EJECT;
break;
case kHIDUsage_Csmr_VolumeIncrement:
keyCode = NX_KEYTYPE_SOUND_UP;
break;
case kHIDUsage_Csmr_VolumeDecrement:
keyCode = NX_KEYTYPE_SOUND_DOWN;
break;
case kHIDUsage_Csmr_Mute:
keyCode = NX_KEYTYPE_MUTE;
break;
case kHIDUsage_Csmr_DisplayBrightnessIncrement:
keyCode = NX_KEYTYPE_BRIGHTNESS_UP;
break;
case kHIDUsage_Csmr_DisplayBrightnessDecrement:
keyCode = NX_KEYTYPE_BRIGHTNESS_DOWN;
break;
default:
break;
}
}
else if (usagePage == kHIDPage_GenericDesktop)
{
switch (usage)
{
case kHIDUsage_GD_SystemPowerDown:
case kHIDUsage_GD_SystemSleep:
case kHIDUsage_GD_SystemWakeUp:
keyCode = NX_POWER_KEY;
break;
}
}
else if (usagePage == kHIDPage_AppleVendorTopCase)
{
switch (usage)
{
case kHIDUsage_AV_TopCase_BrightnessUp:
keyCode = NX_KEYTYPE_BRIGHTNESS_UP;
break;
case kHIDUsage_AV_TopCase_BrightnessDown:
keyCode = NX_KEYTYPE_BRIGHTNESS_DOWN;
break;
case kHIDUsage_AV_TopCase_VideoMirror:
keyCode = NX_KEYTYPE_VIDMIRROR;
break;
case kHIDUsage_AV_TopCase_IlluminationDown:
keyCode = NX_KEYTYPE_ILLUMINATION_DOWN;
break;
case kHIDUsage_AV_TopCase_IlluminationUp:
keyCode = NX_KEYTYPE_ILLUMINATION_UP;
break;
case kHIDUsage_AV_TopCase_IlluminationToggle:
keyCode = NX_KEYTYPE_ILLUMINATION_TOGGLE;
break;
}
}
else if ((usagePage == kHIDPage_KeyboardOrKeypad) &&
(usage == kHIDUsage_KeyboardLockingNumLock))
{
keyCode = NX_KEYTYPE_NUM_LOCK;
}
if (keyCode == -1)
return;
if (repeat != _repeat)
{
_repeat = repeat;
setRepeatMode(_repeat);
}
OSSafeReleaseNULL(_keyboardNub);
if ( NULL != (_keyboardNub = sendingkeyboardNub) )
{
UInt32 currentFlags;
currentFlags = deviceFlags() & ~_cachedEventFlags;
_cachedEventFlags = _keyboardNub->deviceFlags();
currentFlags |= _cachedEventFlags;
_deviceType = _keyboardNub->deviceType();
setDeviceFlags(currentFlags);
_keyboardNub->retain();
}
else
{
findKeyboardsAndGetModifiers();
}
dispatchKeyboardEvent( keyCode, value, timeStamp );
}
unsigned IOHIDConsumer::eventFlags()
{
unsigned flags = 0;
flags = (_keyboardNub) ? _keyboardNub->eventFlags() : _otherEventFlags;
return( flags );
}
unsigned IOHIDConsumer::deviceFlags()
{
unsigned flags = 0;
flags = (_keyboardNub) ? _keyboardNub->deviceFlags() : _otherEventFlags;
return( flags );
}
void IOHIDConsumer::setDeviceFlags(unsigned flags)
{
if ( _keyboardNub )
_keyboardNub->setDeviceFlags(flags);
super::setDeviceFlags(flags);
}
bool IOHIDConsumer::alphaLock()
{
bool state = false;
state = (_keyboardNub) ? _keyboardNub->alphaLock() : _otherCapsLockOn;
return( state );
}
void IOHIDConsumer::setNumLock(bool val)
{
if (_keyboardNub) _keyboardNub->setNumLock(val);
}
bool IOHIDConsumer::numLock()
{
bool state = false;
state = (_keyboardNub) ? _keyboardNub->numLock() : super::numLock();
return( state );
}
bool IOHIDConsumer:: doesKeyLock ( unsigned key)
{
if ( key == NX_KEYTYPE_NUM_LOCK )
return true;
return false;
}
const unsigned char * IOHIDConsumer::defaultKeymapOfLength( UInt32 * length )
{
static const unsigned char ConsumerKeyMap[] =
{
0x00,0x00,
0x00,
0x00,
0x00,
NX_NUMSPECIALKEYS,
NX_KEYTYPE_SOUND_UP, NX_KEYTYPE_SOUND_UP,
NX_KEYTYPE_SOUND_DOWN, NX_KEYTYPE_SOUND_DOWN,
NX_KEYTYPE_BRIGHTNESS_UP, NX_KEYTYPE_BRIGHTNESS_UP,
NX_KEYTYPE_BRIGHTNESS_DOWN, NX_KEYTYPE_BRIGHTNESS_DOWN,
NX_KEYTYPE_CAPS_LOCK, NX_KEYTYPE_CAPS_LOCK,
NX_KEYTYPE_HELP, NX_KEYTYPE_HELP,
NX_POWER_KEY, NX_POWER_KEY,
NX_KEYTYPE_MUTE, NX_KEYTYPE_MUTE,
NX_UP_ARROW_KEY, NX_UP_ARROW_KEY,
NX_DOWN_ARROW_KEY, NX_DOWN_ARROW_KEY,
NX_KEYTYPE_NUM_LOCK, NX_KEYTYPE_NUM_LOCK,
NX_KEYTYPE_CONTRAST_UP, NX_KEYTYPE_CONTRAST_UP,
NX_KEYTYPE_CONTRAST_DOWN, NX_KEYTYPE_CONTRAST_DOWN,
NX_KEYTYPE_LAUNCH_PANEL, NX_KEYTYPE_LAUNCH_PANEL,
NX_KEYTYPE_EJECT, NX_KEYTYPE_EJECT,
NX_KEYTYPE_VIDMIRROR, NX_KEYTYPE_VIDMIRROR,
NX_KEYTYPE_PLAY, NX_KEYTYPE_PLAY,
NX_KEYTYPE_NEXT, NX_KEYTYPE_NEXT,
NX_KEYTYPE_PREVIOUS, NX_KEYTYPE_PREVIOUS,
NX_KEYTYPE_FAST, NX_KEYTYPE_FAST,
NX_KEYTYPE_REWIND, NX_KEYTYPE_REWIND,
NX_KEYTYPE_ILLUMINATION_UP, NX_KEYTYPE_ILLUMINATION_UP,
NX_KEYTYPE_ILLUMINATION_DOWN, NX_KEYTYPE_ILLUMINATION_DOWN,
NX_KEYTYPE_ILLUMINATION_TOGGLE, NX_KEYTYPE_ILLUMINATION_TOGGLE
};
if( length ) *length = sizeof( ConsumerKeyMap );
return( ConsumerKeyMap );
}
UInt32 IOHIDConsumer::findKeyboardsAndGetModifiers()
{
OSIterator *iterator = NULL;
OSDictionary *matchingDictionary = NULL;
IOHIKeyboard *device = NULL;
_otherEventFlags = 0;
_cachedEventFlags = 0;
_otherCapsLockOn = FALSE;
matchingDictionary = IOService::serviceMatching( "IOHIKeyboard" );
if( !matchingDictionary )
{
goto exit;
}
iterator = IOService::getMatchingServices( matchingDictionary );
if( !iterator )
{
goto exit;
}
while( (device = (IOHIKeyboard*) iterator->getNextObject()) )
{
if (!device->getProperty(kIOHIDKeyboardSupportedModifiersKey))
continue;
if( device->alphaLock() )
{
_otherCapsLockOn = TRUE;
}
_otherEventFlags |= device->eventFlags();
}
exit:
if( matchingDictionary ) matchingDictionary->release();
if( iterator ) iterator->release();
return( _otherEventFlags );
}