38 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 
   39 struct timespec last_setup_poll;
 
   40 static int has_setup = 0;
 
   45 static kern_return_t IOServiceCopyCF(io_registry_entry_t service, CFStringRef 
key, CFTypeRef * 
parameter){
 
   46     kern_return_t   kr = KERN_SUCCESS;
 
   47     CFDictionaryRef paramDict;
 
   48     CFTypeRef       tempParameter = NULL;
 
   50     if( (paramDict = IORegistryEntryCreateCFProperty( service, CFSTR(kIOHIDParametersKey), kCFAllocatorDefault, kNilOptions)))
 
   52         if ( (tempParameter = CFDictionaryGetValue( paramDict, key)) )
 
   53             CFRetain(tempParameter);
 
   59         tempParameter = IORegistryEntryCreateCFProperty( service, key, kCFAllocatorDefault, kNilOptions);
 
   62         kr = kIOReturnBadArgument;
 
   64     *parameter = tempParameter;
 
   69 static kern_return_t IOServiceCopyCFRecursive(io_registry_entry_t service, CFStringRef key, CFTypeRef* parameter){
 
   72     io_iterator_t child_iter;
 
   73     if((res = IORegistryEntryCreateIterator(service, kIOServicePlane, kIORegistryIterateRecursively, &child_iter)) != KERN_SUCCESS)
 
   74         return kIOReturnBadArgument;
 
   76     io_registry_entry_t child_service;
 
   77     while((child_service = IOIteratorNext(child_iter)) != 0){
 
   79         IORegistryEntryGetPath(child_service, kIOServicePlane, path);
 
   80         res = IOServiceCopyCF(child_service, key, parameter);
 
   81         IOObjectRelease(child_service);
 
   83         if(res == KERN_SUCCESS)
 
   86     IOObjectRelease(child_iter);
 
   92 static io_service_t GetService(mach_port_t master, 
const char* name){
 
   95     if((res = IOServiceGetMatchingServices(master, IOServiceMatching(name), &iter)) != KERN_SUCCESS)
 
   97     io_service_t service = IOIteratorNext(iter);
 
   98     IOObjectRelease(iter);
 
  103 static kern_return_t IOPointingCopyCFTypeParameter(CFStringRef key, CFTypeRef * parameter){
 
  105     static mach_port_t master = 0;
 
  107     if(!master && (res = IOMasterPort(bootstrap_port, &master)) != KERN_SUCCESS){
 
  109         return kIOReturnError;
 
  112     static io_service_t hidsystem = 0, hipointing = 0;
 
  114         hidsystem = GetService(master, kIOHIDSystemClass);
 
  116         hipointing = GetService(master, kIOHIPointingClass);
 
  119     CFTypeRef tempParameter = NULL;
 
  121     if(IOServiceCopyCF(hipointing, key, &tempParameter) == KERN_SUCCESS)
 
  122         *parameter = tempParameter;
 
  124     else if(IOServiceCopyCF(hidsystem, key, &tempParameter) == KERN_SUCCESS)
 
  125         *parameter = tempParameter;
 
  127     else if(IOServiceCopyCFRecursive(hipointing, key, &tempParameter) == KERN_SUCCESS)
 
  128         *parameter = tempParameter;
 
  129     else if(IOServiceCopyCFRecursive(hidsystem, key, &tempParameter) == KERN_SUCCESS)
 
  130         *parameter = tempParameter;
 
  134         return kIOReturnBadArgument;
 
  145 #define sc2f(sc)    ((sc) * 65536LL) 
  146 #define f2sc(f)     ((f).value / 65536LL) 
  147 static SInt32 as32(IOFixed64 f) { SInt64 res = f2sc(f); 
if(res > INT_MAX) 
return INT_MAX; 
if(res < INT_MIN) 
return INT_MIN; 
return (SInt32)res; }
 
  148 static bool f_gt_sc(IOFixed64 lhs, SInt64 rhs) { 
return lhs.value > sc2f(rhs); }
 
  149 static bool f_lt(IOFixed64 lhs, IOFixed64 rhs) { 
return lhs.value < rhs.value; }
 
  150 static bool f_gt(IOFixed64 lhs, IOFixed64 rhs) { 
return lhs.value > rhs.value; }
 
  151 static IOFixed64 f_add(IOFixed64 lhs, IOFixed64 rhs) { IOFixed64 r = { lhs.value + rhs.value }; 
return r; }
 
  152 static IOFixed64 f_sub(IOFixed64 lhs, IOFixed64 rhs) { IOFixed64 r = { lhs.value - rhs.value }; 
return r; }
 
  153 static IOFixed64 f_div(IOFixed64 lhs, IOFixed64 rhs) { IOFixed64 r = { lhs.value * 65536LL / rhs.value }; 
return r; }
 
  154 static IOFixed64 f_mul(IOFixed64 lhs, IOFixed64 rhs) { IOFixed64 r = { (lhs.value * rhs.value) / 65536LL }; 
return r; }
 
  155 static IOFixed64 f_mul_sc(IOFixed64 lhs, SInt64 rhs) { IOFixed64 r = { lhs.value * rhs }; 
return r; }
 
  157 static IOFixed64 exponent(
const IOFixed64 original, 
const UInt8 
power)
 
  159     IOFixed64 result = {0};
 
  163         for (i = 1; i < 
power; i++) {
 
  164             result = f_mul(result, original);
 
  170 static UInt32 llsqrt(UInt64 
x)
 
  176     for (i = 0; i < 32; i++) {
 
  178         rem = ((rem << 2) + (x >> 62));
 
  191     return(UInt32)(root >> 1);
 
  194 UInt16 lsqrt(UInt32 x)
 
  200     for (i = 0; i < 16; i++) {
 
  202         rem = ((rem << 2) + (x >> 30));
 
  215     return(UInt16)(root >> 1);
 
  218 static IOFixed64 IOQuarticFunction( 
const IOFixed64 x, 
const IOFixed64 *gains )
 
  221     IOFixed64 function_at_x = f_add(f_mul(x, gains[0]), exponent(f_mul(x, gains[1]), 2));
 
  224     if( gains[2].value != 0LL )
 
  225         function_at_x = f_add(function_at_x, exponent(f_mul(x, gains[2]), 3));
 
  227     if( gains[3].value != 0LL )
 
  228         function_at_x = f_add(function_at_x, exponent(f_mul(x, gains[3]), 4));
 
  230     return function_at_x;
 
  233 static IOFixed64 IOQuarticDerivative( 
const IOFixed64 x, 
const IOFixed64 *gains )
 
  237     IOFixed64 derivative_at_x = f_add(gains[0], f_mul_sc(f_mul(x, exponent(gains[1], 2)), 2LL));
 
  240     if( gains[2].value != 0LL )
 
  241         derivative_at_x = f_add(derivative_at_x, f_mul_sc(f_mul(exponent(x, 2), exponent(gains[2], 3)), 3LL));
 
  243     if( gains[3].value != 0LL )
 
  244         derivative_at_x = f_add(derivative_at_x, f_mul_sc(f_mul(exponent(x, 3), exponent(gains[3], 4)), 4LL));
 
  246     return derivative_at_x;
 
  249 static inline IOFixed IOFixedMultiply(IOFixed a, IOFixed b)
 
  251     return (IOFixed)((((SInt64) a) * ((SInt64) b)) >> 16);
 
  254 static inline IOFixed IOFixedDivide(IOFixed a, IOFixed b)
 
  256     return (IOFixed)((((SInt64) a) << 16) / ((SInt64) b));
 
  259 static IOFixed64 OSObjectToIOFixed64(CFNumberRef 
object){
 
  260     IOFixed64 result = {0};
 
  261     if(
object && CFGetTypeID(
object) == CFNumberGetTypeID())
 
  262         CFNumberGetValue(
object, kCFNumberIntType, &result.value);
 
  268 #define MAX_DEVICE_THRESHOLD        0x7fffffff 
  270 #define FRAME_RATE      (67 << 16) 
  271 #define SCREEN_RESOLUTION   (96 << 16) 
  273 #define kIOFixedOne                     0x10000ULL 
  274 #define SCROLL_DEFAULT_RESOLUTION       (9 * kIOFixedOne) 
  275 #define SCROLL_CONSUME_RESOLUTION       (100 * kIOFixedOne) 
  276 #define SCROLL_CONSUME_COUNT_MULTIPLIER 3 
  277 #define SCROLL_EVENT_THRESHOLD_MS_LL    150ULL 
  278 #define SCROLL_EVENT_THRESHOLD_MS       (SCROLL_EVENT_THRESHOLD_MS_LL * kIOFixedOne) 
  279 #define SCROLL_CLEAR_THRESHOLD_MS_LL    500ULL 
  281 #define SCROLL_MULTIPLIER_RANGE         0x00018000 
  282 #define SCROLL_MULTIPLIER_A             0x00000002  
  283 #define SCROLL_MULTIPLIER_B             0x000003bb  
  284 #define SCROLL_MULTIPLIER_C             0x00018041 
  287 #define SCROLL_WHEEL_TO_PIXEL_SCALE     0x000a0000 
  288 #define SCROLL_PIXEL_TO_WHEEL_SCALE     0x0000199a 
  289 #define SCROLL_TIME_DELTA_COUNT     8 
  291 #define CONVERT_SCROLL_FIXED_TO_FRACTION(fixed, fraction)   \ 
  294     fraction = fixed & 0xffff;                      \ 
  296     fraction = fixed | 0xffff0000;                  \ 
  299 #define CONVERT_SCROLL_FIXED_TO_INTEGER(fixedAxis, integer) \ 
  301     SInt32 tempInt = 0;                                 \ 
  302     if((fixedAxis < 0) && (fixedAxis & 0xffff))         \ 
  303     tempInt = (fixedAxis >> 16) + 1;                \ 
  305     tempInt = (fixedAxis >> 16);                    \ 
  309 #define CONVERT_SCROLL_FIXED_TO_COARSE(fixedAxis, coarse)   \ 
  311     SInt32 tempCoarse = 0;                              \ 
  312     CONVERT_SCROLL_FIXED_TO_INTEGER(fixedAxis, tempCoarse)  \ 
  313     if (!tempCoarse && (fixedAxis & 0xffff))            \ 
  314     tempCoarse = (fixedAxis < 0) ? -1 : 1;          \ 
  315     coarse = tempCoarse;                                \ 
  319     kAccelTypeGlobal = -1,
 
  329     IOFixed64   deviceMickysDivider;
 
  330     IOFixed64   cursorSpeedMultiplier;
 
  331     IOFixed64   accelIndex;
 
  333     IOFixed64   tangent[2];
 
  334 } IOHIPointing__PAParameters;
 
  345 } IOHIPointing__PASecondaryParameters;
 
  347 struct CursorDeviceSegment {
 
  352 typedef struct CursorDeviceSegment CursorDeviceSegment;
 
  354 struct ScaleDataState
 
  357     IOFixed         deltaTime[SCROLL_TIME_DELTA_COUNT];
 
  358     IOFixed         deltaAxis[SCROLL_TIME_DELTA_COUNT];
 
  361 typedef struct ScaleDataState ScaleDataState;
 
  362 struct ScaleConsumeState
 
  365     IOFixed     consumeAccum;
 
  367 typedef struct ScaleConsumeState ScaleConsumeState;
 
  368 struct ScrollAxisAccelInfo
 
  370     struct timespec     lastEventTime;
 
  371     void *              scaleSegments;
 
  372     IOItemCount         scaleSegCount;
 
  373     ScaleDataState      state;
 
  374     ScaleConsumeState   consumeState;
 
  375     IOHIPointing__PAParameters          primaryParametrics;
 
  376     IOHIPointing__PASecondaryParameters secondaryParametrics;
 
  378     UInt32              consumeClearThreshold;
 
  379     UInt32              consumeCountThreshold;
 
  380     bool                isHighResScroll;
 
  383 typedef struct ScrollAxisAccelInfo ScrollAxisAccelInfo;
 
  384 struct ScrollAccelInfo
 
  386     ScrollAxisAccelInfo axis[3];
 
  388     IOFixed             rateMultiplier;
 
  391 typedef struct ScrollAccelInfo ScrollAccelInfo;
 
  395 static IOHIPointing__PAParameters* _paraAccelParams = 0;
 
  396 static IOHIPointing__PASecondaryParameters* _paraAccelSecondaryParams = 0;
 
  398 static IOFixed _scrollFixedDeltaAxis1 = 0, _scrollFixedDeltaAxis2 = 0, _scrollFixedDeltaAxis3 = 0;
 
  399 static SInt32 _scrollPointDeltaAxis1 = 0, _scrollPointDeltaAxis2 = 0, _scrollPointDeltaAxis3 = 0;
 
  401 static void* _scaleSegments = 0;
 
  402 static IOItemCount _scaleSegCount = 0;
 
  403 static IOFixed _acceleration = -1, _fractX = 0, _fractY = 0;
 
  405 static ScrollAccelInfo _scrollWheelInfo;
 
  406 static ScrollAccelInfo _scrollPointerInfo;
 
  410 static IOFixed resolution()
 
  413     IOPointingCopyCFTypeParameter(CFSTR(kIOHIDPointerResolutionKey), (CFTypeRef*)&number);
 
  414     IOFixed result = 100 << 16;
 
  416     if (number && CFGetTypeID(number) == CFNumberGetTypeID())
 
  417         CFNumberGetValue(number, kCFNumberIntType, &result);
 
  418     if(number) CFRelease(number);
 
  423 static IOFixed  scrollReportRate()
 
  425     IOFixed     result = FRAME_RATE;
 
  427     IOPointingCopyCFTypeParameter(CFSTR(kIOHIDScrollReportRateKey), (CFTypeRef*)&number);
 
  429     if (number && CFGetTypeID(number) == CFNumberGetTypeID())
 
  430         CFNumberGetValue(number, kCFNumberIntType, &result);
 
  431     if(number) CFRelease(number);
 
  439 static IOFixed  scrollResolutionForType(SInt32 type)
 
  442     CFNumberRef     number      = NULL;
 
  443     CFStringRef key         = NULL;
 
  447         key = CFSTR(kIOHIDScrollResolutionYKey);
 
  450         key = CFSTR(kIOHIDScrollResolutionXKey);
 
  453         key = CFSTR(kIOHIDScrollResolutionZKey);
 
  456         key = CFSTR(kIOHIDScrollResolutionKey);
 
  460     IOPointingCopyCFTypeParameter(key, (CFTypeRef*)&number);
 
  461     if(number && CFGetTypeID(number) == CFNumberGetTypeID())
 
  462         CFNumberGetValue(number, kCFNumberIntType, &res);
 
  464         if(number) CFRelease(number);
 
  465         IOPointingCopyCFTypeParameter(CFSTR(kIOHIDScrollResolutionKey), (CFTypeRef*)&number);
 
  466         if(number && CFGetTypeID(number) == CFNumberGetTypeID())
 
  467             CFNumberGetValue(number, kCFNumberIntType, &res);
 
  469     if(number) CFRelease(number);
 
  477 PACurvesFillParamsFromDict(CFDictionaryRef parameters,
 
  478                            const IOFixed64 devScale,
 
  479                            const IOFixed64 crsrScale,
 
  480                            IOHIPointing__PAParameters *outParams)
 
  482     require(parameters, exit_early);
 
  483     require(CFGetTypeID(parameters) == CFDictionaryGetTypeID(), exit_early);
 
  485     outParams->deviceMickysDivider = devScale;
 
  486     outParams->cursorSpeedMultiplier = crsrScale;
 
  488     outParams->accelIndex = OSObjectToIOFixed64(CFDictionaryGetValue(parameters, CFSTR(kHIDAccelIndexKey)));
 
  490     outParams->gain[0] = OSObjectToIOFixed64(CFDictionaryGetValue(parameters, CFSTR(kHIDAccelGainLinearKey)));
 
  491     outParams->gain[1] = OSObjectToIOFixed64(CFDictionaryGetValue(parameters, CFSTR(kHIDAccelGainParabolicKey)));
 
  492     outParams->gain[2] = OSObjectToIOFixed64(CFDictionaryGetValue(parameters, CFSTR(kHIDAccelGainCubicKey)));
 
  493     outParams->gain[3] = OSObjectToIOFixed64(CFDictionaryGetValue(parameters, CFSTR(kHIDAccelGainQuarticKey)));
 
  495     outParams->tangent[0] = OSObjectToIOFixed64(CFDictionaryGetValue(parameters, CFSTR(kHIDAccelTangentSpeedLinearKey)));
 
  496     outParams->tangent[1] = OSObjectToIOFixed64(CFDictionaryGetValue(parameters, CFSTR(kHIDAccelTangentSpeedParabolicRootKey)));
 
  498     return ((outParams->gain[0].value != 0LL) ||
 
  499             (outParams->gain[1].value != 0LL) ||
 
  500             (outParams->gain[2].value != 0LL) ||
 
  501             (outParams->gain[3].value != 0LL));
 
  508 PACurvesSetupAccelParams (CFArrayRef parametricCurves,
 
  512                           IOHIPointing__PAParameters *primaryParams,
 
  513                           IOHIPointing__PASecondaryParameters *secondaryParams)
 
  515     bool                    success = 
false;
 
  516     CFDictionaryRef         dict = NULL;
 
  518     IOHIPointing__PAParameters high_curve_params;
 
  519     IOHIPointing__PAParameters low_curve_params;
 
  521     require(parametricCurves, exit_early);
 
  522     require(f_gt_sc(crsrScale, 0LL), exit_early);
 
  523     require(f_gt_sc(devScale, 0LL), exit_early);
 
  524     require(f_gt_sc(desired, 0LL), exit_early);
 
  526     CFIndex itrCount = CFArrayGetCount(parametricCurves);
 
  531         dict = (CFDictionaryRef)CFArrayGetValueAtIndex(parametricCurves, itr++);
 
  532         require(PACurvesFillParamsFromDict(dict, devScale, crsrScale, &low_curve_params),
 
  535         while (!success && (NULL != dict)) {
 
  536             if (!PACurvesFillParamsFromDict(dict, devScale, crsrScale, &high_curve_params)) {
 
  539             if (desired.value <= high_curve_params.accelIndex.value) {
 
  543                 low_curve_params = high_curve_params;
 
  548                 dict = (CFDictionaryRef)CFArrayGetValueAtIndex(parametricCurves, itr++);
 
  551         require(success, exit_early);
 
  554     if ( high_curve_params.accelIndex.value > low_curve_params.accelIndex.value ) {
 
  555         IOFixed64   ratio = f_div(f_sub(desired, low_curve_params.accelIndex), f_sub(high_curve_params.accelIndex, low_curve_params.accelIndex));
 
  558         primaryParams->deviceMickysDivider   = high_curve_params.deviceMickysDivider;
 
  559         primaryParams->cursorSpeedMultiplier = high_curve_params.cursorSpeedMultiplier;
 
  560         primaryParams->accelIndex            = desired;
 
  562         for (index = 0; index < 4; index++) {
 
  563             primaryParams->gain[index] = f_add(low_curve_params.gain[index], f_mul(f_sub(high_curve_params.gain[index], low_curve_params.gain[index]), ratio));
 
  564             if (primaryParams->gain[index].value < 0LL)
 
  565                 primaryParams->gain[index].value = 0;
 
  567         for (index = 0; index < 2; index++) {
 
  568             primaryParams->tangent[index] = f_add(low_curve_params.tangent[index], f_mul(f_sub(high_curve_params.tangent[index], low_curve_params.tangent[index]), ratio));
 
  569             if (primaryParams->tangent[index].value < 0LL)
 
  570                 primaryParams->tangent[index].value = 0;
 
  574         *primaryParams = high_curve_params;
 
  577     success = ((primaryParams->gain[0].value != 0LL) ||
 
  578             (primaryParams->gain[1].value != 0LL) ||
 
  579             (primaryParams->gain[2].value != 0LL) ||
 
  580             (primaryParams->gain[3].value != 0LL));
 
  583     bzero(secondaryParams, 
sizeof(*secondaryParams));
 
  584     if ((primaryParams->tangent[1].value > 0LL) && (primaryParams->tangent[1].value < primaryParams->tangent[0].value))
 
  585         secondaryParams->firstTangent = 1;
 
  587     if (secondaryParams->firstTangent == 0) {
 
  588         secondaryParams->y0 = IOQuarticFunction(primaryParams->tangent[0], primaryParams->gain);
 
  589         secondaryParams->m0 = IOQuarticDerivative(primaryParams->tangent[0], primaryParams->gain);
 
  590         secondaryParams->b0 = f_sub(secondaryParams->y0, f_mul(secondaryParams->m0, primaryParams->tangent[0]));
 
  591         secondaryParams->y1 = f_add(f_mul(secondaryParams->m0, primaryParams->tangent[1]), secondaryParams->b0);
 
  594         secondaryParams->y1 = IOQuarticFunction( primaryParams->tangent[1], primaryParams->gain );
 
  595         secondaryParams->m0 = IOQuarticDerivative( primaryParams->tangent[1], primaryParams->gain );
 
  598     secondaryParams->m_root = f_mul_sc(f_mul(secondaryParams->m0, secondaryParams->y1), 2LL);
 
  599     secondaryParams->b_root = f_sub(exponent(secondaryParams->y1, 2), f_mul(secondaryParams->m_root, primaryParams->tangent[1]));
 
  607 PACurvesGetAccelerationMultiplier(
const IOFixed64 device_speed_mickeys,
 
  608                                   const IOHIPointing__PAParameters *params,
 
  609                                   const IOHIPointing__PASecondaryParameters *secondaryParams)
 
  611     IOFixed64 result = {0};
 
  613     if ((device_speed_mickeys.value > result.value) && (params->deviceMickysDivider.value != result.value)) {
 
  614         IOFixed64 standardized_speed = f_div(device_speed_mickeys, params->deviceMickysDivider);
 
  615         IOFixed64 accelerated_speed;
 
  616         if ((params->tangent[secondaryParams->firstTangent].value != 0LL) && (standardized_speed.value <= params->tangent[secondaryParams->firstTangent].value)) {
 
  617             accelerated_speed = IOQuarticFunction(standardized_speed, params->gain);
 
  620             if ((secondaryParams->firstTangent == 0) && (params->tangent[1].value != 0LL) && (standardized_speed.value <= params->tangent[1].value)) {
 
  621                 accelerated_speed = f_add(f_mul(secondaryParams->m0, standardized_speed), secondaryParams->b0);
 
  624                 accelerated_speed.value = sc2f(llsqrt(f2sc(f_add(f_mul(secondaryParams->m_root, standardized_speed), secondaryParams->b_root))));
 
  627         IOFixed64 accelerated_pixels = f_mul(accelerated_speed, params->cursorSpeedMultiplier);
 
  628         result = f_div(accelerated_pixels, device_speed_mickeys);
 
  639 static CFDataRef copyAccelerationTable()
 
  641     static const UInt8 accl[] = {
 
  642         0x00, 0x00, 0x80, 0x00,
 
  643         0x40, 0x32, 0x30, 0x30, 0x00, 0x02, 0x00, 0x00,
 
  644         0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
 
  645         0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
 
  646         0x00, 0x09, 0x00, 0x00, 0x71, 0x3B, 0x00, 0x00,
 
  647         0x60, 0x00, 0x00, 0x04, 0x4E, 0xC5, 0x00, 0x10,
 
  648         0x80, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x5F,
 
  649         0x00, 0x00, 0x00, 0x16, 0xEC, 0x4F, 0x00, 0x8B,
 
  650         0x00, 0x00, 0x00, 0x1D, 0x3B, 0x14, 0x00, 0x94,
 
  651         0x80, 0x00, 0x00, 0x22, 0x76, 0x27, 0x00, 0x96,
 
  652         0x00, 0x00, 0x00, 0x24, 0x62, 0x76, 0x00, 0x96,
 
  653         0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x96,
 
  654         0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x96,
 
  659     IOPointingCopyCFTypeParameter(CFSTR(kIOHIDPointerAccelerationTableKey), (CFTypeRef*)&data);
 
  660     if(data && CFGetTypeID(data) != CFDataGetTypeID()){
 
  665         data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, accl, 
sizeof(accl), kCFAllocatorNull);
 
  670 static CFDataRef copyScrollAccelerationTableForType(SInt32 type)
 
  672     CFDataRef    data    = NULL;
 
  673     CFStringRef key     = NULL;
 
  677         key = CFSTR(kIOHIDScrollAccelerationTableYKey);
 
  680         key = CFSTR(kIOHIDScrollAccelerationTableXKey);
 
  683         key = CFSTR(kIOHIDScrollAccelerationTableZKey);
 
  688         IOPointingCopyCFTypeParameter(key, (CFTypeRef*)&data);
 
  690     if ( !data || CFGetTypeID(data) != CFDataGetTypeID()) {
 
  691         if(data) CFRelease(data);
 
  692         IOPointingCopyCFTypeParameter(CFSTR(kIOHIDScrollAccelerationTableKey), (CFTypeRef*)&data);
 
  695     if ( !data || CFGetTypeID(data) != CFDataGetTypeID()) {
 
  696         if(data) CFRelease(data);
 
  697         data = copyAccelerationTable();
 
  709 static SInt32 Interpolate(  SInt32 x1, SInt32 y1,
 
  710                             SInt32 x2, SInt32 y2,
 
  711                             SInt32 x3, SInt32 y3,
 
  712                             SInt32 scale, Boolean lower )
 
  719     slope = (x2 == x1) ? 0 : IOFixedDivide( y2 - y1, x2 - x1 );
 
  720     intercept = y1 - IOFixedMultiply( slope, x1 );
 
  721     resultY = intercept + IOFixedMultiply( slope, x3 );
 
  723         resultY = y3 - IOFixedMultiply( scale, y3 - resultY );
 
  725         resultY = resultY + IOFixedMultiply( scale, y3 - resultY );
 
  730 static bool SetupAcceleration (CFDataRef data, IOFixed desired, IOFixed devScale, IOFixed crsrScale, 
void ** scaleSegments, IOItemCount * scaleSegCount) {
 
  731     const UInt16 *  lowTable = 0;
 
  732     const UInt16 *  highTable;
 
  734     SInt32  x1, y1, x2, y2, x3, y3;
 
  735     SInt32  prevX1, prevY1;
 
  736     SInt32  upperX, upperY;
 
  737     SInt32  lowerX, lowerY;
 
  738     SInt32  lowAccl = 0, lowPoints = 0;
 
  739     SInt32  highAccl, highPoints;
 
  744     SInt32  scaledX1, scaledY1;
 
  745     SInt32  scaledX2, scaledY2;
 
  747     CursorDeviceSegment *   segments;
 
  748     CursorDeviceSegment *   segment;
 
  751     if( !data || !devScale || !crsrScale)
 
  754     if( desired < (IOFixed) 0) {
 
  756         if(*scaleSegments && *scaleSegCount)
 
  757             free( *scaleSegments);
 
  758         *scaleSegments = NULL;
 
  763     highTable = (
const UInt16 *)CFDataGetBytePtr(data);
 
  765     scaledX1 = scaledY1 = 0;
 
  767     scale = OSReadBigInt32((
volatile void *)highTable, 0);
 
  771     if( desired > 0x8000) {
 
  772         desired = IOFixedMultiply( desired - 0x8000,
 
  777         desired = IOFixedMultiply( desired, scale );
 
  781     count = OSReadBigInt16((
volatile void *)(highTable++), 0);
 
  786         highAccl = OSReadBigInt32((
volatile void *)highTable, 0);
 
  788         highPoints = OSReadBigInt16((
volatile void *)(highTable++), 0);
 
  790         if( desired <= highAccl)
 
  795             scale = (highAccl) ? IOFixedDivide( desired, highAccl ) : 0;
 
  800         lowTable    = highTable;
 
  802         lowPoints   = highPoints;
 
  803         highTable   += lowPoints * 4;
 
  809         scale = (highAccl == lowAccl) ? 0 :
 
  810                                         IOFixedDivide((desired - lowAccl), (highAccl - lowAccl));
 
  816         lowTable    = highTable;
 
  821     if( lowPoints > highPoints)
 
  822         segCount = lowPoints;
 
  824         segCount = highPoints;
 
  826     segments = calloc( 
sizeof(CursorDeviceSegment), segCount );
 
  830     x1 = prevX1 = y1 = prevY1 = 0;
 
  832     lowerX = OSReadBigInt32((
volatile void *)lowTable, 0);
 
  834     lowerY = OSReadBigInt32((
volatile void *)lowTable, 0);
 
  836     upperX = OSReadBigInt32((
volatile void *)highTable, 0);
 
  838     upperY = OSReadBigInt32((
volatile void *)highTable, 0);
 
  843         lower = (lowPoints && (!highPoints || (lowerX <= upperX)));
 
  851             if( lowPoints && (--lowPoints)) {
 
  852                 lowerX = OSReadBigInt32((
volatile void *)lowTable, 0);
 
  854                 lowerY = OSReadBigInt32((
volatile void *)lowTable, 0);
 
  863             if( highPoints && (--highPoints)) {
 
  864                 upperX = OSReadBigInt32((
volatile void *)highTable, 0);
 
  866                 upperY = OSReadBigInt32((
volatile void *)highTable, 0);
 
  872             assert( segment < (segments + segCount) );
 
  874             scaledX2 = IOFixedMultiply( devScale,  x3 );
 
  875             scaledY2 = IOFixedMultiply( crsrScale,
 
  876                                             Interpolate( x1, y1, x2, y2, x3, y3,
 
  878             if( lowPoints || highPoints)
 
  879                 segment->devUnits = scaledX2;
 
  881                 segment->devUnits = MAX_DEVICE_THRESHOLD;
 
  883             segment->slope = ((scaledX2 == scaledX1)) ? 0 :
 
  884                                                         IOFixedDivide((scaledY2 - scaledY1), (scaledX2 - scaledX1));
 
  886             segment->intercept = scaledY2
 
  887                     - IOFixedMultiply( segment->slope, scaledX2 );
 
  895         if( lowPoints && highPoints) {
 
  896             if( lowerX > upperX) {
 
  915     } 
while( lowPoints || highPoints );
 
  917     if( *scaleSegCount && *scaleSegments)
 
  918         free( *scaleSegments);
 
  919     *scaleSegCount = segCount;
 
  920     *scaleSegments = (
void *) segments;
 
  927 static void setupForAcceleration(IOFixed desired){
 
  928     CFArrayRef      parametricAccelerationCurves;
 
  929     IOPointingCopyCFTypeParameter(CFSTR(kHIDTrackingAccelParametricCurvesKey), (CFTypeRef*)¶metricAccelerationCurves);
 
  930     IOFixed         devScale    = IOFixedDivide( resolution(), FRAME_RATE );
 
  931     IOFixed         crsrScale   = IOFixedDivide( SCREEN_RESOLUTION, FRAME_RATE );
 
  932     bool            useParametric = 
false;
 
  934     if (!parametricAccelerationCurves || CFGetTypeID(parametricAccelerationCurves) != CFArrayGetTypeID()) {
 
  935         if(parametricAccelerationCurves) CFRelease(parametricAccelerationCurves);
 
  936         IOPointingCopyCFTypeParameter(CFSTR(kHIDAccelParametricCurvesKey), (CFTypeRef*)¶metricAccelerationCurves);
 
  939     if (parametricAccelerationCurves && CFGetTypeID(parametricAccelerationCurves) == CFArrayGetTypeID()) {
 
  940         if ( !_paraAccelParams )
 
  942             _paraAccelParams = (IOHIPointing__PAParameters*)malloc(
sizeof(IOHIPointing__PAParameters));
 
  944         if ( !_paraAccelSecondaryParams )
 
  946             _paraAccelSecondaryParams = (IOHIPointing__PASecondaryParameters*)malloc(
sizeof(IOHIPointing__PASecondaryParameters));
 
  949         if (_paraAccelParams && _paraAccelSecondaryParams) {
 
  950             IOFixed64 desired64 = {desired};
 
  951             IOFixed64 devScale64 = {devScale};
 
  952             IOFixed64 crsrScale64 = {crsrScale};
 
  954             useParametric = PACurvesSetupAccelParams(parametricAccelerationCurves,
 
  959                                                      _paraAccelSecondaryParams);
 
  962     if(parametricAccelerationCurves) CFRelease(parametricAccelerationCurves);
 
  965     if (!useParametric) {
 
  966         CFDataRef  table         = copyAccelerationTable();
 
  968         if (_paraAccelParams)
 
  969             free(_paraAccelParams);
 
  970         if (_paraAccelSecondaryParams)
 
  971             free(_paraAccelSecondaryParams);
 
  972         _paraAccelParams = NULL;
 
  973         _paraAccelSecondaryParams = NULL;
 
  975         if (SetupAcceleration (table, desired, devScale, crsrScale, &_scaleSegments, &_scaleSegCount))
 
  977             _acceleration = desired;
 
  978             _fractX = _fractY = 0;
 
  980         if(table) CFRelease(table);
 
  984 static void ScaleAxes (
void * scaleSegments, 
int * axis1p, IOFixed *axis1Fractp, 
int * axis2p, IOFixed *axis2Fractp)
 
  989     CursorDeviceSegment *   segment;
 
  994     dx = (*axis1p) << 16;
 
  995     dy = (*axis2p) << 16;
 
  998     mag = (lsqrt(*axis1p * *axis1p + *axis2p * *axis2p)) << 16;
 
 1004         segment = (CursorDeviceSegment *) scaleSegments;
 
 1005         mag > segment->devUnits;
 
 1008     scale = IOFixedDivide(
 
 1009                 segment->intercept + IOFixedMultiply( mag, segment->slope ),
 
 1012     dx = IOFixedMultiply( dx, scale );
 
 1013     dy = IOFixedMultiply( dy, scale );
 
 1019     *axis1p = dx / 65536;
 
 1020     *axis2p = dy / 65536;
 
 1024         *axis1Fractp = dx & 0xffff;
 
 1026         *axis1Fractp = dx | 0xffff0000;
 
 1028         *axis2Fractp = dy & 0xffff;
 
 1030         *axis2Fractp = dy | 0xffff0000;
 
 1033 static void scalePointer(
int* dxp, 
int* dyp)
 
 1042     if (_paraAccelParams && _paraAccelSecondaryParams) {
 
 1043         IOFixed64 deltaX = {sc2f(*dxp)};
 
 1044         IOFixed64 deltaY = {sc2f(*dyp)};
 
 1045         IOFixed64 fractX = {_fractX};
 
 1046         IOFixed64 fractY = {_fractY};
 
 1047         IOFixed64 mag = {sc2f(llsqrt(f2sc(f_add(f_mul(deltaX, deltaX), f_mul(deltaY, deltaY)))))};
 
 1049         IOFixed64 mult = PACurvesGetAccelerationMultiplier(mag, _paraAccelParams, _paraAccelSecondaryParams);
 
 1050         deltaX = f_mul(deltaX, mult);
 
 1051         deltaY = f_mul(deltaY, mult);
 
 1052         deltaX = f_add(deltaX, fractX);
 
 1053         deltaY = f_add(deltaY, fractY);
 
 1055         *dxp = as32(deltaX);
 
 1056         *dyp = as32(deltaY);
 
 1058         _fractX = deltaX.value;
 
 1059         _fractY = deltaY.value;
 
 1062         if( deltaX.value < 0LL )
 
 1063             _fractX |= 0xffff0000;
 
 1065             _fractX &= 0x0000ffff;
 
 1067         if( deltaY.value < 0LL)
 
 1068             _fractY |= 0xffff0000;
 
 1070             _fractY &= 0x0000ffff;
 
 1073         ScaleAxes(_scaleSegments, dxp, &_fractX, dyp, &_fractY);
 
 1077 static void setupScrollForAcceleration( IOFixed desired ){
 
 1078     IOFixed     devScale    = 0;
 
 1079     IOFixed     scrScale    = 0;
 
 1080     IOFixed     reportRate  = scrollReportRate();
 
 1081     CFDataRef   accelTable  = NULL;
 
 1084     _scrollWheelInfo.rateMultiplier    = IOFixedDivide(reportRate, FRAME_RATE);
 
 1085     _scrollPointerInfo.rateMultiplier  = IOFixedDivide(reportRate, FRAME_RATE);
 
 1091         CFArrayRef parametricAccelerationCurves;
 
 1092         IOPointingCopyCFTypeParameter(CFSTR(kHIDScrollAccelParametricCurvesKey), (CFTypeRef*)¶metricAccelerationCurves);
 
 1094         for ( type=kAccelTypeY; type<=kAccelTypeZ; type++) {
 
 1095             IOFixed     res = scrollResolutionForType(type);
 
 1098                 _scrollWheelInfo.axis[type].isHighResScroll    = res > (SCROLL_DEFAULT_RESOLUTION * 2);
 
 1099                 _scrollPointerInfo.axis[type].isHighResScroll  = _scrollWheelInfo.axis[type].isHighResScroll;
 
 1101                 _scrollWheelInfo.axis[type].consumeClearThreshold = (IOFixedDivide(res, SCROLL_CONSUME_RESOLUTION) >> 16) * 2;
 
 1102                 _scrollPointerInfo.axis[type].consumeClearThreshold = _scrollWheelInfo.axis[type].consumeClearThreshold;
 
 1104                 _scrollWheelInfo.axis[type].consumeCountThreshold = _scrollWheelInfo.axis[type].consumeClearThreshold * SCROLL_CONSUME_COUNT_MULTIPLIER;
 
 1105                 _scrollPointerInfo.axis[type].consumeCountThreshold = _scrollPointerInfo.axis[type].consumeClearThreshold * SCROLL_CONSUME_COUNT_MULTIPLIER;
 
 1107                 bzero(&(_scrollWheelInfo.axis[type].state), 
sizeof(ScaleDataState));
 
 1108                 bzero(&(_scrollWheelInfo.axis[type].consumeState), 
sizeof(ScaleConsumeState));
 
 1109                 bzero(&(_scrollPointerInfo.axis[type].state), 
sizeof(ScaleDataState));
 
 1110                 bzero(&(_scrollPointerInfo.axis[type].consumeState), 
sizeof(ScaleConsumeState));
 
 1112                 clock_gettime(CLOCK_MONOTONIC, &(_scrollWheelInfo.axis[type].lastEventTime));
 
 1113                 _scrollPointerInfo.axis[type].lastEventTime = _scrollWheelInfo.axis[type].lastEventTime;
 
 1115                 if (parametricAccelerationCurves && CFGetTypeID(parametricAccelerationCurves) == CFArrayGetTypeID() && reportRate) {
 
 1116                     IOFixed64 desired64 = { desired };
 
 1117                     IOFixed64 devScale64 = { res };
 
 1118                     IOFixed64 scrScale64 = { SCREEN_RESOLUTION };
 
 1120                     devScale64 = f_div(devScale64, *(IOFixed64[]){{ reportRate }});
 
 1122                     scrScale64 = f_div(scrScale64, *(IOFixed64[]){{ FRAME_RATE }});
 
 1124                     _scrollWheelInfo.axis[type].isParametric =
 
 1125                             PACurvesSetupAccelParams(parametricAccelerationCurves,
 
 1129                                                      &_scrollWheelInfo.axis[type].primaryParametrics,
 
 1130                                                      &_scrollWheelInfo.axis[type].secondaryParametrics);
 
 1133                 if (!_scrollWheelInfo.axis[type].isParametric) {
 
 1134                     accelTable = copyScrollAccelerationTableForType(type);
 
 1137                     devScale = IOFixedDivide( res, reportRate );
 
 1138                     scrScale = IOFixedDivide( SCREEN_RESOLUTION, FRAME_RATE );
 
 1140                     SetupAcceleration (accelTable, desired, devScale, scrScale, &(_scrollWheelInfo.axis[type].scaleSegments), &(_scrollWheelInfo.axis[type].scaleSegCount));
 
 1144                     reportRate = FRAME_RATE;
 
 1147                     devScale = IOFixedDivide( res, reportRate );
 
 1148                     scrScale = IOFixedDivide( SCREEN_RESOLUTION, FRAME_RATE );
 
 1150                     SetupAcceleration (accelTable, desired, devScale, scrScale, &(_scrollPointerInfo.axis[type].scaleSegments), &(_scrollPointerInfo.axis[type].scaleSegCount));
 
 1153                         CFRelease(accelTable);
 
 1157         if(parametricAccelerationCurves) CFRelease(parametricAccelerationCurves);
 
 1161 static void AccelerateScrollAxis(   IOFixed *               axisp,
 
 1162                                     ScrollAxisAccelInfo *   scaleInfo,
 
 1163                                     struct timespec*        timeStamp,
 
 1164                                     IOFixed                 rateMultiplier,
 
 1167     IOFixed absAxis             = 0;
 
 1169     IOFixed avgCount            = 0;
 
 1170     IOFixed avgAxis             = 0;
 
 1171     IOFixed timeDeltaMS         = 0;
 
 1172     IOFixed avgTimeDeltaMS      = 0;
 
 1173     UInt64  currentTimeNSLL     = 0;
 
 1174     UInt64  lastEventTimeNSLL   = 0;
 
 1175     UInt64  timeDeltaMSLL       = 0;
 
 1177     if ( ! (scaleInfo && ( scaleInfo->scaleSegments || scaleInfo->isParametric) ) )
 
 1180     absAxis = abs(*axisp);
 
 1185     currentTimeNSLL = timeStamp->tv_nsec + timeStamp->tv_sec * 1000000000;
 
 1186     lastEventTimeNSLL = scaleInfo->lastEventTime.tv_nsec + scaleInfo->lastEventTime.tv_sec * 1000000000;
 
 1188     scaleInfo->lastEventTime = *timeStamp;
 
 1190     timeDeltaMSLL = (currentTimeNSLL - lastEventTimeNSLL) / 1000000;
 
 1197     if ((timeDeltaMSLL >= SCROLL_CLEAR_THRESHOLD_MS_LL) || clear) {
 
 1198         bzero(&(scaleInfo->state), 
sizeof(ScaleDataState));
 
 1199         timeDeltaMSLL = SCROLL_CLEAR_THRESHOLD_MS_LL;
 
 1202     timeDeltaMS = ((UInt32) timeDeltaMSLL) * kIOFixedOne;
 
 1204     scaleInfo->state.deltaTime[scaleInfo->state.deltaIndex] = timeDeltaMS;
 
 1205     scaleInfo->state.deltaAxis[scaleInfo->state.deltaIndex] = absAxis;
 
 1210     for (
int index=0; index < SCROLL_TIME_DELTA_COUNT; index++)
 
 1212         avgIndex = (scaleInfo->state.deltaIndex + SCROLL_TIME_DELTA_COUNT - index) % SCROLL_TIME_DELTA_COUNT;
 
 1213         avgAxis         += scaleInfo->state.deltaAxis[avgIndex];
 
 1216         if ((scaleInfo->state.deltaTime[avgIndex] <= 0) ||
 
 1217                 (scaleInfo->state.deltaTime[avgIndex] >= SCROLL_EVENT_THRESHOLD_MS)) {
 
 1219             avgTimeDeltaMS += SCROLL_EVENT_THRESHOLD_MS;
 
 1223         avgTimeDeltaMS  += scaleInfo->state.deltaTime[avgIndex];
 
 1225         if (avgTimeDeltaMS >= (SCROLL_CLEAR_THRESHOLD_MS_LL * kIOFixedOne)) {
 
 1232     scaleInfo->state.deltaIndex = (scaleInfo->state.deltaIndex + 1) % SCROLL_TIME_DELTA_COUNT;
 
 1234     avgAxis         = (avgCount) ? (avgAxis / avgCount) : 0;
 
 1235     avgTimeDeltaMS  = (avgCount) ? (avgTimeDeltaMS / avgCount) : 0;
 
 1236     avgTimeDeltaMS  = IOFixedMultiply(avgTimeDeltaMS, rateMultiplier);
 
 1237     if (avgTimeDeltaMS > SCROLL_EVENT_THRESHOLD_MS) {
 
 1238         avgTimeDeltaMS = SCROLL_EVENT_THRESHOLD_MS;
 
 1240     else if (avgTimeDeltaMS < kIOFixedOne) {
 
 1242         avgTimeDeltaMS = kIOFixedOne;
 
 1263     IOFixed64           scrollMultiplier;
 
 1264     IOFixed64           timedDelta = { avgTimeDeltaMS };
 
 1265     IOFixed64           axisValue = { *axisp };
 
 1266     IOFixed64           minimumMultiplier = { kIOFixedOne >> 4 };
 
 1268     scrollMultiplier    = f_mul(f_mul(*(IOFixed64[]){ { SCROLL_MULTIPLIER_A } }, timedDelta), timedDelta);
 
 1269     scrollMultiplier = f_sub(scrollMultiplier,     f_mul(*(IOFixed64[]){ { SCROLL_MULTIPLIER_B } }, timedDelta));
 
 1270     scrollMultiplier = f_add(scrollMultiplier,     *(IOFixed64[]){ { SCROLL_MULTIPLIER_C } });
 
 1271     scrollMultiplier = f_mul(scrollMultiplier,     *(IOFixed64[]){ { rateMultiplier } });
 
 1272     scrollMultiplier = f_mul(scrollMultiplier,     *(IOFixed64[]){ { avgAxis } });
 
 1273     if (f_lt(scrollMultiplier, minimumMultiplier)) {
 
 1274         scrollMultiplier = minimumMultiplier;
 
 1277     if (scaleInfo->isParametric) {
 
 1278         scrollMultiplier = PACurvesGetAccelerationMultiplier(scrollMultiplier, &scaleInfo->primaryParametrics, &scaleInfo->secondaryParametrics);
 
 1281         CursorDeviceSegment *segment;
 
 1284         for(segment = (CursorDeviceSegment *) scaleInfo->scaleSegments;
 
 1285             f_gt(scrollMultiplier, *(IOFixed64[]){ { segment->devUnits } });
 
 1291             scrollMultiplier = f_mul(scrollMultiplier, *(IOFixed64[]){ { sc2f((SInt64)lsqrt(avgCount * 16)) } });
 
 1292             scrollMultiplier = f_div(scrollMultiplier, *(IOFixed64[]){ { sc2f(4) } });
 
 1295         scrollMultiplier = f_add(*(IOFixed64[]){ { segment->intercept } }, f_div(f_mul(scrollMultiplier, *(IOFixed64[]){ { segment->slope } }), *(IOFixed64[]){ { absAxis } } ));
 
 1297     axisValue = f_mul(axisValue, scrollMultiplier);
 
 1298     *axisp = axisValue.value;
 
 1301 static void scaleWheel(
int* deltaAxis1, SInt32* fixedDeltaAxis1, SInt32* pointDeltaAxis1, 
struct timespec ts){
 
 1302     int deltaAxis2 = 0, deltaAxis3 = 0;
 
 1304     bool negative = (*deltaAxis1 < 0);
 
 1305     _scrollFixedDeltaAxis1 = *deltaAxis1 * SCROLL_DEFAULT_RESOLUTION;
 
 1307     CONVERT_SCROLL_FIXED_TO_COARSE(IOFixedMultiply(_scrollFixedDeltaAxis1, SCROLL_WHEEL_TO_PIXEL_SCALE), _scrollPointDeltaAxis1);
 
 1309     bool            directionChange[3]          = {0,0,0};
 
 1310     bool            typeChange                  = 
FALSE;
 
 1311     SInt32*         pDeltaAxis[3]               = {deltaAxis1, &deltaAxis2, &deltaAxis3};
 
 1312     SInt32*         pScrollFixedDeltaAxis[3]    = {&_scrollFixedDeltaAxis1, &_scrollFixedDeltaAxis2, &_scrollFixedDeltaAxis3};
 
 1313     IOFixed*        pScrollPointDeltaAxis[3]    = {&_scrollPointDeltaAxis1, &_scrollPointDeltaAxis2, &_scrollPointDeltaAxis3};
 
 1315     for (UInt32 type=kAccelTypeY; type<=kAccelTypeZ; type++ ) {
 
 1316         directionChange[type]       = ((_scrollWheelInfo.axis[type].lastValue == 0) ||
 
 1317                                        ((_scrollWheelInfo.axis[type].lastValue < 0) && (*(pDeltaAxis[type]) > 0)) ||
 
 1318                                        ((_scrollWheelInfo.axis[type].lastValue > 0) && (*(pDeltaAxis[type]) < 0)));
 
 1319         _scrollWheelInfo.axis[type].lastValue  = *(pDeltaAxis[type]);
 
 1321         if ( _scrollWheelInfo.axis[type].scaleSegments || _scrollWheelInfo.axis[type].isParametric ) {
 
 1323             *(pScrollPointDeltaAxis[type])  = _scrollWheelInfo.axis[type].lastValue << 16;
 
 1325             AccelerateScrollAxis(pScrollPointDeltaAxis[type],
 
 1326                                  &(_scrollWheelInfo.axis[type]),
 
 1328                                  _scrollWheelInfo.rateMultiplier,
 
 1329                                  directionChange[type] || typeChange);
 
 1331             CONVERT_SCROLL_FIXED_TO_COARSE(pScrollPointDeltaAxis[type][0], pScrollPointDeltaAxis[type][0]);
 
 1334             *(pScrollFixedDeltaAxis[type]) = *(pScrollPointDeltaAxis[type]) << 16;
 
 1336             if ( directionChange[type] )
 
 1337                 bzero(&(_scrollWheelInfo.axis[type].consumeState), 
sizeof(ScaleConsumeState));
 
 1344             if ( _scrollWheelInfo.axis[type].consumeCountThreshold )
 
 1346                 _scrollWheelInfo.axis[type].consumeState.consumeAccum += *(pScrollFixedDeltaAxis[type]) + ((*(pScrollFixedDeltaAxis[type])) ? _scrollWheelInfo.axis[type].state.fraction : 0);
 
 1347                 _scrollWheelInfo.axis[type].consumeState.consumeCount += abs(_scrollWheelInfo.axis[type].lastValue);
 
 1349                 if (*(pScrollFixedDeltaAxis[type]) &&
 
 1350                         ((abs(_scrollWheelInfo.axis[type].lastValue) >= (SInt32)_scrollWheelInfo.axis[type].consumeClearThreshold) ||
 
 1351                          (_scrollWheelInfo.axis[type].consumeState.consumeCount >= _scrollWheelInfo.axis[type].consumeCountThreshold)))
 
 1353                     *(pScrollFixedDeltaAxis[type]) = _scrollWheelInfo.axis[type].consumeState.consumeAccum;
 
 1354                     _scrollWheelInfo.axis[type].consumeState.consumeAccum = 0;
 
 1355                     _scrollWheelInfo.axis[type].consumeState.consumeCount = 0;
 
 1359                     *(pScrollFixedDeltaAxis[type]) = 0;
 
 1363             *(pScrollFixedDeltaAxis[type]) = IOFixedMultiply(*(pScrollFixedDeltaAxis[type]), SCROLL_PIXEL_TO_WHEEL_SCALE);
 
 1366             CONVERT_SCROLL_FIXED_TO_COARSE(*(pScrollFixedDeltaAxis[type]), *(pDeltaAxis[type]));
 
 1369     *fixedDeltaAxis1 = _scrollFixedDeltaAxis1;
 
 1370     *pointDeltaAxis1 = _scrollPointDeltaAxis1;
 
 1372     if(negative != (*deltaAxis1 < 0))
 
 1373         *deltaAxis1 = -*deltaAxis1;
 
 1374     if(negative != (*fixedDeltaAxis1 < 0))
 
 1375         *fixedDeltaAxis1 = -*fixedDeltaAxis1;
 
 1376     if(negative != (*pointDeltaAxis1 < 0))
 
 1377         *pointDeltaAxis1 = -*pointDeltaAxis1;
 
 1382 static uint get_desired(CFStringRef type_key, CFStringRef fallback_key){
 
 1384     CFTypeRef number = 0;
 
 1385     CFTypeRef accelKey = 0;
 
 1386     if(IOPointingCopyCFTypeParameter(type_key, &accelKey) == kIOReturnSuccess){
 
 1387         if(CFGetTypeID(accelKey) == CFStringGetTypeID())
 
 1388             IOPointingCopyCFTypeParameter(accelKey, &number);
 
 1389         if(accelKey) CFRelease(accelKey);
 
 1392         IOPointingCopyCFTypeParameter(fallback_key, (CFTypeRef*)&number);
 
 1395     if(CFGetTypeID(number) == CFNumberGetTypeID())
 
 1396         CFNumberGetValue(number, kCFNumberIntType, &res);
 
 1397     else if(CFGetTypeID(number) == CFDataGetTypeID())
 
 1398         CFDataGetBytes(number, CFRangeMake(0, 
sizeof(
int)), (UInt8*)&res);
 
 1403 static void do_setup(io_connect_t event, 
struct timespec now){
 
 1405     struct timespec last = last_setup_poll;
 
 1408         static uint desired_mouse = UINT_MAX, desired_wheel = UINT_MAX;
 
 1409         uint desired = get_desired(CFSTR(kIOHIDPointerAccelerationTypeKey), CFSTR(kIOHIDPointerAccelerationKey));
 
 1411         if(desired != desired_mouse || !has_setup)
 
 1412             setupForAcceleration(desired_mouse = desired);
 
 1413         desired = get_desired(CFSTR(kIOHIDScrollAccelerationTypeKey), CFSTR(kIOHIDScrollAccelerationKey));
 
 1414         if(desired != desired_wheel || !has_setup)
 
 1415             setupScrollForAcceleration(desired_wheel = desired);
 
 1417         last_setup_poll = now;
 
 1423 void mouse_accel(io_connect_t event, 
int* x, 
int* 
y){
 
 1424     pthread_mutex_lock(&mutex);
 
 1425     struct timespec now;
 
 1426     clock_gettime(CLOCK_MONOTONIC, &now);
 
 1427     do_setup(event, now);
 
 1429     pthread_mutex_unlock(&mutex);
 
 1432 void wheel_accel(io_connect_t event, 
int* deltaAxis1, SInt32* fixedDeltaAxis1, SInt32* pointDeltaAxis1){
 
 1433     pthread_mutex_lock(&mutex);
 
 1434     struct timespec now;
 
 1435     clock_gettime(CLOCK_MONOTONIC, &now);
 
 1436     do_setup(event, now);
 
 1437     scaleWheel(deltaAxis1, fixedDeltaAxis1, pointDeltaAxis1, now);
 
 1438     pthread_mutex_unlock(&mutex);
 
#define timespec_gt(left, right)
void timespec_add(struct timespec *timespec, long nanoseconds)