#include <IOKit/IOLib.h>
#include "ev_keymap.h"
#include "IOHIDEvent.h"
#include "IOHIDEventData.h"
#include "IOHIDUsageTables.h"
#define EXTERNAL ((unsigned int) -1)
#define super OSObject
OSDefineMetaClassAndStructors(IOHIDEvent, OSObject)
extern unsigned int hid_adb_2_usb_keymap[];
bool IOHIDEvent::initWithCapacity(IOByteCount capacity)
{
if (!super::init())
return false;
if (_data && (!capacity || _capacity < capacity) ) {
IOFree(_data, _capacity);
_data = 0;
}
_capacity = capacity;
if ( !_capacity )
return false;
if ( !_data && !(_data = (IOHIDEventData *) IOMalloc(_capacity)))
return false;
bzero(_data, _capacity);
_data->size = _capacity;
_children = NULL;
return true;
}
bool IOHIDEvent::initWithType(IOHIDEventType type)
{
size_t capacity = 0;
IOHIDEventGetSize(type,capacity);
if ( !initWithCapacity(capacity) )
return false;
_data->type = type;
_typeMask = IOHIDEventTypeMask(type);
return true;
}
bool IOHIDEvent::initWithTypeTimeStamp(IOHIDEventType type, AbsoluteTime timeStamp, IOOptionBits options)
{
if ( !initWithType(type))
return false;
_timeStamp = timeStamp;
_options = options;
return true;
}
void IOHIDEvent::free()
{
if (_capacity != EXTERNAL && _data && _capacity) {
IOFree(_data, _capacity);
_data = NULL;
_capacity = 0;
}
if ( _children ) {
_children->release();
_children = NULL;
}
super::free();
}
AbsoluteTime IOHIDEvent::getTimeStamp()
{
return _timeStamp;
}
void IOHIDEvent::setTimeStamp( AbsoluteTime timeStamp )
{
_timeStamp = timeStamp;
}
IOHIDEvent * IOHIDEvent::withType( IOHIDEventType type,
IOOptionBits options)
{
IOHIDEvent *me = new IOHIDEvent;
if (me && !me->initWithType(type)) {
me->release();
return 0;
}
me->_options = options;
return me;
}
IOHIDEvent * IOHIDEvent::withEventData (
AbsoluteTime timeStamp,
UInt32 type,
NXEventData * data,
IOOptionBits options)
{
IOHIDEvent *me = NULL;
switch ( type ) {
case NX_LMOUSEDOWN:
case NX_LMOUSEUP:
case NX_RMOUSEDOWN:
case NX_RMOUSEUP:
case NX_OMOUSEDOWN:
case NX_OMOUSEUP:
break;
case NX_MOUSEMOVED:
case NX_LMOUSEDRAGGED:
case NX_RMOUSEDRAGGED:
case NX_OMOUSEDRAGGED:
me = IOHIDEvent::translationEvent(timeStamp, data->mouseMove.dx<<16 + data->mouseMove.subx<<8, data->mouseMove.dy<<16 + data->mouseMove.suby<<8, 0, options);
break;
case NX_KEYDOWN:
case NX_KEYUP:
{
uint32_t usage = hid_adb_2_usb_keymap[data->key.keyCode];
if ( usage < kHIDUsage_KeyboardLeftControl || usage > kHIDUsage_KeyboardRightGUI || !data->key.repeat )
me = IOHIDEvent::keyboardEvent(timeStamp, kHIDPage_KeyboardOrKeypad, hid_adb_2_usb_keymap[data->key.keyCode], type==NX_KEYDOWN, options | (data->key.repeat ? kIOHIDKeyboardIsRepeat : 0));
}
break;
case NX_SCROLLWHEELMOVED:
me = IOHIDEvent::scrollEvent(timeStamp, data->scrollWheel.pointDeltaAxis2<<16, data->scrollWheel.pointDeltaAxis1<<16, data->scrollWheel.pointDeltaAxis3<<16, options);
break;
case NX_ZOOM:
me = IOHIDEvent::zoomEvent(timeStamp, data->scrollWheel.pointDeltaAxis2<<16, data->scrollWheel.pointDeltaAxis1<<16, data->scrollWheel.pointDeltaAxis3<<16, options);
break;
case NX_SYSDEFINED:
switch (data->compound.subType) {
case NX_SUBTYPE_AUX_MOUSE_BUTTONS:
me = IOHIDEvent::buttonEvent(timeStamp, data->compound.misc.L[1], options);
break;
case NX_SUBTYPE_AUX_CONTROL_BUTTONS:
uint16_t flavor = data->compound.misc.L[0] >> 16;
switch ( flavor ) {
case NX_KEYTYPE_SOUND_UP:
case NX_KEYTYPE_SOUND_DOWN:
case NX_KEYTYPE_BRIGHTNESS_UP:
case NX_KEYTYPE_BRIGHTNESS_DOWN:
case NX_KEYTYPE_HELP:
case NX_POWER_KEY:
case NX_KEYTYPE_MUTE:
case NX_KEYTYPE_NUM_LOCK:
case NX_KEYTYPE_EJECT:
case NX_KEYTYPE_VIDMIRROR:
case NX_KEYTYPE_PLAY:
case NX_KEYTYPE_NEXT:
case NX_KEYTYPE_PREVIOUS:
case NX_KEYTYPE_FAST:
case NX_KEYTYPE_REWIND:
case NX_KEYTYPE_ILLUMINATION_UP:
case NX_KEYTYPE_ILLUMINATION_DOWN:
case NX_KEYTYPE_ILLUMINATION_TOGGLE:
break;
}
}
break;
}
return me;
}
IOHIDEvent * IOHIDEvent::keyboardEvent( AbsoluteTime timeStamp,
UInt32 usagePage,
UInt32 usage,
Boolean down,
IOOptionBits options)
{
IOHIDEvent *me = new IOHIDEvent;
if (me && !me->initWithTypeTimeStamp(kIOHIDEventTypeKeyboard, timeStamp, options)) {
me->release();
return 0;
}
IOHIDKeyboardEventData * keyboard = (IOHIDKeyboardEventData *)me->_data;
keyboard->usagePage = usagePage;
keyboard->usage = usage;
keyboard->down = down;
return me;
}
IOHIDEvent * IOHIDEvent::_axisEvent( IOHIDEventType type,
AbsoluteTime timeStamp,
IOFixed x,
IOFixed y,
IOFixed z,
IOOptionBits options)
{
IOHIDEvent *me = new IOHIDEvent;
if (me && !me->initWithTypeTimeStamp(type, timeStamp, options)) {
me->release();
return 0;
}
IOHIDAxisEventData * event = (IOHIDAxisEventData *)me->_data;
event->position.x = x;
event->position.y = y;
event->position.z = z;
return me;
}
IOHIDEvent * IOHIDEvent::translationEvent(
AbsoluteTime timeStamp,
IOFixed x,
IOFixed y,
IOFixed z,
IOOptionBits options)
{
return IOHIDEvent::_axisEvent( kIOHIDEventTypeTranslation,
timeStamp,
x,
y,
z,
options);
}
IOHIDEvent * IOHIDEvent::scrollEvent(
AbsoluteTime timeStamp,
IOFixed x,
IOFixed y,
IOFixed z,
IOOptionBits options)
{
return IOHIDEvent::_axisEvent( kIOHIDEventTypeScroll,
timeStamp,
x,
y,
z,
options);
}
IOHIDEvent * IOHIDEvent::zoomEvent(
AbsoluteTime timeStamp,
IOFixed x,
IOFixed y,
IOFixed z,
IOOptionBits options)
{
return IOHIDEvent::_axisEvent( kIOHIDEventTypeZoom,
timeStamp,
x,
y,
z,
options);
}
IOHIDEvent * IOHIDEvent::accelerometerEvent(
AbsoluteTime timeStamp,
IOFixed x,
IOFixed y,
IOFixed z,
IOHIDAccelerometerType type,
IOHIDAccelerometerSubType subType,
IOOptionBits options)
{
IOHIDEvent * event;
IOHIDAccelerometerEventData * data;
event = IOHIDEvent::_axisEvent( kIOHIDEventTypeAccelerometer,
timeStamp,
x,
y,
z,
options);
if ( event ) {
data = (IOHIDAccelerometerEventData *)event->_data;
data->acclType = type;
data->acclSubType = subType;
}
return event;
}
IOHIDEvent * IOHIDEvent::gyroEvent(
AbsoluteTime timeStamp,
IOFixed x,
IOFixed y,
IOFixed z,
IOHIDGyroType type,
IOHIDGyroSubType subType,
IOFixed qx,
IOFixed qy,
IOFixed qz,
IOFixed qw,
IOOptionBits options)
{
IOHIDEvent * event;
IOHIDGyroEventData * data;
event = IOHIDEvent::_axisEvent( kIOHIDEventTypeGyro,
timeStamp,
x,
y,
z,
options);
if ( event ) {
data = (IOHIDGyroEventData *)event->_data;
data->gyroType = type;
data->gyroSubType = subType;
data->quaternionx = qx;
data->quaterniony = qy;
data->quaternionz = qz;
data->quaternionw = qw;
}
return event;
}
IOHIDEvent * IOHIDEvent::compassEvent(
AbsoluteTime timeStamp,
IOFixed x,
IOFixed y,
IOFixed z,
IOHIDCompassType type,
IOOptionBits options)
{
IOHIDEvent * event;
IOHIDCompassEventData * data;
event = IOHIDEvent::_axisEvent( kIOHIDEventTypeCompass,
timeStamp,
x,
y,
z,
options);
if ( event ) {
data = (IOHIDCompassEventData *)event->_data;
data->compassType = type;
}
return event;
}
IOHIDEvent * IOHIDEvent::ambientLightSensorEvent(
AbsoluteTime timeStamp,
UInt32 level,
UInt32 channel0,
UInt32 channel1,
UInt32 channel2,
UInt32 channel3,
IOOptionBits options)
{
IOHIDEvent *me = new IOHIDEvent;
if (me && !me->initWithTypeTimeStamp(kIOHIDEventTypeAmbientLightSensor, timeStamp, options)) {
me->release();
return 0;
}
IOHIDAmbientLightSensorEventData * event = (IOHIDAmbientLightSensorEventData *)me->_data;
event->level = level;
event->ch0 = channel0;
event->ch1 = channel1;
event->ch2 = channel2;
event->ch3 = channel3;
return me;
}
IOHIDEvent * IOHIDEvent::proximityEvent (
AbsoluteTime timeStamp,
IOHIDProximityDetectionMask mask,
UInt32 level,
IOOptionBits options)
{
IOHIDEvent *me = new IOHIDEvent;
if (me && !me->initWithTypeTimeStamp(kIOHIDEventTypeProximity, timeStamp, options)) {
me->release();
return 0;
}
IOHIDProximityEventData * event = (IOHIDProximityEventData *)me->_data;
event->detectionMask = mask;
event->level = level;
return me;
}
IOHIDEvent * IOHIDEvent::temperatureEvent(
AbsoluteTime timeStamp,
IOFixed temperature,
IOOptionBits options)
{
IOHIDEvent *me = new IOHIDEvent;
if (me && !me->initWithTypeTimeStamp(kIOHIDEventTypeTemperature, timeStamp, options)) {
me->release();
return 0;
}
IOHIDTemperatureEventData * event = (IOHIDTemperatureEventData *)me->_data;
event->level = temperature;
return me;
}
IOHIDEvent * IOHIDEvent::buttonEvent(
AbsoluteTime timeStamp,
UInt32 buttonMask,
IOOptionBits options)
{
return IOHIDEvent::buttonEvent(timeStamp, buttonMask, 0, options);
}
IOHIDEvent * IOHIDEvent::buttonEvent(
AbsoluteTime timeStamp,
UInt32 buttonMask,
IOFixed pressure,
IOOptionBits options)
{
IOHIDEvent *me = new IOHIDEvent;
if (me && !me->initWithTypeTimeStamp(kIOHIDEventTypeButton, timeStamp, options)) {
me->release();
return 0;
}
IOHIDButtonEventData * event = (IOHIDButtonEventData *)me->_data;
event->button.buttonMask = buttonMask;
event->button.pressure = pressure;
return me;
}
IOHIDEvent * IOHIDEvent::absolutePointerEvent(
AbsoluteTime timeStamp,
SInt32 x,
SInt32 y,
IOGBounds * bounds,
UInt32 buttonState,
bool inRange,
SInt32 tipPressure,
SInt32 tipPressureMin,
SInt32 tipPressureMax,
IOOptionBits options)
{
const int kIOFixedScale = 16;
IOHIDEvent *me = new IOHIDEvent;
if (me && !me->initWithTypeTimeStamp(kIOHIDEventTypeDigitizer, timeStamp, options)) {
me->release();
return 0;
}
IOHIDDigitizerEventData *event = (IOHIDDigitizerEventData *)me->_data;
x = min(max(x, bounds->minx), bounds->maxx);
y = min(max(y, bounds->miny), bounds->maxy);
event->position.x = IOFixedDivide( (x - bounds->minx)<<kIOFixedScale, (bounds->maxx - bounds->minx)<<kIOFixedScale);;
event->position.y = IOFixedDivide( (y - bounds->miny)<<kIOFixedScale, (bounds->maxy - bounds->miny)<<kIOFixedScale);;
event->position.z = 0;
event->transducerIndex = 1; event->transducerType = 0; event->identity = 2; event->eventMask = 0; event->buttonMask = 0; event->tipPressure = 0; event->barrelPressure = 0;
event->twist = 90<<kIOFixedScale; event->orientationType = kIOHIDDigitizerOrientationTypeQuality;
event->orientation.quality.quality = 0;
event->orientation.quality.density = 0;
event->orientation.quality.irregularity = 0;
event->orientation.quality.majorRadius = 6<<kIOFixedScale;
event->orientation.quality.minorRadius = 6<<kIOFixedScale;
return me;
}
void IOHIDEvent::appendChild(IOHIDEvent *childEvent)
{
if (!_children) {
const OSObject *events[] = { childEvent };
_children = OSArray::withObjects(events, 1);
} else {
_children->setObject(childEvent);
}
}
IOHIDEventType IOHIDEvent::getType()
{
return _data->type;
}
void IOHIDEvent::setType(IOHIDEventType type)
{
initWithType(type);
}
IOHIDEvent * IOHIDEvent::getEvent( IOHIDEventType type,
IOOptionBits options)
{
return (_data->type == type) ? this : NULL;
}
SInt32 IOHIDEvent::getIntegerValue( IOHIDEventField key,
IOOptionBits options)
{
SInt32 value = 0;
GET_EVENT_VALUE(this, key, value, options);
return value;
}
IOFixed IOHIDEvent::getFixedValue( IOHIDEventField key,
IOOptionBits options)
{
IOFixed value = 0;
#define HIDEVENTFIXED 1
GET_EVENT_VALUE(this, key, value, options);
#undef HIDEVENTFIXED
return value;
}
void IOHIDEvent::setIntegerValue( IOHIDEventField key,
SInt32 value,
IOOptionBits options)
{
SET_EVENT_VALUE(this, key, value, options);
}
void IOHIDEvent::setFixedValue( IOHIDEventField key,
IOFixed value,
IOOptionBits options)
{
#define HIDEVENTFIXED 1
SET_EVENT_VALUE(this, key, value, options);
#undef HIDEVENTFIXED
}
size_t IOHIDEvent::getLength()
{
_eventCount = 0;
return getLength(&_eventCount);
}
IOByteCount IOHIDEvent::getLength(UInt32 * count)
{
IOByteCount length = _data->size;
length += sizeof(IOHIDSystemQueueElement);
if ( _children )
{
UInt32 i, childCount;
IOHIDEvent * child;
childCount = _children->getCount();
for(i=0 ;i<childCount; i++)
if ( child = (IOHIDEvent *)_children->getObject(i) )
length += child->getLength(count) - sizeof(IOHIDSystemQueueElement);
}
if ( count )
*count = *count + 1;
return length;
}
IOByteCount IOHIDEvent::appendBytes(UInt8 * bytes, IOByteCount withLength)
{
IOByteCount size = 0;
size = _data->size;
if ( size > withLength )
return 0;
bcopy(_data, bytes, size);
if ( _children )
{
UInt32 i, childCount;
IOHIDEvent * child;
childCount = _children->getCount();
for(i=0 ;i<childCount; i++) {
if ( child = (IOHIDEvent *)_children->getObject(i) )
size += child->appendBytes(bytes + size, withLength - size);
}
}
return size;
}
IOHIDEvent * IOHIDEvent::withBytes( const void * bytes,
IOByteCount size)
{
IOHIDSystemQueueElement * queueElement= NULL;
IOHIDEvent * parent = NULL;
UInt32 index = 0;
UInt32 total = 0;
UInt32 offset = 0;
if ( !bytes || !size )
return NULL;
queueElement = (IOHIDSystemQueueElement *)bytes;
total = size - sizeof(IOHIDSystemQueueElement);
for (index=0; index<queueElement->eventCount && offset<total; index++)
{
IOHIDEventData * eventData = queueElement->events + offset;
IOHIDEvent * event = IOHIDEvent::withType(eventData->type);
if ( !event )
continue;
bcopy(eventData, event->_data, event->_data->size);
*((uint64_t *)&(event->_timeStamp)) = queueElement->timeStamp;
event->_options = queueElement->options;
if ( !parent )
parent = event;
else {
event->release();
}
offset += eventData->size;
}
return parent;
}
IOByteCount IOHIDEvent::readBytes(void * bytes, IOByteCount withLength)
{
IOHIDSystemQueueElement * queueElement= NULL;
queueElement = (IOHIDSystemQueueElement *)bytes;
queueElement->timeStamp = *((uint64_t *)&_timeStamp);
queueElement->options = _options;
queueElement->eventCount = _eventCount;
withLength -= sizeof(IOHIDSystemQueueElement);
return appendBytes((UInt8 *)queueElement->events, withLength);
}
IOHIDEventPhaseBits IOHIDEvent::getPhase()
{
return (_data->options >> kIOHIDEventEventOptionPhaseShift) & kIOHIDEventEventPhaseMask;
}
void IOHIDEvent::setPhase(IOHIDEventPhaseBits phase)
{
_data->options &= ~(kIOHIDEventEventPhaseMask << kIOHIDEventEventOptionPhaseShift);
_data->options |= ((phase & kIOHIDEventEventPhaseMask) << kIOHIDEventEventOptionPhaseShift);
}