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)