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 return result; 1624} 1625 1626 1627OSData * IOHIPointing::copyAccelerationTable() 1628{ 1629 static const UInt8 accl[] = { 1630 0x00, 0x00, 0x80, 0x00, 1631 0x40, 0x32, 0x30, 0x30, 0x00, 0x02, 0x00, 0x00, 1632 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 1633 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 1634 0x00, 0x09, 0x00, 0x00, 0x71, 0x3B, 0x00, 0x00, 1635 0x60, 0x00, 0x00, 0x04, 0x4E, 0xC5, 0x00, 0x10, 1636 0x80, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x5F, 1637 0x00, 0x00, 0x00, 0x16, 0xEC, 0x4F, 0x00, 0x8B, 1638 0x00, 0x00, 0x00, 0x1D, 0x3B, 0x14, 0x00, 0x94, 1639 0x80, 0x00, 0x00, 0x22, 0x76, 0x27, 0x00, 0x96, 1640 0x00, 0x00, 0x00, 0x24, 0x62, 0x76, 0x00, 0x96, 1641 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x96, 1642 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x96, 1643 0x00, 0x00 1644 }; 1645 1646 OSData * data = (OSData*)copyProperty( kIOHIDPointerAccelerationTableKey ); 1647 if (!OSDynamicCast( OSData, data )) 1648 OSSafeReleaseNULL(data); 1649 if (!data) 1650 data = OSData::withBytesNoCopy( (void *) accl, sizeof( accl ) ); 1651 1652 return( data ); 1653} 1654 1655// RY: Added for scroll acceleration 1656// If no scroll accel table is present, this will 1657// default to the pointer acceleration table 1658OSData * IOHIPointing::copyScrollAccelerationTable() 1659{ 1660 return( copyScrollAccelerationTableForType() ); 1661} 1662 1663OSData * IOHIPointing::copyScrollAccelerationTableForType(SInt32 type) 1664{ 1665 OSData * data = NULL; 1666 const char *key = NULL; 1667 1668 switch ( type ) { 1669 case kAccelTypeY: 1670 key = kIOHIDScrollAccelerationTableYKey; 1671 break; 1672 case kAccelTypeX: 1673 key = kIOHIDScrollAccelerationTableXKey; 1674 break; 1675 case kAccelTypeZ: 1676 key = kIOHIDScrollAccelerationTableZKey; 1677 break; 1678 } 1679 1680 if ( key ) 1681 data = (OSData*)copyProperty( key ); 1682 1683 if ( !OSDynamicCast( OSData, data ) ) { 1684 OSSafeRelease(data); 1685 data = (OSData*)copyProperty( kIOHIDScrollAccelerationTableKey ); 1686 if (data && !OSDynamicCast( OSData, data )) { 1687 data->release(); 1688 data = NULL; 1689 } 1690 } 1691 1692 if ( !data ) 1693 data = copyAccelerationTable(); 1694 1695 return( data ); 1696} 1697 1698/*bool GetOSDataValue (OSData * data, UInt32 * value) 1699{ 1700 bool validValue = false; 1701 1702 switch (data->getLength()) 1703 { 1704 case sizeof(UInt8): 1705 *value = *(UInt8 *) data->getBytesNoCopy(); 1706 validValue = true; 1707 break; 1708 1709 case sizeof(UInt16): 1710 *value = *(UInt16 *) data->getBytesNoCopy(); 1711 validValue = true; 1712 break; 1713 1714 case sizeof(UInt32): 1715 *value = *(UInt32 *) data->getBytesNoCopy(); 1716 validValue = true; 1717 break; 1718 } 1719 1720 return validValue; 1721}*/ 1722 1723// RY: This function contains the original portions of 1724// setupForAcceleration. This was separated out to 1725// accomidate the acceleration of scroll axes 1726bool SetupAcceleration (OSData * data, IOFixed desired, IOFixed devScale, IOFixed crsrScale, void ** scaleSegments, IOItemCount * scaleSegCount) { 1727 const UInt16 * lowTable = 0; 1728 const UInt16 * highTable; 1729 1730 SInt32 x1, y1, x2, y2, x3, y3; 1731 SInt32 prevX1, prevY1; 1732 SInt32 upperX, upperY; 1733 SInt32 lowerX, lowerY; 1734 SInt32 lowAccl = 0, lowPoints = 0; 1735 SInt32 highAccl, highPoints; 1736 SInt32 scale; 1737 UInt32 count; 1738 Boolean lower; 1739 1740 SInt32 scaledX1, scaledY1; 1741 SInt32 scaledX2, scaledY2; 1742 1743 CursorDeviceSegment * segments; 1744 CursorDeviceSegment * segment; 1745 SInt32 segCount; 1746 1747 if( !data || !devScale || !crsrScale) 1748 return false; 1749 1750 if( desired < (IOFixed) 0) { 1751 // disabling mouse scaling 1752 if(*scaleSegments && *scaleSegCount) 1753 IODelete( *scaleSegments, 1754 CursorDeviceSegment, *scaleSegCount ); 1755 *scaleSegments = NULL; 1756 *scaleSegCount = 0; 1757 return false; 1758 } 1759 1760 highTable = (const UInt16 *) data->getBytesNoCopy(); 1761 1762 scaledX1 = scaledY1 = 0; 1763 1764 scale = OSReadBigInt32((volatile void *)highTable, 0); 1765 highTable += 4; 1766 1767 // normalize table's default (scale) to 0.5 1768 if( desired > 0x8000) { 1769 desired = IOFixedMultiply( desired - 0x8000, 1770 0x10000 - scale ); 1771 desired <<= 1; 1772 desired += scale; 1773 } else { 1774 desired = IOFixedMultiply( desired, scale ); 1775 desired <<= 1; 1776 } 1777 1778 count = OSReadBigInt16((volatile void *)(highTable++), 0); 1779 scale = (1 << 16); 1780 1781 // find curves bracketing the desired value 1782 do { 1783 highAccl = OSReadBigInt32((volatile void *)highTable, 0); 1784 highTable += 2; 1785 highPoints = OSReadBigInt16((volatile void *)(highTable++), 0); 1786 1787 if( desired <= highAccl) 1788 break; 1789 1790 if( 0 == --count) { 1791 // this much over the highest table 1792 scale = (highAccl) ? IOFixedDivide( desired, highAccl ) : 0; 1793 lowTable = 0; 1794 break; 1795 } 1796 1797 lowTable = highTable; 1798 lowAccl = highAccl; 1799 lowPoints = highPoints; 1800 highTable += lowPoints * 4; 1801 1802 } while( true ); 1803 1804 // scale between the two 1805 if( lowTable) { 1806 scale = (highAccl == lowAccl) ? 0 : 1807 IOFixedDivide((desired - lowAccl), (highAccl - lowAccl)); 1808 1809 } 1810 1811 // or take all the high one 1812 else { 1813 lowTable = highTable; 1814 lowAccl = highAccl; 1815 lowPoints = 0; 1816 } 1817 1818 if( lowPoints > highPoints) 1819 segCount = lowPoints; 1820 else 1821 segCount = highPoints; 1822 segCount *= 2; 1823/* IOLog("lowPoints %ld, highPoints %ld, segCount %ld\n", 1824 lowPoints, highPoints, segCount); */ 1825 segments = IONew( CursorDeviceSegment, segCount ); 1826 assert( segments ); 1827 segment = segments; 1828 1829 x1 = prevX1 = y1 = prevY1 = 0; 1830 1831 lowerX = OSReadBigInt32((volatile void *)lowTable, 0); 1832 lowTable += 2; 1833 lowerY = OSReadBigInt32((volatile void *)lowTable, 0); 1834 lowTable += 2; 1835 upperX = OSReadBigInt32((volatile void *)highTable, 0); 1836 highTable += 2; 1837 upperY = OSReadBigInt32((volatile void *)highTable, 0); 1838 highTable += 2; 1839 1840 do { 1841 // consume next point from first X 1842 lower = (lowPoints && (!highPoints || (lowerX <= upperX))); 1843 1844 if( lower) { 1845 /* highline */ 1846 x2 = upperX; 1847 y2 = upperY; 1848 x3 = lowerX; 1849 y3 = lowerY; 1850 if( lowPoints && (--lowPoints)) { 1851 lowerX = OSReadBigInt32((volatile void *)lowTable, 0); 1852 lowTable += 2; 1853 lowerY = OSReadBigInt32((volatile void *)lowTable, 0); 1854 lowTable += 2; 1855 } 1856 } else { 1857 /* lowline */ 1858 x2 = lowerX; 1859 y2 = lowerY; 1860 x3 = upperX; 1861 y3 = upperY; 1862 if( highPoints && (--highPoints)) { 1863 upperX = OSReadBigInt32((volatile void *)highTable, 0); 1864 highTable += 2; 1865 upperY = OSReadBigInt32((volatile void *)highTable, 0); 1866 highTable += 2; 1867 } 1868 } 1869 { 1870 // convert to line segment 1871 assert( segment < (segments + segCount) ); 1872 1873 scaledX2 = IOFixedMultiply( devScale, /* newX */ x3 ); 1874 scaledY2 = IOFixedMultiply( crsrScale, 1875 /* newY */ Interpolate( x1, y1, x2, y2, x3, y3, 1876 scale, lower ) ); 1877 if( lowPoints || highPoints) 1878 segment->devUnits = scaledX2; 1879 else 1880 segment->devUnits = MAX_DEVICE_THRESHOLD; 1881 1882 segment->slope = ((scaledX2 == scaledX1)) ? 0 : 1883 IOFixedDivide((scaledY2 - scaledY1), (scaledX2 - scaledX1)); 1884 1885 segment->intercept = scaledY2 1886 - IOFixedMultiply( segment->slope, scaledX2 ); 1887/* IOLog("devUnits = %08lx, slope = %08lx, intercept = %08lx\n", 1888 segment->devUnits, segment->slope, segment->intercept); */ 1889 1890 scaledX1 = scaledX2; 1891 scaledY1 = scaledY2; 1892 segment++; 1893 } 1894 1895 // continue on from last point 1896 if( lowPoints && highPoints) { 1897 if( lowerX > upperX) { 1898 prevX1 = x1; 1899 prevY1 = y1; 1900 } else { 1901 /* swaplines */ 1902 prevX1 = x1; 1903 prevY1 = y1; 1904 x1 = x3; 1905 y1 = y3; 1906 } 1907 } else { 1908 x2 = x1; 1909 y2 = y1; 1910 x1 = prevX1; 1911 y1 = prevY1; 1912 prevX1 = x2; 1913 prevY1 = y2; 1914 } 1915 1916 } while( lowPoints || highPoints ); 1917 1918 if( *scaleSegCount && *scaleSegments) 1919 IODelete( *scaleSegments, 1920 CursorDeviceSegment, *scaleSegCount ); 1921 *scaleSegCount = segCount; 1922 *scaleSegments = (void *) segments; 1923 1924 return true; 1925} 1926 1927IOFixed64 OSObjectToIOFixed64(OSObject *in) 1928{ 1929 OSNumber *num = OSDynamicCast(OSNumber, in); 1930 IOFixed64 result; 1931 if (num) { 1932 result.fromFixed(num->unsigned32BitValue()); 1933 } 1934 return result; 1935} 1936 1937bool 1938PACurvesFillParamsFromDict(OSDictionary *parameters, 1939 const IOFixed64 devScale, 1940 const IOFixed64 crsrScale, 1941 IOHIPointing__PAParameters &outParams) 1942{ 1943 require(parameters, exit_early); 1944 1945 outParams.deviceMickysDivider = devScale; 1946 outParams.cursorSpeedMultiplier = crsrScale; 1947 1948 outParams.accelIndex = OSObjectToIOFixed64(parameters->getObject(kHIDAccelIndexKey)); 1949 1950 outParams.gain[0] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelGainLinearKey)); 1951 outParams.gain[1] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelGainParabolicKey)); 1952 outParams.gain[2] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelGainCubicKey)); 1953 outParams.gain[3] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelGainQuarticKey)); 1954 1955 outParams.tangent[0] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelTangentSpeedLinearKey)); 1956 outParams.tangent[1] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelTangentSpeedParabolicRootKey)); 1957// outParams.tangent[2] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelTangentSpeedCubicRootKey)); 1958// outParams.tangent[3] = OSObjectToIOFixed64(parameters->getObject(kHIDAccelTangentSpeedQuarticRootKey)); 1959 1960 return ((outParams.gain[0] != 0LL) || 1961 (outParams.gain[1] != 0LL) || 1962 (outParams.gain[2] != 0LL) || 1963 (outParams.gain[3] != 0LL)); 1964 1965exit_early: 1966 return false; 1967} 1968 1969bool 1970PACurvesSetupAccelParams (OSArray *parametricCurves, 1971 IOFixed64 desired, 1972 IOFixed64 devScale, 1973 IOFixed64 crsrScale, 1974 IOHIPointing__PAParameters &primaryParams, 1975 IOHIPointing__PASecondaryParameters &secondaryParams) 1976{ 1977 bool success = false; 1978 OSCollectionIterator *itr = NULL; 1979 OSDictionary *dict = NULL; 1980 1981 IOHIPointing__PAParameters high_curve_params; 1982 IOHIPointing__PAParameters low_curve_params; 1983 1984// IOLog("%s %d: Called with %08x, %08x, %08x\n", __PRETTY_FUNCTION__, __LINE__, desired.asFixed(), devScale.asFixed(), crsrScale.asFixed()); 1985 1986 require(parametricCurves, exit_early); 1987 require(crsrScale > 0LL, exit_early); 1988 require(devScale > 0LL, exit_early); 1989 require(desired > 0LL, exit_early); 1990 1991 itr = OSCollectionIterator::withCollection(parametricCurves); 1992 require(itr, exit_early); 1993 1994 while (!success) { 1995 itr->reset(); 1996 dict = OSDynamicCast(OSDictionary, itr->getNextObject()); 1997 require(PACurvesFillParamsFromDict(dict, devScale, crsrScale, low_curve_params), 1998 exit_early); 1999 2000 while (!success && (NULL != dict)) { 2001 if (!PACurvesFillParamsFromDict(dict, devScale, crsrScale, high_curve_params)) { 2002 break; 2003 } 2004 if (desired <= high_curve_params.accelIndex) { 2005 success = true; 2006 } 2007 else { 2008 low_curve_params = high_curve_params; 2009 } 2010 dict = OSDynamicCast(OSDictionary, itr->getNextObject()); 2011 } 2012 2013 require(success || !itr->isValid(), exit_early); 2014 }; 2015 2016 if ( high_curve_params.accelIndex > low_curve_params.accelIndex ) { 2017 IOFixed64 ratio = (desired - low_curve_params.accelIndex) / (high_curve_params.accelIndex - low_curve_params.accelIndex); 2018 int index; 2019 2020// IOLog("%s %d: Using %08x, %08x, %08x\n", __PRETTY_FUNCTION__, __LINE__, high_curve_params.accelIndex.asFixed(), low_curve_params.accelIndex.asFixed(), ratio.asFixed()); 2021 2022 primaryParams.deviceMickysDivider = high_curve_params.deviceMickysDivider; 2023 primaryParams.cursorSpeedMultiplier = high_curve_params.cursorSpeedMultiplier; 2024 primaryParams.accelIndex = desired; 2025 2026 for (index = 0; index < 4; index++) { 2027 primaryParams.gain[index] = low_curve_params.gain[index] + (high_curve_params.gain[index] - low_curve_params.gain[index]) * ratio; 2028 if (primaryParams.gain[index] < 0LL) 2029 primaryParams.gain[index].fromFixed(0); 2030 } 2031 for (index = 0; index < 2; index++) { 2032 primaryParams.tangent[index] = low_curve_params.tangent[index] + (high_curve_params.tangent[index] - low_curve_params.tangent[index]) * ratio; 2033 if (primaryParams.tangent[index] < 0LL) 2034 primaryParams.tangent[index].fromFixed(0); 2035 } 2036 } 2037 else { 2038 primaryParams = high_curve_params; 2039 } 2040 2041 success = ((primaryParams.gain[0] != 0LL) || 2042 (primaryParams.gain[1] != 0LL) || 2043 (primaryParams.gain[2] != 0LL) || 2044 (primaryParams.gain[3] != 0LL)); 2045 2046 // calculate secondary values 2047 bzero(&secondaryParams, sizeof(secondaryParams)); 2048 if ((primaryParams.tangent[1] > 0LL) && (primaryParams.tangent[1] < primaryParams.tangent[0])) 2049 secondaryParams.firstTangent = 1; 2050 2051 if (secondaryParams.firstTangent == 0) { 2052 secondaryParams.y0 = IOQuarticFunction(primaryParams.tangent[0], primaryParams.gain); 2053 secondaryParams.m0 = IOQuarticDerivative(primaryParams.tangent[0], primaryParams.gain); 2054 secondaryParams.b0 = secondaryParams.y0 - secondaryParams.m0 * primaryParams.tangent[0]; 2055 secondaryParams.y1 = secondaryParams.m0 * primaryParams.tangent[1] + secondaryParams.b0; 2056 } 2057 else { 2058 secondaryParams.y1 = IOQuarticFunction( primaryParams.tangent[1], primaryParams.gain ); 2059 secondaryParams.m0 = IOQuarticDerivative( primaryParams.tangent[1], primaryParams.gain ); 2060 } 2061 2062 secondaryParams.m_root = secondaryParams.m0 * secondaryParams.y1 * 2LL; 2063 secondaryParams.b_root = exponent(secondaryParams.y1, 2) - secondaryParams.m_root * primaryParams.tangent[1]; 2064 2065exit_early: 2066 if (itr) { 2067 itr->release(); 2068 } 2069 2070 return success; 2071} 2072 2073OSDictionary* 2074PACurvesDebugDictionary(IOHIPointing__PAParameters &primaryParams, 2075 IOHIPointing__PASecondaryParameters &secondaryParams) 2076{ 2077 OSDictionary *result = OSDictionary::withCapacity(20); 2078 2079 require(result, exit_early); 2080 2081#define ADD_NUMBER_FOR(X) \ 2082 do { \ 2083 OSNumber *value = OSNumber::withNumber(X.as64(), 64); \ 2084 if (value) { \ 2085 result->setObject(#X, value); \ 2086 value->release(); \ 2087 } \ 2088 } \ 2089 while (0) 2090 2091 ADD_NUMBER_FOR(primaryParams.deviceMickysDivider); 2092 ADD_NUMBER_FOR(primaryParams.cursorSpeedMultiplier); 2093 ADD_NUMBER_FOR(primaryParams.accelIndex); 2094 ADD_NUMBER_FOR(primaryParams.gain[0]); 2095 ADD_NUMBER_FOR(primaryParams.gain[1]); 2096 ADD_NUMBER_FOR(primaryParams.gain[2]); 2097 ADD_NUMBER_FOR(primaryParams.gain[3]); 2098 ADD_NUMBER_FOR(primaryParams.tangent[0]); 2099 ADD_NUMBER_FOR(primaryParams.tangent[1]); 2100 2101 ADD_NUMBER_FOR(secondaryParams.m0); 2102 ADD_NUMBER_FOR(secondaryParams.b0); 2103 ADD_NUMBER_FOR(secondaryParams.y0); 2104 ADD_NUMBER_FOR(secondaryParams.y1); 2105 ADD_NUMBER_FOR(secondaryParams.m_root); 2106 ADD_NUMBER_FOR(secondaryParams.b_root); 2107 2108#undef ADD_NUMBER_FOR 2109 2110exit_early: 2111 return result; 2112} 2113 2114IOFixed64 2115PACurvesGetAccelerationMultiplier(const IOFixed64 device_speed_mickeys, 2116 const IOHIPointing__PAParameters ¶ms, 2117 const IOHIPointing__PASecondaryParameters &secondaryParams) 2118{ 2119 IOFixed64 result; // defaults to zero 2120 2121 if ((device_speed_mickeys > result) && (params.deviceMickysDivider != result)) { 2122 IOFixed64 standardized_speed = device_speed_mickeys / params.deviceMickysDivider; 2123 IOFixed64 accelerated_speed; 2124 if ((params.tangent[secondaryParams.firstTangent] != 0LL) && (standardized_speed <= params.tangent[secondaryParams.firstTangent])) { 2125 accelerated_speed = IOQuarticFunction(standardized_speed, params.gain); 2126 } 2127 else { 2128 if ((secondaryParams.firstTangent == 0) && (params.tangent[1] != 0LL) && (standardized_speed <= params.tangent[1])) { 2129 accelerated_speed = secondaryParams.m0 * standardized_speed + secondaryParams.b0; 2130 } 2131 else { 2132 accelerated_speed.fromIntFloor(llsqrt(((secondaryParams.m_root * standardized_speed) + secondaryParams.b_root).as64())); 2133 } 2134 } 2135 IOFixed64 accelerated_pixels = accelerated_speed * params.cursorSpeedMultiplier; 2136 result = accelerated_pixels / device_speed_mickeys; 2137 } 2138 else { 2139 result.fromFixed(1); 2140 } 2141 2142 return result; 2143} 2144 2145// RY: This function contains the original portions of 2146// scalePointer. This was separated out to accomidate 2147// the acceleration of other axes 2148void ScaleAxes (void * scaleSegments, int * axis1p, IOFixed *axis1Fractp, int * axis2p, IOFixed *axis2Fractp) 2149{ 2150 SInt32 dx, dy; 2151 SInt32 mag; 2152 IOFixed scale; 2153 CursorDeviceSegment * segment; 2154 2155 if( !scaleSegments) 2156 return; 2157 2158 dx = (*axis1p) << 16; 2159 dy = (*axis2p) << 16; 2160 2161 // mag is (x^2 + y^2)^0.5 and converted to fixed point 2162 mag = (lsqrt(*axis1p * *axis1p + *axis2p * *axis2p)) << 16; 2163 if (mag == 0) 2164 return; 2165 2166 // scale 2167 for( 2168 segment = (CursorDeviceSegment *) scaleSegments; 2169 mag > segment->devUnits; 2170 segment++) {} 2171 2172 scale = IOFixedDivide( 2173 segment->intercept + IOFixedMultiply( mag, segment->slope ), 2174 mag ); 2175 2176 dx = IOFixedMultiply( dx, scale ); 2177 dy = IOFixedMultiply( dy, scale ); 2178 2179 // add fract parts 2180 dx += *axis1Fractp; 2181 dy += *axis2Fractp; 2182 2183 *axis1p = dx / 65536; 2184 *axis2p = dy / 65536; 2185 2186 // get fractional part with sign extend 2187 if( dx >= 0) 2188 *axis1Fractp = dx & 0xffff; 2189 else 2190 *axis1Fractp = dx | 0xffff0000; 2191 if( dy >= 0) 2192 *axis2Fractp = dy & 0xffff; 2193 else 2194 *axis2Fractp = dy | 0xffff0000; 2195} 2196 2197void IOHIPointing::_relativePointerEvent( IOHIPointing * self, 2198 int buttons, 2199 /* deltaX */ int dx, 2200 /* deltaY */ int dy, 2201 /* atTime */ AbsoluteTime ts) 2202{ 2203 RelativePointerEventCallback rpeCallback; 2204 rpeCallback = (RelativePointerEventCallback)self->_relativePointerEventAction; 2205 2206 if (rpeCallback) 2207 (*rpeCallback)(self->_relativePointerEventTarget, 2208 buttons, 2209 dx, 2210 dy, 2211 ts, 2212 self, 2213 0); 2214} 2215 2216 /* Tablet event reporting */ 2217void IOHIPointing::_absolutePointerEvent(IOHIPointing * self, 2218 int buttons, 2219 /* at */ IOGPoint * newLoc, 2220 /* withBounds */ IOGBounds *bounds, 2221 /* inProximity */ bool proximity, 2222 /* withPressure */ int pressure, 2223 /* withAngle */ int stylusAngle, 2224 /* atTime */ AbsoluteTime ts) 2225{ 2226 AbsolutePointerEventCallback apeCallback; 2227 apeCallback = (AbsolutePointerEventCallback)self->_absolutePointerEventAction; 2228 2229 if (apeCallback) 2230 (*apeCallback)(self->_absolutePointerEventTarget, 2231 buttons, 2232 newLoc, 2233 bounds, 2234 proximity, 2235 pressure, 2236 stylusAngle, 2237 ts, 2238 self, 2239 0); 2240 2241} 2242 2243 /* Mouse scroll wheel event reporting */ 2244void IOHIPointing::_scrollWheelEvent(IOHIPointing *self, 2245 short deltaAxis1, 2246 short deltaAxis2, 2247 short deltaAxis3, 2248 AbsoluteTime ts) 2249{ 2250 ScrollWheelEventCallback sweCallback; 2251 sweCallback = (ScrollWheelEventCallback)self->_scrollWheelEventAction; 2252 2253 if (sweCallback) 2254 (*sweCallback)(self->_scrollWheelEventTarget, 2255 (short) deltaAxis1, 2256 (short) deltaAxis2, 2257 (short) deltaAxis3, 2258 self->_scrollFixedDeltaAxis1, 2259 self->_scrollFixedDeltaAxis2, 2260 self->_scrollFixedDeltaAxis3, 2261 self->_scrollPointDeltaAxis1, 2262 self->_scrollPointDeltaAxis2, 2263 self->_scrollPointDeltaAxis3, 2264 self->_scrollType, 2265 ts, 2266 self, 2267 0); 2268} 2269