#include <IOKit/IOLib.h>
#include <IOKit/assert.h>
#include <IOKit/hidsystem/IOHIPointing.h>
#include <IOKit/hidsystem/IOHIDParameter.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#include <libkern/OSByteOrder.h>
#include "IOHIDSystem.h"
#include "IOHIDPointingDevice.h"
#include "IOHIDevicePrivateKeys.h"
#include "ev_private.h"
#ifndef abs
#define abs(_a) ((_a >= 0) ? _a : -_a)
#endif
#ifndef IOFixedSquared
#define IOFixedSquared(a) IOFixedMultiply(a, a)
#endif
#define FRAME_RATE (67 << 16)
#define SCREEN_RESOLUTION (96 << 16)
#define MAX_DEVICE_THRESHOLD 0x7fffffff
#define SCROLL_DEFAULT_RESOLUTION 0x00090000
#define SCROLL_CONSUME_RESOLUTION 0x00640000
#define SCROLL_CONSUME_COUNT_MULTIPLIER 3
#define SCROLL_EVENT_THRESHOLD_MS 0x960000
#define SCROLL_EVENT_THRESHOLD_MS_LL 150ULL
#define SCROLL_CLEAR_THRESHOLD_MS_LL 500ULL
#define SCROLL_MULTIPLIER_RANGE 0x00018000
#define SCROLL_MULTIPLIER_A 0x00000002
#define SCROLL_MULTIPLIER_B 0x000003bb
#define SCROLL_MULTIPLIER_C 0x00018041
#define SCROLL_WHEEL_TO_PIXEL_SCALE 0x000a0000
#define SCROLL_PIXEL_TO_WHEEL_SCALE 0x0000199a
#define CONVERT_SCROLL_FIXED_TO_FRACTION(fixed, fraction) \
{ \
if( fixed >= 0) \
fraction = fixed & 0xffff; \
else \
fraction = fixed | 0xffff0000; \
}
#define CONVERT_SCROLL_FIXED_TO_INTEGER(fixedAxis, integer) \
{ \
SInt32 tempInt = 0; \
if((fixedAxis < 0) && (fixedAxis & 0xffff)) \
tempInt = (fixedAxis >> 16) + 1; \
else \
tempInt = (fixedAxis >> 16); \
integer = tempInt; \
}
#define CONVERT_SCROLL_FIXED_TO_COARSE(fixedAxis, coarse) \
{ \
SInt32 tempCoarse = 0; \
CONVERT_SCROLL_FIXED_TO_INTEGER(fixedAxis, tempCoarse) \
if (!tempCoarse && (fixedAxis & 0xffff)) \
tempCoarse = (fixedAxis < 0) ? -1 : 1; \
coarse = tempCoarse; \
}
#define _scrollButtonMask _reserved->scrollButtonMask
#define _scrollType _reserved->scrollType
#define _scrollZoomMask _reserved->scrollZoomMask
#define _scrollOff _reserved->scrollOff
#define _scrollWheelInfo _reserved->scrollWheelInfo
#define _scrollPointerInfo _reserved->scrollPointerInfo
#define _scrollFixedDeltaAxis1 _reserved->scrollFixedDeltaAxis1
#define _scrollFixedDeltaAxis2 _reserved->scrollFixedDeltaAxis2
#define _scrollFixedDeltaAxis3 _reserved->scrollFixedDeltaAxis3
#define _scrollPointDeltaAxis1 _reserved->scrollPointDeltaAxis1
#define _scrollPointDeltaAxis2 _reserved->scrollPointDeltaAxis2
#define _scrollPointDeltaAxis3 _reserved->scrollPointDeltaAxis3
#define _hidPointingNub _reserved->hidPointingNub
#define _isSeized _reserved->isSeized
#define _openClient _reserved->openClient
#define _accelerateMode _reserved->accelerateMode
#define DEVICE_LOCK IOLockLock( _deviceLock )
#define DEVICE_UNLOCK IOLockUnlock( _deviceLock )
enum {
kAccelTypeGlobal = -1,
kAccelTypeY = 0, kAccelTypeX = 1, kAccelTypeZ = 2 };
struct CursorDeviceSegment {
SInt32 devUnits;
SInt32 slope;
SInt32 intercept;
};
typedef struct CursorDeviceSegment CursorDeviceSegment;
#define SCROLL_TIME_DELTA_COUNT 8
struct ScaleDataState
{
UInt8 deltaIndex;
IOFixed deltaTime[SCROLL_TIME_DELTA_COUNT];
IOFixed deltaAxis[SCROLL_TIME_DELTA_COUNT];
IOFixed fraction;
};
typedef ScaleDataState ScaleDataState;
struct ScaleConsumeState
{
UInt32 consumeCount;
IOFixed consumeAccum;
};
typedef ScaleConsumeState ScaleConsumeState;
struct ScrollAxisAccelInfo
{
AbsoluteTime lastEventTime;
void * scaleSegments;
IOItemCount scaleSegCount;
ScaleDataState state;
ScaleConsumeState consumeState;
SInt32 lastValue;
UInt32 consumeClearThreshold;
UInt32 consumeCountThreshold;
bool isHighResScroll;
};
typedef ScrollAxisAccelInfo ScrollAxisAccelInfo;
struct ScrollAccelInfo
{
ScrollAxisAccelInfo axis[3];
IOFixed rateMultiplier;
UInt32 zoom:1;
};
typedef ScrollAccelInfo ScrollAccelInfo;
static bool SetupAcceleration (OSData * data, IOFixed desired, IOFixed devScale, IOFixed crsrScale, void ** scaleSegments, IOItemCount * scaleSegCount);
static void ScaleAxes (void * scaleSegments, int * axis1p, IOFixed *axis1Fractp, int * axis2p, IOFixed *axis2Fractp);
#define super IOHIDevice
OSDefineMetaClassAndStructors(IOHIPointing, IOHIDevice);
bool IOHIPointing::init(OSDictionary * properties)
{
if (!super::init(properties)) return false;
_reserved = IONew(ExpansionData, 1);
if (!_reserved) return false;
bzero(_reserved, sizeof(ExpansionData));
_scaleSegments = 0;
_scaleSegCount = 0;
_fractX = 0;
_fractY = 0;
_acceleration = -1;
_accelerateMode = ( kAccelScroll | kAccelMouse );
_convertAbsoluteToRelative = false;
_contactToMove = false;
_hadContact = false;
_pressureThresholdToClick = 128;
_previousLocation.x = 0;
_previousLocation.y = 0;
_hidPointingNub = 0;
_isSeized = false;
_buttonMode = NX_RightButton;
_scrollWheelInfo = (ScrollAccelInfo *) IOMalloc(sizeof(ScrollAccelInfo));
if (!_scrollWheelInfo) return false;
bzero(_scrollWheelInfo, sizeof(ScrollAccelInfo));
_scrollPointerInfo = (ScrollAccelInfo *) IOMalloc(sizeof(ScrollAccelInfo));
if (!_scrollPointerInfo) return false;
bzero(_scrollPointerInfo, sizeof(ScrollAccelInfo));
_deviceLock = IOLockAlloc();
if (!_deviceLock) return false;
return true;
}
bool IOHIPointing::start(IOService * provider)
{
static const char * defaultSettings = "(<00000000>, <00002000>, <00005000>,"
"<00008000>, <0000b000>, <0000e000>,"
"<00010000>)";
if (!super::start(provider)) return false;
if (!getProperty(kIOHIDDisallowRemappingOfPrimaryClickKey))
if (provider->getProperty(kIOHIDDisallowRemappingOfPrimaryClickKey))
setProperty(kIOHIDDisallowRemappingOfPrimaryClickKey, provider->getProperty(kIOHIDDisallowRemappingOfPrimaryClickKey));
if (!getProperty(kIOHIDPointerAccelerationTypeKey))
setProperty(kIOHIDPointerAccelerationTypeKey, kIOHIDMouseAccelerationType);
if (!getProperty(kIOHIDPointerAccelerationSettingsKey))
{
OSObject * obj = OSUnserialize(defaultSettings, 0);
if (obj) {
setProperty(kIOHIDPointerAccelerationSettingsKey, obj);
obj->release();
}
}
if (!getProperty(kIOHIDScrollAccelerationTypeKey))
setProperty(kIOHIDScrollAccelerationTypeKey, kIOHIDMouseScrollAccelerationKey);
if (buttonCount() > 1)
{
setProperty(kIOHIDPointerButtonCountKey, buttonCount(), 32);
}
OSNumber * number;
if (number = OSDynamicCast(OSNumber, getProperty(kIOHIDScrollMouseButtonKey)))
{
UInt32 value = number->unsigned32BitValue();
if (!value)
_scrollButtonMask = 0;
else
_scrollButtonMask = (1 << (value-1));
}
_hidPointingNub = IOHIDPointingDevice::newPointingDeviceAndStart(this, buttonCount(), resolution() >> 16);
registerService(kIOServiceSynchronous);
return true;
}
void IOHIPointing::free()
{
if (_deviceLock)
{
IOLock * lock;
IOLockLock(_deviceLock);
lock = _deviceLock;
_deviceLock = NULL;
IOLockUnlock(lock);
IOLockFree(lock);
}
if(_scaleSegments && _scaleSegCount)
IODelete( _scaleSegments, CursorDeviceSegment, _scaleSegCount );
if ( _scrollWheelInfo )
{
UInt32 type;
for (type=kAccelTypeY; type<=kAccelTypeZ; type++) {
if(_scrollWheelInfo->axis[type].scaleSegments && _scrollWheelInfo->axis[type].scaleSegCount)
IODelete( _scrollWheelInfo->axis[type].scaleSegments, CursorDeviceSegment, _scrollWheelInfo->axis[type].scaleSegCount );
}
IOFree(_scrollWheelInfo, sizeof(ScrollAccelInfo));
_scrollWheelInfo = 0;
}
if ( _scrollPointerInfo )
{
UInt32 type;
for (type=kAccelTypeY; type<=kAccelTypeZ; type++) {
if(_scrollPointerInfo->axis[type].scaleSegments && _scrollPointerInfo->axis[type].scaleSegCount)
IODelete( _scrollPointerInfo->axis[type].scaleSegments, CursorDeviceSegment, _scrollPointerInfo->axis[type].scaleSegCount );
}
IOFree(_scrollPointerInfo, sizeof(ScrollAccelInfo));
_scrollPointerInfo = 0;
}
if ( _hidPointingNub )
{
_hidPointingNub->release();
_hidPointingNub = 0;
}
if (_reserved) {
IODelete(_reserved, ExpansionData, 1);
}
super::free();
}
bool IOHIPointing::open(IOService * client,
IOOptionBits options,
RelativePointerEventAction rpeAction,
AbsolutePointerEventAction apeAction,
ScrollWheelEventAction sweAction)
{
if (client == this) {
return super::open(_openClient, options);
}
return open(client,
options,
0,
(RelativePointerEventCallback)rpeAction,
(AbsolutePointerEventCallback)apeAction,
(ScrollWheelEventCallback)sweAction);
}
bool IOHIPointing::open(IOService * client,
IOOptionBits options,
void * refcon,
RelativePointerEventCallback rpeCallback,
AbsolutePointerEventCallback apeCallback,
ScrollWheelEventCallback sweCallback)
{
if (client == this) return true;
_openClient = client;
bool returnValue = open(this, options,
(RelativePointerEventAction)_relativePointerEvent,
(AbsolutePointerEventAction)_absolutePointerEvent,
(ScrollWheelEventAction)_scrollWheelEvent);
if (!returnValue)
return false;
_relativePointerEventTarget = client;
_relativePointerEventAction = (RelativePointerEventAction)rpeCallback;
_absolutePointerEventTarget = client;
_absolutePointerEventAction = (AbsolutePointerEventAction)apeCallback;
_scrollWheelEventTarget = client;
_scrollWheelEventAction = (ScrollWheelEventAction)sweCallback;
return true;
}
void IOHIPointing::close(IOService * client, IOOptionBits)
{
_relativePointerEventAction = NULL;
_relativePointerEventTarget = 0;
_absolutePointerEventAction = NULL;
_absolutePointerEventTarget = 0;
super::close(client);
}
IOReturn IOHIPointing::message( UInt32 type, IOService * provider,
void * argument)
{
IOReturn ret = kIOReturnSuccess;
switch(type)
{
case kIOHIDSystemDeviceSeizeRequestMessage:
if (OSDynamicCast(IOHIDDevice, provider))
{
_isSeized = (bool)argument;
}
break;
default:
ret = super::message(type, provider, argument);
break;
}
return ret;
}
IOReturn IOHIPointing::powerStateWillChangeTo( IOPMPowerFlags powerFlags,
unsigned long newState, IOService * device )
{
return( super::powerStateWillChangeTo( powerFlags, newState, device ));
}
IOReturn IOHIPointing::powerStateDidChangeTo( IOPMPowerFlags powerFlags,
unsigned long newState, IOService * device )
{
return( super::powerStateDidChangeTo( powerFlags, newState, device ));
}
IOHIDKind IOHIPointing::hidKind()
{
return kHIRelativePointingDevice;
}
static void AccelerateScrollAxis( IOFixed * axisp,
ScrollAxisAccelInfo * scaleInfo,
AbsoluteTime timeStamp,
IOFixed rateMultiplier,
bool clear = false)
{
IOFixed absAxis = 0;
IOFixed avgIndex = 0;
IOFixed avgCount = 0;
IOFixed avgAxis = 0;
IOFixed timeDeltaMS = 0;
IOFixed avgTimeDeltaMS = 0;
IOFixed scrollMultiplier = 0;
UInt64 currentTimeNSLL = 0;
UInt64 lastEventTimeNSLL = 0;
UInt64 timeDeltaMSLL = 0;
if (!scaleInfo || !scaleInfo->scaleSegments)
return;
absAxis = abs(*axisp);
if( absAxis == 0 )
return;
absolutetime_to_nanoseconds(timeStamp, ¤tTimeNSLL);
absolutetime_to_nanoseconds(scaleInfo->lastEventTime, &lastEventTimeNSLL);
scaleInfo->lastEventTime = timeStamp;
timeDeltaMSLL = (currentTimeNSLL - lastEventTimeNSLL) / 1000000;
if ((timeDeltaMSLL > SCROLL_CLEAR_THRESHOLD_MS_LL) || clear)
{
bzero(&(scaleInfo->state), sizeof(ScaleDataState));
}
timeDeltaMSLL = ((timeDeltaMSLL > SCROLL_EVENT_THRESHOLD_MS_LL) || clear) ?
SCROLL_EVENT_THRESHOLD_MS_LL : timeDeltaMSLL;
timeDeltaMS = ((UInt32) timeDeltaMSLL) << 16;
scaleInfo->state.deltaTime[scaleInfo->state.deltaIndex] = timeDeltaMS;
scaleInfo->state.deltaAxis[scaleInfo->state.deltaIndex] = absAxis;
scaleInfo->state.deltaIndex = (scaleInfo->state.deltaIndex + 1) % SCROLL_TIME_DELTA_COUNT;
for (avgIndex=0; avgIndex < SCROLL_TIME_DELTA_COUNT; avgIndex++)
{
if (scaleInfo->state.deltaTime[avgIndex] == 0)
continue;
avgAxis += abs(scaleInfo->state.deltaAxis[avgIndex]);
avgTimeDeltaMS += scaleInfo->state.deltaTime[avgIndex];
avgCount ++;
}
avgAxis = (avgCount) ? IOFixedDivide(avgAxis, (avgCount<<16)) : 0;
avgTimeDeltaMS = (avgCount) ? IOFixedDivide(avgTimeDeltaMS, (avgCount<<16)) : 0;
avgTimeDeltaMS = IOFixedMultiply(avgTimeDeltaMS, rateMultiplier);
avgTimeDeltaMS = (avgTimeDeltaMS > SCROLL_EVENT_THRESHOLD_MS) ? SCROLL_EVENT_THRESHOLD_MS : avgTimeDeltaMS;
scrollMultiplier = IOFixedMultiply(SCROLL_MULTIPLIER_A, IOFixedSquared(avgTimeDeltaMS)) -
IOFixedMultiply(SCROLL_MULTIPLIER_B, avgTimeDeltaMS) +
SCROLL_MULTIPLIER_C;
scrollMultiplier = IOFixedMultiply(scrollMultiplier, rateMultiplier);
scrollMultiplier = IOFixedMultiply(scrollMultiplier, avgAxis);
CursorDeviceSegment *segment;
for(
segment = (CursorDeviceSegment *) scaleInfo->scaleSegments;
scrollMultiplier > segment->devUnits;
segment++) {}
scrollMultiplier = IOFixedDivide(
segment->intercept + IOFixedMultiply( scrollMultiplier, segment->slope ),
absAxis );
*axisp = IOFixedMultiply(*axisp, scrollMultiplier);
}
void IOHIPointing::setPointingMode(UInt32 accelerateMode)
{
_accelerateMode = accelerateMode;
_convertAbsoluteToRelative = ((accelerateMode & kAbsoluteConvertMouse) != 0);
}
UInt32 IOHIPointing::getPointingMode()
{
return _accelerateMode;
}
void IOHIPointing::scalePointer(int * dxp, int * dyp)
{
ScaleAxes(_scaleSegments, dxp, &_fractX, dyp, &_fractY);
}
static SInt32 Interpolate( SInt32 x1, SInt32 y1,
SInt32 x2, SInt32 y2,
SInt32 x3, SInt32 y3,
SInt32 scale, Boolean lower )
{
SInt32 slope;
SInt32 intercept;
SInt32 resultY;
slope = (x2 == x1) ? 0 : IOFixedDivide( y2 - y1, x2 - x1 );
intercept = y1 - IOFixedMultiply( slope, x1 );
resultY = intercept + IOFixedMultiply( slope, x3 );
if( lower)
resultY = y3 - IOFixedMultiply( scale, y3 - resultY );
else
resultY = resultY + IOFixedMultiply( scale, y3 - resultY );
return( resultY );
}
void IOHIPointing::setupForAcceleration( IOFixed desired )
{
IOFixed devScale = IOFixedDivide( resolution(), FRAME_RATE );
IOFixed crsrScale = IOFixedDivide( SCREEN_RESOLUTION, FRAME_RATE );
OSData * table = copyAccelerationTable();
if (SetupAcceleration (table, desired, devScale, crsrScale, &_scaleSegments, &_scaleSegCount))
{
_acceleration = desired;
_fractX = _fractY = 0;
if (table) table->release();
}
}
void IOHIPointing::setupScrollForAcceleration( IOFixed desired )
{
IOFixed devScale = 0;
IOFixed scrScale = 0;
IOFixed resolution = 0;
IOFixed reportRate = scrollReportRate();
OSData * accelTable = NULL;
UInt32 type = 0;
_scrollWheelInfo->rateMultiplier = IOFixedDivide(reportRate, FRAME_RATE);
_scrollPointerInfo->rateMultiplier = IOFixedDivide(reportRate, FRAME_RATE);
for ( type=kAccelTypeY; type<=kAccelTypeZ; type++) {
resolution = scrollResolutionForType(type);
if ( resolution ) {
accelTable = copyScrollAccelerationTableForType(type);
devScale = IOFixedDivide( resolution, reportRate );
scrScale = IOFixedDivide( SCREEN_RESOLUTION, FRAME_RATE );
if (SetupAcceleration (accelTable, desired, devScale, scrScale, &(_scrollWheelInfo->axis[type].scaleSegments), &(_scrollWheelInfo->axis[type].scaleSegCount)))
{
bzero(&(_scrollWheelInfo->axis[type].state), sizeof(ScaleDataState));
clock_get_uptime(&(_scrollWheelInfo->axis[type].lastEventTime));
}
_scrollWheelInfo->axis[type].isHighResScroll = resolution > (SCROLL_DEFAULT_RESOLUTION * 2);
_scrollWheelInfo->axis[type].consumeClearThreshold = (IOFixedDivide(resolution, SCROLL_CONSUME_RESOLUTION) >> 16) * 2;
_scrollWheelInfo->axis[type].consumeCountThreshold = _scrollWheelInfo->axis[type].consumeClearThreshold * SCROLL_CONSUME_COUNT_MULTIPLIER;
bzero(&(_scrollWheelInfo->axis[type].consumeState), sizeof(ScaleConsumeState));
resolution = this->resolution();
reportRate = FRAME_RATE;
devScale = IOFixedDivide( resolution, reportRate );
scrScale = IOFixedDivide( SCREEN_RESOLUTION, FRAME_RATE );
if (SetupAcceleration (accelTable, desired, devScale, scrScale, &(_scrollPointerInfo->axis[type].scaleSegments), &(_scrollPointerInfo->axis[type].scaleSegCount)))
{
bzero(&(_scrollPointerInfo->axis[type].state), sizeof(ScaleDataState));
clock_get_uptime(&(_scrollPointerInfo->axis[type].lastEventTime));
}
_scrollPointerInfo->axis[type].isHighResScroll = resolution > (SCROLL_DEFAULT_RESOLUTION * 2);
_scrollPointerInfo->axis[type].consumeClearThreshold = (IOFixedDivide(resolution, SCROLL_CONSUME_RESOLUTION) >> 16) * 2;
_scrollPointerInfo->axis[type].consumeCountThreshold = _scrollPointerInfo->axis[type].consumeClearThreshold * SCROLL_CONSUME_COUNT_MULTIPLIER;
bzero(&(_scrollPointerInfo->axis[type].consumeState), sizeof(ScaleConsumeState));
if (accelTable)
accelTable->release();
}
}
}
bool IOHIPointing::resetPointer()
{
DEVICE_LOCK;
_buttonMode = NX_RightButton;
setupForAcceleration(EV_DEFAULTPOINTERACCELLEVEL);
updateProperties();
DEVICE_UNLOCK;
return true;
}
bool IOHIPointing::resetScroll()
{
DEVICE_LOCK;
setupScrollForAcceleration(EV_DEFAULTSCROLLACCELLEVEL);
DEVICE_UNLOCK;
return true;
}
static void ScalePressure(int *pressure, int pressureMin, int pressureMax)
{
*pressure = ((pressureMin != pressureMax)) ?
(((unsigned)(*pressure - pressureMin) * 65535LL) /
(unsigned)( pressureMax - pressureMin)) : 0;
}
void IOHIPointing::dispatchAbsolutePointerEvent(IOGPoint * newLoc,
IOGBounds * bounds,
UInt32 buttonState,
bool proximity,
int pressure,
int pressureMin,
int pressureMax,
int stylusAngle,
AbsoluteTime ts)
{
int buttons = 0;
int dx, dy;
DEVICE_LOCK;
if( buttonState & 1)
buttons |= EV_LB;
if( buttonState & 2) buttons |= EV_RB;
if(buttonState & 4)
buttons |= 2;
buttons |= buttonState & ~0x7;
if ( pressure > pressureMin )
{
buttons |= EV_LB;
}
if (_buttonMode == NX_OneButton) {
if ((buttons & (EV_LB|EV_RB)) != 0) {
buttons = EV_LB;
}
}
if (_convertAbsoluteToRelative) {
dx = newLoc->x - _previousLocation.x;
dy = newLoc->y - _previousLocation.y;
if ((_contactToMove && !_hadContact && (pressure > pressureMin)) || (abs(dx) > ((bounds->maxx - bounds->minx) / 20)) || (abs(dy) > ((bounds->maxy - bounds->miny) / 20))) {
dx = 0;
dy = 0;
} else {
scalePointer(&dx, &dy);
}
_previousLocation.x = newLoc->x;
_previousLocation.y = newLoc->y;
}
DEVICE_UNLOCK;
_hadContact = (pressure > pressureMin);
if (!_contactToMove || (pressure > pressureMin)) {
ScalePressure(&pressure, pressureMin, pressureMax);
if (_convertAbsoluteToRelative) {
_relativePointerEvent( this,
buttons,
dx,
dy,
ts);
} else {
_absolutePointerEvent( this,
buttons,
newLoc,
bounds,
proximity,
pressure,
stylusAngle,
ts);
}
}
return;
}
void IOHIPointing::dispatchRelativePointerEvent(int dx,
int dy,
UInt32 buttonState,
AbsoluteTime ts)
{
int buttons;
DEVICE_LOCK;
if (_hidPointingNub)
_hidPointingNub->postMouseEvent(buttonState, dx, dy, 0);
if (_isSeized)
{
DEVICE_UNLOCK;
return;
}
buttons = 0;
if( buttonState & 1)
buttons |= EV_LB;
if( buttonState & 2) buttons |= EV_RB;
if(buttonState & 4)
buttons |= 2;
buttons |= buttonState & ~0x7;
if ( _scrollButtonMask & buttonState )
{
DEVICE_UNLOCK;
dispatchScrollWheelEventWithAccelInfo(-dy, -dx, 0, _scrollPointerInfo, ts);
return;
}
if ( _accelerateMode & kAccelMouse ) {
int oldDx = dx;
int oldDy = dy;
scalePointer(&dx, &dy);
if (((oldDx < 0) && (dx > 0)) || ((oldDx > 0) && (dx < 0))) {
IOLog("IOHIPointing::dispatchRelativePointerEvent: Unwanted Direction Change X: oldDx=%d dx=%d\n", oldDy, dy);
}
if (((oldDy < 0) && (dy > 0)) || ((oldDy > 0) && (dy < 0))) {
IOLog("IOHIPointing::dispatchRelativePointerEvent: Unwanted Direction Change Y: oldDy=%d dy=%d\n", oldDy, dy);
}
}
if ( _buttonMode == NX_OneButton )
{
if ( (buttons & (EV_LB|EV_RB)) != 0 ) {
buttons |= EV_LB;
buttons &= ~EV_RB;
}
}
else if ( (buttonCount() > 1) && (_buttonMode == NX_LeftButton) )
{
int temp = 0;
if ( buttons & EV_LB )
temp = EV_RB;
if ( buttons & EV_RB )
temp |= EV_LB;
buttons = (buttons & ~(EV_LB|EV_RB)) | temp;
}
DEVICE_UNLOCK;
_relativePointerEvent(this,
buttons,
dx,
dy,
ts);
}
void IOHIPointing::dispatchScrollWheelEvent(short deltaAxis1,
short deltaAxis2,
short deltaAxis3,
AbsoluteTime ts)
{
dispatchScrollWheelEventWithAccelInfo(deltaAxis1, deltaAxis2, deltaAxis3, _scrollWheelInfo, ts);
}
void IOHIPointing::dispatchScrollWheelEventWithAccelInfo(
SInt32 deltaAxis1,
SInt32 deltaAxis2,
SInt32 deltaAxis3,
ScrollAccelInfo * info,
AbsoluteTime ts)
{
Boolean isHighResScroll = FALSE;
IOHIDSystem * hidSystem = IOHIDSystem::instance();
UInt32 eventFlags = (hidSystem ? hidSystem->eventFlags() : 0);
DEVICE_LOCK;
if (_hidPointingNub && !_hidPointingNub->isScrollPresent())
{
IOHIDPointingDevice * nub = _hidPointingNub;
_hidPointingNub = 0;
DEVICE_UNLOCK;
nub->terminate(kIOServiceSynchronous);
nub->release();
nub = IOHIDPointingDevice::newPointingDeviceAndStart(this, buttonCount(), resolution() >> 16, true);
DEVICE_LOCK;
_hidPointingNub = nub;
}
if (_hidPointingNub)
_hidPointingNub->postMouseEvent(0, 0, 0, deltaAxis1);
if (_isSeized)
{
DEVICE_UNLOCK;
return;
}
if ( _scrollZoomMask && ((SPECIALKEYS_MODIFIER_MASK & eventFlags) == _scrollZoomMask) )
_scrollType = kScrollTypeZoom;
if ( _scrollType != kScrollTypeZoom && _scrollOff ) {
DEVICE_UNLOCK;
return;
}
_scrollFixedDeltaAxis1 = deltaAxis1 << 16;
_scrollFixedDeltaAxis2 = deltaAxis2 << 16;
_scrollFixedDeltaAxis3 = deltaAxis3 << 16;
CONVERT_SCROLL_FIXED_TO_COARSE(IOFixedMultiply(_scrollFixedDeltaAxis1, SCROLL_WHEEL_TO_PIXEL_SCALE), _scrollPointDeltaAxis1);
CONVERT_SCROLL_FIXED_TO_COARSE(IOFixedMultiply(_scrollFixedDeltaAxis2, SCROLL_WHEEL_TO_PIXEL_SCALE), _scrollPointDeltaAxis2);
CONVERT_SCROLL_FIXED_TO_COARSE(IOFixedMultiply(_scrollFixedDeltaAxis3, SCROLL_WHEEL_TO_PIXEL_SCALE), _scrollPointDeltaAxis3);
if ( _accelerateMode & kAccelScroll )
{
bool directionChange[3] = {0,0,0};
bool typeChange = FALSE;
SInt32* pDeltaAxis[3] = {&deltaAxis1, &deltaAxis2, &deltaAxis3};
SInt32* pScrollFixedDeltaAxis[3] = {&_scrollFixedDeltaAxis1, &_scrollFixedDeltaAxis2, &_scrollFixedDeltaAxis3};
IOFixed* pScrollPointDeltaAxis[3] = {&_scrollPointDeltaAxis1, &_scrollPointDeltaAxis2, &_scrollPointDeltaAxis3};
if ( info->zoom != (_scrollType == kScrollTypeZoom))
{
info->zoom = (_scrollType == kScrollTypeZoom);
typeChange = TRUE;
}
for (UInt32 type=kAccelTypeY; type<=kAccelTypeZ; type++ ) {
directionChange[type] = (((info->axis[type].lastValue < 0) && (*(pDeltaAxis[type]) >= 0)) || ((info->axis[type].lastValue >= 0) && (*(pDeltaAxis[type]) < 0)));
info->axis[type].lastValue = *(pDeltaAxis[type]);
if ( info->axis[type].scaleSegments )
{
isHighResScroll |= info->axis[type].isHighResScroll;
*(pScrollPointDeltaAxis[type]) = info->axis[type].lastValue << 16;
AccelerateScrollAxis(pScrollPointDeltaAxis[type],
&(info->axis[type]),
ts,
info->rateMultiplier,
directionChange[type] || typeChange);
if ( info->axis[type].consumeCountThreshold )
{
*(pScrollPointDeltaAxis[type]) += info->axis[type].state.fraction;
CONVERT_SCROLL_FIXED_TO_FRACTION(*(pScrollPointDeltaAxis[type]), info->axis[type].state.fraction);
*(pScrollPointDeltaAxis[type]) /= 65536;
}
else
{
CONVERT_SCROLL_FIXED_TO_COARSE(*(pScrollPointDeltaAxis[type]), *(pScrollPointDeltaAxis[type]));
}
*(pScrollFixedDeltaAxis[type]) = *(pScrollPointDeltaAxis[type]) << 16;
if ( directionChange[type] )
bzero(&(info->axis[type].consumeState), sizeof(ScaleConsumeState));
if ( info->axis[type].consumeCountThreshold )
{
info->axis[type].consumeState.consumeAccum += *(pScrollFixedDeltaAxis[type]) + ((*(pScrollFixedDeltaAxis[type])) ? info->axis[type].state.fraction : 0);
info->axis[type].consumeState.consumeCount += abs(info->axis[type].lastValue);
if (*(pScrollFixedDeltaAxis[type]) &&
((abs(info->axis[type].lastValue) >= info->axis[type].consumeClearThreshold) ||
(info->axis[type].consumeState.consumeCount >= info->axis[type].consumeCountThreshold)))
{
*(pScrollFixedDeltaAxis[type]) = info->axis[type].consumeState.consumeAccum;
info->axis[type].consumeState.consumeAccum = 0;
info->axis[type].consumeState.consumeCount = 0;
}
else
{
*(pScrollFixedDeltaAxis[type]) = 0;
}
}
*(pScrollFixedDeltaAxis[type]) = IOFixedMultiply(*(pScrollFixedDeltaAxis[type]), SCROLL_PIXEL_TO_WHEEL_SCALE);
CONVERT_SCROLL_FIXED_TO_COARSE(*(pScrollFixedDeltaAxis[type]), *(pDeltaAxis[type]));
}
}
}
DEVICE_UNLOCK;
_scrollType |= (isHighResScroll) ? kScrollTypeContinuous : 0;
_scrollWheelEvent( this,
deltaAxis1,
deltaAxis2,
deltaAxis3,
ts);
_scrollType = 0;
}
bool IOHIPointing::updateProperties( void )
{
bool ok;
UInt32 res = resolution();
ok = setProperty( kIOHIDPointerResolutionKey, &res, sizeof( res))
& setProperty( kIOHIDPointerConvertAbsoluteKey, &_convertAbsoluteToRelative,
sizeof( _convertAbsoluteToRelative))
& setProperty( kIOHIDPointerContactToMoveKey, &_contactToMove,
sizeof( _contactToMove));
return( ok & super::updateProperties() );
}
IOReturn IOHIPointing::setParamProperties( OSDictionary * dict )
{
OSData * data;
OSNumber * number;
OSString * pointerAccelKey;
OSString * scrollAccelKey;
IOReturn err = kIOReturnSuccess;
bool updated = false;
UInt32 value;
if( dict->getObject(kIOHIDResetPointerKey))
resetPointer();
if( dict->getObject(kIOHIDScrollResetKey))
resetScroll();
pointerAccelKey = OSDynamicCast( OSString, getProperty(kIOHIDPointerAccelerationTypeKey));
scrollAccelKey = OSDynamicCast( OSString, getProperty(kIOHIDScrollAccelerationTypeKey));
DEVICE_LOCK;
if( (number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDScrollZoomModifierMaskKey))))
{
_scrollZoomMask = number->unsigned32BitValue() & SPECIALKEYS_MODIFIER_MASK;
}
if((number = OSDynamicCast( OSNumber, dict->getObject("TrackpadScroll"))) && scrollAccelKey && scrollAccelKey->isEqualTo(kIOHIDTrackpadScrollAccelerationKey))
{
_scrollOff = number->unsigned32BitValue() == 0;
}
if( pointerAccelKey &&
((number = OSDynamicCast( OSNumber, dict->getObject(pointerAccelKey))) ||
(data = OSDynamicCast( OSData, dict->getObject(pointerAccelKey)))))
{
value = (number) ? number->unsigned32BitValue() :
*((UInt32 *) (data->getBytesNoCopy()));
setupForAcceleration( value );
updated = true;
}
else if( (number = OSDynamicCast( OSNumber,
dict->getObject(kIOHIDPointerAccelerationKey))) ||
(data = OSDynamicCast( OSData,
dict->getObject(kIOHIDPointerAccelerationKey)))) {
value = (number) ? number->unsigned32BitValue() :
*((UInt32 *) (data->getBytesNoCopy()));
setupForAcceleration( value );
updated = true;
if( pointerAccelKey) {
if (!number)
{
number = OSNumber::withNumber(value, 32);
dict->setObject( pointerAccelKey, number );
number->release();
}
else
dict->setObject( pointerAccelKey, number );
}
}
if( scrollAccelKey &&
((number = OSDynamicCast( OSNumber, dict->getObject(scrollAccelKey))) ||
(data = OSDynamicCast( OSData, dict->getObject(scrollAccelKey)))))
{
value = (number) ? number->unsigned32BitValue() :
*((UInt32 *) (data->getBytesNoCopy()));
setupScrollForAcceleration( value );
updated = true;
}
else if( (number = OSDynamicCast( OSNumber,
dict->getObject(kIOHIDScrollAccelerationKey))) ||
(data = OSDynamicCast( OSData,
dict->getObject(kIOHIDScrollAccelerationKey)))) {
value = (number) ? number->unsigned32BitValue() :
*((UInt32 *) (data->getBytesNoCopy()));
setupScrollForAcceleration( value );
updated = true;
if( scrollAccelKey) {
if (!number)
{
number = OSNumber::withNumber(value, 32);
dict->setObject( scrollAccelKey, number );
number->release();
}
else
dict->setObject( scrollAccelKey, number );
}
}
DEVICE_UNLOCK;
if ((number = OSDynamicCast(OSNumber,
dict->getObject(kIOHIDPointerConvertAbsoluteKey))) ||
(data = OSDynamicCast(OSData,
dict->getObject(kIOHIDPointerConvertAbsoluteKey))))
{
value = (number) ? number->unsigned32BitValue() : *((UInt32 *) (data->getBytesNoCopy()));
_convertAbsoluteToRelative = (value != 0) ? true : false;
updated = true;
}
if ((number = OSDynamicCast(OSNumber,
dict->getObject(kIOHIDPointerContactToMoveKey))) ||
(data = OSDynamicCast(OSData,
dict->getObject(kIOHIDPointerContactToMoveKey))))
{
value = (number) ? number->unsigned32BitValue() : *((UInt32 *) (data->getBytesNoCopy()));
_contactToMove = (value != 0) ? true : false;
updated = true;
}
if ((number = OSDynamicCast(OSNumber, dict->getObject(kIOHIDPointerButtonMode))) ||
(data = OSDynamicCast(OSData, dict->getObject(kIOHIDPointerButtonMode))))
{
value = (number) ? number->unsigned32BitValue() :
*((UInt32 *) (data->getBytesNoCopy())) ;
if (getProperty(kIOHIDPointerButtonCountKey))
{
OSBoolean *booleanValue = OSDynamicCast(OSBoolean, getProperty(kIOHIDDisallowRemappingOfPrimaryClickKey));
if (NULL == booleanValue) {
booleanValue = kOSBooleanFalse;
}
switch (value) {
case kIOHIDButtonMode_BothLeftClicks:
_buttonMode = NX_RightButton;
break;
case kIOHIDButtonMode_EnableRightClick:
_buttonMode = NX_RightButton;
break;
case kIOHIDButtonMode_ReverseLeftRightClicks:
_buttonMode = booleanValue->isTrue() ? _buttonMode : NX_LeftButton;
break;
default:
_buttonMode = booleanValue->isTrue() ? _buttonMode : value;
}
updated = true;
}
}
if ((number = OSDynamicCast(OSNumber, dict->getObject(kIOHIDScrollMouseButtonKey))) ||
(data = OSDynamicCast(OSData, dict->getObject(kIOHIDScrollMouseButtonKey))))
{
value = (number) ? number->unsigned32BitValue() :
*((UInt32 *) (data->getBytesNoCopy())) ;
if (!value)
_scrollButtonMask = 0;
else
_scrollButtonMask = (1 << (value-1));
}
if( updated )
updateProperties();
return( err == kIOReturnSuccess ) ? super::setParamProperties(dict) : err;
}
IOItemCount IOHIPointing::buttonCount()
{
return (1);
}
IOFixed IOHIPointing::resolution()
{
OSNumber * number = OSDynamicCast(OSNumber, getProperty(kIOHIDPointerResolutionKey));
if ( number )
return number->unsigned32BitValue();
return (100 << 16);
}
IOFixed IOHIPointing::scrollResolutionForType(SInt32 type)
{
IOFixed resolution = 0;
OSNumber * number = NULL;
char * key = NULL;
switch ( type ) {
case kAccelTypeY:
key = kIOHIDScrollResolutionYKey;
break;
case kAccelTypeX:
key = kIOHIDScrollResolutionXKey;
break;
case kAccelTypeZ:
key = kIOHIDScrollResolutionZKey;
break;
default:
key = kIOHIDScrollResolutionKey;
break;
}
number = OSDynamicCast( OSNumber, getProperty(key) );
if( !number )
number = OSDynamicCast( OSNumber, getProperty(kIOHIDScrollResolutionKey) );
if( number )
resolution = number->unsigned32BitValue();
return( resolution );
}
IOFixed IOHIPointing::scrollReportRate()
{
OSNumber * number = OSDynamicCast( OSNumber,
getProperty( kIOHIDScrollReportRateKey ));
return number ? (number->unsigned32BitValue() ? number->unsigned32BitValue() : FRAME_RATE ) : FRAME_RATE;
}
OSData * IOHIPointing::copyAccelerationTable()
{
static const UInt8 accl[] = {
0x00, 0x00, 0x80, 0x00,
0x40, 0x32, 0x30, 0x30, 0x00, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x09, 0x00, 0x00, 0x71, 0x3B, 0x00, 0x00,
0x60, 0x00, 0x00, 0x04, 0x4E, 0xC5, 0x00, 0x10,
0x80, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x5F,
0x00, 0x00, 0x00, 0x16, 0xEC, 0x4F, 0x00, 0x8B,
0x00, 0x00, 0x00, 0x1D, 0x3B, 0x14, 0x00, 0x94,
0x80, 0x00, 0x00, 0x22, 0x76, 0x27, 0x00, 0x96,
0x00, 0x00, 0x00, 0x24, 0x62, 0x76, 0x00, 0x96,
0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x96,
0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x96,
0x00, 0x00
};
OSData * data = OSDynamicCast( OSData,
getProperty( kIOHIDPointerAccelerationTableKey ));
if( data)
data->retain();
else
data = OSData::withBytesNoCopy( (void *) accl, sizeof( accl ) );
return( data );
}
OSData * IOHIPointing::copyScrollAccelerationTable()
{
return( copyScrollAccelerationTableForType() );
}
OSData * IOHIPointing::copyScrollAccelerationTableForType(SInt32 type)
{
OSData * data = NULL;
char * key = NULL;
switch ( type ) {
case kAccelTypeY:
key = kIOHIDScrollAccelerationTableYKey;
break;
case kAccelTypeX:
key = kIOHIDScrollAccelerationTableXKey;
break;
case kAccelTypeZ:
key = kIOHIDScrollAccelerationTableZKey;
break;
default:
key = kIOHIDScrollAccelerationTableKey;
break;
}
data = OSDynamicCast( OSData, getProperty( key ));
if( !data)
data = OSDynamicCast( OSData, getProperty( kIOHIDScrollAccelerationTableKey ));
if( data)
data->retain();
else
data = copyAccelerationTable();
return( data );
}
bool SetupAcceleration (OSData * data, IOFixed desired, IOFixed devScale, IOFixed crsrScale, void ** scaleSegments, IOItemCount * scaleSegCount) {
const UInt16 * lowTable = 0;
const UInt16 * highTable;
SInt32 x1, y1, x2, y2, x3, y3;
SInt32 prevX1, prevY1;
SInt32 upperX, upperY;
SInt32 lowerX, lowerY;
SInt32 lowAccl = 0, lowPoints = 0;
SInt32 highAccl, highPoints;
SInt32 scale;
UInt32 count;
Boolean lower;
SInt32 scaledX1, scaledY1;
SInt32 scaledX2, scaledY2;
CursorDeviceSegment * segments;
CursorDeviceSegment * segment;
SInt32 segCount;
if( !data || !devScale || !crsrScale)
return false;
if( desired < (IOFixed) 0) {
if(*scaleSegments && *scaleSegCount)
IODelete( *scaleSegments,
CursorDeviceSegment, *scaleSegCount );
*scaleSegments = NULL;
*scaleSegCount = 0;
data->release();
return false;
}
highTable = (const UInt16 *) data->getBytesNoCopy();
scaledX1 = scaledY1 = 0;
scale = OSReadBigInt32((volatile void *)highTable, 0);
highTable += 4;
if( desired > 0x8000) {
desired = IOFixedMultiply( desired - 0x8000,
0x10000 - scale );
desired <<= 1;
desired += scale;
} else {
desired = IOFixedMultiply( desired, scale );
desired <<= 1;
}
count = OSReadBigInt16((volatile void *)(highTable++), 0);
scale = (1 << 16);
do {
highAccl = OSReadBigInt32((volatile void *)highTable, 0);
highTable += 2;
highPoints = OSReadBigInt16((volatile void *)(highTable++), 0);
if( desired <= highAccl)
break;
if( 0 == --count) {
scale = (highAccl) ? IOFixedDivide( desired, highAccl ) : 0;
lowTable = 0;
break;
}
lowTable = highTable;
lowAccl = highAccl;
lowPoints = highPoints;
highTable += lowPoints * 4;
} while( true );
if( lowTable) {
scale = (highAccl == lowAccl) ? 0 :
IOFixedDivide((desired - lowAccl), (highAccl - lowAccl));
}
else {
lowTable = highTable;
lowAccl = highAccl;
lowPoints = 0;
}
if( lowPoints > highPoints)
segCount = lowPoints;
else
segCount = highPoints;
segCount *= 2;
segments = IONew( CursorDeviceSegment, segCount );
assert( segments );
segment = segments;
x1 = prevX1 = y1 = prevY1 = 0;
lowerX = OSReadBigInt32((volatile void *)lowTable, 0);
lowTable += 2;
lowerY = OSReadBigInt32((volatile void *)lowTable, 0);
lowTable += 2;
upperX = OSReadBigInt32((volatile void *)highTable, 0);
highTable += 2;
upperY = OSReadBigInt32((volatile void *)highTable, 0);
highTable += 2;
do {
lower = (lowPoints && (!highPoints || (lowerX <= upperX)));
if( lower) {
x2 = upperX;
y2 = upperY;
x3 = lowerX;
y3 = lowerY;
if( lowPoints && (--lowPoints)) {
lowerX = OSReadBigInt32((volatile void *)lowTable, 0);
lowTable += 2;
lowerY = OSReadBigInt32((volatile void *)lowTable, 0);
lowTable += 2;
}
} else {
x2 = lowerX;
y2 = lowerY;
x3 = upperX;
y3 = upperY;
if( highPoints && (--highPoints)) {
upperX = OSReadBigInt32((volatile void *)highTable, 0);
highTable += 2;
upperY = OSReadBigInt32((volatile void *)highTable, 0);
highTable += 2;
}
}
{
assert( segment < (segments + segCount) );
scaledX2 = IOFixedMultiply( devScale, x3 );
scaledY2 = IOFixedMultiply( crsrScale,
Interpolate( x1, y1, x2, y2, x3, y3,
scale, lower ) );
if( lowPoints || highPoints)
segment->devUnits = scaledX2;
else
segment->devUnits = MAX_DEVICE_THRESHOLD;
segment->slope = ((scaledX2 == scaledX1)) ? 0 :
IOFixedDivide((scaledY2 - scaledY1), (scaledX2 - scaledX1));
segment->intercept = scaledY2
- IOFixedMultiply( segment->slope, scaledX2 );
scaledX1 = scaledX2;
scaledY1 = scaledY2;
segment++;
}
if( lowPoints && highPoints) {
if( lowerX > upperX) {
prevX1 = x1;
prevY1 = y1;
} else {
prevX1 = x1;
prevY1 = y1;
x1 = x3;
y1 = y3;
}
} else {
x2 = x1;
y2 = y1;
x1 = prevX1;
y1 = prevY1;
prevX1 = x2;
prevY1 = y2;
}
} while( lowPoints || highPoints );
if( *scaleSegCount && *scaleSegments)
IODelete( *scaleSegments,
CursorDeviceSegment, *scaleSegCount );
*scaleSegCount = segCount;
*scaleSegments = (void *) segments;
return true;
}
void ScaleAxes (void * scaleSegments, int * axis1p, IOFixed *axis1Fractp, int * axis2p, IOFixed *axis2Fractp)
{
SInt32 dx, dy;
SInt32 absDx, absDy;
SInt32 mag;
IOFixed scale;
CursorDeviceSegment * segment;
if( !scaleSegments)
return;
dx = (*axis1p) << 16;
dy = (*axis2p) << 16;
absDx = abs(dx);
absDy = abs(dy);
if( absDx > absDy)
mag = (absDx + (absDy / 2));
else
mag = (absDy + (absDx / 2));
if( !mag)
return;
for(
segment = (CursorDeviceSegment *) scaleSegments;
mag > segment->devUnits;
segment++) {}
scale = IOFixedDivide(
segment->intercept + IOFixedMultiply( mag, segment->slope ),
mag );
dx = IOFixedMultiply( dx, scale );
dy = IOFixedMultiply( dy, scale );
dx += *axis1Fractp;
dy += *axis2Fractp;
*axis1p = dx / 65536;
*axis2p = dy / 65536;
if( dx >= 0)
*axis1Fractp = dx & 0xffff;
else
*axis1Fractp = dx | 0xffff0000;
if( dy >= 0)
*axis2Fractp = dy & 0xffff;
else
*axis2Fractp = dy | 0xffff0000;
}
void IOHIPointing::_relativePointerEvent( IOHIPointing * self,
int buttons,
int dx,
int dy,
AbsoluteTime ts)
{
RelativePointerEventCallback rpeCallback;
rpeCallback = (RelativePointerEventCallback)self->_relativePointerEventAction;
if (rpeCallback)
(*rpeCallback)(self->_relativePointerEventTarget,
buttons,
dx,
dy,
ts,
self,
0);
}
void IOHIPointing::_absolutePointerEvent(IOHIPointing * self,
int buttons,
IOGPoint * newLoc,
IOGBounds *bounds,
bool proximity,
int pressure,
int stylusAngle,
AbsoluteTime ts)
{
AbsolutePointerEventCallback apeCallback;
apeCallback = (AbsolutePointerEventCallback)self->_absolutePointerEventAction;
if (apeCallback)
(*apeCallback)(self->_absolutePointerEventTarget,
buttons,
newLoc,
bounds,
proximity,
pressure,
stylusAngle,
ts,
self,
0);
}
void IOHIPointing::_scrollWheelEvent(IOHIPointing *self,
short deltaAxis1,
short deltaAxis2,
short deltaAxis3,
AbsoluteTime ts)
{
ScrollWheelEventCallback sweCallback;
sweCallback = (ScrollWheelEventCallback)self->_scrollWheelEventAction;
if (sweCallback)
(*sweCallback)(self->_scrollWheelEventTarget,
(short) deltaAxis1,
(short) deltaAxis2,
(short) deltaAxis3,
self->_scrollFixedDeltaAxis1,
self->_scrollFixedDeltaAxis2,
self->_scrollFixedDeltaAxis3,
self->_scrollPointDeltaAxis1,
self->_scrollPointDeltaAxis2,
self->_scrollPointDeltaAxis3,
self->_scrollType,
ts,
self,
0);
}