1/* 2 * @APPLE_LICENSE_HEADER_START@ 3 * 4 * Copyright (c) 1999-2009 Apple Computer, Inc. All Rights Reserved. 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 * 17 July 1998 sdouglas Initial creation 25 * 01 April 2002 ryepez added support for scroll acceleration 26 */ 27 28#if 0 29#define DEBUG_ASSERT_COMPONENT_NAME_STRING "IOHIPointing" 30#define DEBUG_ASSERT_PRODUCTION_CODE 0 31#endif 32 33#include <AssertMacros.h> 34#include <IOKit/IOLib.h> 35#include <IOKit/assert.h> 36#include <IOKit/hidsystem/IOHIPointing.h> 37#include <IOKit/pwr_mgt/RootDomain.h> 38#include <libkern/OSByteOrder.h> 39#include "IOHIDParameter.h" 40#include "IOHIDSystem.h" 41#include "IOHIDPointingDevice.h" 42#include "IOHIDevicePrivateKeys.h" 43#include "IOHIDParameter.h" 44#include "IOFixed64.h" 45#include "ev_private.h" 46 47#ifndef abs 48#define abs(_a) ((_a >= 0) ? _a : -_a) 49#endif 50 51#ifndef IOFixedSquared 52#define IOFixedSquared(a) IOFixedMultiply(a, a) 53#endif 54 55#define FRAME_RATE (67 << 16) 56#define SCREEN_RESOLUTION (96 << 16) 57 58#define MAX_DEVICE_THRESHOLD 0x7fffffff 59 60#define kIOFixedOne 0x10000ULL 61#define SCROLL_DEFAULT_RESOLUTION (9 * kIOFixedOne) 62#define SCROLL_CONSUME_RESOLUTION (100 * kIOFixedOne) 63#define SCROLL_CONSUME_COUNT_MULTIPLIER 3 64#define SCROLL_EVENT_THRESHOLD_MS_LL 150ULL 65#define SCROLL_EVENT_THRESHOLD_MS (SCROLL_EVENT_THRESHOLD_MS_LL * kIOFixedOne) 66#define SCROLL_CLEAR_THRESHOLD_MS_LL 500ULL 67 68#define SCROLL_MULTIPLIER_RANGE 0x00018000 69#define SCROLL_MULTIPLIER_A 0x00000002 /*IOFixedDivide(SCROLL_MULTIPLIER_RANGE,SCROLL_EVENT_THRESHOLD_MS*2)*/ 70#define SCROLL_MULTIPLIER_B 0x000003bb /*IOFixedDivide(SCROLL_MULTIPLIER_RANGE*3,(SCROLL_EVENT_THRESHOLD_MS^2)*2)*/ 71#define SCROLL_MULTIPLIER_C 0x00018041 72 73 74#define SCROLL_WHEEL_TO_PIXEL_SCALE 0x000a0000/* IOFixedDivide(SCREEN_RESOLUTION, SCROLL_DEFAULT_RESOLUTION) */ 75#define SCROLL_PIXEL_TO_WHEEL_SCALE 0x0000199a/* IOFixedDivide(SCREEN_RESOLUTION, SCROLL_DEFAULT_RESOLUTION) */ 76 77#define CONVERT_SCROLL_FIXED_TO_FRACTION(fixed, fraction) \ 78{ \ 79 if( fixed >= 0) \ 80 fraction = fixed & 0xffff; \ 81 else \ 82 fraction = fixed | 0xffff0000; \ 83} 84 85#define CONVERT_SCROLL_FIXED_TO_INTEGER(fixedAxis, integer) \ 86{ \ 87 SInt32 tempInt = 0; \ 88 if((fixedAxis < 0) && (fixedAxis & 0xffff)) \ 89 tempInt = (fixedAxis >> 16) + 1; \ 90 else \ 91 tempInt = (fixedAxis >> 16); \ 92 integer = tempInt; \ 93} 94 95#define CONVERT_SCROLL_FIXED_TO_COARSE(fixedAxis, coarse) \ 96{ \ 97 SInt32 tempCoarse = 0; \ 98 CONVERT_SCROLL_FIXED_TO_INTEGER(fixedAxis, tempCoarse) \ 99 if (!tempCoarse && (fixedAxis & 0xffff)) \ 100 tempCoarse = (fixedAxis < 0) ? -1 : 1; \ 101 coarse = tempCoarse; \ 102} 103 104 105#define _scrollButtonMask _reserved->scrollButtonMask 106#define _scrollType _reserved->scrollType 107#define _scrollZoomMask _reserved->scrollZoomMask 108#define _scrollOff _reserved->scrollOff 109#define _lastScrollWasZoom _reserved->lastScrollWasZoom 110 111#define _scrollWheelInfo _reserved->scrollWheelInfo 112#define _scrollPointerInfo _reserved->scrollPointerInfo 113#define _paraAccelParams _reserved->paraAccelParams 114#define _paraAccelSecondaryParams _reserved->paraAccelSecondaryParams 115 116#define _scrollFixedDeltaAxis1 _reserved->scrollFixedDeltaAxis1 117#define _scrollFixedDeltaAxis2 _reserved->scrollFixedDeltaAxis2 118#define _scrollFixedDeltaAxis3 _reserved->scrollFixedDeltaAxis3 119#define _scrollPointDeltaAxis1 _reserved->scrollPointDeltaAxis1 120#define _scrollPointDeltaAxis2 _reserved->scrollPointDeltaAxis2 121#define _scrollPointDeltaAxis3 _reserved->scrollPointDeltaAxis3 122 123#define _hidPointingNub _reserved->hidPointingNub 124#define _isSeized _reserved->isSeized 125#define _openClient _reserved->openClient 126#define _accelerateMode _reserved->accelerateMode 127 128#define DEVICE_LOCK IOLockLock( _deviceLock ) 129#define DEVICE_UNLOCK IOLockUnlock( _deviceLock ) 130 131enum { 132 kAccelTypeGlobal = -1, 133 kAccelTypeY = 0, //delta axis 1 134 kAccelTypeX = 1, //delta axis 2 135 kAccelTypeZ = 2 //delta axis 3 136}; 137 138struct CursorDeviceSegment { 139 SInt32 devUnits; 140 SInt32 slope; 141 SInt32 intercept; 142}; 143typedef struct CursorDeviceSegment CursorDeviceSegment; 144 145#define SCROLL_TIME_DELTA_COUNT 8 146struct ScaleDataState 147{ 148 UInt8 deltaIndex; 149 IOFixed deltaTime[SCROLL_TIME_DELTA_COUNT]; 150 IOFixed deltaAxis[SCROLL_TIME_DELTA_COUNT]; 151 IOFixed fraction; 152}; 153typedef ScaleDataState ScaleDataState; 154 155struct ScaleConsumeState 156{ 157 UInt32 consumeCount; 158 IOFixed consumeAccum; 159}; 160typedef ScaleConsumeState ScaleConsumeState; 161 162struct IOHIPointing__PAParameters 163{ 164 IOFixed64 deviceMickysDivider; 165 IOFixed64 cursorSpeedMultiplier; 166 IOFixed64 accelIndex; 167 IOFixed64 gain[4]; 168 IOFixed64 tangent[2]; 169}; 170 171struct IOHIPointing__PASecondaryParameters 172{ 173 int firstTangent; 174 IOFixed64 m0; // m1 == m0 175 IOFixed64 b0; // no b1 176 IOFixed64 y0; 177 IOFixed64 y1; 178 IOFixed64 m_root; 179 IOFixed64 b_root; 180}; 181 182struct ScrollAxisAccelInfo 183{ 184 AbsoluteTime lastEventTime; 185 void * scaleSegments; 186 IOItemCount scaleSegCount; 187 ScaleDataState state; 188 ScaleConsumeState consumeState; 189 IOHIPointing__PAParameters primaryParametrics; 190 IOHIPointing__PASecondaryParameters secondaryParametrics; 191 SInt32 lastValue; 192 UInt32 consumeClearThreshold; 193 UInt32 consumeCountThreshold; 194 bool isHighResScroll; 195 bool isParametric; 196}; 197typedef ScrollAxisAccelInfo ScrollAxisAccelInfo; 198 199struct ScrollAccelInfo 200{ 201 ScrollAxisAccelInfo axis[3]; 202 203 IOFixed rateMultiplier; 204 UInt32 zoom:1; 205}; 206typedef ScrollAccelInfo ScrollAccelInfo; 207 208static bool SetupAcceleration (OSData * data, IOFixed desired, IOFixed devScale, IOFixed crsrScale, void ** scaleSegments, IOItemCount * scaleSegCount); 209static void ScaleAxes (void * scaleSegments, int * axis1p, IOFixed *axis1Fractp, int * axis2p, IOFixed *axis2Fractp); 210static IOFixed64 OSObjectToIOFixed64(OSObject *in); 211static bool PACurvesFillParamsFromDict(OSDictionary *parameters, const IOFixed64 devScale, const IOFixed64 crsrScale, IOHIPointing__PAParameters &outParams); 212static bool PACurvesSetupAccelParams (OSArray *parametricCurves, IOFixed64 desired, IOFixed64 devScale, IOFixed64 crsrScale, IOHIPointing__PAParameters &primaryParams, IOHIPointing__PASecondaryParameters &secondaryParams); 213static IOFixed64 PACurvesGetAccelerationMultiplier(const IOFixed64 device_speed_mickeys, const IOHIPointing__PAParameters ¶ms, const IOHIPointing__PASecondaryParameters &secondaryParams); 214static OSDictionary* PACurvesDebugDictionary(IOHIPointing__PAParameters &primaryParams, IOHIPointing__PASecondaryParameters &secondaryParams); 215 216 217struct IOHIPointing::ExpansionData 218{ 219 UInt32 scrollType; 220 221 ScrollAccelInfo * scrollWheelInfo; 222 ScrollAccelInfo * scrollPointerInfo; 223 IOHIPointing__PAParameters *paraAccelParams; 224 IOHIPointing__PASecondaryParameters *paraAccelSecondaryParams; 225 226 IOFixed scrollFixedDeltaAxis1; 227 IOFixed scrollFixedDeltaAxis2; 228 IOFixed scrollFixedDeltaAxis3; 229 SInt32 scrollPointDeltaAxis1; 230 SInt32 scrollPointDeltaAxis2; 231 SInt32 scrollPointDeltaAxis3; 232 UInt32 scrollButtonMask; 233 234 // Added to post events to the HID Manager 235 IOHIDPointingDevice * hidPointingNub; 236 IOService * openClient; 237 238 UInt32 accelerateMode; 239 UInt32 scrollZoomMask; 240 bool isSeized; 241 bool lastScrollWasZoom; 242 bool scrollOff; 243 bool scrollResolutionWarningComplete; 244}; 245 246#define super IOHIDevice 247OSDefineMetaClassAndStructors(IOHIPointing, IOHIDevice); 248 249bool IOHIPointing::init(OSDictionary * properties) 250{ 251 if (!super::init(properties)) return false; 252 253 /* 254 * Initialize minimal state. 255 */ 256 257 _reserved = IONew(ExpansionData, 1); 258 259 if (!_reserved) return false; 260 261 bzero(_reserved, sizeof(ExpansionData)); 262 263 // Initialize pointer accel items 264 _scaleSegments = 0; 265 _scaleSegCount = 0; 266 _fractX = 0; 267 _fractY = 0; 268 269 _acceleration = -1; 270 _accelerateMode = ( kAccelScroll | kAccelMouse ); 271 _convertAbsoluteToRelative = false; 272 _contactToMove = false; 273 _hadContact = false; 274 _pressureThresholdToClick = 128; 275 _previousLocation.x = 0; 276 _previousLocation.y = 0; 277 278 _hidPointingNub = 0; 279 280 _isSeized = false; 281 282 // default to right mouse button generating unique events 283 _buttonMode = NX_RightButton; 284 285 _scrollWheelInfo = (ScrollAccelInfo *) IOMalloc(sizeof(ScrollAccelInfo)); 286 if (!_scrollWheelInfo) return false; 287 288 bzero(_scrollWheelInfo, sizeof(ScrollAccelInfo)); 289 290 _scrollPointerInfo = (ScrollAccelInfo *) IOMalloc(sizeof(ScrollAccelInfo)); 291 if (!_scrollPointerInfo) return false; 292 293 bzero(_scrollPointerInfo, sizeof(ScrollAccelInfo)); 294 295 _deviceLock = IOLockAlloc(); 296 if (!_deviceLock) return false; 297 298 return true; 299} 300 301bool IOHIPointing::start(IOService * provider) 302{ 303 if (!super::start(provider)) return false; 304 305 // default acceleration settings 306 if (!getProperty(kIOHIDPointerAccelerationTypeKey)) 307 setProperty(kIOHIDPointerAccelerationTypeKey, kIOHIDMouseAccelerationType); 308 309 if (!getProperty(kIOHIDScrollAccelerationTypeKey)) 310 setProperty(kIOHIDScrollAccelerationTypeKey, kIOHIDMouseScrollAccelerationKey); 311 312 if (!getProperty(kIOHIDDisallowRemappingOfPrimaryClickKey)) 313 if (provider->getProperty(kIOHIDDisallowRemappingOfPrimaryClickKey)) 314 setProperty(kIOHIDDisallowRemappingOfPrimaryClickKey, provider->getProperty(kIOHIDDisallowRemappingOfPrimaryClickKey)); 315 316 /* 317 * RY: Publish a property containing the button Count. This will 318 * will be used to determine whether or not the button 319 * behaviors can be modified. 320 */ 321 if (buttonCount() > 1) 322 { 323 setProperty(kIOHIDPointerButtonCountKey, buttonCount(), 32); 324 } 325 326 OSNumber * number = (OSNumber*)copyProperty(kIOHIDScrollMouseButtonKey); 327 328 if (OSDynamicCast(OSNumber, number)) 329 { 330 UInt32 value = number->unsigned32BitValue(); 331 332 if (!value) 333 _scrollButtonMask = 0; 334 else 335 _scrollButtonMask = (1 << (value-1)); 336 } 337 OSSafeReleaseNULL(number); 338 339 // create a IOHIDPointingDevice to post events to the HID Manager 340 _hidPointingNub = IOHIDPointingDevice::newPointingDeviceAndStart(this, buttonCount(), resolution() >> 16); 341 342 /* 343 * IOHIPointing serves both as a service and a nub (we lead a double 344 * life). Register ourselves as a nub to kick off matching. 345 */ 346 347 registerService(kIOServiceAsynchronous); 348 349 return true; 350} 351 352void IOHIPointing::free() 353// Description: Go Away. Be careful when freeing the lock. 354{ 355 356 if (_deviceLock) 357 { 358 IOLock * lock; 359 360 IOLockLock(_deviceLock); 361 362 lock = _deviceLock; 363 _deviceLock = NULL; 364 365 IOLockUnlock(lock); 366 IOLockFree(lock); 367 } 368 369 if(_scaleSegments && _scaleSegCount) 370 IODelete( _scaleSegments, CursorDeviceSegment, _scaleSegCount ); 371 372 if ( _scrollWheelInfo ) 373 { 374 UInt32 type; 375 for (type=kAccelTypeY; type<=kAccelTypeZ; type++) { 376 if(_scrollWheelInfo->axis[type].scaleSegments && _scrollWheelInfo->axis[type].scaleSegCount) 377 IODelete( _scrollWheelInfo->axis[type].scaleSegments, CursorDeviceSegment, _scrollWheelInfo->axis[type].scaleSegCount ); 378 } 379 380 IOFree(_scrollWheelInfo, sizeof(ScrollAccelInfo)); 381 _scrollWheelInfo = 0; 382 } 383 384 if ( _paraAccelParams ) 385 { 386 IOFree(_paraAccelParams, sizeof(IOHIPointing__PAParameters)); 387 _paraAccelParams = 0; 388 } 389 390 if ( _paraAccelSecondaryParams ) 391 { 392 IOFree(_paraAccelSecondaryParams, sizeof(IOHIPointing__PASecondaryParameters)); 393 _paraAccelSecondaryParams = 0; 394 } 395 396 if ( _scrollPointerInfo ) 397 { 398 UInt32 type; 399 for (type=kAccelTypeY; type<=kAccelTypeZ; type++) { 400 if(_scrollPointerInfo->axis[type].scaleSegments && _scrollPointerInfo->axis[type].scaleSegCount) 401 IODelete( _scrollPointerInfo->axis[type].scaleSegments, CursorDeviceSegment, _scrollPointerInfo->axis[type].scaleSegCount ); 402 } 403 404 IOFree(_scrollPointerInfo, sizeof(ScrollAccelInfo)); 405 _scrollPointerInfo = 0; 406 } 407 408 if ( _hidPointingNub ) 409 { 410 _hidPointingNub->release(); 411 _hidPointingNub = 0; 412 } 413 414 if (_reserved) { 415 IODelete(_reserved, ExpansionData, 1); 416 } 417 418 super::free(); 419} 420 421bool IOHIPointing::open(IOService * client, 422 IOOptionBits options, 423 RelativePointerEventAction rpeAction, 424 AbsolutePointerEventAction apeAction, 425 ScrollWheelEventAction sweAction) 426{ 427 if (client == this) { 428 return super::open(_openClient, options); 429 } 430 431 return open(client, 432 options, 433 0, 434 (RelativePointerEventCallback)rpeAction, 435 (AbsolutePointerEventCallback)apeAction, 436 (ScrollWheelEventCallback)sweAction); 437} 438 439bool IOHIPointing::open(IOService * client, 440 IOOptionBits options, 441 void * refcon __unused, 442 RelativePointerEventCallback rpeCallback, 443 AbsolutePointerEventCallback apeCallback, 444 ScrollWheelEventCallback sweCallback) 445{ 446 if (client == this) return true; 447 448 _openClient = client; 449 450 bool returnValue = open(this, options, 451 (RelativePointerEventAction)_relativePointerEvent, 452 (AbsolutePointerEventAction)_absolutePointerEvent, 453 (ScrollWheelEventAction)_scrollWheelEvent); 454 455 if (!returnValue) 456 return false; 457 458 // Note: client object is already retained by superclass' open() 459 _relativePointerEventTarget = client; 460 _relativePointerEventAction = (RelativePointerEventAction)rpeCallback; 461 _absolutePointerEventTarget = client; 462 _absolutePointerEventAction = (AbsolutePointerEventAction)apeCallback; 463 _scrollWheelEventTarget = client; 464 _scrollWheelEventAction = (ScrollWheelEventAction)sweCallback; 465 466 return true; 467} 468 469void IOHIPointing::close(IOService * client, IOOptionBits) 470{ 471 _relativePointerEventAction = NULL; 472 _relativePointerEventTarget = 0; 473 _absolutePointerEventAction = NULL; 474 _absolutePointerEventTarget = 0; 475 super::close(client); 476} 477 478IOReturn IOHIPointing::message( UInt32 type, IOService * provider, 479 void * argument) 480{ 481 IOReturn ret = kIOReturnSuccess; 482 483 switch(type) 484 { 485 case kIOHIDSystemDeviceSeizeRequestMessage: 486 if (OSDynamicCast(IOHIDDevice, provider)) 487 { 488 _isSeized = (bool)argument; 489 } 490 break; 491 492 default: 493 ret = super::message(type, provider, argument); 494 break; 495 } 496 497 return ret; 498} 499 500IOReturn IOHIPointing::powerStateWillChangeTo( IOPMPowerFlags powerFlags, 501 unsigned long newState, IOService * device ) 502{ 503 return( super::powerStateWillChangeTo( powerFlags, newState, device )); 504} 505 506IOReturn IOHIPointing::powerStateDidChangeTo( IOPMPowerFlags powerFlags, 507 unsigned long newState, IOService * device ) 508{ 509 return( super::powerStateDidChangeTo( powerFlags, newState, device )); 510} 511 512IOHIDKind IOHIPointing::hidKind() 513{ 514 return kHIRelativePointingDevice; 515} 516 517static void AccelerateScrollAxis( IOFixed * axisp, 518 ScrollAxisAccelInfo * scaleInfo, 519 AbsoluteTime timeStamp, 520 IOFixed rateMultiplier, 521 bool clear = false) 522{ 523 IOFixed absAxis = 0; 524 int avgIndex = 0; 525 IOFixed avgCount = 0; 526 IOFixed avgAxis = 0; 527 IOFixed timeDeltaMS = 0; 528 IOFixed avgTimeDeltaMS = 0; 529 UInt64 currentTimeNSLL = 0; 530 UInt64 lastEventTimeNSLL = 0; 531 UInt64 timeDeltaMSLL = 0; 532 533 if ( ! (scaleInfo && ( scaleInfo->scaleSegments || scaleInfo->isParametric) ) ) 534 return; 535 536 absAxis = abs(*axisp); 537 538 if( absAxis == 0 ) 539 return; 540 541 absolutetime_to_nanoseconds(timeStamp, ¤tTimeNSLL); 542 absolutetime_to_nanoseconds(scaleInfo->lastEventTime, &lastEventTimeNSLL); 543 544 scaleInfo->lastEventTime = timeStamp; 545 546 timeDeltaMSLL = (currentTimeNSLL - lastEventTimeNSLL) / 1000000; 547 548 // RY: To compensate for non continual motion, we have added a second 549 // threshold. This whill allow a user with a standard scroll wheel 550 // to continue with acceleration when lifting the finger within a 551 // predetermined time. We should also clear out the last time deltas 552 // if the direction has changed. 553 if ((timeDeltaMSLL >= SCROLL_CLEAR_THRESHOLD_MS_LL) || clear) { 554 bzero(&(scaleInfo->state), sizeof(ScaleDataState)); 555 timeDeltaMSLL = SCROLL_CLEAR_THRESHOLD_MS_LL; 556 } 557 558 timeDeltaMS = ((UInt32) timeDeltaMSLL) * kIOFixedOne; 559 560 scaleInfo->state.deltaTime[scaleInfo->state.deltaIndex] = timeDeltaMS; 561 scaleInfo->state.deltaAxis[scaleInfo->state.deltaIndex] = absAxis; 562 563 // RY: To eliminate jerkyness associated with the scroll acceleration, 564 // we scroll based on the average of the last n events. This has the 565 // effect of make acceleration smoother with accel and decel. 566 for (int index=0; index < SCROLL_TIME_DELTA_COUNT; index++) 567 { 568 avgIndex = (scaleInfo->state.deltaIndex + SCROLL_TIME_DELTA_COUNT - index) % SCROLL_TIME_DELTA_COUNT; 569 avgAxis += scaleInfo->state.deltaAxis[avgIndex]; 570 avgCount ++; 571 572 if ((scaleInfo->state.deltaTime[avgIndex] <= 0) || 573 (scaleInfo->state.deltaTime[avgIndex] >= SCROLL_EVENT_THRESHOLD_MS)) { 574 // the previous event was too long before this one. stop looking. 575 avgTimeDeltaMS += SCROLL_EVENT_THRESHOLD_MS; 576 break; 577 } 578 579 avgTimeDeltaMS += scaleInfo->state.deltaTime[avgIndex]; 580 581 if (avgTimeDeltaMS >= (SCROLL_CLEAR_THRESHOLD_MS_LL * kIOFixedOne)) { 582 // the previous event was too long ago. stop looking. 583 break; 584 } 585 } 586 587 // Bump the next index 588 scaleInfo->state.deltaIndex = (scaleInfo->state.deltaIndex + 1) % SCROLL_TIME_DELTA_COUNT; 589 590 avgAxis = (avgCount) ? (avgAxis / avgCount) : 0; 591 avgTimeDeltaMS = (avgCount) ? (avgTimeDeltaMS / avgCount) : 0; 592 avgTimeDeltaMS = IOFixedMultiply(avgTimeDeltaMS, rateMultiplier); 593 if (avgTimeDeltaMS > SCROLL_EVENT_THRESHOLD_MS) { 594 avgTimeDeltaMS = SCROLL_EVENT_THRESHOLD_MS; 595 } 596 else if (avgTimeDeltaMS < kIOFixedOne) { 597 // anything less than 1 ms is not resonable 598 avgTimeDeltaMS = kIOFixedOne; 599 } 600 601 // RY: Since we want scroll acceleration to work with the 602 // time delta and the accel curves, we have come up with 603 // this approach: 604 // 605 // scrollMultiplier = (SCROLL_MULTIPLIER_A * (avgTimeDeltaMS^2)) + 606 // (SCROLL_MULTIPLIER_B * avgTimeDeltaMS) + 607 // SCROLL_MULTIPLIER_C 608 // 609 // scrollMultiplier *= avgDeviceDelta 610 // 611 // The boost curve follows a quadratic/parabolic curve which 612 // results in a smoother boost. 613 // 614 // The resulting multipler is applied to the average axis 615 // magnitude and then compared against the accleration curve. 616 // 617 // The value acquired from the graph will then be multiplied 618 // to the current axis delta. 619 IOFixed64 scrollMultiplier; 620 IOFixed64 timedDelta = IOFixed64::withFixed(avgTimeDeltaMS); 621 IOFixed64 axisValue = IOFixed64::withFixed(*axisp); 622 IOFixed64 minimumMultiplier = IOFixed64::withFixed(kIOFixedOne >> 4); 623 624 scrollMultiplier = IOFixed64::withFixed(SCROLL_MULTIPLIER_A) * timedDelta * timedDelta; 625 scrollMultiplier -= IOFixed64::withFixed(SCROLL_MULTIPLIER_B) * timedDelta; 626 scrollMultiplier += IOFixed64::withFixed(SCROLL_MULTIPLIER_C); 627 scrollMultiplier *= IOFixed64::withFixed(rateMultiplier); 628 scrollMultiplier *= IOFixed64::withFixed(avgAxis); 629 if (scrollMultiplier < minimumMultiplier) { 630 scrollMultiplier = minimumMultiplier; 631 } 632 633 if (scaleInfo->isParametric) { 634 scrollMultiplier = PACurvesGetAccelerationMultiplier(scrollMultiplier, scaleInfo->primaryParametrics, scaleInfo->secondaryParametrics); 635 } 636 else { 637 CursorDeviceSegment *segment; 638 639 // scale 640 for(segment = (CursorDeviceSegment *) scaleInfo->scaleSegments; 641 scrollMultiplier > IOFixed64::withFixed(segment->devUnits); 642 segment++) 643 {} 644 645 if (avgCount > 2) { 646 // Continuous scrolling in one direction indicates a desire to go faster. 647 scrollMultiplier *= (SInt64)lsqrt(avgCount * 16); 648 scrollMultiplier /= 4; 649 } 650 651 scrollMultiplier = (IOFixed64::withFixed(segment->intercept) + scrollMultiplier * IOFixed64::withFixed(segment->slope)) / IOFixed64::withFixed(absAxis); 652 } 653 axisValue *= scrollMultiplier; 654 *axisp = axisValue.asFixed(); 655} 656 657void IOHIPointing::setPointingMode(UInt32 accelerateMode) 658{ 659 _accelerateMode = accelerateMode; 660 661 _convertAbsoluteToRelative = ((accelerateMode & kAbsoluteConvertMouse) != 0); 662} 663 664UInt32 IOHIPointing::getPointingMode() 665{ 666 return _accelerateMode; 667} 668 669void IOHIPointing::setScrollType(UInt32 scrollType) 670{ 671 _scrollType = scrollType; 672} 673 674UInt32 IOHIPointing::getScrollType() 675{ 676 return _scrollType; 677} 678 679void IOHIPointing::scalePointer(int * dxp, int * dyp) 680// Description: Perform pointer acceleration computations here. 681// Given the resolution, dx, dy, and time, compute the velocity 682// of the pointer over a Manhatten distance in inches/second. 683// Using this velocity, do a lookup in the pointerScaling table 684// to select a scaling factor. Scale dx and dy up as appropriate. 685// Preconditions: 686// * _deviceLock should be held on entry 687{ 688 if (_paraAccelParams && _paraAccelSecondaryParams) { 689 IOFixed64 deltaX; 690 IOFixed64 deltaY; 691 IOFixed64 fractX; 692 IOFixed64 fractY; 693 IOFixed64 mag; 694 deltaX.fromIntFloor(*dxp); 695 deltaY.fromIntFloor(*dyp); 696 fractX.fromFixed(_fractX); 697 fractY.fromFixed(_fractY); 698 mag.fromIntFloor(llsqrt((deltaX * deltaX + deltaY * deltaY).as64())); 699 700 IOFixed64 mult = PACurvesGetAccelerationMultiplier(mag, *_paraAccelParams, *_paraAccelSecondaryParams); 701 deltaX *= mult; 702 deltaY *= mult; 703 deltaX += fractX; 704 deltaY += fractY; 705 706 *dxp = deltaX.as32(); 707 *dyp = deltaY.as32(); 708 709 _fractX = deltaX.asFixed(); 710 _fractY = deltaY.asFixed(); 711 712 // sign extend fractional part 713 if( deltaX < 0LL ) 714 _fractX |= 0xffff0000; 715 else 716 _fractX &= 0x0000ffff; 717 718 if( deltaY < 0LL) 719 _fractY |= 0xffff0000; 720 else 721 _fractY &= 0x0000ffff; 722 } 723 else { 724 ScaleAxes(_scaleSegments, dxp, &_fractX, dyp, &_fractY); 725 } 726} 727 728/* 729 Routine: Interpolate 730 This routine interpolates to find a point on the line [x1,y1] [x2,y2] which 731 is intersected by the line [x3,y3] [x3,y"]. The resulting y' is calculated 732 by interpolating between y3 and y", towards the higher acceleration curve. 733*/ 734 735static SInt32 Interpolate( SInt32 x1, SInt32 y1, 736 SInt32 x2, SInt32 y2, 737 SInt32 x3, SInt32 y3, 738 SInt32 scale, Boolean lower ) 739{ 740 741 SInt32 slope; 742 SInt32 intercept; 743 SInt32 resultY; 744 745 slope = (x2 == x1) ? 0 : IOFixedDivide( y2 - y1, x2 - x1 ); 746 intercept = y1 - IOFixedMultiply( slope, x1 ); 747 resultY = intercept + IOFixedMultiply( slope, x3 ); 748 if( lower) 749 resultY = y3 - IOFixedMultiply( scale, y3 - resultY ); 750 else 751 resultY = resultY + IOFixedMultiply( scale, y3 - resultY ); 752 753 return( resultY ); 754} 755 756 757void IOHIPointing::setupForAcceleration( IOFixed desired ) 758{ 759 OSArray *parametricAccelerationCurves = (OSArray*)copyProperty(kHIDTrackingAccelParametricCurvesKey, gIOServicePlane); 760 IOFixed devScale = IOFixedDivide( resolution(), FRAME_RATE ); 761 IOFixed crsrScale = IOFixedDivide( SCREEN_RESOLUTION, FRAME_RATE ); 762 bool useParametric = false; 763 764// IOLog("%s %d: got %08x and %p\n", __PRETTY_FUNCTION__, __LINE__, desired, parametricAccelerationCurves); 765 if (!OSDynamicCast( OSArray, parametricAccelerationCurves)) { 766 OSSafeReleaseNULL(parametricAccelerationCurves); 767 parametricAccelerationCurves = (OSArray*)copyProperty(kHIDAccelParametricCurvesKey, gIOServicePlane); 768 } 769 // Try to set up the parametric acceleration data 770 if (OSDynamicCast( OSArray, parametricAccelerationCurves )) { 771 if ( !_paraAccelParams ) 772 { 773 _paraAccelParams = (IOHIPointing__PAParameters*)IOMalloc(sizeof(IOHIPointing__PAParameters)); 774 } 775 if ( !_paraAccelSecondaryParams ) 776 { 777 _paraAccelSecondaryParams = (IOHIPointing__PASecondaryParameters*)IOMalloc(sizeof(IOHIPointing__PASecondaryParameters)); 778 } 779 780// IOLog("%s %d: have %p and %p\n", __PRETTY_FUNCTION__, __LINE__, _paraAccelParams, _paraAccelSecondaryParams); 781 782 if (_paraAccelParams && _paraAccelSecondaryParams) { 783 IOFixed64 desired64; 784 IOFixed64 devScale64; 785 IOFixed64 crsrScale64; 786 787 // IOLog("%s: Calling PACurvesSetupAccelParams with %08x, %08x, %08x\n", __PRETTY_FUNCTION__, desired, devScale, crsrScale); 788 789 useParametric = PACurvesSetupAccelParams(parametricAccelerationCurves, 790 desired64.fromFixed(desired), 791 devScale64.fromFixed(devScale), 792 crsrScale64.fromFixed(crsrScale), 793 *_paraAccelParams, 794 *_paraAccelSecondaryParams); 795 if (useParametric && getProperty(kHIDAccelParametricCurvesDebugKey, gIOServicePlane)) { 796 OSDictionary *debugInfo = PACurvesDebugDictionary(*_paraAccelParams, *_paraAccelSecondaryParams); 797 if (debugInfo) { 798 setProperty(kHIDAccelParametricCurvesDebugKey, debugInfo); 799 debugInfo->release(); 800 } 801 } 802 } 803 } 804 OSSafeReleaseNULL(parametricAccelerationCurves); 805 806// IOLog("%s %d: %s parametric\n", __PRETTY_FUNCTION__, __LINE__, useParametric ? "using" : "NOT using"); 807 808 // If that fails, fall back to classic acceleration 809 if (!useParametric) { 810 OSData * table = copyAccelerationTable(); 811 812 if (_paraAccelParams) 813 IOFree(_paraAccelParams, sizeof(IOHIPointing__PAParameters)); 814 if (_paraAccelSecondaryParams) 815 IOFree(_paraAccelSecondaryParams, sizeof(IOHIPointing__PASecondaryParameters)); 816 _paraAccelParams = NULL; 817 _paraAccelSecondaryParams = NULL; 818 819 if (SetupAcceleration (table, desired, devScale, crsrScale, &_scaleSegments, &_scaleSegCount)) 820 { 821 _acceleration = desired; 822 _fractX = _fractY = 0; 823 } 824 if (table) table->release(); 825 } 826} 827 828void IOHIPointing::setupScrollForAcceleration( IOFixed desired ) 829{ 830 IOFixed devScale = 0; 831 IOFixed scrScale = 0; 832 IOFixed reportRate = scrollReportRate(); 833 OSData * accelTable = NULL; 834 UInt32 type = 0; 835 836 _scrollWheelInfo->rateMultiplier = IOFixedDivide(reportRate, FRAME_RATE); 837 _scrollPointerInfo->rateMultiplier = IOFixedDivide(reportRate, FRAME_RATE); 838 839 if (desired < 0) { 840 setPointingMode(getPointingMode() | kAccelNoScrollAcceleration); 841 setProperty(kHIDScrollAccelParametricCurvesDebugKey, OSSymbol::withCString("desired < 0")); 842 } 843 else { 844 setPointingMode(getPointingMode() & ~kAccelNoScrollAcceleration); 845 846 OSArray *parametricAccelerationCurves = (OSArray*)copyProperty(kHIDScrollAccelParametricCurvesKey, gIOServicePlane); 847//#define SWITCH_ALL_SCROLL_ACCELERATION_TO_PARAMETRICS 848#ifdef SWITCH_ALL_SCROLL_ACCELERATION_TO_PARAMETRICS // { 849#warning SWITCH_ALL_SCROLL_ACCELERATION_TO_PARAMETRICS is defined 850 if (!OSDynamicCast( OSArray, parametricAccelerationCurves)) { 851 OSSafeReleaseNULL(parametricAccelerationCurves); 852 parametricAccelerationCurves = (OSArray*)copyProperty(kHIDAccelParametricCurvesKey, gIOServicePlane); 853 } 854#endif // } SWITCH_ALL_SCROLL_ACCELERATION_TO_PARAMETRICS 855 856 OSArray *currentDebugArray = (OSArray *)copyProperty(kHIDScrollAccelParametricCurvesDebugKey); 857 OSArray *newDebugArray = NULL; 858 if (OSDynamicCast(OSArray, currentDebugArray)) { 859 newDebugArray = OSArray::withArray(currentDebugArray); 860 } 861 else { 862 OSSymbol const * base[] = { 863 OSSymbol::withCString("initted"), 864 OSSymbol::withCString("initted"), 865 OSSymbol::withCString("initted") }; 866 newDebugArray = OSArray::withObjects((OSObject const **)base, 3); 867 } 868 OSSafeReleaseNULL(currentDebugArray); 869 870 for ( type=kAccelTypeY; type<=kAccelTypeZ; type++) { 871 IOFixed res = scrollResolutionForType(type); 872 // Zero scroll resolution says you don't want acceleration. 873 if ( res ) { 874 _scrollWheelInfo->axis[type].isHighResScroll = res > (SCROLL_DEFAULT_RESOLUTION * 2); 875 _scrollPointerInfo->axis[type].isHighResScroll = _scrollWheelInfo->axis[type].isHighResScroll; 876 877 _scrollWheelInfo->axis[type].consumeClearThreshold = (IOFixedDivide(res, SCROLL_CONSUME_RESOLUTION) >> 16) * 2; 878 _scrollPointerInfo->axis[type].consumeClearThreshold = _scrollWheelInfo->axis[type].consumeClearThreshold; 879 880 _scrollWheelInfo->axis[type].consumeCountThreshold = _scrollWheelInfo->axis[type].consumeClearThreshold * SCROLL_CONSUME_COUNT_MULTIPLIER; 881 _scrollPointerInfo->axis[type].consumeCountThreshold = _scrollPointerInfo->axis[type].consumeClearThreshold * SCROLL_CONSUME_COUNT_MULTIPLIER; 882 883 bzero(&(_scrollWheelInfo->axis[type].state), sizeof(ScaleDataState)); 884 bzero(&(_scrollWheelInfo->axis[type].consumeState), sizeof(ScaleConsumeState)); 885 bzero(&(_scrollPointerInfo->axis[type].state), sizeof(ScaleDataState)); 886 bzero(&(_scrollPointerInfo->axis[type].consumeState), sizeof(ScaleConsumeState)); 887 888 clock_get_uptime(&(_scrollWheelInfo->axis[type].lastEventTime)); 889 _scrollPointerInfo->axis[type].lastEventTime = _scrollWheelInfo->axis[type].lastEventTime; 890 891 if (OSDynamicCast( OSArray, parametricAccelerationCurves ) && reportRate) { 892 IOFixed64 desired64; 893 IOFixed64 devScale64; 894 IOFixed64 scrScale64; 895 IOFixed64 temp; 896 897 desired64.fromFixed(desired); 898 899 devScale64.fromFixed(res); 900 devScale64 /= temp.fromFixed(reportRate); 901 902 scrScale64.fromFixed(SCREEN_RESOLUTION); 903 scrScale64 /= temp.fromFixed(FRAME_RATE); 904 905 _scrollWheelInfo->axis[type].isParametric = 906 PACurvesSetupAccelParams(parametricAccelerationCurves, 907 desired64, 908 devScale64, 909 scrScale64, 910 _scrollWheelInfo->axis[type].primaryParametrics, 911 _scrollWheelInfo->axis[type].secondaryParametrics); 912 if (_scrollWheelInfo->axis[type].isParametric) { 913 OSDictionary *debugInfo = 914 PACurvesDebugDictionary(_scrollWheelInfo->axis[type].primaryParametrics, 915 _scrollWheelInfo->axis[type].secondaryParametrics); 916 if (debugInfo) { 917 newDebugArray->replaceObject(type, debugInfo); 918 debugInfo->release(); 919 } 920 else { 921 IOLog("IOHIPointing 0x%llx unable to generate debug info for scroll axis %d\n", getRegistryEntryID(), type); 922 newDebugArray->replaceObject(type, OSSymbol::withCString("no debug info")); 923 } 924 } 925 else { 926 IOLog("IOHIPointing 0x%llx unable to generate parametric data for axis %d\n", getRegistryEntryID(), type); 927 newDebugArray->replaceObject(type, OSSymbol::withCString("not parametric")); 928 } 929 } 930 931 if (!_scrollWheelInfo->axis[type].isParametric) { 932 accelTable = copyScrollAccelerationTableForType(type); 933 934 // Setup pixel scroll wheel acceleration table 935 devScale = IOFixedDivide( res, reportRate ); 936 scrScale = IOFixedDivide( SCREEN_RESOLUTION, FRAME_RATE ); 937 938 SetupAcceleration (accelTable, desired, devScale, scrScale, &(_scrollWheelInfo->axis[type].scaleSegments), &(_scrollWheelInfo->axis[type].scaleSegCount)); 939 940 // Grab the pointer resolution 941 res = this->resolution(); 942 reportRate = FRAME_RATE; 943 944 // Setup pixel pointer drag/scroll acceleration table 945 devScale = IOFixedDivide( res, reportRate ); 946 scrScale = IOFixedDivide( SCREEN_RESOLUTION, FRAME_RATE ); 947 948 SetupAcceleration (accelTable, desired, devScale, scrScale, &(_scrollPointerInfo->axis[type].scaleSegments), &(_scrollPointerInfo->axis[type].scaleSegCount)); 949 950 char buff[256] = ""; 951 snprintf(buff, sizeof(buff), "Non Parametric: desired = 0x%08x; devScale = 0x%08x; scrScale = 0x%08x", desired, devScale, scrScale); 952 OSString *debugInfo = OSString::withCString(buff); 953 if (debugInfo) { 954 newDebugArray->replaceObject(type, debugInfo); 955 debugInfo->release(); 956 } 957 else { 958 IOLog("IOHIPointing 0x%llx unable to generate traditional debug info for scroll axis %d\n", getRegistryEntryID(), type); 959 newDebugArray->replaceObject(type, OSSymbol::withCString("traditional but no debug info")); 960 } 961 962 if (accelTable) 963 accelTable->release(); 964 } 965 } 966 else { 967 newDebugArray->replaceObject(type, OSSymbol::withCString("no scroll resolution for type")); 968 } 969 } 970 setProperty(kHIDScrollAccelParametricCurvesDebugKey, newDebugArray); 971 OSSafeReleaseNULL(newDebugArray); 972 OSSafeReleaseNULL(parametricAccelerationCurves); 973 } 974} 975 976 977bool IOHIPointing::resetPointer() 978{ 979 DEVICE_LOCK; 980 981 _buttonMode = NX_RightButton; 982 setupForAcceleration(EV_DEFAULTPOINTERACCELLEVEL); 983 updateProperties(); 984 985 DEVICE_UNLOCK; 986 return true; 987} 988 989bool IOHIPointing::resetScroll() 990{ 991 DEVICE_LOCK; 992 993 setupScrollForAcceleration(EV_DEFAULTSCROLLACCELLEVEL); 994 995 DEVICE_UNLOCK; 996 return true; 997} 998 999static void ScalePressure(int *pressure, int pressureMin, int pressureMax) 1000{ 1001 // scaled pressure value; MAX=(2^16)-1, MIN=0 1002 *pressure = ((pressureMin != pressureMax)) ? 1003 (((unsigned)(*pressure - pressureMin) * 65535LL) / 1004 (unsigned)( pressureMax - pressureMin)) : 0; 1005} 1006 1007 1008void IOHIPointing::dispatchAbsolutePointerEvent(IOGPoint * newLoc, 1009 IOGBounds * bounds, 1010 UInt32 buttonState, 1011 bool proximity, 1012 int pressure, 1013 int pressureMin, 1014 int pressureMax, 1015 int stylusAngle, 1016 AbsoluteTime ts) 1017{ 1018 int buttons = 0; 1019 int dx, dy; 1020 1021 DEVICE_LOCK; 1022 1023 if( buttonState & 1) 1024 buttons |= EV_LB; 1025 1026 //if( buttonCount() > 1) { 1027 if( buttonState & 2) // any others down 1028 buttons |= EV_RB; 1029 // Other magic bit reshuffling stuff. It seems there was space 1030 // left over at some point for a "middle" mouse button between EV_LB and EV_RB 1031 if(buttonState & 4) 1032 buttons |= 2; 1033 // Add in the rest of the buttons in a linear fasion... 1034 buttons |= buttonState & ~0x7; 1035 // } 1036 1037 /* There should not be a threshold applied to pressure for generating a button event. 1038 As soon as the pen hits the tablet, a mouse down should occur 1039 1040 if ((_pressureThresholdToClick < 255) && ((pressure - pressureMin) > ((pressureMax - pressureMin) * _pressureThresholdToClick / 256))) { 1041 buttons |= EV_LB; 1042 } 1043 */ 1044 if ( pressure > pressureMin ) 1045 { 1046 buttons |= EV_LB; 1047 } 1048 1049 if (_buttonMode == NX_OneButton) { 1050 if ((buttons & (EV_LB|EV_RB)) != 0) { 1051 buttons = EV_LB; 1052 } 1053 } 1054 1055 if (_convertAbsoluteToRelative) { 1056 dx = newLoc->x - _previousLocation.x; 1057 dy = newLoc->y - _previousLocation.y; 1058 1059 if ((_contactToMove && !_hadContact && (pressure > pressureMin)) || (abs(dx) > ((bounds->maxx - bounds->minx) / 20)) || (abs(dy) > ((bounds->maxy - bounds->miny) / 20))) { 1060 dx = 0; 1061 dy = 0; 1062 } else { 1063 scalePointer(&dx, &dy); 1064 } 1065 1066 _previousLocation.x = newLoc->x; 1067 _previousLocation.y = newLoc->y; 1068 } 1069 1070 DEVICE_UNLOCK; 1071 1072 _hadContact = (pressure > pressureMin); 1073 1074 if (!_contactToMove || (pressure > pressureMin)) { 1075 1076 ScalePressure(&pressure, pressureMin, pressureMax); 1077 1078 if (_convertAbsoluteToRelative) { 1079 _relativePointerEvent( this, 1080 buttons, 1081 dx, 1082 dy, 1083 ts); 1084 } else { 1085 _absolutePointerEvent( this, 1086 buttons, 1087 newLoc, 1088 bounds, 1089 proximity, 1090 pressure, 1091 stylusAngle, 1092 ts); 1093 } 1094 } 1095 1096 return; 1097} 1098 1099void IOHIPointing::dispatchRelativePointerEvent(int dx, 1100 int dy, 1101 UInt32 buttonState, 1102 AbsoluteTime ts) 1103{ 1104 int buttons; 1105 1106 DEVICE_LOCK; 1107 1108 // post the raw event to the IOHIDPointingDevice 1109 if (_hidPointingNub) 1110 _hidPointingNub->postMouseEvent(buttonState, dx, dy, 0); 1111 1112 if (_isSeized) 1113 { 1114 DEVICE_UNLOCK; 1115 return; 1116 } 1117 1118 buttons = 0; 1119 1120 if( buttonState & 1) 1121 buttons |= EV_LB; 1122 1123 //if( buttonCount() > 1) { 1124 if( buttonState & 2) // any others down 1125 buttons |= EV_RB; 1126 // Other magic bit reshuffling stuff. It seems there was space 1127 // left over at some point for a "middle" mouse button between EV_LB and EV_RB 1128 if(buttonState & 4) 1129 buttons |= 2; 1130 // Add in the rest of the buttons in a linear fasion... 1131 buttons |= buttonState & ~0x7; 1132 //} 1133 1134 if ( _scrollButtonMask & buttonState ) 1135 { 1136 1137 DEVICE_UNLOCK; 1138 1139 dispatchScrollWheelEventWithAccelInfo(-dy, -dx, 0, _scrollPointerInfo, ts); 1140 1141 return; 1142 } 1143 1144 // Perform pointer acceleration computations 1145 if ( _accelerateMode & kAccelMouse ) { 1146 int oldDx = dx; 1147 int oldDy = dy; 1148 1149 scalePointer(&dx, &dy); 1150 1151 if (((oldDx < 0) && (dx > 0)) || ((oldDx > 0) && (dx < 0))) { 1152 IOLog("IOHIPointing::dispatchRelativePointerEvent: Unwanted Direction Change X: oldDx=%d dx=%d\n", oldDy, dy); 1153 } 1154 1155 1156 if (((oldDy < 0) && (dy > 0)) || ((oldDy > 0) && (dy < 0))) { 1157 IOLog("IOHIPointing::dispatchRelativePointerEvent: Unwanted Direction Change Y: oldDy=%d dy=%d\n", oldDy, dy); 1158 } 1159 } 1160 1161 // Perform button tying and mapping. This 1162 // stuff applies to relative posn devices (mice) only. 1163 if ( _buttonMode == NX_OneButton ) 1164 { 1165 // Remap both Left and Right (but no others?) to Left. 1166 if ( (buttons & (EV_LB|EV_RB)) != 0 ) { 1167 buttons |= EV_LB; 1168 buttons &= ~EV_RB; 1169 } 1170 } 1171 else if ( (buttonCount() > 1) && (_buttonMode == NX_LeftButton) ) 1172 // Menus on left button. Swap! 1173 { 1174 int temp = 0; 1175 if ( buttons & EV_LB ) 1176 temp = EV_RB; 1177 if ( buttons & EV_RB ) 1178 temp |= EV_LB; 1179 // Swap Left and Right, preserve everything else 1180 buttons = (buttons & ~(EV_LB|EV_RB)) | temp; 1181 } 1182 DEVICE_UNLOCK; 1183 1184 _relativePointerEvent(this, 1185 /* buttons */ buttons, 1186 /* deltaX */ dx, 1187 /* deltaY */ dy, 1188 /* atTime */ ts); 1189} 1190 1191void IOHIPointing::dispatchScrollWheelEvent(short deltaAxis1, 1192 short deltaAxis2, 1193 short deltaAxis3, 1194 AbsoluteTime ts) 1195{ 1196 dispatchScrollWheelEventWithAccelInfo(deltaAxis1, deltaAxis2, deltaAxis3, _scrollWheelInfo, ts); 1197} 1198 1199void IOHIPointing::dispatchScrollWheelEventWithAccelInfo( 1200 SInt32 deltaAxis1, 1201 SInt32 deltaAxis2, 1202 SInt32 deltaAxis3, 1203 ScrollAccelInfo * info, 1204 AbsoluteTime ts) 1205{ 1206 Boolean isHighResScroll = FALSE; 1207 IOHIDSystem * hidSystem = IOHIDSystem::instance(); 1208 UInt32 eventFlags = (hidSystem ? hidSystem->eventFlags() : 0); 1209 1210 DEVICE_LOCK; 1211 1212 // Change the report descriptor for the IOHIDPointingDevice 1213 // to include a scroll whell 1214 if (_hidPointingNub && !_hidPointingNub->isScrollPresent()) 1215 { 1216 IOHIDPointingDevice * nub = _hidPointingNub; 1217 1218 _hidPointingNub = 0; 1219 1220 DEVICE_UNLOCK; 1221 1222 nub->terminate(kIOServiceAsynchronous); // rdar://8810574 1223 nub->release(); 1224 1225 nub = IOHIDPointingDevice::newPointingDeviceAndStart(this, buttonCount(), resolution() >> 16, true); 1226 1227 DEVICE_LOCK; 1228 1229 _hidPointingNub = nub; 1230 } 1231 1232 // Post the raw event to IOHIDPointingDevice 1233 if (_hidPointingNub) 1234 _hidPointingNub->postMouseEvent(0, 0, 0, deltaAxis1); 1235 1236 if (_isSeized) { 1237 DEVICE_UNLOCK; 1238 return; 1239 } 1240 1241 if (_scrollZoomMask) { 1242 bool isModifiedToZoom = ((SPECIALKEYS_MODIFIER_MASK & eventFlags) == _scrollZoomMask); 1243 bool isMomentum = (0 != (_scrollType & kScrollTypeMomentumAny)); 1244 if ((isMomentum && _lastScrollWasZoom) || (isModifiedToZoom && !isMomentum)) { 1245 _lastScrollWasZoom = true; 1246 _scrollType |= kScrollTypeZoom; 1247 } 1248 else { 1249 _lastScrollWasZoom = false; 1250 } 1251 } 1252 else { 1253 _lastScrollWasZoom = false; 1254 } 1255 1256 if (!(_scrollType & kScrollTypeZoom) && _scrollOff ) { 1257 DEVICE_UNLOCK; 1258 return; 1259 } 1260 1261 _scrollFixedDeltaAxis1 = deltaAxis1 << 16; 1262 _scrollFixedDeltaAxis2 = deltaAxis2 << 16; 1263 _scrollFixedDeltaAxis3 = deltaAxis3 << 16; 1264 1265 CONVERT_SCROLL_FIXED_TO_COARSE(IOFixedMultiply(_scrollFixedDeltaAxis1, SCROLL_WHEEL_TO_PIXEL_SCALE), _scrollPointDeltaAxis1); 1266 CONVERT_SCROLL_FIXED_TO_COARSE(IOFixedMultiply(_scrollFixedDeltaAxis2, SCROLL_WHEEL_TO_PIXEL_SCALE), _scrollPointDeltaAxis2); 1267 CONVERT_SCROLL_FIXED_TO_COARSE(IOFixedMultiply(_scrollFixedDeltaAxis3, SCROLL_WHEEL_TO_PIXEL_SCALE), _scrollPointDeltaAxis3); 1268 1269 isHighResScroll = info->axis[kAccelTypeX].isHighResScroll || 1270 info->axis[kAccelTypeY].isHighResScroll || 1271 info->axis[kAccelTypeZ].isHighResScroll; 1272 1273 // Perform pointer acceleration computations 1274 if (( _accelerateMode & kAccelScroll ) && !( _accelerateMode & kAccelNoScrollAcceleration )) 1275 { 1276 bool directionChange[3] = {0,0,0}; 1277 bool typeChange = FALSE; 1278 SInt32* pDeltaAxis[3] = {&deltaAxis1, &deltaAxis2, &deltaAxis3}; 1279 SInt32* pScrollFixedDeltaAxis[3] = {&_scrollFixedDeltaAxis1, &_scrollFixedDeltaAxis2, &_scrollFixedDeltaAxis3}; 1280 IOFixed* pScrollPointDeltaAxis[3] = {&_scrollPointDeltaAxis1, &_scrollPointDeltaAxis2, &_scrollPointDeltaAxis3}; 1281 1282 if ( info->zoom != (_scrollType == kScrollTypeZoom)) 1283 { 1284 info->zoom = (_scrollType == kScrollTypeZoom); 1285 typeChange = TRUE; 1286 } 1287 1288 for (UInt32 type=kAccelTypeY; type<=kAccelTypeZ; type++ ) { 1289 directionChange[type] = ((info->axis[type].lastValue == 0) || 1290 ((info->axis[type].lastValue < 0) && (*(pDeltaAxis[type]) > 0)) || 1291 ((info->axis[type].lastValue > 0) && (*(pDeltaAxis[type]) < 0))); 1292 info->axis[type].lastValue = *(pDeltaAxis[type]); 1293 1294 if ( info->axis[type].scaleSegments || info->axis[type].isParametric ) 1295 { 1296 *(pScrollPointDeltaAxis[type]) = info->axis[type].lastValue << 16; 1297 1298 AccelerateScrollAxis(pScrollPointDeltaAxis[type], 1299 &(info->axis[type]), 1300 ts, 1301 info->rateMultiplier, 1302 directionChange[type] || typeChange); 1303 1304 CONVERT_SCROLL_FIXED_TO_COARSE(pScrollPointDeltaAxis[type][0], pScrollPointDeltaAxis[type][0]); 1305 1306 // RY: Convert pixel value to points 1307 *(pScrollFixedDeltaAxis[type]) = *(pScrollPointDeltaAxis[type]) << 16; 1308 1309 if ( directionChange[type] ) 1310 bzero(&(info->axis[type].consumeState), sizeof(ScaleConsumeState)); 1311 1312 // RY: throttle the tranlation of scroll based on the resolution threshold. 1313 // This allows us to not generated traditional scroll wheel (line) events 1314 // for high res devices at really low (fine granularity) speeds. This 1315 // prevents a succession of single scroll events that can make scrolling 1316 // slowly actually seem faster. 1317 if ( info->axis[type].consumeCountThreshold ) 1318 { 1319 info->axis[type].consumeState.consumeAccum += *(pScrollFixedDeltaAxis[type]) + ((*(pScrollFixedDeltaAxis[type])) ? info->axis[type].state.fraction : 0); 1320 info->axis[type].consumeState.consumeCount += abs(info->axis[type].lastValue); 1321 1322 if (*(pScrollFixedDeltaAxis[type]) && 1323 ((abs(info->axis[type].lastValue) >= (SInt32)info->axis[type].consumeClearThreshold) || 1324 (info->axis[type].consumeState.consumeCount >= info->axis[type].consumeCountThreshold))) 1325 { 1326 *(pScrollFixedDeltaAxis[type]) = info->axis[type].consumeState.consumeAccum; 1327 info->axis[type].consumeState.consumeAccum = 0; 1328 info->axis[type].consumeState.consumeCount = 0; 1329 } 1330 else 1331 { 1332 *(pScrollFixedDeltaAxis[type]) = 0; 1333 } 1334 } 1335 1336 *(pScrollFixedDeltaAxis[type]) = IOFixedMultiply(*(pScrollFixedDeltaAxis[type]), SCROLL_PIXEL_TO_WHEEL_SCALE); 1337 1338 // RY: Generate fixed point and course scroll deltas. 1339 CONVERT_SCROLL_FIXED_TO_COARSE(*(pScrollFixedDeltaAxis[type]), *(pDeltaAxis[type])); 1340 } 1341 } 1342 } 1343 1344 DEVICE_UNLOCK; 1345 1346 _scrollType |= (isHighResScroll) ? kScrollTypeContinuous : 0; 1347 1348 _scrollWheelEvent( this, 1349 deltaAxis1, 1350 deltaAxis2, 1351 deltaAxis3, 1352 ts); 1353 _scrollType = 0; 1354} 1355 1356bool IOHIPointing::updateProperties( void ) 1357{ 1358 bool ok; 1359 UInt32 res = resolution(); 1360 1361 ok = setProperty( kIOHIDPointerResolutionKey, res, 32) 1362 & setProperty( kIOHIDPointerConvertAbsoluteKey, &_convertAbsoluteToRelative, 1363 sizeof( _convertAbsoluteToRelative)) 1364 & setProperty( kIOHIDPointerContactToMoveKey, &_contactToMove, 1365 sizeof( _contactToMove)); 1366 1367 return( ok & super::updateProperties() ); 1368} 1369 1370IOReturn IOHIPointing::setParamProperties( OSDictionary * dict ) 1371{ 1372 OSData *data; 1373 OSNumber *number; 1374 OSString *pointerAccelKey; 1375 OSString *scrollAccelKey; 1376 IOReturn err = kIOReturnSuccess; 1377 bool updated = false; 1378 UInt32 value; 1379 1380 // The resetPointer and resetScroll methods attempt to grab the DEVICE_LOCK 1381 // We should make these calls outside of DEVICE_LOCK as it is not recursive 1382 if( dict->getObject(kIOHIDResetPointerKey)) 1383 resetPointer(); 1384 1385 if( dict->getObject(kIOHIDScrollResetKey)) 1386 resetScroll(); 1387 1388 pointerAccelKey = (OSString*)copyProperty(kIOHIDPointerAccelerationTypeKey); 1389 scrollAccelKey = (OSString*)copyProperty(kIOHIDScrollAccelerationTypeKey); 1390 1391 DEVICE_LOCK; 1392 1393 if( (number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDScrollZoomModifierMaskKey)))) 1394 { 1395 _scrollZoomMask = number->unsigned32BitValue() & SPECIALKEYS_MODIFIER_MASK; 1396 } 1397 1398 number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDDeviceScrollWithTrackpadKey)); 1399 if((number) && OSDynamicCast( OSString, scrollAccelKey ) && scrollAccelKey->isEqualTo(kIOHIDTrackpadScrollAccelerationKey)) 1400 { 1401 _scrollOff = number->unsigned32BitValue() == 0; 1402 } 1403 1404 number = OSDynamicCast(OSNumber, dict->getObject(kIOHIDDeviceScrollDisableKey)); 1405 if (number) { 1406 _scrollOff = number->unsigned32BitValue() != 0; 1407 } 1408 1409 if ( OSDynamicCast( OSString, pointerAccelKey ) && 1410 ((number = OSDynamicCast( OSNumber, dict->getObject(pointerAccelKey))) || 1411 (data = OSDynamicCast( OSData, dict->getObject(pointerAccelKey))))) 1412 { 1413 value = (number) ? number->unsigned32BitValue() : 1414 *((UInt32 *) (data->getBytesNoCopy())); 1415 setupForAcceleration( value ); 1416 updated = true; 1417 } 1418 else if ( (number = OSDynamicCast( OSNumber, 1419 dict->getObject(kIOHIDPointerAccelerationKey))) || 1420 (data = OSDynamicCast( OSData, 1421 dict->getObject(kIOHIDPointerAccelerationKey)))) { 1422 1423 value = (number) ? number->unsigned32BitValue() : 1424 *((UInt32 *) (data->getBytesNoCopy())); 1425 1426 setupForAcceleration( value ); 1427 updated = true; 1428 if( pointerAccelKey) { 1429 // If this is an OSData object, create an OSNumber to store in the registry 1430 if (!number) 1431 { 1432 number = OSNumber::withNumber(value, 32); 1433 dict->setObject( pointerAccelKey, number ); 1434 number->release(); 1435 } 1436 else 1437 dict->setObject( pointerAccelKey, number ); 1438 } 1439 1440 } 1441 OSSafeReleaseNULL(pointerAccelKey); 1442 1443 // Scroll accel setup 1444 // use same mechanism as pointer accel setup 1445 if( OSDynamicCast( OSString, scrollAccelKey ) && 1446 ((number = OSDynamicCast( OSNumber, dict->getObject(scrollAccelKey))) || 1447 (data = OSDynamicCast( OSData, dict->getObject(scrollAccelKey))))) { 1448 value = (number) ? number->unsigned32BitValue() : 1449 *((UInt32 *) (data->getBytesNoCopy())); 1450 setupScrollForAcceleration( value ); 1451 updated = true; 1452 } 1453 else if((number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDScrollAccelerationKey))) || 1454 (data = OSDynamicCast( OSData, dict->getObject(kIOHIDScrollAccelerationKey)))) { 1455 1456 value = (number) ? number->unsigned32BitValue() : 1457 *((UInt32 *) (data->getBytesNoCopy())); 1458 1459 setupScrollForAcceleration( value ); 1460 updated = true; 1461 if( OSDynamicCast( OSString, scrollAccelKey) ) { 1462 // If this is an OSData object, create an OSNumber to store in the registry 1463 if (!number) 1464 { 1465 number = OSNumber::withNumber(value, 32); 1466 dict->setObject( scrollAccelKey, number ); 1467 number->release(); 1468 } 1469 else 1470 dict->setObject( scrollAccelKey, number ); 1471 } 1472 } 1473 OSSafeReleaseNULL(scrollAccelKey); 1474 1475 DEVICE_UNLOCK; 1476 1477 if ((number = OSDynamicCast(OSNumber, 1478 dict->getObject(kIOHIDPointerConvertAbsoluteKey))) || 1479 (data = OSDynamicCast(OSData, 1480 dict->getObject(kIOHIDPointerConvertAbsoluteKey)))) 1481 { 1482 value = (number) ? number->unsigned32BitValue() : *((UInt32 *) (data->getBytesNoCopy())); 1483 _convertAbsoluteToRelative = (value != 0) ? true : false; 1484 updated = true; 1485 } 1486 1487 if ((number = OSDynamicCast(OSNumber, 1488 dict->getObject(kIOHIDPointerContactToMoveKey))) || 1489 (data = OSDynamicCast(OSData, 1490 dict->getObject(kIOHIDPointerContactToMoveKey)))) 1491 { 1492 value = (number) ? number->unsigned32BitValue() : *((UInt32 *) (data->getBytesNoCopy())); 1493 _contactToMove = (value != 0) ? true : false; 1494 updated = true; 1495 } 1496 1497 if ((number = OSDynamicCast(OSNumber, dict->getObject(kIOHIDPointerButtonMode))) || 1498 (data = OSDynamicCast(OSData, dict->getObject(kIOHIDPointerButtonMode)))) 1499 { 1500 value = (number) ? number->unsigned32BitValue() : 1501 *((UInt32 *) (data->getBytesNoCopy())); 1502 1503 if (getProperty(kIOHIDPointerButtonCountKey)) 1504 { 1505 switch (value) { 1506 case kIOHIDButtonMode_BothLeftClicks: 1507 _buttonMode = NX_OneButton; 1508 break; 1509 1510 case kIOHIDButtonMode_EnableRightClick: 1511 _buttonMode = NX_RightButton; 1512 break; 1513 1514 case kIOHIDButtonMode_ReverseLeftRightClicks: 1515 // vtn3: rdar://problem/5816671 1516 _buttonMode = (getProperty(kIOHIDDisallowRemappingOfPrimaryClickKey) == kOSBooleanTrue) ? _buttonMode : NX_LeftButton; 1517 break; 1518 1519 default: 1520 // vtn3: rdar://problem/5816671 1521 _buttonMode = (getProperty(kIOHIDDisallowRemappingOfPrimaryClickKey) == kOSBooleanTrue) ? _buttonMode : value; 1522 } 1523 updated = true; 1524 } 1525 } 1526 1527 if ((number = OSDynamicCast(OSNumber, dict->getObject(kIOHIDScrollMouseButtonKey))) || 1528 (data = OSDynamicCast(OSData, dict->getObject(kIOHIDScrollMouseButtonKey)))) 1529 { 1530 value = (number) ? number->unsigned32BitValue() : 1531 *((UInt32 *) (data->getBytesNoCopy())) ; 1532 1533 if (!value) 1534 _scrollButtonMask = 0; 1535 else 1536 _scrollButtonMask = (1 << (value-1)); 1537 } 1538 1539 if( updated ) 1540 updateProperties(); 1541 1542 return( err == kIOReturnSuccess ) ? super::setParamProperties(dict) : err; 1543} 1544 1545// subclasses override 1546 1547IOItemCount IOHIPointing::buttonCount() 1548{ 1549 return (1); 1550} 1551 1552IOFixed IOHIPointing::resolution() 1553{ 1554 OSNumber * number = (OSNumber*)copyProperty(kIOHIDPointerResolutionKey); 1555 IOFixed result = 100 << 16; 1556 1557 if ( OSDynamicCast(OSNumber, number) ) 1558 result = number->unsigned32BitValue(); 1559 OSSafeReleaseNULL(number); 1560 1561 return result; 1562} 1563 1564// RY: Added this method to obtain the resolution 1565// of the scroll wheel. The default value is 0, 1566// which should prevent any accel from being applied. 1567IOFixed IOHIPointing::scrollResolutionForType(SInt32 type) 1568{ 1569 IOFixed res = 0; 1570 OSNumber * number = NULL; 1571 const char *key = NULL; 1572 1573 switch ( type ) { 1574 case kAccelTypeY: 1575 key = kIOHIDScrollResolutionYKey; 1576 break; 1577 case kAccelTypeX: 1578 key = kIOHIDScrollResolutionXKey; 1579 break; 1580 case kAccelTypeZ: 1581 key = kIOHIDScrollResolutionZKey; 1582 break; 1583 default: 1584 key = kIOHIDScrollResolutionKey; 1585 break; 1586 1587 } 1588 1589 number = (OSNumber*)copyProperty(key); 1590 if( !OSDynamicCast( OSNumber, number ) ) { 1591 OSSafeRelease(number); 1592 number = (OSNumber*)copyProperty(kIOHIDScrollResolutionKey); 1593 } 1594 1595 if (!number) { 1596 if (_reserved && !_reserved->scrollResolutionWarningComplete) { 1597 kprintf("IOHIPointing::0x%llx has no %s. This /implies/ no scroll acceleration.\n", 1598 getRegistryEntryID(), 1599 kIOHIDScrollResolutionKey); 1600 _reserved->scrollResolutionWarningComplete = true; 1601 } 1602 } 1603 1604 if( OSDynamicCast( OSNumber, number ) ) 1605 res = number->unsigned32BitValue(); 1606 OSSafeRelease(number); 1607 1608 return( res ); 1609} 1610 1611// RY: Added this method to obtain the report rate 1612// of the scroll wheel. The default value is 67 << 16. 1613IOFixed IOHIPointing::scrollReportRate() 1614{ 1615 IOFixed result = FRAME_RATE; 1616 OSNumber *number = (OSNumber*)copyProperty( kIOHIDScrollReportRateKey ); 1617 1618 if (OSDynamicCast( OSNumber, number )) 1619 if (number->unsigned32BitValue()) 1620 result = number->unsigned32BitValue(); 1621 OSSafeRelease(number); 1622 1623 if (result == 0) 1624 result = FRAME_RATE; 1625 1626 return result; 1627} 1628 1629 1630OSData * IOHIPointing::copyAccelerationTable() 1631{ 1632 static const UInt8 accl[] = { 1633 0x00, 0x00, 0x80, 0x00, 1634 0x40, 0x32, 0x30, 0x30, 0x00, 0x02, 0x00, 0x00, 1635 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 1636 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 1637 0x00, 0x09, 0x00, 0x00, 0x71, 0x3B, 0x00, 0x00, 1638 0x60, 0x00, 0x00, 0x04, 0x4E, 0xC5, 0x00, 0x10, 1639 0x80, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x5F, 1640 0x00, 0x00, 0x00, 0x16, 0xEC, 0x4F, 0x00, 0x8B, 1641 0x00, 0x00, 0x00, 0x1D, 0x3B, 0x14, 0x00, 0x94, 1642 0x80, 0x00, 0x00, 0x22, 0x76, 0x27, 0x00, 0x96, 1643 0x00, 0x00, 0x00, 0x24, 0x62, 0x76, 0x00, 0x96, 1644 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x96, 1645 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x96, 1646 0x00, 0x00 1647 }; 1648 1649 OSData * data = (OSData*)copyProperty( kIOHIDPointerAccelerationTableKey ); 1650 if (!OSDynamicCast( OSData, data )) 1651 OSSafeReleaseNULL(data); 1652 if (!data) 1653 data = OSData::withBytesNoCopy( (void *) accl, sizeof( accl ) ); 1654 1655 return( data ); 1656} 1657 1658// RY: Added for scroll acceleration 1659// If no scroll accel table is present, this will 1660// default to the pointer acceleration table 1661OSData * IOHIPointing::copyScrollAccelerationTable() 1662{ 1663 return( copyScrollAccelerationTableForType() ); 1664} 1665 1666OSData * IOHIPointing::copyScrollAccelerationTableForType(SInt32 type) 1667{ 1668 OSData * data = NULL; 1669 const char *key = NULL; 1670 1671 switch ( type ) { 1672 case kAccelTypeY: 1673 key = kIOHIDScrollAccelerationTableYKey; 1674 break; 1675 case kAccelTypeX: 1676 key = kIOHIDScrollAccelerationTableXKey; 1677 break; 1678 case kAccelTypeZ: 1679 key = kIOHIDScrollAccelerationTableZKey; 1680 break; 1681 } 1682 1683 if ( key ) 1684 data = (OSData*)copyProperty( key ); 1685 1686 if ( !OSDynamicCast( OSData, data ) ) { 1687 OSSafeRelease(data); 1688 data = (OSData*)copyProperty( kIOHIDScrollAccelerationTableKey ); 1689 if (data && !OSDynamicCast( OSData, data )) { 1690 data->release(); 1691 data = NULL; 1692 } 1693 } 1694 1695 if ( !data ) 1696 data = copyAccelerationTable(); 1697 1698 return( data ); 1699} 1700 1701/*bool GetOSDataValue (OSData * data, UInt32 * value) 1702{ 1703 bool validValue = false; 1704 1705 switch (data->getLength()) 1706 { 1707 case sizeof(UInt8): 1708 *value = *(UInt8 *) data->getBytesNoCopy(); 1709 validValue = true; 1710 break; 1711 1712 case sizeof(UInt16): 1713 *value = *(UInt16 *) data->getBytesNoCopy(); 1714 validValue = true; 1715 break; 1716 1717 case sizeof(UInt32): 1718 *value = *(UInt32 *) data->getBytesNoCopy(); 1719 validValue = true; 1720 break; 1721 } 1722 1723 return validValue; 1724}*/ 1725 1726// RY: This function contains the original portions of 1727// setupForAcceleration. This was separated out to 1728// accomidate the acceleration of scroll axes 1729bool SetupAcceleration (OSData * data, IOFixed desired, IOFixed devScale, IOFixed crsrScale, void ** scaleSegments, IOItemCount * scaleSegCount) { 1730 const UInt16 * lowTable = 0; 1731 const UInt16 * highTable; 1732 1733 SInt32 x1, y1, x2, y2, x3, y3; 1734 SInt32 prevX1, prevY1; 1735 SInt32 upperX, upperY; 1736 SInt32 lowerX, lowerY; 1737 SInt32 lowAccl = 0, lowPoints = 0; 1738 SInt32 highAccl, highPoints; 1739 SInt32 scale; 1740 UInt32 count; 1741 Boolean lower; 1742 1743 SInt32 scaledX1, scaledY1; 1744 SInt32 scaledX2, scaledY2; 1745 1746 CursorDeviceSegment * segments; 1747 CursorDeviceSegment * segment; 1748 SInt32 segCount; 1749 1750 if( !data || !devScale || !crsrScale) 1751 return false; 1752 1753 if( desired < (IOFixed) 0) { 1754 // disabling mouse scaling 1755 if(*scaleSegments && *scaleSegCount) 1756 IODelete( *scaleSegments, 1757 CursorDeviceSegment, *scaleSegCount ); 1758 *scaleSegments = NULL; 1759 *scaleSegCount = 0; 1760 return false; 1761 } 1762 1763 highTable = (const UInt16 *) data->getBytesNoCopy(); 1764 1765 scaledX1 = scaledY1 = 0; 1766 1767 scale = OSReadBigInt32((volatile void *)highTable, 0); 1768 highTable += 4; 1769 1770 // normalize table's default (scale) to 0.5 1771 if( desired > 0x8000) { 1772 desired = IOFixedMultiply( desired - 0x8000, 1773 0x10000 - scale ); 1774 desired <<= 1; 1775 desired += scale; 1776 } else { 1777 desired = IOFixedMultiply( desired, scale ); 1778 desired <<= 1; 1779 } 1780 1781 count = OSReadBigInt16((volatile void *)(highTable++), 0); 1782 scale = (1 << 16); 1783 1784 // find curves bracketing the desired value 1785 do { 1786 highAccl = OSReadBigInt32((volatile void *)highTable, 0); 1787 highTable += 2; 1788 highPoints = OSReadBigInt16((volatile void *)(highTable++), 0); 1789 1790 if( desired <= highAccl) 1791 break; 1792 1793 if( 0 == --count) { 1794 // this much over the highest table 1795 scale = (highAccl) ? IOFixedDivide( desired, highAccl ) : 0; 1796 lowTable = 0; 1797 break; 1798 } 1799 1800 lowTable = highTable; 1801 lowAccl = highAccl; 1802 lowPoints = highPoints; 1803 highTable += lowPoints * 4; 1804 1805 } while( true ); 1806 1807 // scale between the two 1808 if( lowTable) { 1809 scale = (highAccl == lowAccl) ? 0 : 1810 IOFixedDivide((desired - lowAccl), (highAccl - lowAccl)); 1811 1812 } 1813 1814 // or take all the high one 1815 else { 1816 lowTable = highTable; 1817 lowAccl = highAccl; 1818 lowPoints = 0; 1819 } 1820 1821 if( lowPoints > highPoints) 1822 segCount = lowPoints; 1823 else 1824 segCount = highPoints; 1825 segCount *= 2; 1826/* IOLog("lowPoints %ld, highPoints %ld, segCount %ld\n", 1827 lowPoints, highPoints, segCount); */ 1828 segments = IONew( CursorDeviceSegment, segCount ); 1829 assert( segments ); 1830 segment = segments; 1831 1832 x1 = prevX1 = y1 = prevY1 = 0; 1833 1834 lowerX = OSReadBigInt32((volatile void *)lowTable, 0); 1835 lowTable += 2; 1836 lowerY = OSReadBigInt32((volatile void *)lowTable, 0); 1837 lowTable += 2; 1838 upperX = OSReadBigInt32((volatile void *)highTable, 0); 1839 highTable += 2; 1840 upperY = OSReadBigInt32((volatile void *)highTable, 0); 1841 highTable += 2; 1842 1843 do { 1844 // consume next point from first X 1845 lower = (lowPoints && (!highPoints || (lowerX <= upperX))); 1846 1847 if( lower) { 1848 /* highline */ 1849 x2 = upperX; 1850 y2 = upperY; 1851 x3 = lowerX; 1852 y3 = lowerY; 1853 if( lowPoints && (--lowPoints)) { 1854 lowerX = OSReadBigInt32((volatile void *)lowTable, 0); 1855 lowTable += 2; 1856 lowerY = OSReadBigInt32((volatile void *)lowTable, 0); 1857 lowTable += 2; 1858 } 1859 } else { 1860 /* lowline */ 1861 x2 = lowerX; 1862 y2 = lowerY; 1863 x3 = upperX; 1864 y3 = upperY; 1865 if( highPoints && (--highPoints)) { 1866 upperX = OSReadBigInt32((volatile void *)highTable, 0); 1867 highTable += 2; 1868 upperY = OSReadBigInt32((volatile void *)highTable, 0); 1869 highTable += 2; 1870 } 1871 } 1872 { 1873 // convert to line segment 1874 assert( segment < (segments + segCount) ); 1875 1876 scaledX2 = IOFixedMultiply( devScale, /* newX */ x3 ); 1877 scaledY2 = IOFixedMultiply( crsrScale, 1878 /* newY */ Interpolate( x1, y1, x2, y2, x3, y3, 1879 scale, lower ) ); 1880 if( lowPoints || highPoints) 1881 segment->devUnits = scaledX2; 1882 else 1883 segment->devUnits = MAX_DEVICE_THRESHOLD; 1884 1885 segment->slope = ((scaledX2 == scaledX1)) ? 0 : 1886 IOFixedDivide((scaledY2 - scaledY1), (scaledX2 - scaledX1)); 1887 1888 segment->intercept = scaledY2 1889 - IOFixedMultiply( segment->slope, scaledX2 ); 1890/* IOLog("devUnits = %08lx, slope = %08lx, intercept = %08lx\n", 1891 segment->devUnits, segment->slope, segment->intercept); */ 1892 1893 scaledX1 = scaledX2; 1894 scaledY1 = scaledY2; 1895 segment++; 1896 } 1897 1898 // continue on from last point 1899 if( lowPoints && highPoints) { 1900 if( lowerX > upperX) { 1901 prevX1 = x1; 1902 prevY1 = y1; 1903 } else { 1904 /* swaplines */ 1905 prevX1 = x1; 1906 prevY1 = y1; 1907 x1 = x3; 1908 y1 = y3; 1909 } 1910 } else { 1911 x2 = x1; 1912 y2 = y1; 1913 x1 = prevX1; 1914 y1 = prevY1; 1915 prevX1 = x2; 1916 prevY1 = y2; 1917 } 1918 1919 } while( lowPoints || highPoints ); 1920 1921 if( *scaleSegCount && *scaleSegments) 1922 IODelete( *scaleSegments, 1923 CursorDeviceSegment, *scaleSegCount ); 1924 *scaleSegCount = segCount; 1925 *scaleSegments = (void *) segments; 1926 1927 return true; 1928} 1929 1930IOFixed64 OSObjectToIOFixed64(OSObject *in) 1931{ 1932 OSNumber *num = OSDynamicCast(OSNumber, in); 1933 IOFixed64 result; 1934 if (num) { 1935 result.fromFixed(num->unsigned32BitValue()); 1936 } 1937 return result; 1938} 1939 1940bool 1941PACurvesFillParamsFromDict(OSDictionary *parameters, 1942 const IOFixed64 devScale, 1943 const IOFixed64 crsrScale, 1944 IOHIPointing__PAParameters &outParams) 1945{ 1946 require(parameters, exit_early); 1947 1948 outParams.deviceMickysDivider = devScale; 1949 outParams.cursorSpeedMultiplier = crsrScale; 1950 1951 outParams.accelIndex = OSObjectToIOFixed64(parameters->getObject(kHIDAccelIndexKey)); 1952 1953 outParams.gain[0] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelGainLinearKey)); 1954 outParams.gain[1] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelGainParabolicKey)); 1955 outParams.gain[2] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelGainCubicKey)); 1956 outParams.gain[3] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelGainQuarticKey)); 1957 1958 outParams.tangent[0] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelTangentSpeedLinearKey)); 1959 outParams.tangent[1] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelTangentSpeedParabolicRootKey)); 1960// outParams.tangent[2] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelTangentSpeedCubicRootKey)); 1961// outParams.tangent[3] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelTangentSpeedQuarticRootKey)); 1962 1963 return ((outParams.gain[0] != 0LL) || 1964 (outParams.gain[1] != 0LL) || 1965 (outParams.gain[2] != 0LL) || 1966 (outParams.gain[3] != 0LL)); 1967 1968exit_early: 1969 return false; 1970} 1971 1972bool 1973PACurvesSetupAccelParams (OSArray *parametricCurves, 1974 IOFixed64 desired, 1975 IOFixed64 devScale, 1976 IOFixed64 crsrScale, 1977 IOHIPointing__PAParameters &primaryParams, 1978 IOHIPointing__PASecondaryParameters &secondaryParams) 1979{ 1980 bool success = false; 1981 OSCollectionIterator *itr = NULL; 1982 OSDictionary *dict = NULL; 1983 1984 IOHIPointing__PAParameters high_curve_params; 1985 IOHIPointing__PAParameters low_curve_params; 1986 1987// IOLog("%s %d: Called with %08x, %08x, %08x\n", __PRETTY_FUNCTION__, __LINE__, desired.asFixed(), devScale.asFixed(), crsrScale.asFixed()); 1988 1989 require(parametricCurves, exit_early); 1990 require(crsrScale > 0LL, exit_early); 1991 require(devScale > 0LL, exit_early); 1992 require(desired > 0LL, exit_early); 1993 1994 itr = OSCollectionIterator::withCollection(parametricCurves); 1995 require(itr, exit_early); 1996 1997 while (!success) { 1998 itr->reset(); 1999 dict = OSDynamicCast(OSDictionary, itr->getNextObject()); 2000 require(PACurvesFillParamsFromDict(dict, devScale, crsrScale, low_curve_params), 2001 exit_early); 2002 2003 while (!success && (NULL != dict)) { 2004 if (!PACurvesFillParamsFromDict(dict, devScale, crsrScale, high_curve_params)) { 2005 break; 2006 } 2007 if (desired <= high_curve_params.accelIndex) { 2008 success = true; 2009 } 2010 else { 2011 low_curve_params = high_curve_params; 2012 } 2013 dict = OSDynamicCast(OSDictionary, itr->getNextObject()); 2014 } 2015 2016 require(success || !itr->isValid(), exit_early); 2017 }; 2018 2019 if ( high_curve_params.accelIndex > low_curve_params.accelIndex ) { 2020 IOFixed64 ratio = (desired - low_curve_params.accelIndex) / (high_curve_params.accelIndex - low_curve_params.accelIndex); 2021 int index; 2022 2023// IOLog("%s %d: Using %08x, %08x, %08x\n", __PRETTY_FUNCTION__, __LINE__, high_curve_params.accelIndex.asFixed(), low_curve_params.accelIndex.asFixed(), ratio.asFixed()); 2024 2025 primaryParams.deviceMickysDivider = high_curve_params.deviceMickysDivider; 2026 primaryParams.cursorSpeedMultiplier = high_curve_params.cursorSpeedMultiplier; 2027 primaryParams.accelIndex = desired; 2028 2029 for (index = 0; index < 4; index++) { 2030 primaryParams.gain[index] = low_curve_params.gain[index] + (high_curve_params.gain[index] - low_curve_params.gain[index]) * ratio; 2031 if (primaryParams.gain[index] < 0LL) 2032 primaryParams.gain[index].fromFixed(0); 2033 } 2034 for (index = 0; index < 2; index++) { 2035 primaryParams.tangent[index] = low_curve_params.tangent[index] + (high_curve_params.tangent[index] - low_curve_params.tangent[index]) * ratio; 2036 if (primaryParams.tangent[index] < 0LL) 2037 primaryParams.tangent[index].fromFixed(0); 2038 } 2039 } 2040 else { 2041 primaryParams = high_curve_params; 2042 } 2043 2044 success = ((primaryParams.gain[0] != 0LL) || 2045 (primaryParams.gain[1] != 0LL) || 2046 (primaryParams.gain[2] != 0LL) || 2047 (primaryParams.gain[3] != 0LL)); 2048 2049 // calculate secondary values 2050 bzero(&secondaryParams, sizeof(secondaryParams)); 2051 if ((primaryParams.tangent[1] > 0LL) && (primaryParams.tangent[1] < primaryParams.tangent[0])) 2052 secondaryParams.firstTangent = 1; 2053 2054 if (secondaryParams.firstTangent == 0) { 2055 secondaryParams.y0 = IOQuarticFunction(primaryParams.tangent[0], primaryParams.gain); 2056 secondaryParams.m0 = IOQuarticDerivative(primaryParams.tangent[0], primaryParams.gain); 2057 secondaryParams.b0 = secondaryParams.y0 - secondaryParams.m0 * primaryParams.tangent[0]; 2058 secondaryParams.y1 = secondaryParams.m0 * primaryParams.tangent[1] + secondaryParams.b0; 2059 } 2060 else { 2061 secondaryParams.y1 = IOQuarticFunction( primaryParams.tangent[1], primaryParams.gain ); 2062 secondaryParams.m0 = IOQuarticDerivative( primaryParams.tangent[1], primaryParams.gain ); 2063 } 2064 2065 secondaryParams.m_root = secondaryParams.m0 * secondaryParams.y1 * 2LL; 2066 secondaryParams.b_root = exponent(secondaryParams.y1, 2) - secondaryParams.m_root * primaryParams.tangent[1]; 2067 2068exit_early: 2069 if (itr) { 2070 itr->release(); 2071 } 2072 2073 return success; 2074} 2075 2076OSDictionary* 2077PACurvesDebugDictionary(IOHIPointing__PAParameters &primaryParams, 2078 IOHIPointing__PASecondaryParameters &secondaryParams) 2079{ 2080 OSDictionary *result = OSDictionary::withCapacity(20); 2081 2082 require(result, exit_early); 2083 2084#define ADD_NUMBER_FOR(X) \ 2085 do { \ 2086 OSNumber *value = OSNumber::withNumber(X.as64(), 64); \ 2087 if (value) { \ 2088 result->setObject(#X, value); \ 2089 value->release(); \ 2090 } \ 2091 } \ 2092 while (0) 2093 2094 ADD_NUMBER_FOR(primaryParams.deviceMickysDivider); 2095 ADD_NUMBER_FOR(primaryParams.cursorSpeedMultiplier); 2096 ADD_NUMBER_FOR(primaryParams.accelIndex); 2097 ADD_NUMBER_FOR(primaryParams.gain[0]); 2098 ADD_NUMBER_FOR(primaryParams.gain[1]); 2099 ADD_NUMBER_FOR(primaryParams.gain[2]); 2100 ADD_NUMBER_FOR(primaryParams.gain[3]); 2101 ADD_NUMBER_FOR(primaryParams.tangent[0]); 2102 ADD_NUMBER_FOR(primaryParams.tangent[1]); 2103 2104 ADD_NUMBER_FOR(secondaryParams.m0); 2105 ADD_NUMBER_FOR(secondaryParams.b0); 2106 ADD_NUMBER_FOR(secondaryParams.y0); 2107 ADD_NUMBER_FOR(secondaryParams.y1); 2108 ADD_NUMBER_FOR(secondaryParams.m_root); 2109 ADD_NUMBER_FOR(secondaryParams.b_root); 2110 2111#undef ADD_NUMBER_FOR 2112 2113exit_early: 2114 return result; 2115} 2116 2117IOFixed64 2118PACurvesGetAccelerationMultiplier(const IOFixed64 device_speed_mickeys, 2119 const IOHIPointing__PAParameters ¶ms, 2120 const IOHIPointing__PASecondaryParameters &secondaryParams) 2121{ 2122 IOFixed64 result; // defaults to zero 2123 2124 if ((device_speed_mickeys > result) && (params.deviceMickysDivider != result)) { 2125 IOFixed64 standardized_speed = device_speed_mickeys / params.deviceMickysDivider; 2126 IOFixed64 accelerated_speed; 2127 if ((params.tangent[secondaryParams.firstTangent] != 0LL) && (standardized_speed <= params.tangent[secondaryParams.firstTangent])) { 2128 accelerated_speed = IOQuarticFunction(standardized_speed, params.gain); 2129 } 2130 else { 2131 if ((secondaryParams.firstTangent == 0) && (params.tangent[1] != 0LL) && (standardized_speed <= params.tangent[1])) { 2132 accelerated_speed = secondaryParams.m0 * standardized_speed + secondaryParams.b0; 2133 } 2134 else { 2135 accelerated_speed.fromIntFloor(llsqrt(((secondaryParams.m_root * standardized_speed) + secondaryParams.b_root).as64())); 2136 } 2137 } 2138 IOFixed64 accelerated_pixels = accelerated_speed * params.cursorSpeedMultiplier; 2139 result = accelerated_pixels / device_speed_mickeys; 2140 } 2141 else { 2142 result.fromFixed(1); 2143 } 2144 2145 return result; 2146} 2147 2148// RY: This function contains the original portions of 2149// scalePointer. This was separated out to accomidate 2150// the acceleration of other axes 2151void ScaleAxes (void * scaleSegments, int * axis1p, IOFixed *axis1Fractp, int * axis2p, IOFixed *axis2Fractp) 2152{ 2153 SInt32 dx, dy; 2154 SInt32 mag; 2155 IOFixed scale; 2156 CursorDeviceSegment * segment; 2157 2158 if( !scaleSegments) 2159 return; 2160 2161 dx = (*axis1p) << 16; 2162 dy = (*axis2p) << 16; 2163 2164 // mag is (x^2 + y^2)^0.5 and converted to fixed point 2165 mag = (lsqrt(*axis1p * *axis1p + *axis2p * *axis2p)) << 16; 2166 if (mag == 0) 2167 return; 2168 2169 // scale 2170 for( 2171 segment = (CursorDeviceSegment *) scaleSegments; 2172 mag > segment->devUnits; 2173 segment++) {} 2174 2175 scale = IOFixedDivide( 2176 segment->intercept + IOFixedMultiply( mag, segment->slope ), 2177 mag ); 2178 2179 dx = IOFixedMultiply( dx, scale ); 2180 dy = IOFixedMultiply( dy, scale ); 2181 2182 // add fract parts 2183 dx += *axis1Fractp; 2184 dy += *axis2Fractp; 2185 2186 *axis1p = dx / 65536; 2187 *axis2p = dy / 65536; 2188 2189 // get fractional part with sign extend 2190 if( dx >= 0) 2191 *axis1Fractp = dx & 0xffff; 2192 else 2193 *axis1Fractp = dx | 0xffff0000; 2194 if( dy >= 0) 2195 *axis2Fractp = dy & 0xffff; 2196 else 2197 *axis2Fractp = dy | 0xffff0000; 2198} 2199 2200void IOHIPointing::_relativePointerEvent( IOHIPointing * self, 2201 int buttons, 2202 /* deltaX */ int dx, 2203 /* deltaY */ int dy, 2204 /* atTime */ AbsoluteTime ts) 2205{ 2206 RelativePointerEventCallback rpeCallback; 2207 rpeCallback = (RelativePointerEventCallback)self->_relativePointerEventAction; 2208 2209 if (rpeCallback) 2210 (*rpeCallback)(self->_relativePointerEventTarget, 2211 buttons, 2212 dx, 2213 dy, 2214 ts, 2215 self, 2216 0); 2217} 2218 2219 /* Tablet event reporting */ 2220void IOHIPointing::_absolutePointerEvent(IOHIPointing * self, 2221 int buttons, 2222 /* at */ IOGPoint * newLoc, 2223 /* withBounds */ IOGBounds *bounds, 2224 /* inProximity */ bool proximity, 2225 /* withPressure */ int pressure, 2226 /* withAngle */ int stylusAngle, 2227 /* atTime */ AbsoluteTime ts) 2228{ 2229 AbsolutePointerEventCallback apeCallback; 2230 apeCallback = (AbsolutePointerEventCallback)self->_absolutePointerEventAction; 2231 2232 if (apeCallback) 2233 (*apeCallback)(self->_absolutePointerEventTarget, 2234 buttons, 2235 newLoc, 2236 bounds, 2237 proximity, 2238 pressure, 2239 stylusAngle, 2240 ts, 2241 self, 2242 0); 2243 2244} 2245 2246 /* Mouse scroll wheel event reporting */ 2247void IOHIPointing::_scrollWheelEvent(IOHIPointing *self, 2248 short deltaAxis1, 2249 short deltaAxis2, 2250 short deltaAxis3, 2251 AbsoluteTime ts) 2252{ 2253 ScrollWheelEventCallback sweCallback; 2254 sweCallback = (ScrollWheelEventCallback)self->_scrollWheelEventAction; 2255 2256 if (sweCallback) 2257 (*sweCallback)(self->_scrollWheelEventTarget, 2258 (short) deltaAxis1, 2259 (short) deltaAxis2, 2260 (short) deltaAxis3, 2261 self->_scrollFixedDeltaAxis1, 2262 self->_scrollFixedDeltaAxis2, 2263 self->_scrollFixedDeltaAxis3, 2264 self->_scrollPointDeltaAxis1, 2265 self->_scrollPointDeltaAxis2, 2266 self->_scrollPointDeltaAxis3, 2267 self->_scrollType, 2268 ts, 2269 self, 2270 0); 2271} 2272