#if 0
#define DEBUG_ASSERT_COMPONENT_NAME_STRING "IOHIPointing"
#define DEBUG_ASSERT_PRODUCTION_CODE 0
#endif
#include <AssertMacros.h>
#include <IOKit/IOLib.h>
#include <IOKit/assert.h>
#include <IOKit/hidsystem/IOHIPointing.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#include <libkern/OSByteOrder.h>
#include "IOHIDParameter.h"
#include "IOHIDSystem.h"
#include "IOHIDPointingDevice.h"
#include "IOHIDevicePrivateKeys.h"
#include "IOHIDParameter.h"
#include "IOFixed64.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 kIOFixedOne 0x10000ULL
#define SCROLL_DEFAULT_RESOLUTION (9 * kIOFixedOne)
#define SCROLL_CONSUME_RESOLUTION (100 * kIOFixedOne)
#define SCROLL_CONSUME_COUNT_MULTIPLIER 3
#define SCROLL_EVENT_THRESHOLD_MS_LL 150ULL
#define SCROLL_EVENT_THRESHOLD_MS (SCROLL_EVENT_THRESHOLD_MS_LL * kIOFixedOne)
#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 _lastScrollWasZoom _reserved->lastScrollWasZoom
#define _scrollWheelInfo _reserved->scrollWheelInfo
#define _scrollPointerInfo _reserved->scrollPointerInfo
#define _paraAccelParams _reserved->paraAccelParams
#define _paraAccelSecondaryParams _reserved->paraAccelSecondaryParams
#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 IOHIPointing__PAParameters
{
IOFixed64 deviceMickysDivider;
IOFixed64 cursorSpeedMultiplier;
IOFixed64 accelIndex;
IOFixed64 gain[4];
IOFixed64 tangent[2];
};
struct IOHIPointing__PASecondaryParameters
{
int firstTangent;
IOFixed64 m0; IOFixed64 b0; IOFixed64 y0;
IOFixed64 y1;
IOFixed64 m_root;
IOFixed64 b_root;
};
struct ScrollAxisAccelInfo
{
AbsoluteTime lastEventTime;
void * scaleSegments;
IOItemCount scaleSegCount;
ScaleDataState state;
ScaleConsumeState consumeState;
IOHIPointing__PAParameters primaryParametrics;
IOHIPointing__PASecondaryParameters secondaryParametrics;
SInt32 lastValue;
UInt32 consumeClearThreshold;
UInt32 consumeCountThreshold;
bool isHighResScroll;
bool isParametric;
};
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);
static IOFixed64 OSObjectToIOFixed64(OSObject *in);
static bool PACurvesFillParamsFromDict(OSDictionary *parameters, const IOFixed64 devScale, const IOFixed64 crsrScale, IOHIPointing__PAParameters &outParams);
static bool PACurvesSetupAccelParams (OSArray *parametricCurves, IOFixed64 desired, IOFixed64 devScale, IOFixed64 crsrScale, IOHIPointing__PAParameters &primaryParams, IOHIPointing__PASecondaryParameters &secondaryParams);
static IOFixed64 PACurvesGetAccelerationMultiplier(const IOFixed64 device_speed_mickeys, const IOHIPointing__PAParameters ¶ms, const IOHIPointing__PASecondaryParameters &secondaryParams);
static OSDictionary* PACurvesDebugDictionary(IOHIPointing__PAParameters &primaryParams, IOHIPointing__PASecondaryParameters &secondaryParams);
struct IOHIPointing::ExpansionData
{
UInt32 scrollType;
ScrollAccelInfo * scrollWheelInfo;
ScrollAccelInfo * scrollPointerInfo;
IOHIPointing__PAParameters *paraAccelParams;
IOHIPointing__PASecondaryParameters *paraAccelSecondaryParams;
IOFixed scrollFixedDeltaAxis1;
IOFixed scrollFixedDeltaAxis2;
IOFixed scrollFixedDeltaAxis3;
SInt32 scrollPointDeltaAxis1;
SInt32 scrollPointDeltaAxis2;
SInt32 scrollPointDeltaAxis3;
UInt32 scrollButtonMask;
IOHIDPointingDevice * hidPointingNub;
IOService * openClient;
UInt32 accelerateMode;
UInt32 scrollZoomMask;
bool isSeized;
bool lastScrollWasZoom;
bool scrollOff;
bool scrollResolutionWarningComplete;
};
#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)
{
if (!super::start(provider)) return false;
if (!getProperty(kIOHIDPointerAccelerationTypeKey))
setProperty(kIOHIDPointerAccelerationTypeKey, kIOHIDMouseAccelerationType);
if (!getProperty(kIOHIDScrollAccelerationTypeKey))
setProperty(kIOHIDScrollAccelerationTypeKey, kIOHIDMouseScrollAccelerationKey);
if (!getProperty(kIOHIDDisallowRemappingOfPrimaryClickKey))
if (provider->getProperty(kIOHIDDisallowRemappingOfPrimaryClickKey))
setProperty(kIOHIDDisallowRemappingOfPrimaryClickKey, provider->getProperty(kIOHIDDisallowRemappingOfPrimaryClickKey));
if (buttonCount() > 1)
{
setProperty(kIOHIDPointerButtonCountKey, buttonCount(), 32);
}
OSNumber * number = (OSNumber*)copyProperty(kIOHIDScrollMouseButtonKey);
if (OSDynamicCast(OSNumber, number))
{
UInt32 value = number->unsigned32BitValue();
if (!value)
_scrollButtonMask = 0;
else
_scrollButtonMask = (1 << (value-1));
}
OSSafeReleaseNULL(number);
_hidPointingNub = IOHIDPointingDevice::newPointingDeviceAndStart(this, buttonCount(), resolution() >> 16);
registerService(kIOServiceAsynchronous);
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 ( _paraAccelParams )
{
IOFree(_paraAccelParams, sizeof(IOHIPointing__PAParameters));
_paraAccelParams = 0;
}
if ( _paraAccelSecondaryParams )
{
IOFree(_paraAccelSecondaryParams, sizeof(IOHIPointing__PASecondaryParameters));
_paraAccelSecondaryParams = 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 __unused,
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;
int avgIndex = 0;
IOFixed avgCount = 0;
IOFixed avgAxis = 0;
IOFixed timeDeltaMS = 0;
IOFixed avgTimeDeltaMS = 0;
UInt64 currentTimeNSLL = 0;
UInt64 lastEventTimeNSLL = 0;
UInt64 timeDeltaMSLL = 0;
if ( ! (scaleInfo && ( scaleInfo->scaleSegments || scaleInfo->isParametric) ) )
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 = SCROLL_CLEAR_THRESHOLD_MS_LL;
}
timeDeltaMS = ((UInt32) timeDeltaMSLL) * kIOFixedOne;
scaleInfo->state.deltaTime[scaleInfo->state.deltaIndex] = timeDeltaMS;
scaleInfo->state.deltaAxis[scaleInfo->state.deltaIndex] = absAxis;
for (int index=0; index < SCROLL_TIME_DELTA_COUNT; index++)
{
avgIndex = (scaleInfo->state.deltaIndex + SCROLL_TIME_DELTA_COUNT - index) % SCROLL_TIME_DELTA_COUNT;
avgAxis += scaleInfo->state.deltaAxis[avgIndex];
avgCount ++;
if ((scaleInfo->state.deltaTime[avgIndex] <= 0) ||
(scaleInfo->state.deltaTime[avgIndex] >= SCROLL_EVENT_THRESHOLD_MS)) {
avgTimeDeltaMS += SCROLL_EVENT_THRESHOLD_MS;
break;
}
avgTimeDeltaMS += scaleInfo->state.deltaTime[avgIndex];
if (avgTimeDeltaMS >= (SCROLL_CLEAR_THRESHOLD_MS_LL * kIOFixedOne)) {
break;
}
}
scaleInfo->state.deltaIndex = (scaleInfo->state.deltaIndex + 1) % SCROLL_TIME_DELTA_COUNT;
avgAxis = (avgCount) ? (avgAxis / avgCount) : 0;
avgTimeDeltaMS = (avgCount) ? (avgTimeDeltaMS / avgCount) : 0;
avgTimeDeltaMS = IOFixedMultiply(avgTimeDeltaMS, rateMultiplier);
if (avgTimeDeltaMS > SCROLL_EVENT_THRESHOLD_MS) {
avgTimeDeltaMS = SCROLL_EVENT_THRESHOLD_MS;
}
else if (avgTimeDeltaMS < kIOFixedOne) {
avgTimeDeltaMS = kIOFixedOne;
}
IOFixed64 scrollMultiplier;
IOFixed64 timedDelta = IOFixed64::withFixed(avgTimeDeltaMS);
IOFixed64 axisValue = IOFixed64::withFixed(*axisp);
IOFixed64 minimumMultiplier = IOFixed64::withFixed(kIOFixedOne >> 4);
scrollMultiplier = IOFixed64::withFixed(SCROLL_MULTIPLIER_A) * timedDelta * timedDelta;
scrollMultiplier -= IOFixed64::withFixed(SCROLL_MULTIPLIER_B) * timedDelta;
scrollMultiplier += IOFixed64::withFixed(SCROLL_MULTIPLIER_C);
scrollMultiplier *= IOFixed64::withFixed(rateMultiplier);
scrollMultiplier *= IOFixed64::withFixed(avgAxis);
if (scrollMultiplier < minimumMultiplier) {
scrollMultiplier = minimumMultiplier;
}
if (scaleInfo->isParametric) {
scrollMultiplier = PACurvesGetAccelerationMultiplier(scrollMultiplier, scaleInfo->primaryParametrics, scaleInfo->secondaryParametrics);
}
else {
CursorDeviceSegment *segment;
for(segment = (CursorDeviceSegment *) scaleInfo->scaleSegments;
scrollMultiplier > IOFixed64::withFixed(segment->devUnits);
segment++)
{}
if (avgCount > 2) {
scrollMultiplier *= (SInt64)lsqrt(avgCount * 16);
scrollMultiplier /= 4;
}
scrollMultiplier = (IOFixed64::withFixed(segment->intercept) + scrollMultiplier * IOFixed64::withFixed(segment->slope)) / IOFixed64::withFixed(absAxis);
}
axisValue *= scrollMultiplier;
*axisp = axisValue.asFixed();
}
void IOHIPointing::setPointingMode(UInt32 accelerateMode)
{
_accelerateMode = accelerateMode;
_convertAbsoluteToRelative = ((accelerateMode & kAbsoluteConvertMouse) != 0);
}
UInt32 IOHIPointing::getPointingMode()
{
return _accelerateMode;
}
void IOHIPointing::setScrollType(UInt32 scrollType)
{
_scrollType = scrollType;
}
UInt32 IOHIPointing::getScrollType()
{
return _scrollType;
}
void IOHIPointing::scalePointer(int * dxp, int * dyp)
{
if (_paraAccelParams && _paraAccelSecondaryParams) {
IOFixed64 deltaX;
IOFixed64 deltaY;
IOFixed64 fractX;
IOFixed64 fractY;
IOFixed64 mag;
deltaX.fromIntFloor(*dxp);
deltaY.fromIntFloor(*dyp);
fractX.fromFixed(_fractX);
fractY.fromFixed(_fractY);
mag.fromIntFloor(llsqrt((deltaX * deltaX + deltaY * deltaY).as64()));
IOFixed64 mult = PACurvesGetAccelerationMultiplier(mag, *_paraAccelParams, *_paraAccelSecondaryParams);
deltaX *= mult;
deltaY *= mult;
deltaX += fractX;
deltaY += fractY;
*dxp = deltaX.as32();
*dyp = deltaY.as32();
_fractX = deltaX.asFixed();
_fractY = deltaY.asFixed();
if( deltaX < 0LL )
_fractX |= 0xffff0000;
else
_fractX &= 0x0000ffff;
if( deltaY < 0LL)
_fractY |= 0xffff0000;
else
_fractY &= 0x0000ffff;
}
else {
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 )
{
OSArray *parametricAccelerationCurves = (OSArray*)copyProperty(kHIDTrackingAccelParametricCurvesKey, gIOServicePlane);
IOFixed devScale = IOFixedDivide( resolution(), FRAME_RATE );
IOFixed crsrScale = IOFixedDivide( SCREEN_RESOLUTION, FRAME_RATE );
bool useParametric = false;
if (!OSDynamicCast( OSArray, parametricAccelerationCurves)) {
OSSafeReleaseNULL(parametricAccelerationCurves);
parametricAccelerationCurves = (OSArray*)copyProperty(kHIDAccelParametricCurvesKey, gIOServicePlane);
}
if (OSDynamicCast( OSArray, parametricAccelerationCurves )) {
if ( !_paraAccelParams )
{
_paraAccelParams = (IOHIPointing__PAParameters*)IOMalloc(sizeof(IOHIPointing__PAParameters));
}
if ( !_paraAccelSecondaryParams )
{
_paraAccelSecondaryParams = (IOHIPointing__PASecondaryParameters*)IOMalloc(sizeof(IOHIPointing__PASecondaryParameters));
}
if (_paraAccelParams && _paraAccelSecondaryParams) {
IOFixed64 desired64;
IOFixed64 devScale64;
IOFixed64 crsrScale64;
useParametric = PACurvesSetupAccelParams(parametricAccelerationCurves,
desired64.fromFixed(desired),
devScale64.fromFixed(devScale),
crsrScale64.fromFixed(crsrScale),
*_paraAccelParams,
*_paraAccelSecondaryParams);
if (useParametric && getProperty(kHIDAccelParametricCurvesDebugKey, gIOServicePlane)) {
OSDictionary *debugInfo = PACurvesDebugDictionary(*_paraAccelParams, *_paraAccelSecondaryParams);
if (debugInfo) {
setProperty(kHIDAccelParametricCurvesDebugKey, debugInfo);
debugInfo->release();
}
}
}
}
OSSafeReleaseNULL(parametricAccelerationCurves);
if (!useParametric) {
OSData * table = copyAccelerationTable();
if (_paraAccelParams)
IOFree(_paraAccelParams, sizeof(IOHIPointing__PAParameters));
if (_paraAccelSecondaryParams)
IOFree(_paraAccelSecondaryParams, sizeof(IOHIPointing__PASecondaryParameters));
_paraAccelParams = NULL;
_paraAccelSecondaryParams = NULL;
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 reportRate = scrollReportRate();
OSData * accelTable = NULL;
UInt32 type = 0;
_scrollWheelInfo->rateMultiplier = IOFixedDivide(reportRate, FRAME_RATE);
_scrollPointerInfo->rateMultiplier = IOFixedDivide(reportRate, FRAME_RATE);
if (desired < 0) {
setPointingMode(getPointingMode() | kAccelNoScrollAcceleration);
setProperty(kHIDScrollAccelParametricCurvesDebugKey, OSSymbol::withCString("desired < 0"));
}
else {
setPointingMode(getPointingMode() & ~kAccelNoScrollAcceleration);
OSArray *parametricAccelerationCurves = (OSArray*)copyProperty(kHIDScrollAccelParametricCurvesKey, gIOServicePlane);
#ifdef SWITCH_ALL_SCROLL_ACCELERATION_TO_PARAMETRICS // {
#warning SWITCH_ALL_SCROLL_ACCELERATION_TO_PARAMETRICS is defined
if (!OSDynamicCast( OSArray, parametricAccelerationCurves)) {
OSSafeReleaseNULL(parametricAccelerationCurves);
parametricAccelerationCurves = (OSArray*)copyProperty(kHIDAccelParametricCurvesKey, gIOServicePlane);
}
#endif // } SWITCH_ALL_SCROLL_ACCELERATION_TO_PARAMETRICS
OSArray *currentDebugArray = (OSArray *)copyProperty(kHIDScrollAccelParametricCurvesDebugKey);
OSArray *newDebugArray = NULL;
if (OSDynamicCast(OSArray, currentDebugArray)) {
newDebugArray = OSArray::withArray(currentDebugArray);
}
else {
OSSymbol const * base[] = {
OSSymbol::withCString("initted"),
OSSymbol::withCString("initted"),
OSSymbol::withCString("initted") };
newDebugArray = OSArray::withObjects((OSObject const **)base, 3);
}
OSSafeReleaseNULL(currentDebugArray);
for ( type=kAccelTypeY; type<=kAccelTypeZ; type++) {
IOFixed res = scrollResolutionForType(type);
if ( res ) {
_scrollWheelInfo->axis[type].isHighResScroll = res > (SCROLL_DEFAULT_RESOLUTION * 2);
_scrollPointerInfo->axis[type].isHighResScroll = _scrollWheelInfo->axis[type].isHighResScroll;
_scrollWheelInfo->axis[type].consumeClearThreshold = (IOFixedDivide(res, SCROLL_CONSUME_RESOLUTION) >> 16) * 2;
_scrollPointerInfo->axis[type].consumeClearThreshold = _scrollWheelInfo->axis[type].consumeClearThreshold;
_scrollWheelInfo->axis[type].consumeCountThreshold = _scrollWheelInfo->axis[type].consumeClearThreshold * SCROLL_CONSUME_COUNT_MULTIPLIER;
_scrollPointerInfo->axis[type].consumeCountThreshold = _scrollPointerInfo->axis[type].consumeClearThreshold * SCROLL_CONSUME_COUNT_MULTIPLIER;
bzero(&(_scrollWheelInfo->axis[type].state), sizeof(ScaleDataState));
bzero(&(_scrollWheelInfo->axis[type].consumeState), sizeof(ScaleConsumeState));
bzero(&(_scrollPointerInfo->axis[type].state), sizeof(ScaleDataState));
bzero(&(_scrollPointerInfo->axis[type].consumeState), sizeof(ScaleConsumeState));
clock_get_uptime(&(_scrollWheelInfo->axis[type].lastEventTime));
_scrollPointerInfo->axis[type].lastEventTime = _scrollWheelInfo->axis[type].lastEventTime;
if (OSDynamicCast( OSArray, parametricAccelerationCurves ) && reportRate) {
IOFixed64 desired64;
IOFixed64 devScale64;
IOFixed64 scrScale64;
IOFixed64 temp;
desired64.fromFixed(desired);
devScale64.fromFixed(res);
devScale64 /= temp.fromFixed(reportRate);
scrScale64.fromFixed(SCREEN_RESOLUTION);
scrScale64 /= temp.fromFixed(FRAME_RATE);
_scrollWheelInfo->axis[type].isParametric =
PACurvesSetupAccelParams(parametricAccelerationCurves,
desired64,
devScale64,
scrScale64,
_scrollWheelInfo->axis[type].primaryParametrics,
_scrollWheelInfo->axis[type].secondaryParametrics);
if (_scrollWheelInfo->axis[type].isParametric) {
OSDictionary *debugInfo =
PACurvesDebugDictionary(_scrollWheelInfo->axis[type].primaryParametrics,
_scrollWheelInfo->axis[type].secondaryParametrics);
if (debugInfo) {
newDebugArray->replaceObject(type, debugInfo);
debugInfo->release();
}
else {
IOLog("IOHIPointing 0x%llx unable to generate debug info for scroll axis %d\n", getRegistryEntryID(), type);
newDebugArray->replaceObject(type, OSSymbol::withCString("no debug info"));
}
}
else {
IOLog("IOHIPointing 0x%llx unable to generate parametric data for axis %d\n", getRegistryEntryID(), type);
newDebugArray->replaceObject(type, OSSymbol::withCString("not parametric"));
}
}
if (!_scrollWheelInfo->axis[type].isParametric) {
accelTable = copyScrollAccelerationTableForType(type);
devScale = IOFixedDivide( res, reportRate );
scrScale = IOFixedDivide( SCREEN_RESOLUTION, FRAME_RATE );
SetupAcceleration (accelTable, desired, devScale, scrScale, &(_scrollWheelInfo->axis[type].scaleSegments), &(_scrollWheelInfo->axis[type].scaleSegCount));
res = this->resolution();
reportRate = FRAME_RATE;
devScale = IOFixedDivide( res, reportRate );
scrScale = IOFixedDivide( SCREEN_RESOLUTION, FRAME_RATE );
SetupAcceleration (accelTable, desired, devScale, scrScale, &(_scrollPointerInfo->axis[type].scaleSegments), &(_scrollPointerInfo->axis[type].scaleSegCount));
char buff[256] = "";
snprintf(buff, sizeof(buff), "Non Parametric: desired = 0x%08x; devScale = 0x%08x; scrScale = 0x%08x", desired, devScale, scrScale);
OSString *debugInfo = OSString::withCString(buff);
if (debugInfo) {
newDebugArray->replaceObject(type, debugInfo);
debugInfo->release();
}
else {
IOLog("IOHIPointing 0x%llx unable to generate traditional debug info for scroll axis %d\n", getRegistryEntryID(), type);
newDebugArray->replaceObject(type, OSSymbol::withCString("traditional but no debug info"));
}
if (accelTable)
accelTable->release();
}
}
else {
newDebugArray->replaceObject(type, OSSymbol::withCString("no scroll resolution for type"));
}
}
setProperty(kHIDScrollAccelParametricCurvesDebugKey, newDebugArray);
OSSafeReleaseNULL(newDebugArray);
OSSafeReleaseNULL(parametricAccelerationCurves);
}
}
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(kIOServiceAsynchronous); 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) {
bool isModifiedToZoom = ((SPECIALKEYS_MODIFIER_MASK & eventFlags) == _scrollZoomMask);
bool isMomentum = (0 != (_scrollType & kScrollTypeMomentumAny));
if ((isMomentum && _lastScrollWasZoom) || (isModifiedToZoom && !isMomentum)) {
_lastScrollWasZoom = true;
_scrollType |= kScrollTypeZoom;
}
else {
_lastScrollWasZoom = false;
}
}
else {
_lastScrollWasZoom = false;
}
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);
isHighResScroll = info->axis[kAccelTypeX].isHighResScroll ||
info->axis[kAccelTypeY].isHighResScroll ||
info->axis[kAccelTypeZ].isHighResScroll;
if (( _accelerateMode & kAccelScroll ) && !( _accelerateMode & kAccelNoScrollAcceleration ))
{
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) ||
((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 || info->axis[type].isParametric )
{
*(pScrollPointDeltaAxis[type]) = info->axis[type].lastValue << 16;
AccelerateScrollAxis(pScrollPointDeltaAxis[type],
&(info->axis[type]),
ts,
info->rateMultiplier,
directionChange[type] || typeChange);
CONVERT_SCROLL_FIXED_TO_COARSE(pScrollPointDeltaAxis[type][0], pScrollPointDeltaAxis[type][0]);
*(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) >= (SInt32)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, 32)
& 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 = (OSString*)copyProperty(kIOHIDPointerAccelerationTypeKey);
scrollAccelKey = (OSString*)copyProperty(kIOHIDScrollAccelerationTypeKey);
DEVICE_LOCK;
if( (number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDScrollZoomModifierMaskKey))))
{
_scrollZoomMask = number->unsigned32BitValue() & SPECIALKEYS_MODIFIER_MASK;
}
number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDDeviceScrollWithTrackpadKey));
if((number) && OSDynamicCast( OSString, scrollAccelKey ) && scrollAccelKey->isEqualTo(kIOHIDTrackpadScrollAccelerationKey))
{
_scrollOff = number->unsigned32BitValue() == 0;
}
number = OSDynamicCast(OSNumber, dict->getObject(kIOHIDDeviceScrollDisableKey));
if (number) {
_scrollOff = number->unsigned32BitValue() != 0;
}
if ( OSDynamicCast( OSString, 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 );
}
}
OSSafeReleaseNULL(pointerAccelKey);
if( OSDynamicCast( OSString, 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( OSDynamicCast( OSString, scrollAccelKey) ) {
if (!number)
{
number = OSNumber::withNumber(value, 32);
dict->setObject( scrollAccelKey, number );
number->release();
}
else
dict->setObject( scrollAccelKey, number );
}
}
OSSafeReleaseNULL(scrollAccelKey);
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))
{
switch (value) {
case kIOHIDButtonMode_BothLeftClicks:
_buttonMode = NX_OneButton;
break;
case kIOHIDButtonMode_EnableRightClick:
_buttonMode = NX_RightButton;
break;
case kIOHIDButtonMode_ReverseLeftRightClicks:
_buttonMode = (getProperty(kIOHIDDisallowRemappingOfPrimaryClickKey) == kOSBooleanTrue) ? _buttonMode : NX_LeftButton;
break;
default:
_buttonMode = (getProperty(kIOHIDDisallowRemappingOfPrimaryClickKey) == kOSBooleanTrue) ? _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 = (OSNumber*)copyProperty(kIOHIDPointerResolutionKey);
IOFixed result = 100 << 16;
if ( OSDynamicCast(OSNumber, number) )
result = number->unsigned32BitValue();
OSSafeReleaseNULL(number);
return result;
}
IOFixed IOHIPointing::scrollResolutionForType(SInt32 type)
{
IOFixed res = 0;
OSNumber * number = NULL;
const 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 = (OSNumber*)copyProperty(key);
if( !OSDynamicCast( OSNumber, number ) ) {
OSSafeRelease(number);
number = (OSNumber*)copyProperty(kIOHIDScrollResolutionKey);
}
if (!number) {
if (_reserved && !_reserved->scrollResolutionWarningComplete) {
kprintf("IOHIPointing::0x%llx has no %s. This /implies/ no scroll acceleration.\n",
getRegistryEntryID(),
kIOHIDScrollResolutionKey);
_reserved->scrollResolutionWarningComplete = true;
}
}
if( OSDynamicCast( OSNumber, number ) )
res = number->unsigned32BitValue();
OSSafeRelease(number);
return( res );
}
IOFixed IOHIPointing::scrollReportRate()
{
IOFixed result = FRAME_RATE;
OSNumber *number = (OSNumber*)copyProperty( kIOHIDScrollReportRateKey );
if (OSDynamicCast( OSNumber, number ))
if (number->unsigned32BitValue())
result = number->unsigned32BitValue();
OSSafeRelease(number);
if (result == 0)
result = FRAME_RATE;
return result;
}
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 = (OSData*)copyProperty( kIOHIDPointerAccelerationTableKey );
if (!OSDynamicCast( OSData, data ))
OSSafeReleaseNULL(data);
if (!data)
data = OSData::withBytesNoCopy( (void *) accl, sizeof( accl ) );
return( data );
}
OSData * IOHIPointing::copyScrollAccelerationTable()
{
return( copyScrollAccelerationTableForType() );
}
OSData * IOHIPointing::copyScrollAccelerationTableForType(SInt32 type)
{
OSData * data = NULL;
const char *key = NULL;
switch ( type ) {
case kAccelTypeY:
key = kIOHIDScrollAccelerationTableYKey;
break;
case kAccelTypeX:
key = kIOHIDScrollAccelerationTableXKey;
break;
case kAccelTypeZ:
key = kIOHIDScrollAccelerationTableZKey;
break;
}
if ( key )
data = (OSData*)copyProperty( key );
if ( !OSDynamicCast( OSData, data ) ) {
OSSafeRelease(data);
data = (OSData*)copyProperty( kIOHIDScrollAccelerationTableKey );
if (data && !OSDynamicCast( OSData, data )) {
data->release();
data = NULL;
}
}
if ( !data )
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;
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;
}
IOFixed64 OSObjectToIOFixed64(OSObject *in)
{
OSNumber *num = OSDynamicCast(OSNumber, in);
IOFixed64 result;
if (num) {
result.fromFixed(num->unsigned32BitValue());
}
return result;
}
bool
PACurvesFillParamsFromDict(OSDictionary *parameters,
const IOFixed64 devScale,
const IOFixed64 crsrScale,
IOHIPointing__PAParameters &outParams)
{
require(parameters, exit_early);
outParams.deviceMickysDivider = devScale;
outParams.cursorSpeedMultiplier = crsrScale;
outParams.accelIndex = OSObjectToIOFixed64(parameters->getObject(kHIDAccelIndexKey));
outParams.gain[0] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelGainLinearKey));
outParams.gain[1] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelGainParabolicKey));
outParams.gain[2] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelGainCubicKey));
outParams.gain[3] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelGainQuarticKey));
outParams.tangent[0] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelTangentSpeedLinearKey));
outParams.tangent[1] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelTangentSpeedParabolicRootKey));
return ((outParams.gain[0] != 0LL) ||
(outParams.gain[1] != 0LL) ||
(outParams.gain[2] != 0LL) ||
(outParams.gain[3] != 0LL));
exit_early:
return false;
}
bool
PACurvesSetupAccelParams (OSArray *parametricCurves,
IOFixed64 desired,
IOFixed64 devScale,
IOFixed64 crsrScale,
IOHIPointing__PAParameters &primaryParams,
IOHIPointing__PASecondaryParameters &secondaryParams)
{
bool success = false;
OSCollectionIterator *itr = NULL;
OSDictionary *dict = NULL;
IOHIPointing__PAParameters high_curve_params;
IOHIPointing__PAParameters low_curve_params;
require(parametricCurves, exit_early);
require(crsrScale > 0LL, exit_early);
require(devScale > 0LL, exit_early);
require(desired > 0LL, exit_early);
itr = OSCollectionIterator::withCollection(parametricCurves);
require(itr, exit_early);
while (!success) {
itr->reset();
dict = OSDynamicCast(OSDictionary, itr->getNextObject());
require(PACurvesFillParamsFromDict(dict, devScale, crsrScale, low_curve_params),
exit_early);
while (!success && (NULL != dict)) {
if (!PACurvesFillParamsFromDict(dict, devScale, crsrScale, high_curve_params)) {
break;
}
if (desired <= high_curve_params.accelIndex) {
success = true;
}
else {
low_curve_params = high_curve_params;
}
dict = OSDynamicCast(OSDictionary, itr->getNextObject());
}
require(success || !itr->isValid(), exit_early);
};
if ( high_curve_params.accelIndex > low_curve_params.accelIndex ) {
IOFixed64 ratio = (desired - low_curve_params.accelIndex) / (high_curve_params.accelIndex - low_curve_params.accelIndex);
int index;
primaryParams.deviceMickysDivider = high_curve_params.deviceMickysDivider;
primaryParams.cursorSpeedMultiplier = high_curve_params.cursorSpeedMultiplier;
primaryParams.accelIndex = desired;
for (index = 0; index < 4; index++) {
primaryParams.gain[index] = low_curve_params.gain[index] + (high_curve_params.gain[index] - low_curve_params.gain[index]) * ratio;
if (primaryParams.gain[index] < 0LL)
primaryParams.gain[index].fromFixed(0);
}
for (index = 0; index < 2; index++) {
primaryParams.tangent[index] = low_curve_params.tangent[index] + (high_curve_params.tangent[index] - low_curve_params.tangent[index]) * ratio;
if (primaryParams.tangent[index] < 0LL)
primaryParams.tangent[index].fromFixed(0);
}
}
else {
primaryParams = high_curve_params;
}
success = ((primaryParams.gain[0] != 0LL) ||
(primaryParams.gain[1] != 0LL) ||
(primaryParams.gain[2] != 0LL) ||
(primaryParams.gain[3] != 0LL));
bzero(&secondaryParams, sizeof(secondaryParams));
if ((primaryParams.tangent[1] > 0LL) && (primaryParams.tangent[1] < primaryParams.tangent[0]))
secondaryParams.firstTangent = 1;
if (secondaryParams.firstTangent == 0) {
secondaryParams.y0 = IOQuarticFunction(primaryParams.tangent[0], primaryParams.gain);
secondaryParams.m0 = IOQuarticDerivative(primaryParams.tangent[0], primaryParams.gain);
secondaryParams.b0 = secondaryParams.y0 - secondaryParams.m0 * primaryParams.tangent[0];
secondaryParams.y1 = secondaryParams.m0 * primaryParams.tangent[1] + secondaryParams.b0;
}
else {
secondaryParams.y1 = IOQuarticFunction( primaryParams.tangent[1], primaryParams.gain );
secondaryParams.m0 = IOQuarticDerivative( primaryParams.tangent[1], primaryParams.gain );
}
secondaryParams.m_root = secondaryParams.m0 * secondaryParams.y1 * 2LL;
secondaryParams.b_root = exponent(secondaryParams.y1, 2) - secondaryParams.m_root * primaryParams.tangent[1];
exit_early:
if (itr) {
itr->release();
}
return success;
}
OSDictionary*
PACurvesDebugDictionary(IOHIPointing__PAParameters &primaryParams,
IOHIPointing__PASecondaryParameters &secondaryParams)
{
OSDictionary *result = OSDictionary::withCapacity(20);
require(result, exit_early);
#define ADD_NUMBER_FOR(X) \
do { \
OSNumber *value = OSNumber::withNumber(X.as64(), 64); \
if (value) { \
result->setObject(#X, value); \
value->release(); \
} \
} \
while (0)
ADD_NUMBER_FOR(primaryParams.deviceMickysDivider);
ADD_NUMBER_FOR(primaryParams.cursorSpeedMultiplier);
ADD_NUMBER_FOR(primaryParams.accelIndex);
ADD_NUMBER_FOR(primaryParams.gain[0]);
ADD_NUMBER_FOR(primaryParams.gain[1]);
ADD_NUMBER_FOR(primaryParams.gain[2]);
ADD_NUMBER_FOR(primaryParams.gain[3]);
ADD_NUMBER_FOR(primaryParams.tangent[0]);
ADD_NUMBER_FOR(primaryParams.tangent[1]);
ADD_NUMBER_FOR(secondaryParams.m0);
ADD_NUMBER_FOR(secondaryParams.b0);
ADD_NUMBER_FOR(secondaryParams.y0);
ADD_NUMBER_FOR(secondaryParams.y1);
ADD_NUMBER_FOR(secondaryParams.m_root);
ADD_NUMBER_FOR(secondaryParams.b_root);
#undef ADD_NUMBER_FOR
exit_early:
return result;
}
IOFixed64
PACurvesGetAccelerationMultiplier(const IOFixed64 device_speed_mickeys,
const IOHIPointing__PAParameters ¶ms,
const IOHIPointing__PASecondaryParameters &secondaryParams)
{
IOFixed64 result;
if ((device_speed_mickeys > result) && (params.deviceMickysDivider != result)) {
IOFixed64 standardized_speed = device_speed_mickeys / params.deviceMickysDivider;
IOFixed64 accelerated_speed;
if ((params.tangent[secondaryParams.firstTangent] != 0LL) && (standardized_speed <= params.tangent[secondaryParams.firstTangent])) {
accelerated_speed = IOQuarticFunction(standardized_speed, params.gain);
}
else {
if ((secondaryParams.firstTangent == 0) && (params.tangent[1] != 0LL) && (standardized_speed <= params.tangent[1])) {
accelerated_speed = secondaryParams.m0 * standardized_speed + secondaryParams.b0;
}
else {
accelerated_speed.fromIntFloor(llsqrt(((secondaryParams.m_root * standardized_speed) + secondaryParams.b_root).as64()));
}
}
IOFixed64 accelerated_pixels = accelerated_speed * params.cursorSpeedMultiplier;
result = accelerated_pixels / device_speed_mickeys;
}
else {
result.fromFixed(1);
}
return result;
}
void ScaleAxes (void * scaleSegments, int * axis1p, IOFixed *axis1Fractp, int * axis2p, IOFixed *axis2Fractp)
{
SInt32 dx, dy;
SInt32 mag;
IOFixed scale;
CursorDeviceSegment * segment;
if( !scaleSegments)
return;
dx = (*axis1p) << 16;
dy = (*axis2p) << 16;
mag = (lsqrt(*axis1p * *axis1p + *axis2p * *axis2p)) << 16;
if (mag == 0)
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);
}