#include <IOKit/hidsystem/ev_keymap.h>
#include <IOKit/hidsystem/IOHIKeyboard.h>
#include <IOKit/hidsystem/IOHIDShared.h>
#include <IOKit/hidsystem/IOHIDUsageTables.h>
#include "IOHIDElement.h"
#include "IOHIDConsumer.h"
#define super IOHIKeyboard
#define DEBUGGING_LEVEL 0
#define kPower 0x01
#define kVolumeUp 0x02
#define kVolumeDown 0x03
#define kVolumeMute 0x04
#define kPlay 0x05
#define kFastForward 0x06
#define kRewind 0x07
#define kNextTrack 0x08
#define kPreviousTrack 0x09
#define kEject 0x0a
#define InitButtons(ptrs) \
{ \
ptrs = 0; \
ptrs ## Count = 0; \
}
#define AppendButtons(ptrs, ptr) \
{ \
UInt32 size = sizeof(UInt32 *) * ( ptrs ## Count); \
UInt32 ** tempPtrs = IOMalloc(size + sizeof(UInt32 *)); \
\
if (ptrs) { \
bcopy( ptrs, tempPtrs, size ); \
IOFree(ptrs, size); \
} \
ptrs = tempPtrs; \
ptrs[ ptrs ## Count ++] = ptr; \
}
#define ReleaseButtons(ptrs) \
{ \
UInt32 size = sizeof(UInt32 *) * ( ptrs ## Count); \
IOFree(ptrs, size); \
ptrs = 0; \
ptrs ## Count = 0; \
}
#define GetButtonValues(ptrs, value) \
{ \
for (int i=0; i< ptrs ## Count ; i++) \
{ \
value |= (ptrs[i][0] & 0x1); \
} \
}
OSDefineMetaClassAndStructors( IOHIDConsumer, IOHIKeyboard )
IOHIDConsumer *
IOHIDConsumer::Consumer(OSArray *elements)
{
IOHIDConsumer *consumer = new IOHIDConsumer;
if ((consumer == 0) || !consumer->init() ||
!consumer->findDesiredElements(elements))
{
if (consumer) consumer->release();
return 0;
}
return consumer;
}
bool
IOHIDConsumer::init(OSDictionary *properties)
{
if (!super::init(properties)) return false;
_soundUpIsPressed = false;
_soundDownIsPressed = false;
InitButtons(_systemPowerValuePtrs);
InitButtons(_systemSleepValuePtrs);
InitButtons(_systemWakeUpValuePtrs);
InitButtons(_volumeIncValuePtrs);
InitButtons(_volumeDecValuePtrs);
InitButtons(_volumeMuteValuePtrs);
InitButtons(_powerValuePtrs);
InitButtons(_resetValuePtrs);
InitButtons(_sleepValuePtrs);
InitButtons(_playValuePtrs);
InitButtons(_playOrPauseValuePtrs);
InitButtons(_playOrSkipPtrs);
InitButtons(_nextTrackValuePtrs);
InitButtons(_prevTrackValuePtrs);
InitButtons(_fastFowardValuePtrs);
InitButtons(_rewindValuePtrs);
InitButtons(_stopOrEjectPtrs);
InitButtons(_ejectValuePtrs);
return true;
}
void IOHIDConsumer::free()
{
ReleaseButtons(_systemPowerValuePtrs);
ReleaseButtons(_systemSleepValuePtrs);
ReleaseButtons(_systemWakeUpValuePtrs);
ReleaseButtons(_volumeIncValuePtrs);
ReleaseButtons(_volumeDecValuePtrs);
ReleaseButtons(_volumeMuteValuePtrs);
ReleaseButtons(_powerValuePtrs);
ReleaseButtons(_resetValuePtrs);
ReleaseButtons(_sleepValuePtrs);
ReleaseButtons(_playValuePtrs);
ReleaseButtons(_playOrPauseValuePtrs);
ReleaseButtons(_playOrSkipPtrs);
ReleaseButtons(_nextTrackValuePtrs);
ReleaseButtons(_prevTrackValuePtrs);
ReleaseButtons(_fastFowardValuePtrs);
ReleaseButtons(_rewindValuePtrs);
ReleaseButtons(_stopOrEjectPtrs);
ReleaseButtons(_ejectValuePtrs);
super::free();
}
bool
IOHIDConsumer::findDesiredElements(OSArray *elements)
{
IOHIDElement *element;
bool found = false;
if (!elements)
return false;
for (int i=0; i<elements->getCount(); i++)
{
element = elements->getObject(i);
if (element->getUsagePage() == kHIDPage_Consumer)
{
switch(element->getUsage())
{
case kHIDUsage_Csmr_Power:
AppendButtons(_powerValuePtrs, element->getElementValue()->value);
found = true;
break;
case kHIDUsage_Csmr_Reset:
AppendButtons(_resetValuePtrs, element->getElementValue()->value);
found = true;
break;
case kHIDUsage_Csmr_Sleep:
AppendButtons(_sleepValuePtrs, element->getElementValue()->value);
found = true;
break;
case kHIDUsage_Csmr_Play:
AppendButtons(_playValuePtrs, element->getElementValue()->value);
found = true;
break;
case kHIDUsage_Csmr_PlayOrPause:
AppendButtons(_playOrPauseValuePtrs, element->getElementValue()->value);
found = true;
break;
case kHIDUsage_Csmr_PlayOrSkip:
AppendButtons(_playOrSkipPtrs, element->getElementValue()->value);
found = true;
break;
case kHIDUsage_Csmr_ScanNextTrack:
AppendButtons(_nextTrackValuePtrs, element->getElementValue()->value);
found = true;
break;
case kHIDUsage_Csmr_ScanPreviousTrack:
AppendButtons(_prevTrackValuePtrs, element->getElementValue()->value);
found = true;
break;
case kHIDUsage_Csmr_FastForward:
AppendButtons(_fastFowardValuePtrs, element->getElementValue()->value);
found = true;
break;
case kHIDUsage_Csmr_Rewind:
AppendButtons(_rewindValuePtrs, element->getElementValue()->value);
found = true;
break;
case kHIDUsage_Csmr_StopOrEject:
AppendButtons(_stopOrEjectPtrs, element->getElementValue()->value);
found = true;
break;
case kHIDUsage_Csmr_Eject:
AppendButtons(_ejectValuePtrs, element->getElementValue()->value);
found = true;
break;
case kHIDUsage_Csmr_VolumeIncrement:
AppendButtons(_volumeIncValuePtrs, element->getElementValue()->value);
found = true;
break;
case kHIDUsage_Csmr_VolumeDecrement:
AppendButtons(_volumeDecValuePtrs, element->getElementValue()->value);
found = true;
break;
case kHIDUsage_Csmr_Mute:
AppendButtons(_volumeMuteValuePtrs, element->getElementValue()->value);
found = true;
break;
default:
break;
}
}
else if (element->getUsagePage() == kHIDPage_GenericDesktop)
{
switch (element->getUsage())
{
case kHIDUsage_GD_SystemPowerDown:
AppendButtons(_systemPowerValuePtrs, element->getElementValue()->value);
found = true;
break;
case kHIDUsage_GD_SystemSleep:
AppendButtons(_systemSleepValuePtrs, element->getElementValue()->value);
found = true;
break;
case kHIDUsage_GD_SystemWakeUp:
AppendButtons(_systemWakeUpValuePtrs, element->getElementValue()->value);
found = true;
break;
}
}
}
return found;
}
void IOHIDConsumer::handleReport()
{
AbsoluteTime now;
bool muteIsPressed = false;
bool ejectIsPressed = false;
bool powerIsPressed = false;
bool playIsPressed = false;
bool soundUpIsPressed = false;
bool soundDownIsPressed = false;
bool fastForwardIsPressed = false;
bool rewindIsPressed = false;
bool nextTrackIsPressed = false;
bool prevTrackIsPressed = false;
clock_get_uptime( &now );
FindKeyboardsAndGetModifiers();
powerIsPressed = 0;
GetButtonValues(_powerValuePtrs, powerIsPressed);
GetButtonValues(_resetValuePtrs, powerIsPressed);
GetButtonValues(_sleepValuePtrs, powerIsPressed);
GetButtonValues(_systemPowerValuePtrs, powerIsPressed);
GetButtonValues(_systemSleepValuePtrs, powerIsPressed);
GetButtonValues(_systemWakeUpValuePtrs, powerIsPressed);
playIsPressed = 0;
GetButtonValues(_playValuePtrs, playIsPressed);
GetButtonValues(_playOrPauseValuePtrs, playIsPressed);
GetButtonValues(_playOrSkipPtrs, playIsPressed);
ejectIsPressed = 0;
GetButtonValues(_ejectValuePtrs, ejectIsPressed);
muteIsPressed = 0;
GetButtonValues(_volumeMuteValuePtrs, muteIsPressed);
soundUpIsPressed = 0;
GetButtonValues(_volumeIncValuePtrs, soundUpIsPressed);
soundDownIsPressed = 0;
GetButtonValues(_volumeDecValuePtrs, soundDownIsPressed);
fastForwardIsPressed = 0;
GetButtonValues(_fastFowardValuePtrs, fastForwardIsPressed);
rewindIsPressed = 0;
GetButtonValues(_rewindValuePtrs, rewindIsPressed);
nextTrackIsPressed = 0;
GetButtonValues(_nextTrackValuePtrs, nextTrackIsPressed);
prevTrackIsPressed = 0;
GetButtonValues(_prevTrackValuePtrs, prevTrackIsPressed);
if ( !( muteIsPressed && soundUpIsPressed && soundDownIsPressed ) )
{
if ( muteIsPressed != _muteIsPressed )
{
dispatchKeyboardEvent( kVolumeMute, muteIsPressed, now );
}
if( soundUpIsPressed != _soundUpIsPressed )
{
dispatchKeyboardEvent( kVolumeUp, soundUpIsPressed, now );
}
if( soundDownIsPressed != _soundDownIsPressed )
{
dispatchKeyboardEvent( kVolumeDown, soundDownIsPressed, now );
}
}
if ( ejectIsPressed != _ejectIsPressed )
{
dispatchKeyboardEvent( kEject, ejectIsPressed, now );
}
if ( powerIsPressed != _powerIsPressed )
{
dispatchKeyboardEvent( kPower, powerIsPressed, now );
}
if ( playIsPressed != _playIsPressed )
{
dispatchKeyboardEvent( kPlay, playIsPressed, now );
}
if( fastForwardIsPressed != _fastForwardIsPressed )
{
dispatchKeyboardEvent( kFastForward, soundUpIsPressed, now );
}
if( rewindIsPressed != _rewindIsPressed )
{
dispatchKeyboardEvent( kRewind, soundDownIsPressed, now );
}
if( nextTrackIsPressed != _nextTrackIsPressed )
{
dispatchKeyboardEvent( kNextTrack, soundUpIsPressed, now );
}
if( prevTrackIsPressed != _prevTrackIsPressed )
{
dispatchKeyboardEvent( kPreviousTrack, soundDownIsPressed, now );
}
_soundUpIsPressed = soundUpIsPressed;
_soundDownIsPressed = soundDownIsPressed;
_muteIsPressed = muteIsPressed;
_ejectIsPressed = ejectIsPressed;
_powerIsPressed = powerIsPressed;
_playIsPressed = playIsPressed;
_fastForwardIsPressed = fastForwardIsPressed;
_rewindIsPressed = rewindIsPressed;
_nextTrackIsPressed = nextTrackIsPressed;
_prevTrackIsPressed = prevTrackIsPressed;
}
unsigned IOHIDConsumer::eventFlags()
{
return( _eventFlags );
}
bool IOHIDConsumer::alphaLock()
{
return( _capsLockOn );
}
const unsigned char * IOHIDConsumer::defaultKeymapOfLength( UInt32 * length )
{
static const unsigned char ConsumerKeyMap[] =
{
0x00,0x00,
0x00,
0x00,
0x00,
0x0a,
NX_POWER_KEY, kPower,
NX_KEYTYPE_SOUND_UP, kVolumeUp,
NX_KEYTYPE_SOUND_DOWN, kVolumeDown,
NX_KEYTYPE_MUTE, kVolumeMute,
NX_KEYTYPE_PLAY, kPlay,
NX_KEYTYPE_NEXT, kNextTrack,
NX_KEYTYPE_PREVIOUS, kPreviousTrack,
NX_KEYTYPE_FAST, kFastForward,
NX_KEYTYPE_REWIND, kRewind,
NX_KEYTYPE_EJECT, kEject
};
if( length ) *length = sizeof( ConsumerKeyMap );
return( ConsumerKeyMap );
}
UInt32 IOHIDConsumer::FindKeyboardsAndGetModifiers()
{
OSIterator *iterator = NULL;
OSDictionary *matchingDictionary = NULL;
IOHIKeyboard *device = NULL;
_eventFlags = 0;
_capsLockOn = 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() )
{
_capsLockOn = TRUE;
}
_eventFlags |= device->eventFlags();
}
exit:
if( matchingDictionary ) matchingDictionary->release();
if( iterator ) iterator->release();
return( _eventFlags );
}