1/* 2 * @APPLE_LICENSE_HEADER_START@ 3 * 4 * Copyright (c) 1999-2012 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#define DEBUG_ASSERT_COMPONENT_NAME_STRING "IOHIDSystem" 25//#define DEBUG_ASSERT_PRODUCTION_CODE 0 26 27 28#include <AssertMacros.h> 29#include "IOHIDKeys.h" 30 31#include "IOHIDEvent.h" 32#include <IOKit/system.h> 33#include <IOKit/assert.h> 34 35#include <libkern/c++/OSContainers.h> 36#include <libkern/c++/OSCollectionIterator.h> 37 38#include <kern/queue.h> 39 40#include <IOKit/IOTimerEventSource.h> 41#include <IOKit/IOCommandGate.h> 42#include <IOKit/IOMessage.h> 43#include <IOKit/IOWorkLoop.h> 44#include <IOKit/IOPlatformExpert.h> 45#include <IOKit/hidsystem/IOHIDevice.h> 46#include <IOKit/hidsystem/IOHIDParameter.h> 47#include <IOKit/usb/USB.h> 48#include <IOKit/pwr_mgt/RootDomain.h> 49#include <kern/clock.h> 50#include "IOHIDShared.h" 51#include "IOHIDSystem.h" 52#include "IOHIDEventService.h" 53#include "IOHIDPointing.h" 54#include "IOHIDKeyboard.h" 55#include "IOHIDConsumer.h" 56#include "IOHITablet.h" 57#include "IOHIDPointingDevice.h" 58#include "IOHIDKeyboardDevice.h" 59#include "IOHIDPrivate.h" 60#include "IOHIDPrivateKeys.h" 61#include "IOHIDEventServiceQueue.h" 62#include "IOLLEvent.h" 63 64#include "ev_private.h" 65#include "IOHIDUserClient.h" 66#include "AppleHIDUsageTables.h" 67#include "IOHIDKeyboard.h" 68#include "IOHIDFamilyTrace.h" 69#include "IOHIDWorkLoop.h" 70#include "IOHIDSystemCursorHelper.h" 71 72#include <sys/kdebug.h> 73#include <sys/proc.h> 74 75#ifdef __cplusplus 76 extern "C" 77 { 78 #include <UserNotification/KUNCUserNotifications.h> 79 void cons_cinput( char c); 80 } 81#endif 82 83extern "C" { 84 #include <sys/kauth.h> 85 86 #define CONFIG_MACF 1 87 #include <security/mac_framework.h> 88 #undef CONFIG_MACF 89}; 90 91bool displayWranglerUp( OSObject *, void *, IOService * ); 92 93#if 0 94#define PROFILE_TRACE(X) IOHID_DEBUG(kIOHIDDebugCode_Profiling, X, __LINE__, 0, 0) 95#else 96#define PROFILE_TRACE(X) 97#endif 98 99static IOHIDSystem * evInstance = 0; 100MasterAudioFunctions *masterAudioFunctions = 0; 101 102#define xpr_ev_cursor(x, a, b, c, d, e) 103 104#ifndef kIOFBWaitCursorFramesKey 105#define kIOFBWaitCursorFramesKey "IOFBWaitCursorFrames" 106#endif 107#ifndef kIOFBWaitCursorPeriodKey 108#define kIOFBWaitCursorPeriodKey "IOFBWaitCursorPeriod" 109#endif 110 111#ifndef kIOUserClientCrossEndianKey 112#define kIOUserClientCrossEndianKey "IOUserClientCrossEndian" 113#endif 114 115#ifndef kIOUserClientCrossEndianCompatibleKey 116#define kIOUserClientCrossEndianCompatibleKey "IOUserClientCrossEndianCompatible" 117#endif 118 119#ifndef abs 120#define abs(_a) ((_a >= 0) ? _a : -_a) 121#endif 122 123#define NORMAL_MODIFIER_MASK (NX_COMMANDMASK | NX_CONTROLMASK | NX_SHIFTMASK | NX_ALTERNATEMASK) 124 125#define EV_MAX_SCREENS 32 126 127#define IDLE_HID_ACTIVITY_NSECS ((uint64_t)(5*60*NSEC_PER_SEC)) 128 129static UInt8 ScalePressure(unsigned pressure) 130{ 131 return ((pressure * (unsigned long long)EV_MAXPRESSURE) / (unsigned)(65535LL)); 132} 133 134#define EV_NS_TO_TICK(ns) AbsoluteTimeToTick(ns) 135#define EV_TICK_TO_NS(tick,ns) TickToAbsoluteTime(tick,ns) 136 137/* COMMAND GATE COMPATIBILITY TYPE DEFS */ 138typedef struct _IOHIDCmdGateActionArgs { 139 void* arg0; 140 void* arg1; 141 void* arg2; 142 void* arg3; 143 void* arg4; 144 void* arg5; 145 void* arg6; 146 void* arg7; 147 void* arg8; 148 void* arg9; 149 void* arg10; 150 void* arg11; 151} IOHIDCmdGateActionArgs; 152/* END COMMAND GATE COMPATIBILITY TYPE DEFS */ 153 154/* HID SYSTEM EVENT LOCK OUT SUPPORT */ 155 156static bool gKeySwitchLocked = false; 157static bool gUseKeyswitch = true; 158static IONotifier * gSwitchNotification = 0; 159 160// IONotificationHandler 161static bool keySwitchNotificationHandler(void *target __unused, void *refCon __unused, IOService *service, IONotifier * /* ignored */) 162{ 163 164 gKeySwitchLocked = (service->getProperty("Keyswitch") == kOSBooleanTrue); 165 166 return true; 167} 168 169/* END HID SYSTEM EVENT LOCK OUT SUPPORT */ 170 171// RY: Consume any keyboard events that come in before the 172// deadline after the system wakes up or if the keySwitch is locked 173#define kHIDConsumeCauseNone 0x00 174#define kHIDConsumeCauseKeyLock 0x01 175#define kHIDConsumeCauseDeadline 0x02 176 177static inline UInt32 ShouldConsumeHIDEvent(AbsoluteTime ts, AbsoluteTime deadline, bool checkKeySwitch = true ) 178{ 179 if (checkKeySwitch && gKeySwitchLocked && gUseKeyswitch) 180 return kHIDConsumeCauseKeyLock; 181 182 if ( AbsoluteTime_to_scalar(&ts) == 0 ) 183 clock_get_uptime(&ts); 184 185 if (CMP_ABSOLUTETIME(&ts, &deadline) <= 0) 186 { 187 return kHIDConsumeCauseDeadline; 188 } 189 190 return kHIDConsumeCauseNone; 191} 192 193#define WAKE_DISPLAY_ON_MOVEMENT (NX_WAKEMASK & MOVEDEVENTMASK) 194 195#define DISPLAY_IS_ENABLED (displayState & IOPMDeviceUsable) 196 197#define TICKLE_DISPLAY(event) \ 198{ \ 199 if (!evStateChanging && displayManager) { \ 200 IOHID_DEBUG(kIOHIDDebugCode_DisplayTickle, event, __LINE__, 0, 0); \ 201 if (!DISPLAY_IS_ENABLED) kprintf("IOHIDSystem tickle when screen off for event %d at line %d\n", (int)event, __LINE__); \ 202 displayManager->activityTickle(IOHID_DEBUG_CODE(event)); \ 203 } \ 204 updateHidActivity(); \ 205} 206 207#define CONVERT_EV_TO_HW_BUTTONS(ev_buttons,hw_buttons) \ 208 hw_buttons = ev_buttons & ~7; /* Keep everything but bottom 3 bits. */ \ 209 hw_buttons |= (ev_buttons & 3) << 1; /* Map bits 01 to 12 */ \ 210 hw_buttons |= (ev_buttons & 4) >> 2; /* Map bit 2 back to bit 0 */ 211 212#define CONVERT_EV_TO_HW_DELTA(ev_buttons,hw_delta) \ 213 hw_delta = ev_buttons & ~7; \ 214 hw_delta |= (ev_buttons & 3) << 1; /* Map bits 01 to 12 */ \ 215 hw_delta |= (ev_buttons & 4) >> 2; /* Map bit 2 back to bit 0 */ 216 217#define CONVERT_HW_TO_WV_BUTTONS(hw_buttons,ev_buttons) \ 218 ev_buttons = hw_buttons & ~7; /* Keep everything but bottom 3 bits. */ \ 219 ev_buttons |= (hw_buttons & 6) >> 1; /* Map bits 12 to 01 */ \ 220 ev_buttons |= (hw_buttons & 1) << 2; /* Map bit 0 to bit 2 */ 221 222 223 224enum { 225 // Options for IOHIDPostEvent() 226 kIOHIDSetGlobalEventFlags = 0x00000001, 227 kIOHIDSetCursorPosition = 0x00000002, 228 kIOHIDSetRelativeCursorPosition = 0x00000004, 229 kIOHIDPostHIDManagerEvent = 0x00000008 230}; 231 232#define kIOHIDPowerOnThresholdNS (500ULL * kMillisecondScale) // 1/2 second 233#define kIOHIDRelativeTickleThresholdNS (50ULL * kMillisecondScale) // 1/20 second 234#define kIOHIDRelativeTickleThresholdPixel 3 235#define kIOHIDDispaySleepAbortThresholdNS (5ULL * kSecondScale) // 5 seconds 236#define kIOHIDChattyMouseSuppressionDelayNS kSecondScale // 1 second 237#define kIOHIDSystenDistantFuture INT64_MAX 238 239static AbsoluteTime gIOHIDPowerOnThresoldAbsoluteTime; 240static AbsoluteTime gIOHIDRelativeTickleThresholdAbsoluteTime; 241// gIOHIDDisplaySleepAbortThresholdAbsoluteTime - Time before which display sleep 242// can be aborted by a mouse/scroll motion 243static AbsoluteTime gIOHIDDisplaySleepAbortThresholdAbsoluteTime; 244static AbsoluteTime gIOHIDZeroAbsoluteTime; 245 246//************************************************************ 247// Cached Mouse Event Info Support 248//************************************************************ 249enum { 250 kCachedMousePointingTabletEventDispFlag = 0x01, 251 kCachedMousePointingTabletEventPendFlag = 0x02, 252 kCachedMousePointingEventDispFlag = 0x04, 253 kCachedMouseTabletEventDispFlag = 0x08 254}; 255 256typedef struct _CachedMouseEventStruct { 257 OSObject * service; 258 UInt64 eventDeadline; 259 UInt64 reportInterval_ns; 260 SInt32 lastButtons; 261 SInt32 accumX; 262 SInt32 accumY; 263 bool proximity; 264 UInt32 state; 265 UInt8 subType; 266 NXEventData tabletData; 267 NXEventData proximityData; 268 UInt16 pointerFractionX; 269 UInt16 pointerFractionY; 270 UInt8 lastPressure; 271} CachedMouseEventStruct; 272 273//************************************************************ 274static void CalculateEventCountsForService(CachedMouseEventStruct *mouseStruct) 275{ 276 if ( mouseStruct ) { 277 mouseStruct->reportInterval_ns = 8000000; // default to 8ms 278 if ( mouseStruct->service ) { 279 IORegistryEntry *senderEntry = OSDynamicCast(IORegistryEntry, mouseStruct->service); 280 if (senderEntry) { 281 OSNumber *reportInterval_us = (OSNumber*)senderEntry->copyProperty(kIOHIDReportIntervalKey, gIOServicePlane, kIORegistryIterateRecursively| kIORegistryIterateParents); 282 if (OSDynamicCast(OSNumber, reportInterval_us)) { 283 mouseStruct->reportInterval_ns = reportInterval_us->unsigned64BitValue() * 1000; 284 } 285 else { 286 IOLog("No interval found for %s. Using %lld\n", senderEntry->getLocation(), mouseStruct->reportInterval_ns); 287 } 288 OSSafeReleaseNULL(reportInterval_us); 289 } 290 } 291 } 292} 293 294//************************************************************ 295static void CalculateEventCountsForAllServices(OSArray *events) 296{ 297 if ( events ) 298 { 299 int count = events->getCount(); 300 int i; 301 302 for ( i=0; i<count; i++ ) 303 { 304 OSData *data; 305 CachedMouseEventStruct *mouseEvent; 306 if ( (data = (OSData *)events->getObject(i) ) && 307 (mouseEvent = (CachedMouseEventStruct *)data->getBytesNoCopy()) ) 308 { 309 CalculateEventCountsForService(mouseEvent); 310 } 311 } 312 } 313} 314 315//************************************************************ 316static SInt32 GetCachedMouseButtonStates(OSArray *events) 317{ 318 CachedMouseEventStruct * mouseEvent = 0; 319 OSData * data = 0; 320 SInt32 buttonState = 0; 321 UInt32 count = 0; 322 UInt32 i = 0; 323 324 if ( events ) 325 { 326 count = events->getCount(); 327 328 for ( i=0; i<count; i++ ) 329 { 330 if ( (data = (OSData *)events->getObject(i)) && 331 (mouseEvent = (CachedMouseEventStruct *)data->getBytesNoCopy())) 332 { 333 buttonState |= mouseEvent->lastButtons; 334 } 335 } 336 } 337 338 return buttonState; 339} 340 341//************************************************************ 342static void ClearCachedMouseButtonStates(OSArray *events) 343{ 344 CachedMouseEventStruct * mouseEvent = 0; 345 OSData * data = 0; 346 UInt32 count = 0; 347 UInt32 i = 0; 348 349 if ( events ) 350 { 351 count = events->getCount(); 352 353 for ( i=0; i<count; i++ ) 354 { 355 if ( (data = (OSData *)events->getObject(i)) && 356 (mouseEvent = (CachedMouseEventStruct *)data->getBytesNoCopy())) 357 { 358 mouseEvent->lastButtons = 0; 359 CalculateEventCountsForService(mouseEvent); 360 } 361 } 362 } 363} 364 365//************************************************************ 366static CachedMouseEventStruct * GetCachedMouseEventForService(OSArray *events, OSObject *service, UInt32 * index = 0) 367{ 368 CachedMouseEventStruct * mouseEvent = 0; 369 OSData * data = 0; 370 UInt32 count = 0; 371 UInt32 i = 0; 372 373 if ( events ) 374 { 375 count = events->getCount(); 376 377 for ( i=0; i<count; i++ ) 378 { 379 if ( (data = (OSData *)events->getObject(i)) && 380 (mouseEvent = (CachedMouseEventStruct *)data->getBytesNoCopy()) && 381 (mouseEvent->service == service) ) 382 { 383 if ( index ) *index = i; 384 return mouseEvent; 385 } 386 } 387 } 388 389 return NULL; 390} 391 392//************************************************************ 393static void AppendNewCachedMouseEventForService(OSArray *events, OSObject *service) 394{ 395 CachedMouseEventStruct temp; 396 OSData * data; 397 398 bzero(&temp, sizeof(CachedMouseEventStruct)); 399 temp.service = service; 400 401 data = OSData::withBytes(&temp, sizeof(CachedMouseEventStruct)); 402 events->setObject(data); 403 data->release(); 404 CalculateEventCountsForAllServices(events); 405} 406 407//************************************************************ 408static void RemoveCachedMouseEventForService(OSArray *events, OSObject *service) 409{ 410 UInt32 index; 411 412 if ( events && GetCachedMouseEventForService(events, service, &index) ) 413 { 414 events->removeObject(index); 415 } 416 CalculateEventCountsForAllServices(events); 417} 418 419//************************************************************ 420// NX System Info Support 421//************************************************************ 422#define kNXSystemInfoKey "NXSystemInfo" 423 424static void AppendNewNXSystemInfoForService(OSArray *systemInfo, IOService *service) 425{ 426 OSDictionary * deviceInfo = NULL; 427 OSNumber * deviceID = NULL; 428 IOHIDevice * hiDevice = NULL; 429 OSObject * object = NULL; 430 431 if ( !systemInfo || !(hiDevice = OSDynamicCast(IOHIDevice, service))) 432 return; 433 434 deviceInfo = OSDictionary::withCapacity(4); 435 436 if ( !deviceInfo ) 437 return; 438 439 deviceID = OSNumber::withNumber(hiDevice->getRegistryEntryID(), 64); 440 if (deviceID) 441 { 442 deviceInfo->setObject("serviceID", deviceID); 443 deviceID->release(); 444 } 445 446 object = hiDevice->copyProperty(kIOHIDKindKey); 447 if ( object ) 448 { 449 deviceInfo->setObject(kIOHIDKindKey, object); 450 object->release(); 451 } 452 453 object = hiDevice->copyProperty(kIOHIDInterfaceIDKey); 454 if ( object ) 455 { 456 deviceInfo->setObject(kIOHIDInterfaceIDKey, object); 457 object->release(); 458 } 459 460 object = hiDevice->copyProperty(kIOHIDSubinterfaceIDKey); 461 if ( object ) 462 { 463 deviceInfo->setObject(kIOHIDSubinterfaceIDKey, object); 464 object->release(); 465 } 466 467 if ( hiDevice->metaCast("AppleADBKeyboard") || (hiDevice->getProvider() && hiDevice->getProvider()->metaCast("AppleEmbeddedKeyboard")) ) 468 deviceInfo->setObject("built-in", kOSBooleanTrue); 469 470 // RY: Hack for rdar://4365935 Turning on NumLock causes Keyboard 471 // Viewer to display the external keyboard 472 // Because keyboardType information is not passed in special key 473 // events, CG infers that this event comes from the default keyboard, 474 // or first keyboard in NXSystemInfo. Unforunately, in some cases a 475 // USB external keyboard will enumerate before a USB internal keyboard. 476 // If this is encountered, we should alway insert the internal keyboard 477 // at the beginning of the list. This will cause CG to guess correctly. 478 // RY: Extension for rdar://4418444 Keyboard Viewer defaults to wrong 479 // keyboard layout when launched. 480 // We should also insert keyboards to the front of the list, prefering 481 // Apple, if the front does not already contain a built-in keyboard. 482 OSDictionary * tempSystemInfo; 483 OSNumber * number; 484 485 // If a keyboard 486 if ( ((hiDevice->hidKind() == kHIKeyboardDevice) && (hiDevice->deviceType() != 0))&& 487 // And keyboard is built-in 488 ( (deviceInfo->getObject("built-in") == kOSBooleanTrue) || 489 // Or, first item in the list is not a keyboard 490 !((tempSystemInfo = OSDynamicCast(OSDictionary, systemInfo->getObject(0))) && (number = OSDynamicCast(OSNumber,tempSystemInfo->getObject(kIOHIDKindKey))) && (number->unsigned32BitValue() == kHIKeyboardDevice)) || 491 // Or, if the keyboard is Apple and the first item in the list is not built-in 492 // vtn3: potentially unsafe, but a pain to fix. leave it for now. 493 ((number = OSDynamicCast(OSNumber, hiDevice->getProperty(kIOHIDVendorIDKey))) && (number->unsigned32BitValue() == kIOUSBVendorIDAppleComputer) && (tempSystemInfo->getObject("built-in") != kOSBooleanTrue)) ) ) 494 { 495 systemInfo->setObject(0, deviceInfo); 496 } 497 else 498 { 499 systemInfo->setObject(deviceInfo); 500 } 501 502 deviceInfo->release(); 503} 504 505static void RemoveNXSystemInfoForService(OSArray *systemInfo, IOService *service) 506{ 507 OSDictionary * deviceInfo = NULL; 508 OSNumber * serviceID = NULL; 509 UInt32 i, count; 510 511 if ( !systemInfo || !OSDynamicCast(IOHIDevice, service)) 512 return; 513 514 count = systemInfo->getCount(); 515 516 for ( i=0; i<count; i++ ) 517 { 518 if ( (deviceInfo = (OSDictionary *)systemInfo->getObject(i)) && 519 (serviceID = (OSNumber *)deviceInfo->getObject("serviceID")) && 520 (serviceID->unsigned64BitValue() == service->getRegistryEntryID()) ) 521 { 522 systemInfo->removeObject(i); 523 break; 524 } 525 } 526} 527 528//************************************************************ 529// keyboardEventQueue support 530//************************************************************ 531static queue_head_t gKeyboardEQ; 532static IOLock * gKeyboardEQLock = 0; 533 534typedef IOReturn (*KeyboardEQAction)(IOHIDSystem * self, void *args); 535 536typedef struct _KeyboardEQElement { 537 queue_chain_t link; 538 539 KeyboardEQAction action; 540 OSObject * sender; 541 AbsoluteTime ts; 542 543 union { 544 struct { 545 unsigned eventType; 546 unsigned flags; 547 unsigned key; 548 unsigned charCode; 549 unsigned charSet; 550 unsigned origCharCode; 551 unsigned origCharSet; 552 unsigned keyboardType; 553 bool repeat; 554 } keyboard; 555 struct { 556 unsigned eventType; 557 unsigned flags; 558 unsigned key; 559 unsigned flavor; 560 UInt64 guid; 561 bool repeat; 562 } keyboardSpecial; 563 struct { 564 unsigned flags; 565 } flagsChanged; 566 } event; 567} KeyboardEQElement; 568 569#define KEYBOARD_EQ_LOCK if (gKeyboardEQLock) IOLockLock(gKeyboardEQLock); 570#define KEYBOARD_EQ_UNLOCK if (gKeyboardEQLock) IOLockUnlock(gKeyboardEQLock); 571 572 573static UInt8 stickyKeysState = false; 574 575static void notifyHIDevices(IOService *service, OSArray *hiDevices, UInt32 type) 576{ 577 IOHIKeyboard *keyboard; 578 579 if(!stickyKeysState || !hiDevices) 580 return; 581 582 switch ( type ) 583 { 584 case kIOHIDSystem508MouseClickMessage: 585 case kIOHIDSystem508SpecialKeyDownMessage: 586 for(unsigned index=0; index<hiDevices->getCount(); index++) 587 { 588 keyboard = OSDynamicCast(IOHIKeyboard, hiDevices->getObject(index)); 589 if (keyboard) 590 keyboard->IOHIKeyboard::message(type, service); 591 } 592 break; 593 } 594} 595 596/* This function exists because IOHIDSystem uses OSArrays of OSNumbers. Since 597 * OSArray::containsObject() compares by pointer equality instead of 598 * OSObject::isEqualTo(). OSNumbers cannot be found by value with 599 * containsObject(), so we must use this instead. 600 */ 601#define kObjectNotFound ((unsigned int) -1) 602static unsigned int 603getArrayIndexForObject(OSArray *array, OSObject* object) 604{ 605 OSObject *tmp; 606 u_int i; 607 608 for (i = 0; i < array->getCount(); ++i) { 609 tmp = array->getObject(i); 610 if (tmp->isEqualTo(object)) { 611 return i; 612 } 613 } 614 615 return kObjectNotFound; 616} 617 618static void 619hidActivityThread_cb(thread_call_param_t us, thread_call_param_t ) 620{ 621 ((IOHIDSystem *)us)->hidActivityChecker(); 622} 623 624typedef struct { 625 IOCommandGate::Action handler; 626 IOService *newService; 627} 628IOHIDSystem_notificationData; 629 630#define super IOService 631OSDefineMetaClassAndStructors(IOHIDSystem, IOService); 632 633struct IOHIDSystem::ExpansionData 634{ 635 // The goal of the cursorHelper is to isolate all of the cursor 636 // calculations and updates into one class. 637 IOHIDSystemCursorHelper cursorHelper; 638 UInt32 delayedScrollMomentum; 639 UInt8 scDirection; 640 UInt8 scIgnoreMomentum; 641 UInt8 scMouseCanReset; 642 UInt8 scIncrementedThisPhrase; 643 UInt16 scCount; 644 UInt16 scCountMax; 645 IOFixed64 scAccelerationFactor; 646 UInt64 scMinDeltaSqToStart; 647 UInt64 scMinDeltaSqToSustain; 648 UInt64 scLastScrollEndTime; 649 UInt64 scLastScrollSustainTime; 650 UInt64 scMaxTimeDeltaBetween; 651 UInt64 scMaxTimeDeltaToSustain; 652 IOFixedPoint64 scLastScrollLocation; 653 OSDictionary *devicePhaseState; 654 655 UInt64 periodicEventLast; 656 UInt64 periodicEventNext; 657 UInt64 cursorEventLast; 658 UInt64 cursorMoveLast; 659 UInt64 cursorMoveDelta; 660 UInt64 cursorWaitLast; 661 UInt64 cursorWaitDelta; 662 663 IONotifier * displayWranglerMatching; 664 665 bool continuousCursor; 666 bool hidActivityIdle; // Is HID activity idle for more than IDLE_HID_ACTIVITY_NSECS ? 667 AbsoluteTime lastTickleTime; 668 thread_call_t hidActivityThread; 669 670 // async delayed notifications 671 IOLock *delayedNotificationLock; 672 OSArray *delayedNotificationArray; 673 IOTimerEventSource *delayedNotificationSource; 674 675 OSDictionary *senderIDDictionary; 676}; 677 678#define _cursorHelper (_privateData->cursorHelper) 679#define _devicePhaseState (_privateData->devicePhaseState) 680#define _delayedScrollMomentum (_privateData->delayedScrollMomentum) 681#define _scCount (_privateData->scCount) 682#define _scCountMax (_privateData->scCountMax) 683#define _scDirection (_privateData->scDirection) 684#define _scIgnoreMomentum (_privateData->scIgnoreMomentum) 685#define _scIncrementedThisPhrase (_privateData->scIncrementedThisPhrase) 686#define _scMouseCanReset (_privateData->scMouseCanReset) 687#define _scMinDeltaSqToStart (_privateData->scMinDeltaSqToStart) 688#define _scMinDeltaSqToSustain (_privateData->scMinDeltaSqToSustain) 689#define _scLastScrollEndTime (_privateData->scLastScrollEndTime) 690#define _scLastScrollSustainTime (_privateData->scLastScrollSustainTime) 691#define _scMaxTimeDeltaBetween (_privateData->scMaxTimeDeltaBetween) 692#define _scMaxTimeDeltaToSustain (_privateData->scMaxTimeDeltaToSustain) 693#define _scLastScrollLocation (_privateData->scLastScrollLocation) 694#define _scAccelerationFactor (_privateData->scAccelerationFactor) 695 696#define _periodicEventLast (_privateData->periodicEventLast) 697#define _periodicEventNext (_privateData->periodicEventNext) 698#define _cursorEventLast (_privateData->cursorEventLast) 699#define _cursorMoveLast (_privateData->cursorMoveLast) 700#define _cursorMoveDelta (_privateData->cursorMoveDelta) 701#define _cursorWaitLast (_privateData->cursorWaitLast) 702#define _cursorWaitDelta (_privateData->cursorWaitDelta) 703 704#define _displayWranglerMatching (_privateData->displayWranglerMatching) 705 706#define _continuousCursor (_privateData->continuousCursor) 707#define _hidActivityIdle (_privateData->hidActivityIdle) 708#define _lastTickleTime (_privateData->lastTickleTime) 709#define _hidActivityThread (_privateData->hidActivityThread) 710 711#define _delayedNotificationLock (_privateData->delayedNotificationLock) 712#define _delayedNotificationArray (_privateData->delayedNotificationArray) 713#define _delayedNotificationSource (_privateData->delayedNotificationSource) 714 715#define _senderIDDictionary (_privateData->senderIDDictionary) 716 717enum { 718 kScrollDirectionInvalid = 0, 719 kScrollDirectionXPositive, 720 kScrollDirectionXNegative, 721 kScrollDirectionYPositive, 722 kScrollDirectionYNegative, 723 kScrollDirectionZPositive, 724 kScrollDirectionZNegative, 725}; 726 727#define _cursorLog(ts) do { \ 728 if (evg != 0) \ 729 if (evg->logCursorUpdates) { \ 730 _cursorHelper.logPosition(__func__, ts); \ 731 } \ 732 } \ 733 while(false) 734 735#define _cursorLogTimed() do { \ 736 if (evg != 0) \ 737 if (evg->logCursorUpdates) { \ 738 AbsoluteTime ts; \ 739 clock_get_uptime(&ts); \ 740 _cursorHelper.logPosition(__func__, AbsoluteTime_to_scalar(&ts)); \ 741 } \ 742 } \ 743 while(false) 744 745/* Return the current instance of the EventDriver, or 0 if none. */ 746IOHIDSystem * IOHIDSystem::instance() 747{ 748 return evInstance; 749} 750 751#define kDefaultMinimumDelta 0x1ffffffffULL 752 753bool IOHIDSystem::init(OSDictionary * properties) 754{ 755 if (!super::init(properties)) 756 return false; 757 758 _privateData = (ExpansionData*)IOMalloc(sizeof(ExpansionData)); 759 if (!_privateData) 760 return false; 761 bzero(_privateData, sizeof(ExpansionData)); 762 _periodicEventNext = kIOHIDSystenDistantFuture; 763 764 if (!_cursorHelper.init()) 765 return false; 766 _cursorLogTimed(); 767 768 // hard defaults. these exist just to keep the state machine sane. 769 _scMinDeltaSqToStart = _scMinDeltaSqToSustain = kDefaultMinimumDelta; 770 _scAccelerationFactor.fromIntFloor(5); 771 _scCountMax = 2000; 772 773 /* 774 * Initialize minimal state. 775 */ 776 evScreen = NULL; 777 periodicES = 0; 778 eventConsumerES = 0; 779 keyboardEQES = 0; 780 cmdGate = 0; 781 workLoop = 0; 782 cachedEventFlags = 0; 783 displayState = IOPMDeviceUsable; 784 AbsoluteTime_to_scalar(&lastEventTime) = 0; 785 AbsoluteTime_to_scalar(&lastUndimEvent) = 0; 786 AbsoluteTime_to_scalar(&rootDomainStateChangeDeadline) = 0; 787 AbsoluteTime_to_scalar(&displayStateChangeDeadline) = 0; 788 AbsoluteTime_to_scalar(&displaySleepWakeupDeadline) = 0; 789 AbsoluteTime_to_scalar(&gIOHIDZeroAbsoluteTime) = 0; 790 displaySleepDrivenByPM = false; 791 792 793 ioHIDevices = OSArray::withCapacity(2); 794 cachedButtonStates = OSArray::withCapacity(3); 795 touchEventPosters = OSSet::withCapacity(2); 796 consumedKeys = OSArray::withCapacity(5); 797 _senderIDDictionary = OSDictionary::withCapacity(2); 798 799 // RY: Populate cachedButtonStates key=0 with a button State 800 // This will cover all pointing devices that don't support 801 // the new private methods. 802 AppendNewCachedMouseEventForService(cachedButtonStates, 0); 803 804 nanoseconds_to_absolutetime(kIOHIDPowerOnThresholdNS, &gIOHIDPowerOnThresoldAbsoluteTime); 805 nanoseconds_to_absolutetime(kIOHIDRelativeTickleThresholdNS, &gIOHIDRelativeTickleThresholdAbsoluteTime); 806 nanoseconds_to_absolutetime(kIOHIDDispaySleepAbortThresholdNS, &gIOHIDDisplaySleepAbortThresholdAbsoluteTime); 807 808 queue_init(&gKeyboardEQ); 809 gKeyboardEQLock = IOLockAlloc(); 810 return true; 811} 812 813IOHIDSystem * IOHIDSystem::probe(IOService * provider, 814 SInt32 * score) 815{ 816 if (!super::probe(provider,score)) return 0; 817 818 return this; 819} 820 821/* 822 * Perform reusable initialization actions here. 823 */ 824IOWorkLoop * IOHIDSystem::getWorkLoop() const 825{ 826 return workLoop; 827} 828 829bool IOHIDSystem::start(IOService * provider) 830{ 831 bool iWasStarted = false; 832 OSObject *obj = NULL; 833 OSNumber *number = NULL; 834 OSDictionary *matchingDevice = serviceMatching("IOHIDevice"); 835 OSDictionary *matchingService = serviceMatching("IOHIDEventService"); 836 OSDictionary *matchingWrangler = serviceMatching("IODisplayWrangler"); 837 OSDictionary *matchingKeyswitch = serviceMatching("AppleKeyswitch"); 838 IOServiceMatchingNotificationHandler iohidNotificationHandler = OSMemberFunctionCast(IOServiceMatchingNotificationHandler, this, &IOHIDSystem::genericNotificationHandler); 839 840 require(super::start(provider), exit_early); 841 842 _setScrollCountParameters(); 843 844 evInstance = this; 845 846 /* A few details to be set up... */ 847 _cursorHelper.desktopLocation().fromIntFloor(INIT_CURSOR_X, INIT_CURSOR_Y); 848 _cursorHelper.desktopLocationDelta().fromIntFloor(0, 0); 849 _cursorHelper.updateScreenLocation(NULL, NULL); 850 _cursorLogTimed(); 851 _delayedNotificationLock = IOLockAlloc(); 852 _delayedNotificationArray = OSArray::withCapacity(2); 853 854 evScreenSize = sizeof(EvScreen) * EV_MAX_SCREENS; 855 evScreen = (void *) IOMalloc(evScreenSize); 856 bzero(evScreen, evScreenSize); 857 savedParameters = OSDictionary::withCapacity(4); 858 859 require(evScreen && savedParameters && _delayedNotificationLock && _delayedNotificationArray, exit_early); 860 861 bzero(evScreen, evScreenSize); 862 firstWaitCursorFrame = EV_WAITCURSOR; 863 maxWaitCursorFrame = EV_MAXCURSOR; 864 createParameters(); 865 866 // Allocated and publish the systemInfo array 867 systemInfo = OSArray::withCapacity(4); 868 if (systemInfo) { 869 setProperty(kNXSystemInfoKey, systemInfo); 870 } 871 872 // Let's go ahead and cache our registry name. 873 // This was added to remove a call to getName while 874 // we are disabling preemption 875 registryName = getName(); 876 877 obj = copyProperty(kIOHIDPowerOnDelayNSKey, gIOServicePlane); 878 if (obj != NULL) { 879 number = OSDynamicCast(OSNumber, obj); 880 if (number != NULL) { 881 UInt64 value = number->unsigned64BitValue(); 882 if (value < kMillisecondScale) { 883 // logging not yet available 884 } 885 else if (value > (10ULL * kSecondScale)) { 886 // logging not yet available 887 } 888 else { 889 setProperty(kIOHIDPowerOnDelayNSKey, number); 890 gIOHIDPowerOnThresoldAbsoluteTime = value; 891 } 892 } 893 obj->release(); 894 } 895 896 /* 897 * Start up the work loop 898 */ 899 workLoop = IOHIDWorkLoop::workLoop(); 900 cmdGate = IOCommandGate::commandGate(this); 901 periodicES = IOTimerEventSource::timerEventSource(this, (IOTimerEventSource::Action) &_periodicEvents ); 902 eventConsumerES = IOInterruptEventSource::interruptEventSource(this, (IOInterruptEventSource::Action) &doKickEventConsumer); 903 keyboardEQES = IOInterruptEventSource::interruptEventSource(this, (IOInterruptEventSource::Action) &doProcessKeyboardEQ); 904 _delayedNotificationSource = IOTimerEventSource::timerEventSource(this, OSMemberFunctionCast(IOTimerEventSource::Action, this, &IOHIDSystem::doProcessNotifications)); 905 906 require(workLoop && cmdGate && periodicES && eventConsumerES && keyboardEQES && _delayedNotificationSource, exit_early); 907 908 require_noerr(workLoop->addEventSource(cmdGate), exit_early); 909 require_noerr(workLoop->addEventSource(periodicES), exit_early); 910 require_noerr(workLoop->addEventSource(eventConsumerES), exit_early); 911 require_noerr(workLoop->addEventSource(keyboardEQES), exit_early); 912 require_noerr(workLoop->addEventSource(_delayedNotificationSource), exit_early); 913 914 publishNotify = addMatchingNotification(gIOPublishNotification, 915 matchingDevice, 916 iohidNotificationHandler, 917 this, 918 (void *)&IOHIDSystem::handlePublishNotification ); 919 require(publishNotify, exit_early); 920 921 eventPublishNotify = addMatchingNotification(gIOPublishNotification, 922 matchingService, 923 iohidNotificationHandler, 924 this, 925 (void *)&IOHIDSystem::handlePublishNotification ); 926 require(eventPublishNotify, exit_early); 927 928 terminateNotify = addMatchingNotification(gIOTerminatedNotification, 929 matchingDevice, 930 iohidNotificationHandler, 931 this, 932 (void *)&IOHIDSystem::handleTerminateNotification ); 933 require(terminateNotify, exit_early); 934 935 eventTerminateNotify = addMatchingNotification(gIOTerminatedNotification, 936 matchingService, 937 iohidNotificationHandler, 938 this, 939 (void *)&IOHIDSystem::handleTerminateNotification ); 940 require(eventTerminateNotify, exit_early); 941 942 // RY: Listen to the root domain 943 rootDomain = (IOService *)getPMRootDomain(); 944 945 if (rootDomain) 946 rootDomain->registerInterestedDriver(this); 947 948 registerPrioritySleepWakeInterest(powerStateHandler, this, 0); 949 950 _displayWranglerMatching = addMatchingNotification(gIOPublishNotification, 951 matchingWrangler, 952 iohidNotificationHandler, 953 this, 954 (void *)&IOHIDSystem::handlePublishNotification); 955 require(_displayWranglerMatching, exit_early); 956 957 // Get notified everytime AppleKeyswitch registers (each time keyswitch changes) 958 gSwitchNotification = addMatchingNotification(gIOPublishNotification, 959 matchingKeyswitch, 960 keySwitchNotificationHandler, 961 this, 962 0); 963 require(gSwitchNotification, exit_early); 964 965 /* 966 * IOHIDSystem serves both as a service and a nub (we lead a double 967 * life). Register ourselves as a nub to kick off matching. 968 */ 969 970#if !TARGET_OS_EMBEDDED 971 _hidActivityThread = thread_call_allocate(hidActivityThread_cb, (thread_call_param_t)this); 972 _hidActivityIdle = true; 973 require(_hidActivityThread, exit_early); 974#endif 975 976 registerService(); 977 iWasStarted = true; 978 979exit_early: 980 matchingDevice->release(); 981 matchingService->release(); 982 matchingWrangler->release(); 983 matchingKeyswitch->release(); 984 985 if (!iWasStarted) 986 evInstance = 0; 987 988 return iWasStarted; 989} 990 991void IOHIDSystem::setDisplaySleepDrivenByPM(bool val) 992{ 993 displaySleepDrivenByPM = val; 994} 995 996IOReturn IOHIDSystem::powerStateHandler( void *target, void *refCon __unused, 997 UInt32 messageType, IOService *service __unused, void *messageArgs, vm_size_t argSize __unused) 998{ 999 1000 IOPMSystemCapabilityChangeParameters * params; 1001 IOHIDSystem* myThis = OSDynamicCast( IOHIDSystem, (OSObject*)target ); 1002 1003 1004 if ( messageType != kIOMessageSystemCapabilityChange ) { 1005 // We are not interested in anything other than cap change. 1006 return kIOReturnSuccess; 1007 } 1008 params = (IOPMSystemCapabilityChangeParameters *) messageArgs; 1009 1010 if ((params->changeFlags & kIOPMSystemCapabilityWillChange) && 1011 (params->fromCapabilities & kIOPMSystemCapabilityGraphics) && 1012 (params->toCapabilities & kIOPMSystemCapabilityGraphics) == 0) { 1013 1014 /* 1015 * This display sleep driven by IOPMrootDomain. Don't let HID activity 1016 * tickle display 1017 */ 1018 myThis->setDisplaySleepDrivenByPM(true); 1019 1020 } 1021 return kIOReturnSuccess; 1022} 1023 1024// powerStateDidChangeTo 1025// 1026// The display wrangler has changed state, so the displays have changed 1027// state, too. We save the new state. 1028 1029IOReturn IOHIDSystem::powerStateDidChangeTo( IOPMPowerFlags theFlags, unsigned long state, IOService * service) 1030{ 1031 IOHID_DEBUG(kIOHIDDebugCode_PowerStateChangeEvent, service, state, theFlags, 0); 1032 if (service == displayManager) 1033 { 1034 displayState = theFlags; 1035 if (theFlags & IOPMDeviceUsable) { 1036 clock_get_uptime(&displayStateChangeDeadline); 1037 ADD_ABSOLUTETIME(&displayStateChangeDeadline, 1038 &gIOHIDRelativeTickleThresholdAbsoluteTime); 1039 AbsoluteTime_to_scalar(&displaySleepWakeupDeadline) = 0; 1040 1041 // Reset all flags. Flag key release events may not get delivered as they 1042 // come late in system sleep or display sleep process. 1043 updateEventFlags(0); 1044 } 1045 else { 1046 // If the display has transitioned from usable to unusable state 1047 // because of display sleep then set the deadline before which 1048 // pointer movement can bring the display to usable state. 1049 // Also make sure that this display sleep is not driven by IOPM as part of system sleep 1050 1051 if ( !CMP_ABSOLUTETIME(&displaySleepWakeupDeadline, &gIOHIDZeroAbsoluteTime) && 1052 (kOSBooleanFalse == rootDomain->copyProperty("DisplayIdleForDemandSleep"))) { 1053 clock_get_uptime(&displaySleepWakeupDeadline); 1054 ADD_ABSOLUTETIME(&displaySleepWakeupDeadline, &gIOHIDDisplaySleepAbortThresholdAbsoluteTime); 1055 } 1056 displaySleepDrivenByPM = false; // Reset flag for next use 1057 } 1058 1059 } 1060 else if (service == rootDomain) 1061 { 1062 if (theFlags & kIOPMPowerOn) 1063 { 1064 clock_get_uptime(&rootDomainStateChangeDeadline); 1065 ADD_ABSOLUTETIME(&rootDomainStateChangeDeadline, &gIOHIDPowerOnThresoldAbsoluteTime); 1066 ClearCachedMouseButtonStates(cachedButtonStates); 1067 } 1068 } 1069 return IOPMNoErr; 1070} 1071 1072bool IOHIDSystem::genericNotificationHandler(void * handler, 1073 IOService * newService, 1074 IONotifier * /* notifier */) 1075{ 1076 bool result = false; 1077 1078 if (handler && newService && _delayedNotificationSource) { 1079 IOHIDSystem_notificationData rawData = {(IOCommandGate::Action)handler, newService}; 1080 OSData *data = OSData::withBytes(&rawData, sizeof(rawData)); 1081 1082 if (data) { 1083 newService->retain(); 1084 IOLockLock(_delayedNotificationLock); 1085 _delayedNotificationArray->setObject(data); 1086 retain(); // Retain IOHIDSystem in case it tries to go away before this notification is processed. 1087 IOLockUnlock(_delayedNotificationLock); 1088 data->release(); 1089 _delayedNotificationSource->setTimeoutUS(1); 1090 result = true; 1091 } 1092 } 1093 1094 return result; 1095} 1096 1097void IOHIDSystem::doProcessNotifications(IOTimerEventSource *sender __unused) 1098{ 1099 bool reschedule = false; 1100 1101 while (_delayedNotificationArray->getCount() > 0) { 1102 // retrieve the first item from the queue 1103 IOLockLock(_delayedNotificationLock); 1104 OSData *notificationData = OSDynamicCast(OSData, _delayedNotificationArray->getObject(0)); 1105 if (notificationData) { 1106 notificationData->retain(); 1107 } 1108 _delayedNotificationArray->removeObject(0); 1109 IOLockUnlock(_delayedNotificationLock); 1110 1111 // process the notification 1112 if (notificationData) { 1113 const IOHIDSystem_notificationData *data = (const IOHIDSystem_notificationData *)notificationData->getBytesNoCopy(); 1114 cmdGate->runAction(data->handler, data->newService); 1115 data->newService->release(); 1116 notificationData->release(); 1117 release(); // IOHIDSystem was retained in case it tried to go away before this notification was processed. 1118 } 1119 } 1120 1121 if (reschedule) { 1122 _delayedNotificationSource->setTimeoutUS(1); 1123 } 1124} 1125 1126 1127bool IOHIDSystem::handlePublishNotification( 1128 void * target, 1129 IOService * newService ) 1130{ 1131 IOHIDSystem * self = (IOHIDSystem *) target; 1132 1133 if (newService->isInactive()) { 1134 // device went away before we could add it. ignore. 1135 return true; 1136 } 1137 1138 // avoiding OSDynamicCast & dependency on graphics family 1139 if( newService->metaCast("IODisplayWrangler")) { 1140 if( !self->displayManager) { 1141 self->displayManager = newService; 1142 self->displayState = newService->registerInterestedDriver(self); 1143 } 1144 return true; 1145 } 1146 1147 self->attach( newService ); 1148 1149 if( OSDynamicCast(IOHIDevice, newService) || 1150 OSDynamicCast(IOHIDEventService, newService)) { 1151 OSNumber *altSender = OSDynamicCast(OSNumber, newService->getProperty(kIOHIDAltSenderIdKey, gIOServicePlane)); 1152 if (altSender) { 1153 self->_privateData->senderIDDictionary->setObject((const OSSymbol *)newService, altSender); 1154 } 1155 1156 if (self->ioHIDevices) { 1157 if (self->ioHIDevices->getNextIndexOfObject(newService, 0) == (unsigned)-1) 1158 self->ioHIDevices->setObject(newService); 1159 } 1160 1161 if (OSDynamicCast(IOHIPointing, newService)) 1162 { 1163 AppendNewCachedMouseEventForService(self->cachedButtonStates, newService); 1164 } 1165 1166 OSArray * newSystemInfo = OSArray::withArray(self->systemInfo); 1167 if ( newSystemInfo ) 1168 { 1169 AppendNewNXSystemInfoForService(newSystemInfo, newService); 1170 self->setProperty(kNXSystemInfoKey, newSystemInfo); 1171 OSSafeReleaseNULL(self->systemInfo); 1172 self->systemInfo = newSystemInfo; 1173 } 1174 1175 if(self->eventsOpen || OSDynamicCast(IOHIKeyboard, newService)) 1176 self->registerEventSource( newService ); 1177 } 1178 1179 return true; 1180} 1181 1182bool IOHIDSystem::handleTerminateNotification( 1183 void * target, 1184 IOService * service ) 1185{ 1186 IOHIDSystem * self = (IOHIDSystem *) target; 1187 OSArray * newSystemInfo = NULL; 1188 int index; 1189 1190 require(OSDynamicCast(IOHIDSystem, self), exit_early); 1191 if( self->eventsOpen && ( 1192 OSDynamicCast(IOHIDevice, service) || 1193 OSDynamicCast(IOHIDEventService, service))) 1194 { 1195 service->close(self); 1196 self->_privateData->senderIDDictionary->removeObject((const OSSymbol *)service); 1197 } 1198 1199 // <rdar://problem/14116334&14536084&14757282&14775621> 1200 // self->detach(service); 1201 1202 if (self->ioHIDevices) { 1203 if ((index = self->ioHIDevices->getNextIndexOfObject(service, 0)) != -1) 1204 self->ioHIDevices->removeObject(index); 1205 } 1206 1207 newSystemInfo = OSArray::withArray(self->systemInfo); 1208 if ( newSystemInfo ) 1209 { 1210 RemoveNXSystemInfoForService(newSystemInfo, service); 1211 self->setProperty(kNXSystemInfoKey, newSystemInfo); 1212 OSSafeReleaseNULL(self->systemInfo); 1213 self->systemInfo = newSystemInfo; 1214 } 1215 1216 // RY: Remove this object from the cachedButtonState 1217 if (OSDynamicCast(IOHIPointing, service)) 1218 { 1219 // Clear the service button state 1220 AbsoluteTime ts; 1221 clock_get_uptime(&ts); 1222 if ( (self->displayState & IOPMDeviceUsable) ) { 1223 self->relativePointerEvent(0, 0, 0, ts, service); 1224 } 1225 1226 CachedMouseEventStruct *cachedMouseEvent; 1227 if ((cachedMouseEvent = GetCachedMouseEventForService(self->cachedButtonStates, service)) && 1228 (cachedMouseEvent->proximityData.proximity.enterProximity)) 1229 { 1230 cachedMouseEvent->proximityData.proximity.enterProximity = false; 1231 cachedMouseEvent->state |= kCachedMousePointingTabletEventPendFlag; 1232 self->proximityEvent(&(cachedMouseEvent->proximityData), ts, service); 1233 cachedMouseEvent->state &= ~kCachedMousePointingTabletEventPendFlag; 1234 1235 IOGBounds bounds = {0, 0, 0, 0}; 1236 IOGPoint newLoc = {0, 0}; 1237 self->absolutePointerEvent(0, &newLoc, &bounds, false, 0, 0, ts, service); 1238 } 1239 1240 RemoveCachedMouseEventForService(self->cachedButtonStates, service); 1241 } 1242 1243exit_early: 1244 return true; 1245} 1246 1247/* 1248 * Free locally allocated resources, and then ourselves. 1249 */ 1250void IOHIDSystem::free() 1251{ 1252 if (cmdGate) { 1253 evClose(); 1254 } 1255 1256 // we are going away. stop the workloop. 1257 if (workLoop) { 1258 workLoop->disableAllEventSources(); 1259 } 1260 1261 if (periodicES) { 1262 periodicES->cancelTimeout(); 1263 1264 if ( workLoop ) 1265 workLoop->removeEventSource( periodicES ); 1266 1267 periodicES->release(); 1268 periodicES = 0; 1269 } 1270 if (eventConsumerES) { 1271 eventConsumerES->disable(); 1272 1273 if ( workLoop ) 1274 workLoop->removeEventSource( eventConsumerES ); 1275 1276 eventConsumerES->release(); 1277 eventConsumerES = 0; 1278 } 1279 if (keyboardEQES) { 1280 keyboardEQES->disable(); 1281 1282 if ( workLoop ) 1283 workLoop->removeEventSource( keyboardEQES ); 1284 keyboardEQES->release(); 1285 keyboardEQES = 0; 1286 } 1287 1288 if (_privateData) { 1289 if (_delayedNotificationSource) { 1290 _delayedNotificationSource->cancelTimeout(); 1291 if ( workLoop ) 1292 workLoop->removeEventSource( _delayedNotificationSource ); 1293 _delayedNotificationSource->release(); 1294 } 1295 if (_delayedNotificationLock) { 1296 IOLockFree(_delayedNotificationLock); 1297 _delayedNotificationLock = 0; 1298 } 1299 OSSafeReleaseNULL(_delayedNotificationArray); 1300 } 1301 1302 1303 if (evScreen) IOFree( (void *)evScreen, evScreenSize ); 1304 evScreen = (void *)0; 1305 evScreenSize = 0; 1306 1307 if (publishNotify) { 1308 publishNotify->remove(); 1309 publishNotify = 0; 1310 } 1311 if (gSwitchNotification) { 1312 gSwitchNotification->remove(); 1313 gSwitchNotification = 0; 1314 } 1315 if (terminateNotify) { 1316 terminateNotify->remove(); 1317 terminateNotify = 0; 1318 } 1319 if (eventPublishNotify) { 1320 eventPublishNotify->remove(); 1321 eventPublishNotify = 0; 1322 } 1323 if (eventTerminateNotify) { 1324 eventTerminateNotify->remove(); 1325 eventTerminateNotify = 0; 1326 } 1327 if (_displayWranglerMatching) { 1328 _displayWranglerMatching->remove(); 1329 _displayWranglerMatching = 0; 1330 } 1331 1332 OSSafeReleaseNULL(cmdGate); // gate is already closed 1333 OSSafeReleaseNULL(workLoop); 1334 OSSafeReleaseNULL(ioHIDevices); 1335 OSSafeReleaseNULL(cachedButtonStates); 1336 OSSafeReleaseNULL(consumedKeys); 1337 OSSafeReleaseNULL(systemInfo); 1338 1339 if ( gKeyboardEQLock ) { 1340 IOLock * lock = gKeyboardEQLock; 1341 IOLockLock(lock); 1342 gKeyboardEQLock = 0; 1343 IOLockUnlock(lock); 1344 IOLockFree(lock); 1345 } 1346 1347 OSSafeReleaseNULL(_hidKeyboardDevice); 1348 OSSafeReleaseNULL(_hidPointingDevice); 1349 1350 if (_privateData) { 1351 _cursorHelper.finalize(); 1352 IOFree((void*)_privateData, sizeof(ExpansionData)); 1353 _privateData = NULL; 1354 } 1355 1356 super::free(); 1357} 1358 1359 1360 1361/* 1362 * Open the driver for business. This call must be made before 1363 * any other calls to the Event driver. We can only be opened by 1364 * one user at a time. 1365 */ 1366IOReturn IOHIDSystem::evOpen(void) 1367{ 1368 IOReturn r = kIOReturnSuccess; 1369 1370 if ( evOpenCalled == true ) 1371 { 1372 r = kIOReturnBusy; 1373 goto done; 1374 } 1375 evOpenCalled = true; 1376 1377 if (!evInitialized) 1378 { 1379 evInitialized = true; 1380 // Put code here that is to run on the first open ONLY. 1381 } 1382 1383done: 1384 return r; 1385} 1386 1387IOReturn IOHIDSystem::evClose(void){ 1388 return cmdGate->runAction((IOCommandGate::Action)doEvClose); 1389} 1390 1391IOReturn IOHIDSystem::doEvClose(IOHIDSystem *self) 1392 /* IOCommandGate::Action */ 1393{ 1394 return self->evCloseGated(); 1395} 1396 1397IOReturn IOHIDSystem::evCloseGated(void) 1398{ 1399 if ( evOpenCalled == false ) 1400 return kIOReturnBadArgument; 1401 1402 evStateChanging = true; 1403 1404 // Early close actions here 1405 if( cursorEnabled) 1406 hideCursor(); 1407 cursorStarted = false; 1408 cursorEnabled = false; 1409 1410 // Release the input devices. 1411 detachEventSources(); 1412 1413 // Clear screens registry and related data 1414 if ( evScreen != (void *)0 ) 1415 { 1416 screens = 0; 1417 lastShmemPtr = (void *)0; 1418 } 1419 // Remove port notification for the eventPort and clear the port out 1420 setEventPortGated(MACH_PORT_NULL); 1421// ipc_port_release_send(event_port); 1422 1423 // Clear local state to shutdown 1424 evStateChanging = false; 1425 evOpenCalled = false; 1426 eventsOpen = false; 1427 1428 return kIOReturnSuccess; 1429} 1430 1431// 1432// Dispatch state to screens registered with the Event Driver 1433// Pending state changes for a device may be coalesced. 1434// 1435// 1436// This should be run from a command gate action. 1437// 1438void IOHIDSystem::evDispatch( 1439 /* command */ EvCmd evcmd) 1440{ 1441 if( !eventsOpen || (evcmd == EVLEVEL) || (evcmd == EVNOP)) 1442 return; 1443 1444 for( int i = 0; i < screens; i++ ) { 1445 bool onscreen = (0 != (cursorScreens & (1 << i))); 1446 1447 if (onscreen) { 1448 EvScreen *esp = &((EvScreen*)evScreen)[i]; 1449 1450 if ( esp->instance ) { 1451 IOGPoint p; 1452 p.x = evg->screenCursorFixed.x / 256; // Copy from shmem. 1453 p.y = evg->screenCursorFixed.y / 256; 1454 1455 switch ( evcmd ) 1456 { 1457 case EVMOVE: 1458 esp->instance->moveCursor(&p, evg->frame); 1459 break; 1460 1461 case EVSHOW: 1462 esp->instance->showCursor(&p, evg->frame); 1463 break; 1464 1465 case EVHIDE: 1466 esp->instance->hideCursor(); 1467 break; 1468 1469 default: 1470 // should never happen 1471 break; 1472 } 1473 } 1474 } 1475 } 1476} 1477 1478// 1479// Dispatch mechanism for special key press. If a port has been registered, 1480// a message is built to be sent out to that port notifying that the key has 1481// changed state. A level in the range 0-64 is provided for convenience. 1482// 1483void IOHIDSystem::evSpecialKeyMsg(unsigned key, 1484 /* direction */ unsigned dir, 1485 /* flags */ unsigned f, 1486 /* level */ unsigned l) 1487{ 1488 mach_port_t dst_port; 1489 struct evioSpecialKeyMsg *msg; 1490 1491 static const struct evioSpecialKeyMsg init_msg = 1492 { { MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, // mach3xxx, is the right? 1493 MACH_MSG_TYPE_MAKE_SEND), // mach_msg_bits_t msgh_bits; 1494 sizeof (struct evioSpecialKeyMsg), // mach_msg_size_t msgh_size; 1495 MACH_PORT_NULL, // mach_port_t msgh_remote_port; 1496 MACH_PORT_NULL, // mach_port_t msgh_local_port; 1497 0, // mach_msg_size_t msgh_reserved; 1498 EV_SPECIAL_KEY_MSG_ID // mach_msg_id_t msgh_id; 1499 }, 1500 0, /* key */ 1501 0, /* direction */ 1502 0, /* flags */ 1503 0 /* level */ 1504 }; 1505 1506 if ( (dst_port = specialKeyPort(key)) == MACH_PORT_NULL ) 1507 return; 1508 msg = (struct evioSpecialKeyMsg *) IOMalloc( 1509 sizeof (struct evioSpecialKeyMsg) ); 1510 if ( msg == NULL ) 1511 return; 1512 1513 // Initialize the message. 1514 bcopy( &init_msg, msg, sizeof (struct evioSpecialKeyMsg) ); 1515 msg->Head.msgh_remote_port = dst_port; 1516 msg->key = key; 1517 msg->direction = dir; 1518 msg->flags = f; 1519 msg->level = l; 1520 1521 // Send the message out from the command gate. 1522 cmdGate->runAction((IOCommandGate::Action)doSpecialKeyMsg,(void*)msg); 1523} 1524 1525// 1526// Reset instance variables to their default state for mice/pointers 1527// 1528 1529void IOHIDSystem::_resetMouseParameters(void) 1530{ 1531 if ( eventsOpen == false ) 1532 return; 1533 1534 OSDictionary *tempDict = OSDictionary::withCapacity(3); 1535 UInt64 nano; 1536 1537 nanoseconds_to_absolutetime( EV_DCLICKTIME, &clickTimeThresh); 1538 clickSpaceThresh.x = clickSpaceThresh.y = EV_DCLICKSPACE; 1539 AbsoluteTime_to_scalar( &clickTime) = 0; 1540 clickLoc.x = clickLoc.y = -EV_DCLICKSPACE; 1541 clickState = 1; 1542 1543 if (tempDict) { 1544 UInt32 tempClickSpace[] = {clickSpaceThresh.x, clickSpaceThresh.y}; 1545 makeInt32ArrayParamProperty( tempDict, kIOHIDClickSpaceKey, 1546 tempClickSpace, sizeof(tempClickSpace)/sizeof(UInt32) ); 1547 1548 nano = EV_DCLICKTIME; 1549 makeNumberParamProperty( tempDict, kIOHIDClickTimeKey, 1550 nano, 64 ); 1551 1552 setParamProperties(tempDict); 1553 1554 tempDict->release(); 1555 } 1556} 1557 1558//////////////////////////////////////////////////////////////////////////// 1559//#define LOG_SCREEN_REGISTRATION 1560#ifdef LOG_SCREEN_REGISTRATION 1561#warning LOG_SCREEN_REGISTRATION is defined 1562#define log_screen_reg(fmt, args...) kprintf(">>> " fmt, args) 1563#else 1564#define log_screen_reg(fmt, args...) 1565#endif 1566 1567//////////////////////////////////////////////////////////////////////////// 1568int 1569IOHIDSystem::registerScreen(IOGraphicsDevice * io_gd, 1570 IOGBounds * boundsPtr, 1571 IOGBounds * virtualBoundsPtr) 1572{ 1573 int result = -1; 1574 1575 // If we are not open for business, fail silently 1576 if (eventsOpen) { 1577 // for this version of the call, these must all be supplied 1578 if (!io_gd || !boundsPtr || !virtualBoundsPtr) { 1579 IOLog("%s invalid call %p %p %p\n", __PRETTY_FUNCTION__, io_gd, boundsPtr, virtualBoundsPtr); 1580 } 1581 else { 1582 UInt32 index; 1583 IOReturn ret = workLoop->runAction((IOWorkLoop::Action)&IOHIDSystem::doRegisterScreen, 1584 this, io_gd, boundsPtr, virtualBoundsPtr, &index); 1585 if (ret == kIOReturnSuccess) { 1586 result = SCREENTOKEN + index; 1587 } 1588 else { 1589 IOLog("%s failed %08x\n", __PRETTY_FUNCTION__, ret); 1590 } 1591 } 1592 } 1593 log_screen_reg("%s: registered token %d\n", __PRETTY_FUNCTION__, result); 1594 return result; 1595} 1596 1597//////////////////////////////////////////////////////////////////////////// 1598IOReturn 1599IOHIDSystem::extRegisterVirtualDisplay(void* token_ptr,void*,void*,void*,void*,void*) 1600{ 1601 IOReturn result = kIOReturnBadArgument; 1602 if (token_ptr) { 1603 SInt32 index; 1604 UInt64 *token = (UInt64 *)token_ptr; 1605 result = workLoop->runAction((IOWorkLoop::Action)&IOHIDSystem::doRegisterScreen, 1606 this, NULL, NULL, NULL, &index); 1607 if ((index >= 0) && (index < EV_MAX_SCREENS)) { 1608 *token = SCREENTOKEN + index; 1609 } 1610 else { 1611 *token = 0; 1612 if (result == kIOReturnSuccess) { 1613 result = kIOReturnInternalError; 1614 IOLog("IOHIDSystem tried to return an invalid token with no error\n"); 1615 } 1616 } 1617 log_screen_reg("%s: registered token %lld on %x\n", __PRETTY_FUNCTION__, *token, result); 1618 } 1619 return result; 1620} 1621 1622//////////////////////////////////////////////////////////////////////////// 1623IOReturn 1624IOHIDSystem::doRegisterScreen(IOHIDSystem *self, 1625 IOGraphicsDevice *io_gd, 1626 IOGBounds *bounds, 1627 IOGBounds *virtualBounds, 1628 void *index) 1629{ 1630 return self->registerScreenGated(io_gd, bounds, virtualBounds, (SInt32*)index); 1631} 1632 1633//////////////////////////////////////////////////////////////////////////// 1634//#define LOG_SCROLL_STATE 1635#ifdef LOG_SCROLL_STATE 1636# define log_scroll_state(s, ...) kprintf(">>> %s:%d " s, "IOHIDSystem", __LINE__, __VA_ARGS__) 1637# define log_scroll_state_b(s, ...) kprintf(">>> %s:%d " s, "IOHIDSystem", __LINE__, __VA_ARGS__) 1638#else 1639# define log_scroll_state(s, ...) 1640# define log_scroll_state_b(s, ...) 1641#endif 1642 1643//////////////////////////////////////////////////////////////////////////// 1644IOReturn 1645IOHIDSystem::registerScreenGated(IOGraphicsDevice *io_gd, 1646 IOGBounds *boundsPtr, 1647 IOGBounds *virtualBoundsPtr, 1648 SInt32 *index) 1649{ 1650 EvScreen *screen_ptr = NULL; 1651 OSNumber *num = NULL; 1652 IOReturn result = kIOReturnSuccess; 1653 *index = -1; 1654 1655 if ( lastShmemPtr == (void *)0 ) 1656 lastShmemPtr = evs; 1657 1658 /* shmemSize and bounds already set */ 1659 log_screen_reg("%s %p %p %p\n", __func__, io_gd, boundsPtr, virtualBoundsPtr); 1660 1661 // locate next available screen 1662 for (int i = 0; (i < EV_MAX_SCREENS) && (screen_ptr == NULL); i++) { 1663 screen_ptr = &((EvScreen*)evScreen)[i]; 1664 1665 if (io_gd && (screen_ptr->instance == io_gd)) { 1666 // Empty slot. 1667 log_screen_reg("%s refound at index %d\n", __func__, i); 1668 *index = i; 1669 } 1670 else if (screen_ptr->creator_pid) { 1671 proc_t isStillAlive = proc_find(screen_ptr->creator_pid); 1672 if (isStillAlive) { 1673 // Still in use. 1674 screen_ptr = NULL; 1675 proc_rele(isStillAlive); 1676 } 1677 else { 1678 // Dead head. 1679 IOLog("IOHIDSystem::%s: Screen %d recycled from pid %d\n", __func__, i, screen_ptr->creator_pid); 1680 *index = i; 1681 screen_ptr->creator_pid = 0; 1682 screen_ptr->displayBounds = NULL; 1683 screen_ptr->desktopBounds = NULL; 1684 } 1685 } 1686 else if (screen_ptr->instance) { 1687 // Still in use. 1688 screen_ptr = NULL; // try the next one 1689 } 1690 else { 1691 // New slot 1692 log_screen_reg("%s new index at %d\n", __func__, i); 1693 *index = i; 1694 } 1695 } 1696 1697 if (!screen_ptr) { 1698 IOLog("IOHIDSystem::%s: No space found for new screen\n", __func__); 1699 result = kIOReturnNoResources; 1700 } 1701 else if (io_gd && boundsPtr && virtualBoundsPtr) { 1702 // called by video driver. they maintain their own bounds. 1703 screen_ptr->instance = io_gd; 1704 screen_ptr->displayBounds = boundsPtr; 1705 screen_ptr->desktopBounds = virtualBoundsPtr; 1706 screen_ptr->creator_pid = 0; // kernel made 1707 1708 // Update our idea of workSpace bounds 1709 if ( boundsPtr->minx < workSpace.minx ) 1710 workSpace.minx = boundsPtr->minx; 1711 if ( boundsPtr->miny < workSpace.miny ) 1712 workSpace.miny = boundsPtr->miny; 1713 if ( boundsPtr->maxx < workSpace.maxx ) 1714 workSpace.maxx = boundsPtr->maxx; 1715 if ( screen_ptr->displayBounds->maxy < workSpace.maxy ) 1716 workSpace.maxy = boundsPtr->maxy; 1717 1718 // perform other bookkeeping 1719 num = (OSNumber*)io_gd->copyProperty(kIOFBWaitCursorFramesKey); 1720 if(OSDynamicCast(OSNumber, num) && 1721 (num->unsigned32BitValue() > maxWaitCursorFrame)) { 1722 firstWaitCursorFrame = 0; 1723 maxWaitCursorFrame = num->unsigned32BitValue(); 1724 evg->lastFrame = maxWaitCursorFrame; 1725 } 1726 OSSafeReleaseNULL(num); 1727 num = (OSNumber*)io_gd->copyProperty(kIOFBWaitCursorPeriodKey); 1728 if( OSDynamicCast(OSNumber, num) ) { 1729 clock_interval_to_absolutetime_interval(num->unsigned32BitValue(), kNanosecondScale, &_cursorWaitDelta); 1730 } 1731 OSSafeReleaseNULL(num); 1732 } 1733 else if (!io_gd && !boundsPtr && !virtualBoundsPtr) { 1734 // called by window server. we maintain the bounds. 1735 screen_ptr->displayBounds = (IOGBounds*)screen_ptr->scratch; 1736 screen_ptr->desktopBounds = screen_ptr->displayBounds + 1; 1737 screen_ptr->creator_pid = proc_selfpid(); 1738 1739 // default the bounds to lala land 1740 screen_ptr->displayBounds->minx = screen_ptr->desktopBounds->minx = screen_ptr->displayBounds->miny = screen_ptr->desktopBounds->miny = -30001; 1741 screen_ptr->displayBounds->maxx = screen_ptr->desktopBounds->maxx = screen_ptr->displayBounds->maxy = screen_ptr->desktopBounds->maxy = -30000; 1742 } 1743 else { 1744 result = kIOReturnBadArgument; 1745 } 1746 1747 if (result == kIOReturnSuccess) { 1748 log_screen_reg(">>> display %d is for %d\n", *index, screen_ptr->creator_pid); 1749 if (*index >= screens) { 1750 screens = 1 + *index; 1751 } 1752 } 1753 1754 return result; 1755} 1756 1757//////////////////////////////////////////////////////////////////////////// 1758void IOHIDSystem::unregisterScreen(int token) { 1759 uintptr_t index = token - SCREENTOKEN; 1760 log_screen_reg("%s: unregistering token %d\n", __PRETTY_FUNCTION__, token); 1761 if (index < EV_MAX_SCREENS) { 1762 IOReturn ret = cmdGate->runAction((IOCommandGate::Action)doUnregisterScreen, (void *)index); 1763 if (ret != kIOReturnSuccess) { 1764 IOLog("%s recieved %08x for token %d.\n", __PRETTY_FUNCTION__, ret, token); 1765 } 1766 } 1767 else { 1768 IOLog("%s called with invalid token %d.\n", __PRETTY_FUNCTION__, token); 1769 } 1770} 1771 1772//////////////////////////////////////////////////////////////////////////// 1773IOReturn 1774IOHIDSystem::extUnregisterVirtualDisplay(void* token_ptr,void*,void*,void*,void*,void*) 1775{ 1776 IOReturn result = kIOReturnSuccess; 1777 uintptr_t token = (uintptr_t)token_ptr; 1778 uintptr_t index = token - SCREENTOKEN; 1779 if (index < EV_MAX_SCREENS) { 1780 result = cmdGate->runAction((IOCommandGate::Action)doUnregisterScreen, (void *)index); 1781 } 1782 else { 1783 IOLog("%s called with invalid token %d.\n", __PRETTY_FUNCTION__, (int)token); 1784 result = kIOReturnBadArgument; 1785 } 1786 log_screen_reg("%s: unregistering token %lu on %x\n", __PRETTY_FUNCTION__, token, result); 1787 1788 return result; 1789} 1790 1791//////////////////////////////////////////////////////////////////////////// 1792IOReturn IOHIDSystem::doUnregisterScreen (IOHIDSystem *self, void * arg0, void *arg1) 1793 /* IOCommandGate::Action */ 1794{ 1795 uintptr_t index = (uintptr_t) arg0; 1796 uintptr_t internal = (uintptr_t) arg1; 1797 1798 return self->unregisterScreenGated(index, internal); 1799} 1800 1801//////////////////////////////////////////////////////////////////////////// 1802IOReturn IOHIDSystem::unregisterScreenGated(int index, bool internal) 1803{ 1804 IOReturn result = kIOReturnSuccess; 1805 log_screen_reg("%s %d %d %d\n", __func__, index, internal, screens); 1806 1807 if ( eventsOpen == false || index >= screens ) { 1808 result = kIOReturnNoResources; 1809 } 1810 else { 1811 EvScreen *screen_ptr = ((EvScreen*)evScreen)+index; 1812 1813 if (!screen_ptr->displayBounds) { 1814 IOLog("%s called with invalid index %d\n", __PRETTY_FUNCTION__, index); 1815 result = kIOReturnBadArgument; 1816 } 1817 else if (internal && !screen_ptr->instance) { 1818 IOLog("%s called internally on an external device %d\n", __PRETTY_FUNCTION__, index); 1819 result = kIOReturnNoDevice; 1820 } 1821 else if (!internal && screen_ptr->instance) { 1822 IOLog("%s called externally on an internal device %d\n", __PRETTY_FUNCTION__, index); 1823 result = kIOReturnNotPermitted; 1824 } 1825 else { 1826 hideCursor(); 1827 1828 // clear the variables 1829 screen_ptr->instance = NULL; 1830 screen_ptr->desktopBounds = NULL; 1831 screen_ptr->displayBounds = NULL; 1832 screen_ptr->creator_pid = 0; 1833 1834 // Put the cursor someplace reasonable if it was on the destroyed screen 1835 cursorScreens &= ~(1 << index); 1836 // This will jump the cursor back on screen 1837 setCursorPosition((IOGPoint *)&evg->cursorLoc, true); 1838 1839 showCursor(); 1840 } 1841 } 1842 1843 return result; 1844} 1845 1846//////////////////////////////////////////////////////////////////////////// 1847IOReturn 1848IOHIDSystem::extSetVirtualDisplayBounds(void* token_ptr,void* minx,void* maxx,void* miny,void* maxy,void*) 1849{ 1850 IOReturn result = kIOReturnSuccess; 1851 uintptr_t token = (uintptr_t)token_ptr; 1852 uintptr_t index = token - SCREENTOKEN; 1853 log_screen_reg("%s: set bounds on token %lu\n", __PRETTY_FUNCTION__, token); 1854 if (index < EV_MAX_SCREENS) { 1855 IOGBounds tempBounds = { (uintptr_t) minx, (uintptr_t) maxx, (uintptr_t) miny, (uintptr_t) maxy }; 1856 result = cmdGate->runAction((IOCommandGate::Action)doSetDisplayBounds, (void*) index, (void*) &tempBounds); 1857 } 1858 else { 1859 IOLog("%s called with invalid token %d.\n", __PRETTY_FUNCTION__, (int)token); 1860 result = kIOReturnBadArgument; 1861 } 1862 1863 return result; 1864} 1865 1866//////////////////////////////////////////////////////////////////////////// 1867IOReturn 1868IOHIDSystem::doSetDisplayBounds (IOHIDSystem *self, void * arg0, void * arg1) 1869{ 1870 uintptr_t index = (uintptr_t) arg0; 1871 IOGBounds *tempBounds = (IOGBounds*) arg1; 1872 1873 return self->setDisplayBoundsGated(index, tempBounds); 1874} 1875 1876//////////////////////////////////////////////////////////////////////////// 1877IOReturn 1878IOHIDSystem::setDisplayBoundsGated (UInt32 index, IOGBounds *tempBounds) 1879{ 1880 IOReturn result = kIOReturnSuccess; 1881 log_screen_reg("%s ((%d,%d),(%d,%d))\n", __func__, tempBounds->minx, tempBounds->miny, tempBounds->maxx, tempBounds->maxy); 1882 1883 if ( eventsOpen == false || index >= (UInt32)screens ) { 1884 result = kIOReturnNoResources; 1885 } 1886 else { 1887 EvScreen *screen_ptr = ((EvScreen*)evScreen)+index; 1888 1889 if (screen_ptr->instance) { 1890 IOLog("%s called on an internal device %d\n", __PRETTY_FUNCTION__, (int)index); 1891 result = kIOReturnNotPermitted; 1892 } 1893 else if (!screen_ptr->displayBounds || !screen_ptr->desktopBounds) { 1894 IOLog("%s called with invalid index %d\n", __PRETTY_FUNCTION__, (int)index); 1895 result = kIOReturnBadArgument; 1896 } 1897 else { 1898 // looks good 1899 hideCursor(); 1900 *(screen_ptr->displayBounds) = *(screen_ptr->desktopBounds) = *tempBounds; 1901 // Put the cursor someplace reasonable if it was on the moved screen 1902 cursorScreens &= ~(1 << index); 1903 // This will jump the cursor back on screen 1904 setCursorPosition((IOGPoint *)&evg->cursorLoc, true); 1905 showCursor(); 1906 } 1907 } 1908 return result; 1909} 1910 1911//////////////////////////////////////////////////////////////////////////// 1912/* Member of EventClient protocol 1913 * 1914 * Absolute position input devices and some specialized output devices 1915 * may need to know the bounding rectangle for all attached displays. 1916 * The following method returns a IOGBounds* for the workspace. Please note 1917 * that the bounds are kept as signed values, and that on a multi-display 1918 * system the minx and miny values may very well be negative. 1919 */ 1920IOGBounds * IOHIDSystem::workspaceBounds() 1921{ 1922 return &workSpace; 1923} 1924 1925IOReturn IOHIDSystem::registerEventQueue(IODataQueue * queue) 1926{ 1927 return cmdGate->runAction((IOCommandGate::Action)doRegisterEventQueue, (void *)queue); 1928} 1929 1930IOReturn IOHIDSystem::doRegisterEventQueue (IOHIDSystem *self, void * arg0) 1931 /* IOCommandGate::Action */ 1932{ 1933 return self->registerEventQueueGated((IODataQueue *)arg0); 1934} 1935 1936IOReturn IOHIDSystem::registerEventQueueGated(void * p1) 1937{ 1938 IODataQueue * queue = (IODataQueue *)p1; 1939 if ( !queue ) 1940 return kIOReturnBadArgument; 1941 1942 if ( !dataQueueSet ) 1943 dataQueueSet = OSSet::withCapacity(4); 1944 1945 dataQueueSet->setObject(queue); 1946 1947 return kIOReturnSuccess; 1948} 1949 1950IOReturn IOHIDSystem::unregisterEventQueue(IODataQueue * queue) 1951{ 1952 return cmdGate->runAction((IOCommandGate::Action)doUnregisterEventQueue, (void *)queue); 1953} 1954 1955IOReturn IOHIDSystem::doUnregisterEventQueue (IOHIDSystem *self, void * arg0) 1956 /* IOCommandGate::Action */ 1957{ 1958 return self->unregisterEventQueueGated((IODataQueue *)arg0); 1959} 1960 1961IOReturn IOHIDSystem::unregisterEventQueueGated(void * p1) 1962{ 1963 IODataQueue * queue = (IODataQueue *)p1; 1964 1965 if ( !queue ) 1966 return kIOReturnBadArgument; 1967 1968 if ( dataQueueSet ) 1969 dataQueueSet->removeObject(queue); 1970 1971 return kIOReturnSuccess; 1972} 1973 1974IOReturn IOHIDSystem::createShmem(void* p1, void*, void*, void*, void*, void*) 1975{ // IOMethod 1976 return cmdGate->runAction((IOCommandGate::Action)doCreateShmem, p1); 1977} 1978 1979IOReturn IOHIDSystem::doCreateShmem (IOHIDSystem *self, void * arg0) 1980 /* IOCommandGate::Action */ 1981{ 1982 return self->createShmemGated(arg0); 1983} 1984 1985IOReturn IOHIDSystem::createShmemGated(void* p1) 1986{ 1987 1988 int shmemVersion = (uintptr_t)p1; 1989 IOByteCount size; 1990 bool clean = false; 1991 1992 if ( shmemVersion < kIOHIDLastCompatibleShmemVersion ) { 1993 IOLog("IOHIDSystem::createShmemGated called with low version: %d < %d\n", shmemVersion, kIOHIDLastCompatibleShmemVersion); 1994 return kIOReturnUnsupported; 1995 } 1996 1997 if ( shmemVersion > kIOHIDCurrentShmemVersion ) { 1998 IOLog("IOHIDSystem::createShmemGated called with hi version: %d > %d\n", shmemVersion, kIOHIDCurrentShmemVersion); 1999 return kIOReturnUnsupported; 2000 } 2001 2002 if ( 0 == globalMemory) { 2003 2004 size = sizeof(EvOffsets) + sizeof(EvGlobals); 2005 globalMemory = IOBufferMemoryDescriptor::withOptions( kIODirectionNone | kIOMemoryKernelUserShared, size ); 2006 2007 if ( !globalMemory) 2008 return kIOReturnNoMemory; 2009 2010 shmem_addr = (uintptr_t) globalMemory->getBytesNoCopy(); 2011 shmem_size = size; 2012 2013 clean = true; 2014 } 2015 2016 initShmem(clean); 2017 2018 return kIOReturnSuccess; 2019} 2020 2021// Initialize the shared memory area. 2022// 2023// This should be run from a command gate action. 2024void IOHIDSystem::initShmem(bool clean) 2025{ 2026 int i; 2027 EvOffsets *eop; 2028 int oldFlags = 0; 2029 2030 /* top of sharedMem is EvOffsets structure */ 2031 eop = (EvOffsets *) shmem_addr; 2032 2033 if (!clean) { 2034 oldFlags = ((EvGlobals *)((char *)shmem_addr + sizeof(EvOffsets)))->eventFlags; 2035 } 2036 2037 bzero( (void*)shmem_addr, shmem_size); 2038 2039 /* fill in EvOffsets structure */ 2040 eop->evGlobalsOffset = sizeof(EvOffsets); 2041 eop->evShmemOffset = eop->evGlobalsOffset + sizeof(EvGlobals); 2042 2043 /* find pointers to start of globals and private shmem region */ 2044 evg = (EvGlobals *)((char *)shmem_addr + eop->evGlobalsOffset); 2045 evs = (void *)((char *)shmem_addr + eop->evShmemOffset); 2046 2047 evg->version = kIOHIDCurrentShmemVersion; 2048 evg->structSize = sizeof( EvGlobals); 2049 2050 /* Set default wait cursor parameters */ 2051 evg->waitCursorEnabled = TRUE; 2052 evg->globalWaitCursorEnabled = TRUE; 2053 evg->lastFrame = maxWaitCursorFrame; 2054 evg->waitThreshold = (12 * EV_TICKS_PER_SEC) / 10; 2055 2056 evg->buttons = 0; 2057 evg->eNum = INITEVENTNUM; 2058 evg->eventFlags = oldFlags; 2059 2060 evg->cursorLoc.x = _cursorHelper.desktopLocation().xValue().as32(); 2061 evg->cursorLoc.y = _cursorHelper.desktopLocation().yValue().as32(); 2062 evg->desktopCursorFixed.x = _cursorHelper.desktopLocation().xValue().asFixed24x8(); 2063 evg->desktopCursorFixed.y = _cursorHelper.desktopLocation().yValue().asFixed24x8(); 2064 evg->screenCursorFixed.x = _cursorHelper.getScreenLocation().xValue().asFixed24x8(); 2065 evg->screenCursorFixed.y = _cursorHelper.getScreenLocation().yValue().asFixed24x8(); 2066 2067 evg->updateCursorPositionFromFixed = 0; 2068 evg->logCursorUpdates = 0; 2069 evg->dontCoalesce = 0; 2070 evg->dontWantCoalesce = 0; 2071 evg->wantPressure = 0; 2072 evg->wantPrecision = 0; 2073 evg->mouseRectValid = 0; 2074 evg->movedMask = 0; 2075 evg->cursorSema = OS_SPINLOCK_INIT; 2076 evg->waitCursorSema = OS_SPINLOCK_INIT; 2077 2078 /* Set up low-level queues */ 2079 lleqSize = LLEQSIZE; 2080 for (i=lleqSize; --i != -1; ) { 2081 evg->lleq[i].event.type = 0; 2082 AbsoluteTime_to_scalar(&evg->lleq[i].event.time) = 0; 2083 evg->lleq[i].event.flags = 0; 2084 evg->lleq[i].sema = OS_SPINLOCK_INIT; 2085 evg->lleq[i].next = i+1; 2086 } 2087 evg->LLELast = 0; 2088 evg->lleq[lleqSize-1].next = 0; 2089 evg->LLEHead = evg->lleq[evg->LLELast].next; 2090 evg->LLETail = evg->lleq[evg->LLELast].next; 2091 2092 _cursorLogTimed(); 2093 2094 // Set eventsOpen last to avoid race conditions. 2095 eventsOpen = true; 2096} 2097 2098// 2099// Set the event port. The event port is both an ownership token 2100// and a live port we hold send rights on. The port is owned by our client, 2101// the WindowServer. We arrange to be notified on a port death so that 2102// we can tear down any active resources set up during this session. 2103// An argument of PORT_NULL will cause us to forget any port death 2104// notification that's set up. 2105// 2106// This should be run from a command gate action. 2107// 2108void IOHIDSystem::setEventPort(mach_port_t port) 2109{ 2110 if ((eventPort != port) && (workLoop)) 2111 workLoop->runAction((IOWorkLoop::Action)&IOHIDSystem::doSetEventPort, this, (void*)port); 2112} 2113 2114IOReturn IOHIDSystem::doSetEventPort(IOHIDSystem *self, void *port_void, void *arg1 __unused, void *arg2 __unused, void *arg3 __unused) 2115{ 2116 self->setEventPortGated((mach_port_t)port_void); 2117 return kIOReturnSuccess; 2118} 2119 2120void IOHIDSystem::setEventPortGated(mach_port_t port) 2121{ 2122 static struct _eventMsg init_msg = { { 2123 // mach_msg_bits_t msgh_bits; 2124 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,0), 2125 // mach_msg_size_t msgh_size; 2126 sizeof (struct _eventMsg), 2127 // mach_port_t msgh_remote_port; 2128 MACH_PORT_NULL, 2129 // mach_port_t msgh_local_port; 2130 MACH_PORT_NULL, 2131 // mach_msg_size_t msgh_reserved; 2132 0, 2133 // mach_msg_id_t msgh_id; 2134 0 2135 } }; 2136 2137 init_msg.h.msgh_remote_port = port; 2138 2139 if ( eventMsg == NULL ) 2140 eventMsg = IOMalloc( sizeof (struct _eventMsg) ); 2141 2142 // Initialize the events available message. 2143 *((struct _eventMsg *)eventMsg) = init_msg; 2144 eventPort = port; 2145 2146 // RY: Added this check so that the event consumer 2147 // can get notified if the queue in not empty. 2148 // Otherwise the event consumer will never get a 2149 // notification. 2150 if (EventsInQueue()) 2151 kickEventConsumer(); 2152} 2153 2154// 2155// Set the port to be used for a special key notification. This could be more 2156// robust about letting ports be set... 2157// 2158IOReturn IOHIDSystem::setSpecialKeyPort( 2159 /* keyFlavor */ int special_key, 2160 /* keyPort */ mach_port_t key_port) 2161{ 2162 if ( special_key >= 0 && special_key < NX_NUM_SCANNED_SPECIALKEYS ) 2163 _specialKeyPort[special_key] = key_port; 2164 return kIOReturnSuccess; 2165} 2166 2167mach_port_t IOHIDSystem::specialKeyPort(int special_key) 2168{ 2169 if ( special_key >= 0 && special_key < NX_NUM_SCANNED_SPECIALKEYS ) 2170 return _specialKeyPort[special_key]; 2171 return MACH_PORT_NULL; 2172} 2173 2174// 2175// Set the port to be used for stack shot 2176// 2177void IOHIDSystem::setStackShotPort(mach_port_t port) 2178{ 2179 stackShotPort = port; 2180 2181 static IOHIDSystem_stackShotMessage init_msg = 2182 { 2183 { // mach_msg_header_t header 2184 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,0), // mach_msg_bits_t msgh_bits; 2185 sizeof (init_msg), // mach_msg_size_t msgh_size; 2186 MACH_PORT_NULL, // mach_port_t msgh_remote_port; 2187 MACH_PORT_NULL, // mach_port_t msgh_local_port; 2188 0, // mach_msg_size_t msgh_reserved; 2189 0 // mach_msg_id_t msgh_id; 2190 }, 2191 0 // UInt32 flavor 2192 }; 2193 2194 if ( stackShotMsg ) { 2195 IOFree(stackShotMsg, sizeof(IOHIDSystem_stackShotMessage)); 2196 stackShotMsg = NULL; 2197 } 2198 2199 if ( stackShotPort ) { 2200 if ( !(stackShotMsg = IOMalloc(sizeof(IOHIDSystem_stackShotMessage))) ) 2201 return; 2202 2203 // Initialize the events available message. 2204 init_msg.header.msgh_remote_port = stackShotPort; 2205 *((IOHIDSystem_stackShotMessage*)stackShotMsg) = init_msg; 2206 } 2207} 2208 2209UInt32 IOHIDSystem::eventFlags() 2210{ 2211 return evg ? (evg->eventFlags) : 0; 2212} 2213 2214void IOHIDSystem::dispatchEvent(IOHIDEvent *event, IOOptionBits options __unused) 2215{ 2216 if ( !event || !dataQueueSet) 2217 return; 2218 2219 OSCollectionIterator * iterator = OSCollectionIterator::withCollection(dataQueueSet); 2220 IOHIDEventServiceQueue * dataQueue = NULL; 2221 2222 if ( !iterator ) 2223 return; 2224 2225 while ((dataQueue = OSDynamicCast(IOHIDEventServiceQueue, iterator->getNextObject()))) { 2226 dataQueue->enqueueEvent(event); 2227 } 2228 2229 iterator->release(); 2230 2231} 2232 2233void IOHIDSystem::updateHidActivity() 2234{ 2235#if !TARGET_OS_EMBEDDED 2236 clock_get_uptime(&_lastTickleTime); 2237 if (_hidActivityIdle) 2238 thread_call_enter(_hidActivityThread); 2239#endif 2240} 2241 2242void IOHIDSystem::hidActivityChecker( ) 2243{ 2244 cmdGate->runAction((IOCommandGate::Action)reportUserHidActivity, NULL); 2245} 2246 2247void IOHIDSystem::reportUserHidActivity(IOHIDSystem *self, void *args ) 2248{ 2249 self->reportUserHidActivityGated(args); 2250} 2251 2252void IOHIDSystem::reportUserHidActivityGated(void *args __unused) 2253{ 2254 AbsoluteTime deadline = 0; 2255 AbsoluteTime ts; 2256 static AbsoluteTime idleHidActivity = 0; 2257 2258 if (!idleHidActivity) 2259 nanoseconds_to_absolutetime(IDLE_HID_ACTIVITY_NSECS, &idleHidActivity); 2260 2261 2262 clock_get_uptime(&ts); 2263 if ((ts-_lastTickleTime) < idleHidActivity) { 2264 if (_hidActivityIdle) { 2265 _hidActivityIdle = false; 2266 messageClients(kIOHIDSystemUserHidActivity, (void *)_hidActivityIdle ); 2267 } 2268 clock_absolutetime_interval_to_deadline((idleHidActivity+_lastTickleTime-ts), &deadline); 2269 2270 thread_call_enter_delayed(_hidActivityThread, deadline); 2271 } 2272 else if ( !_hidActivityIdle ) { 2273 _hidActivityIdle = true; 2274 messageClients(kIOHIDSystemUserHidActivity, (void *)_hidActivityIdle ); 2275 } 2276} 2277 2278IOReturn IOHIDSystem::extGetUserHidActivityState(void *arg0,void*,void*,void*,void*,void*) 2279{ 2280 return cmdGate->runAction((IOCommandGate::Action)getUserHidActivityState, arg0); 2281} 2282 2283IOReturn IOHIDSystem::getUserHidActivityState(IOHIDSystem *self, void *arg0) 2284{ 2285 return self->getUserHidActivityStateGated(arg0); 2286} 2287 2288IOReturn IOHIDSystem::getUserHidActivityStateGated(void *state) 2289{ 2290 if (state) { 2291 *((uint64_t*)state) = _hidActivityIdle ? 1 : 0; 2292 return kIOReturnSuccess; 2293 } 2294 return kIOReturnBadArgument; 2295} 2296 2297// 2298// Helper functions for postEvent 2299// 2300static inline int myAbs(int a) { return(a > 0 ? a : -a); } 2301 2302short IOHIDSystem::getUniqueEventNum() 2303{ 2304 while (++evg->eNum == NULLEVENTNUM) 2305 ; /* sic */ 2306 return(evg->eNum); 2307} 2308 2309// postEvent 2310// 2311// This routine actually places events in the event queue which is in 2312// the EvGlobals structure. It is called from all parts of the ev 2313// driver. 2314// 2315// This should be run from a command gate action. 2316// 2317 2318void IOHIDSystem::postEvent(int what, 2319 /* at */ IOFixedPoint64 *location, 2320 /* atTime */ AbsoluteTime ts, 2321 /* withData */ NXEventData * myData, 2322 /* sender */ OSObject * sender, 2323 /* extPID */ UInt32 extPID, 2324 /* processKEQ*/bool processKEQ) 2325{ 2326 // Clear out the keyboard queue up until this TS. This should keep 2327 // the events in order. 2328 PROFILE_TRACE(7); 2329 if ( processKEQ ) 2330 processKeyboardEQ(this, &ts); 2331 2332 NXEQElement * theHead = (NXEQElement *) &evg->lleq[evg->LLEHead]; 2333 NXEQElement * theLast = (NXEQElement *) &evg->lleq[evg->LLELast]; 2334 NXEQElement * theTail = (NXEQElement *) &evg->lleq[evg->LLETail]; 2335 int wereEvents; 2336 2337 if (CMP_ABSOLUTETIME(&ts, &lastEventTime) < 0) { 2338 ts = lastEventTime; 2339 } 2340 lastEventTime = ts; 2341 2342 // dispatch new event 2343 // RY: doesn't appear there is any traction here after 6 years 2344#if 0 2345 IOHIDEvent * event = IOHIDEvent::withEventData(ts, what, myData); 2346 if ( event ) { 2347 dispatchEvent(event); 2348 event->release(); 2349 } 2350#endif 2351 2352 /* Some events affect screen dimming (idle time) */ 2353 if (EventCodeMask(what) & NX_UNDIMMASK) { 2354 lastUndimEvent = ts; 2355 } 2356 2357 wereEvents = EventsInQueue(); 2358 2359 xpr_ev_post("postEvent: what %d, X %d Y %d Q %d, needKick %d\n", what,location->x,location->y, EventsInQueue(), needToKickEventConsumer); 2360 IOHID_DEBUG(kIOHIDDebugCode_PostEvent, what, theHead, theTail, sender); 2361 2362 if ((!evg->dontCoalesce) /* Coalescing enabled */ 2363 && (theHead != theTail) 2364 && (theLast->event.type == what) 2365 && (EventCodeMask(what) & COALESCEEVENTMASK) 2366 && OSSpinLockTry(&theLast->sema)) { 2367 /* coalesce events */ 2368 theLast->event.location.x = location->xValue().as64(); 2369 theLast->event.location.y = location->yValue().as64(); 2370 absolutetime_to_nanoseconds(ts, &theLast->event.time); 2371 if (myData != NULL) 2372 theLast->event.data = *myData; 2373 OSSpinLockUnlock(&theLast->sema); 2374 } 2375 else if (theTail->next != evg->LLEHead) { 2376 /* store event in tail */ 2377 theTail->event.type = what; 2378 // <rdar://problem/12682920> Task: Switch event.service_id to use registry ID 2379 // theTail->event.service_id = (uintptr_t)sender; 2380 theTail->event.service_id = 0; 2381 if (sender) { 2382 OSNumber *altSender = OSDynamicCast(OSNumber, _senderIDDictionary->getObject((const OSSymbol *)sender)); 2383 if (altSender) { 2384 theTail->event.service_id = altSender->unsigned64BitValue(); 2385 } 2386 else { 2387 IORegistryEntry *entry = OSDynamicCast(IORegistryEntry, sender); 2388 if (entry) { 2389 theTail->event.service_id = (uintptr_t)entry->getRegistryEntryID(); 2390 } 2391 else { 2392 theTail->event.service_id = getRegistryEntryID(); 2393 } 2394 } 2395 } 2396 else { 2397 theTail->event.service_id = getRegistryEntryID(); 2398 } 2399 theTail->event.ext_pid = extPID; 2400 theTail->event.location.x = location->xValue().as64(); 2401 theTail->event.location.y = location->yValue().as64(); 2402 theTail->event.flags = evg->eventFlags; 2403 absolutetime_to_nanoseconds(ts, &theLast->event.time); 2404 theTail->event.window = 0; 2405 2406 if (myData != NULL) 2407 theTail->event.data = *myData; 2408 2409 switch (what) { 2410 case NX_LMOUSEDOWN: 2411 theTail->event.data.mouse.eventNum = 2412 leftENum = getUniqueEventNum(); 2413 break; 2414 case NX_RMOUSEDOWN: 2415 theTail->event.data.mouse.eventNum = 2416 rightENum = getUniqueEventNum(); 2417 break; 2418 case NX_LMOUSEUP: 2419 theTail->event.data.mouse.eventNum = leftENum; 2420 leftENum = NULLEVENTNUM; 2421 // Inform the devices that the mouse was clicked 2422 notifyHIDevices(this, ioHIDevices, kIOHIDSystem508MouseClickMessage); 2423 break; 2424 case NX_RMOUSEUP: 2425 theTail->event.data.mouse.eventNum = rightENum; 2426 rightENum = NULLEVENTNUM; 2427 // Inform the devices that the mouse was clicked 2428 notifyHIDevices(this, ioHIDevices, kIOHIDSystem508MouseClickMessage); 2429 break; 2430 } 2431 2432 if (EventCodeMask(what) & PRESSUREEVENTMASK) { 2433 // this case will not happen unless someone modifies PRESSUREEVENTMASK 2434 if (!((EventCodeMask(what) & MOUSEEVENTMASK) || (EventCodeMask(what) & MOVEDEVENTMASK))) 2435 IOLog("%s: postEvent unknown pressure event, cannot fill pressure.\n", registryName); 2436 } 2437 if (EventCodeMask(what) & MOUSEEVENTMASK) { 2438 /* Click state */ 2439 AbsoluteTime delta = ts; 2440 SUB_ABSOLUTETIME( &delta, &clickTime); 2441 if ((CMP_ABSOLUTETIME(&delta, &clickTimeThresh) <= 0) 2442 && (myAbs(location->xValue().as64() - clickLoc.x) <= clickSpaceThresh.x) 2443 && (myAbs(location->yValue().as64() - clickLoc.y) <= clickSpaceThresh.y)) { 2444 if ((what == NX_LMOUSEDOWN)||(what == NX_RMOUSEDOWN)) { 2445 clickTime = ts; 2446 theTail->event.data.mouse.click = ++clickState; 2447 } 2448 else { 2449 theTail->event.data.mouse.click = clickState; 2450 } 2451 } 2452 else if ((what == NX_LMOUSEDOWN)||(what == NX_RMOUSEDOWN)) { 2453 clickLoc = *location; 2454 clickTime = ts; 2455 clickState = 1; 2456 theTail->event.data.mouse.click = clickState; 2457 } 2458 else 2459 theTail->event.data.mouse.click = 0; 2460 } 2461#if PMON 2462 pmon_log_event(PMON_SOURCE_EV, 2463 KP_EV_POST_EVENT, 2464 what, 2465 evg->eventFlags, 2466 theClock); 2467#endif 2468 evg->LLETail = theTail->next; 2469 evg->LLELast = theLast->next; 2470 if ( ! wereEvents ) // Events available, so wake event consumer 2471 kickEventConsumer(); 2472 } 2473 else { 2474 /* 2475 * if queue is full, ignore event, too hard to take care of all cases 2476 */ 2477 static uint64_t next_log = 0; 2478 if (AbsoluteTime_to_scalar(&ts) > next_log) 2479 { 2480 IOLog("%s: postEvent LLEventQueue overflow.\n", registryName); 2481 nanoseconds_to_absolutetime(60000000000LL, (AbsoluteTime*)&next_log); 2482 next_log += AbsoluteTime_to_scalar(&ts); 2483 } 2484 kickEventConsumer(); 2485#if PMON 2486 pmon_log_event( PMON_SOURCE_EV, 2487 KP_EV_QUEUE_FULL, 2488 what, 2489 evg->eventFlags, 2490 theClock); 2491#endif 2492 } 2493 PROFILE_TRACE(8); 2494} 2495 2496/* 2497 * - kickEventConsumer 2498 * 2499 * Try to send a message out to let the event consumer know that 2500 * there are now events available for consumption. 2501 */ 2502 2503void IOHIDSystem::kickEventConsumer() 2504{ 2505 xpr_ev_post("kickEventConsumer (need == %d)\n", 2506 needToKickEventConsumer,2,3,4,5); 2507 2508 if ( needToKickEventConsumer == true ) 2509 return; // Request is already pending 2510 2511 needToKickEventConsumer = true; // Posting a request now 2512 2513 // Trigger eventConsumerES, so that doKickEventConsumer 2514 // is run from the workloop thread. 2515 eventConsumerES->interruptOccurred(0, 0, 0); 2516} 2517 2518/* 2519 * - sendStackShotMessage 2520 * 2521 * Try to send a message out to let the stack shot know we got 2522 * the magic key sequence 2523 */ 2524 2525void IOHIDSystem::sendStackShotMessage(UInt32 flavor) 2526{ 2527 kern_return_t r; 2528 mach_msg_header_t *msgh; 2529 2530 xpr_ev_post("sendStackShotMessage\n", 1,2,3,4,5); 2531 2532 if (stackShotMsg) { 2533 ((IOHIDSystem_stackShotMessage*)stackShotMsg)->flavor = flavor; 2534 msgh = (mach_msg_header_t *)stackShotMsg; 2535 if( msgh) { 2536 2537 r = mach_msg_send_from_kernel( msgh, msgh->msgh_size); 2538 switch ( r ) { 2539 case MACH_SEND_TIMED_OUT:/* Already has a message posted */ 2540 case MACH_MSG_SUCCESS: /* Message is posted */ 2541 break; 2542 default: /* Log the error */ 2543 IOLog("%s: sendStackShotMessage msg_send returned %d\n", registryName, r); 2544 break; 2545 } 2546 } 2547 } 2548} 2549 2550/* 2551 * HID System no longer runs the following methods on the EventSource thread. 2552 * Instead all are run from the caller thread through the use of command gates. 2553 * This will limit the amount of context switching that takes place. 2554 */ 2555 2556 2557/* 2558 * The following methods are executed from the caller thread only. 2559 */ 2560 2561/* 2562 * The method is now called from a command gate and is run on the caller thread 2563 */ 2564 2565void IOHIDSystem::doSpecialKeyMsg(IOHIDSystem * self, 2566 struct evioSpecialKeyMsg *msg) /* IOCommandGate::Action */ 2567{ 2568 kern_return_t r; 2569 2570 xpr_ev_post("doSpecialKeyMsg 0x%x\n", msg,2,3,4,5); 2571 2572 2573 /* FIXME: Don't block */ 2574 r = mach_msg_send_from_kernel( &msg->Head, msg->Head.msgh_size); 2575 2576 xpr_ev_post("doSpecialKeyMsg: msg_send() == %d\n",r,2,3,4,5); 2577 if ( r != MACH_MSG_SUCCESS ) 2578 { 2579 IOLog("%s: doSpecialKeyMsg msg_send returned %d\n", 2580 self->registryName, r); 2581 } 2582 if ( r == MACH_SEND_INVALID_DEST ) /* Invalidate the port */ 2583 { 2584 self->setSpecialKeyPort( 2585 /* keyFlavor */ msg->key, 2586 /* keyPort */ MACH_PORT_NULL); 2587 } 2588 IOFree( (void *)msg, sizeof (struct evioSpecialKeyMsg) ); 2589} 2590 2591/* 2592 * This is now being run from the workloop via an IOInterruptEventSource. 2593 * Note that we perform a non-blocking send. The Event port in the event 2594 * consumer has a queue depth of 1 message. Once the consumer picks up that 2595 * message, it runs until the event queue is exhausted before trying to read 2596 * another message. If a message is pending,there is no need to enqueue a 2597 * second one. This also keeps us from blocking the I/O thread in a msg_send 2598 * which could result in a deadlock if the consumer were to make a call into 2599 * the event driver. 2600 */ 2601void IOHIDSystem::doKickEventConsumer(IOHIDSystem * self) /*IOInterruptEventSource::Action */ 2602{ 2603 kern_return_t r; 2604 mach_msg_header_t *msgh; 2605 2606 self->needToKickEventConsumer = false; // Request received and processed 2607 2608 // RY: If the eventPost is null, do nothing 2609 if ( self->eventPort == MACH_PORT_NULL ) 2610 return; 2611 2612 xpr_ev_post("doKickEventConsumer\n", 1,2,3,4,5); 2613 2614 msgh = (mach_msg_header_t *)self->eventMsg; 2615 if( msgh) { 2616 2617 r = mach_msg_send_from_kernel( msgh, msgh->msgh_size); 2618 switch ( r ) 2619 { 2620 case MACH_SEND_TIMED_OUT:/* Already has a message posted */ 2621 case MACH_MSG_SUCCESS: /* Message is posted */ 2622 break; 2623 default: /* Log the error */ 2624 IOLog("%s: doKickEventConsumer msg_send returned %d\n", 2625 self->registryName, r); 2626 break; 2627 } 2628 } 2629} 2630 2631void IOHIDSystem::scheduleNextPeriodicEvent() 2632{ 2633 if ( !eventsOpen ) { 2634 // If eventsOpen is false, then the driver shmem is 2635 // no longer valid, and it is in the process of shutting down. 2636 // We should give up without rescheduling. 2637 IOHID_DEBUG(kIOHIDDebugCode_Scheduling, 0, 0, 0, 0); 2638 } 2639 else { 2640 uint64_t scheduledEvent = _periodicEventNext; 2641 uint64_t now = 0; 2642 static uint64_t kOneMS = 0; 2643 if (!kOneMS) { 2644 clock_interval_to_absolutetime_interval(1, kMillisecondScale, &kOneMS); 2645 } 2646 clock_get_uptime(&now); 2647 2648 if ((scheduledEvent > _periodicEventLast) && (scheduledEvent < (now + kOneMS))) { 2649 // we have an event scheduled in the next MS. Do not reschedule. 2650 } 2651 else { 2652 if (scheduledEvent <= _periodicEventLast) { 2653 // scheduledEvent is old. do not reuse. 2654 scheduledEvent = kIOHIDSystenDistantFuture; 2655 } 2656 2657 if (screens && (kIOPMDeviceUsable | displayState)) { 2658 // displays are on and nothing is scheduled. 2659 // calculate deltas 2660 uint64_t nextMove = _cursorMoveLast + _cursorMoveDelta; 2661 uint64_t nextWait = _cursorWaitLast + _cursorWaitDelta; 2662 2663 if (_cursorMoveDelta) { 2664 if (_cursorEventLast > _cursorMoveLast) { 2665 scheduledEvent = nextMove; 2666 } 2667 } 2668 2669 bool waitCursorShouldAlreadyBeUp = evg->waitCursorEnabled && 2670 evg->globalWaitCursorEnabled && 2671 evg->ctxtTimedOut && 2672 _cursorWaitDelta; 2673 if (waitCursorShouldAlreadyBeUp) { 2674 if (evg->waitCursorUp) { 2675 if (scheduledEvent > nextWait) { 2676 // update the wait cursor 2677 scheduledEvent = nextWait; 2678 } 2679 } 2680 else { 2681 // *show* the wait cursor immediately 2682 scheduledEvent = now + kOneMS; 2683 } 2684 2685 } 2686 else if (evg->waitCursorUp) { 2687 // *hide* the wait cursor immediately 2688 scheduledEvent = now + kOneMS; 2689 } 2690#if 0 2691 kprintf(" %d%d%d%d %lld : %lld %lld %lld %llu\n", 2692 evg->waitCursorEnabled, evg->globalWaitCursorEnabled, evg->ctxtTimedOut, evg->waitCursorUp, 2693 now, 2694 scheduledEvent, nextMove, nextWait, _cursorWaitDelta); 2695#endif 2696 IOHID_DEBUG(kIOHIDDebugCode_Scheduling, scheduledEvent, nextMove, nextWait, 0); 2697 } 2698 else { 2699 // We have something to do, but no one is "listening". 2700 // Try again in 50 ms. 2701 scheduledEvent = now + (50 * kOneMS); 2702 IOHID_DEBUG(kIOHIDDebugCode_Scheduling, scheduledEvent, 0, 0, 0); 2703 } 2704 2705 if (kIOHIDSystenDistantFuture == scheduledEvent) { 2706 // no periodic events. cancel any pending periodic timer. 2707 periodicES->cancelTimeout(); 2708 } 2709 else { 2710 _periodicEventNext = scheduledEvent; 2711 if (now + kOneMS > _periodicEventNext) { 2712 // do not schedule the event too soon. 2713 _periodicEventNext = now + kOneMS; 2714 } 2715 if (now + (100 * kOneMS) < _periodicEventNext) { 2716 // after 100 ms, we really should check again. *something* is happening. 2717 _periodicEventNext = now + (100 * kOneMS); 2718 } 2719 IOReturn err = periodicES->wakeAtTime(_periodicEventNext); 2720 if (err) { 2721 IOLog("%s:%d wakeAtTime failed for %lld: %08x (%s)\n", __func__, __LINE__, _periodicEventNext, err, stringFromReturn(err)); 2722 } 2723 } 2724 } 2725 } 2726} 2727 2728// Periodic events are driven from this method. 2729// After taking care of all pending work, the method 2730// calls scheduleNextPeriodicEvent to compute and set the 2731// next callout. 2732 2733// Modified this method to call a command Gate action. 2734// This will hopefully insure that this is serialized 2735// with other actions associated with the command gate. 2736 2737void IOHIDSystem::_periodicEvents(IOHIDSystem * self, 2738 IOTimerEventSource *timer) 2739{ 2740 self->periodicEvents(timer); 2741} 2742 2743void IOHIDSystem::periodicEvents(IOTimerEventSource * timer __unused) 2744{ 2745 // If eventsOpen is false, then the driver shmem is 2746 // no longer valid, and it is in the process of shutting down. 2747 // We should give up without rescheduling. 2748 if ( !eventsOpen ) 2749 return; 2750 2751 clock_get_uptime(&_periodicEventLast); // update last event 2752 _periodicEventNext = kIOHIDSystenDistantFuture; // currently no next event 2753 2754 // Update cursor position if needed 2755 if (_periodicEventLast >= _cursorMoveLast + _cursorMoveDelta) { 2756 _cursorHelper.startPosting(); 2757 _cursorHelper.applyPostingDelta(); 2758 _setCursorPosition(false, false, lastSender); 2759 OSSafeReleaseNULL(lastSender); 2760 _cursorMoveLast = _periodicEventLast; 2761 } 2762 2763 // WAITCURSOR ACTION 2764 if ( OSSpinLockTry(&evg->waitCursorSema) ) 2765 { 2766 if ( OSSpinLockTry(&evg->cursorSema) ) 2767 { 2768 // If wait cursor enabled and context timed out, do waitcursor 2769 if (evg->waitCursorEnabled && evg->globalWaitCursorEnabled) 2770 { 2771 /* WAIT CURSOR SHOULD BE ON */ 2772 if (!evg->waitCursorUp) { 2773 showWaitCursor(); 2774 _cursorWaitLast = _periodicEventLast; 2775 } 2776 } 2777 else { 2778 /* WAIT CURSOR SHOULD BE OFF */ 2779 if (evg->waitCursorUp) { 2780 hideWaitCursor(); 2781 _cursorWaitLast = _periodicEventLast; 2782 } 2783 } 2784 /* Animate cursor */ 2785 if (evg->waitCursorUp && ((_cursorWaitLast + _cursorWaitDelta) < _periodicEventLast)) { 2786 animateWaitCursor(); 2787 _cursorWaitLast = _periodicEventLast; 2788 } 2789 OSSpinLockUnlock(&evg->cursorSema); 2790 } 2791 OSSpinLockUnlock(&evg->waitCursorSema); 2792 } 2793 2794 scheduleNextPeriodicEvent(); 2795 2796 return; 2797} 2798 2799// 2800// Start the cursor system running. 2801// 2802// At this point, the WindowServer is up, running, and ready to process events. 2803// We will attach the keyboard and mouse, if none are available yet. 2804// 2805bool IOHIDSystem::resetCursor() 2806{ 2807 volatile IOGPoint * p; 2808 UInt32 newScreens = 0; 2809 SInt32 candidate = 0; 2810 SInt32 pinScreen = -1L; 2811 2812 p = &evg->cursorLoc; 2813 2814 /* Get mask of screens on which the cursor is present */ 2815 EvScreen *screen = (EvScreen *)evScreen; 2816 for (int i = 0; i < screens; i++ ) { 2817 if (!screen[i].desktopBounds) 2818 continue; 2819 if ((screen[i].desktopBounds->maxx - screen[i].desktopBounds->minx) < 128) 2820 continue; 2821 candidate = i; 2822 if (_cursorHelper.desktopLocation().inRect(*screen[i].desktopBounds)) { 2823 pinScreen = i; 2824 newScreens |= (1 << i); 2825 } 2826 } 2827 2828 if (newScreens == 0) 2829 pinScreen = candidate; 2830 2831 if (!cursorPinned) { 2832 // reset pin rect 2833 if (((EvScreen*)evScreen)[pinScreen].desktopBounds) { 2834 cursorPin = *(((EvScreen*)evScreen)[pinScreen].desktopBounds); 2835 cursorPin.maxx--; /* Make half-open rectangle */ 2836 cursorPin.maxy--; 2837 cursorPinScreen = pinScreen; 2838 } 2839 else { 2840 // How do you pin when there are no screens with bounds... 2841 } 2842 } 2843 2844 if (newScreens == 0) { 2845 /* Pin new cursor position to cursorPin rect */ 2846 p->x = (p->x < cursorPin.minx) ? 2847 cursorPin.minx : ((p->x > cursorPin.maxx) ? 2848 cursorPin.maxx : p->x); 2849 p->y = (p->y < cursorPin.miny) ? 2850 cursorPin.miny : ((p->y > cursorPin.maxy) ? 2851 cursorPin.maxy : p->y); 2852 2853 /* regenerate mask for new position */ 2854 for (int i = 0; i < screens; i++ ) { 2855 if (!screen[i].desktopBounds) 2856 continue; 2857 if ((screen[i].desktopBounds->maxx - screen[i].desktopBounds->minx) < 128) 2858 continue; 2859 if (_cursorHelper.desktopLocation().inRect(*screen[i].desktopBounds)){ 2860 pinScreen = i; 2861 newScreens |= (1 << i); 2862 } 2863 } 2864 } 2865 2866 cursorScreens = newScreens; 2867 IOFixedPoint64 tempLoc; 2868 if (evg->updateCursorPositionFromFixed) { 2869 tempLoc.fromFixed24x8(evg->desktopCursorFixed.x, evg->desktopCursorFixed.y); 2870 } 2871 else { 2872 tempLoc.fromIntFloor(evg->cursorLoc.x, evg->cursorLoc.y); 2873 } 2874 _cursorHelper.desktopLocationDelta() += tempLoc - _cursorHelper.desktopLocation(); 2875 _cursorHelper.desktopLocation() = tempLoc; 2876 if (pinScreen >= 0) { 2877 _cursorHelper.updateScreenLocation(screen[pinScreen].desktopBounds, screen[pinScreen].displayBounds); 2878 } 2879 else { 2880 _cursorHelper.updateScreenLocation(NULL, NULL); 2881 } 2882 2883 _cursorMoveDelta = _cursorWaitDelta = 0; 2884 _cursorHelper.desktopLocationPosting().fromIntFloor(0, 0); 2885 _cursorHelper.clearEventCounts(); 2886 2887 _cursorLogTimed(); 2888 2889 scheduleNextPeriodicEvent(); 2890 2891 return( true ); 2892} 2893 2894bool IOHIDSystem::startCursor() 2895{ 2896 if (0 == screens) { 2897 // no screens, no cursor 2898 } 2899 else { 2900 cursorPinned = false; 2901 resetCursor(); 2902 showCursor(); 2903 2904 // Start the cursor control callouts 2905 scheduleNextPeriodicEvent(); 2906 2907 cursorStarted = true; 2908 } 2909 2910 return( cursorStarted ); 2911} 2912 2913// 2914// Wait Cursor machinery. These methods should be run from a command 2915// gate action and the shared memory area must be set up. 2916// 2917void IOHIDSystem::showWaitCursor() 2918{ 2919 xpr_ev_cursor("showWaitCursor\n",1,2,3,4,5); 2920 evg->waitCursorUp = true; 2921 hideCursor(); 2922 evg->frame = EV_WAITCURSOR; 2923 showCursor(); 2924} 2925 2926void IOHIDSystem::hideWaitCursor() 2927{ 2928 xpr_ev_cursor("hideWaitCursor\n",1,2,3,4,5); 2929 evg->waitCursorUp = false; 2930 hideCursor(); 2931 evg->frame = EV_STD_CURSOR; 2932 showCursor(); 2933} 2934 2935void IOHIDSystem::animateWaitCursor() 2936{ 2937 xpr_ev_cursor("animateWaitCursor\n",1,2,3,4,5); 2938 changeCursor(evg->frame + 1); 2939} 2940 2941void IOHIDSystem::changeCursor(int frame) 2942{ 2943 evg->frame = ((frame > (int)maxWaitCursorFrame) || (frame > evg->lastFrame)) ? firstWaitCursorFrame : frame; 2944 xpr_ev_cursor("changeCursor %d\n",evg->frame,2,3,4,5); 2945 moveCursor(); 2946} 2947 2948// 2949// Return the screen number in which point p lies. Return -1 if the point 2950// lies outside of all registered screens. 2951// 2952int IOHIDSystem::pointToScreen(IOGPoint * p) 2953{ 2954 int i; 2955 EvScreen *screen = (EvScreen *)evScreen; 2956 for (i=screens; --i != -1; ) { 2957 if ((screen[i].desktopBounds != 0) 2958 && (p->x >= screen[i].desktopBounds->minx) 2959 && (p->x < screen[i].desktopBounds->maxx) 2960 && (p->y >= screen[i].desktopBounds->miny) 2961 && (p->y < screen[i].desktopBounds->maxy)) 2962 return i; 2963 } 2964 return(-1); /* Cursor outside of known screen boundary */ 2965} 2966 2967// 2968// API used to drive event state out to attached screens 2969// 2970// These should be run from a command gate action. 2971// 2972inline void IOHIDSystem::showCursor() 2973{ 2974 evDispatch(/* command */ EVSHOW); 2975} 2976inline void IOHIDSystem::hideCursor() 2977{ 2978 evDispatch(/* command */ EVHIDE); 2979} 2980 2981inline void IOHIDSystem::moveCursor() 2982{ 2983 evDispatch(/* command */ EVMOVE); 2984} 2985 2986// 2987// - attachDefaultEventSources 2988// Attach the default event sources. 2989// 2990void IOHIDSystem::attachDefaultEventSources() 2991{ 2992 IOService * source; 2993 OSIterator * sources; 2994 2995 2996 sources = getProviderIterator(); 2997 2998 if (!sources) return; 2999 3000 while( (source = (IOService *)sources->getNextObject())) { 3001 if ((OSDynamicCast(IOHIDevice, source) && !OSDynamicCast(IOHIKeyboard, source)) 3002 || OSDynamicCast(IOHIDEventService, source)) { 3003 3004 registerEventSource(source); 3005 } 3006 } 3007 sources->release(); 3008} 3009 3010// 3011// - detachEventSources 3012// Detach all event sources 3013// 3014void IOHIDSystem::detachEventSources() 3015{ 3016 OSIterator * iter; 3017 IOService * srcInstance; 3018 3019 iter = getOpenProviderIterator(); 3020 if( iter) { 3021 while( (srcInstance = (IOService *) iter->getNextObject())) { 3022 3023 if ( ! OSDynamicCast(IOHIKeyboard, srcInstance) ) { 3024 #ifdef DEBUG 3025 kprintf("detachEventSource:%s\n", srcInstance->getName()); 3026 #endif 3027 srcInstance->close(this); 3028 } 3029 } 3030 iter->release(); 3031 } 3032} 3033 3034// 3035// EventSrcClient implementation 3036// 3037 3038// 3039// A new device instance desires to be added to our list. 3040// Try to get ownership of the device. If we get it, add it to 3041// the list. 3042// 3043bool IOHIDSystem::registerEventSource(IOService * source) 3044{ 3045 bool success = false; 3046 3047#ifdef DEBUG 3048 kprintf("registerEventSource:%s\n", source->getName()); 3049#endif 3050 3051 if ( OSDynamicCast(IOHIKeyboard, source) ) { 3052 success = ((IOHIKeyboard*)source)->open(this, kIOServiceSeize,0, 3053 (KeyboardEventCallback) _keyboardEvent, 3054 (KeyboardSpecialEventCallback) _keyboardSpecialEvent, 3055 (UpdateEventFlagsCallback) _updateEventFlags); 3056 source->setProperty(kIOHIDResetKeyboardKey, kOSBooleanTrue); 3057 } else if ( OSDynamicCast(IOHIPointing, source) ) { 3058 if ( OSDynamicCast(IOHITablet, source) ) { 3059 success = ((IOHITablet*)source)->open(this, kIOServiceSeize,0, 3060 (RelativePointerEventCallback) _relativePointerEvent, 3061 (AbsolutePointerEventCallback) _absolutePointerEvent, 3062 (ScrollWheelEventCallback) _scrollWheelEvent, 3063 (TabletEventCallback) _tabletEvent, 3064 (ProximityEventCallback) _proximityEvent); 3065 } else { 3066 success = ((IOHIPointing*)source)->open(this, kIOServiceSeize,0, 3067 (RelativePointerEventCallback) _relativePointerEvent, 3068 (AbsolutePointerEventCallback) _absolutePointerEvent, 3069 (ScrollWheelEventCallback) _scrollWheelEvent); 3070 } 3071 source->setProperty(kIOHIDResetPointerKey, kOSBooleanTrue); 3072 } else { 3073 success = source->open(this, kIOServiceSeize, 0); 3074 } 3075 3076 if ( success ) 3077 { 3078 3079 OSDictionary * newParams = OSDictionary::withDictionary( savedParameters ); 3080 if( newParams) { 3081 3082 // update with user settings 3083 if ( OSDynamicCast(IOHIDevice, source) ) 3084 ((IOHIDevice *)source)->setParamProperties( newParams ); 3085 else if ( OSDynamicCast(IOHIDEventService, source) ) 3086 ((IOHIDEventService *)source)->setSystemProperties( newParams ); 3087 3088 setProperty( kIOHIDParametersKey, newParams ); 3089 newParams->release(); 3090 savedParameters = newParams; 3091 } 3092 3093 } 3094 else 3095 IOLog("%s: Seize of %s failed.\n", registryName, source->getName()); 3096 3097 return success; 3098} 3099 3100IOReturn IOHIDSystem::message(UInt32 type, IOService * provider, 3101 void * argument) 3102{ 3103 IOReturn status = kIOReturnSuccess; 3104 3105 switch (type) 3106 { 3107 case kIOMessageServiceIsTerminated: 3108 if (provider) { 3109 provider->close( this ); 3110 } 3111 break; 3112 3113 case kIOMessageServiceWasClosed: 3114 break; 3115 3116 case kIOHIDSystemActivityTickle: { 3117 intptr_t nxEvent = (intptr_t) argument; 3118 if ((nxEvent >= 0) && (nxEvent <= NX_LASTEVENT)) { 3119 if (!evStateChanging && displayManager) { 3120 IOHID_DEBUG(kIOHIDDebugCode_DisplayTickle, nxEvent, __LINE__, displayState, 3121 provider ? provider->getRegistryEntryID() : 0); 3122 if (DISPLAY_IS_ENABLED || (NX_WAKEMASK & EventCodeMask(nxEvent))) { 3123 if (!DISPLAY_IS_ENABLED) { 3124 kprintf("IOHIDSystem tickle when screen off for event %ld\n", nxEvent); 3125 } 3126 displayManager->activityTickle(IOHID_DEBUG_CODE(nxEvent)); 3127 } 3128 } 3129 } 3130 else if (nxEvent == NX_HARDWARE_TICKLE) { 3131 if (!evStateChanging && displayManager) { 3132 IOHID_DEBUG(kIOHIDDebugCode_DisplayTickle, nxEvent, __LINE__, displayState, 3133 provider ? provider->getRegistryEntryID() : 0); 3134 if (!DISPLAY_IS_ENABLED) { 3135 kprintf("IOHIDSystem tickle when screen off for hardware event from %08llx\n", 3136 provider ? provider->getRegistryEntryID() : 0); 3137 } 3138 displayManager->activityTickle(IOHID_DEBUG_CODE(nxEvent)); 3139 } 3140 } 3141 else { 3142 IOLog("kIOHIDSystemActivityTickle message for unsupported event %ld sent from %08llx\n", 3143 nxEvent, provider ? provider->getRegistryEntryID() : 0); 3144 } 3145 break; 3146 } 3147 3148 default: 3149 status = super::message(type, provider, argument); 3150 break; 3151 } 3152 3153 return status; 3154} 3155 3156// 3157// This will scale the point at location in the coordinate system represented by bounds 3158// to the coordinate system of the current screen. 3159// This is needed for absolute pointer events that come from devices with different bounds. 3160// 3161void IOHIDSystem::scaleLocationToCurrentScreen(IOGPoint *location, IOGBounds *bounds __unused) 3162{ 3163 IOHIDSystem * hidsystem = instance(); 3164 3165 if ( hidsystem ) { 3166 IOFixedPoint64 temp; 3167 temp.fromIntFloor(location->x, location->y); 3168 hidsystem->_scaleLocationToCurrentScreen(temp, bounds); 3169 *location = (IOGPoint)temp; 3170 } 3171} 3172 3173void IOHIDSystem::_scaleLocationToCurrentScreen(IOFixedPoint64 &location, IOGBounds *bounds) 3174{ 3175 if (!bounds) { 3176 // no transform can be performed 3177 } 3178 else { 3179 if (*(UInt64*)&cursorPin == *(UInt64*)bounds) { 3180 // no transform needed 3181 } 3182 else { 3183 int boundsWidth = bounds->maxx - bounds->minx; 3184 int boundsHeight = bounds->maxy - bounds->miny; 3185 int cursorPinWidth = cursorPin.maxx - cursorPin.minx; 3186 int cursorPinHeight = cursorPin.maxy - cursorPin.miny; 3187 if ((boundsWidth <= 0) || (boundsHeight <= 0) || (cursorPinWidth <= 0) || (cursorPinHeight <= 0)) { 3188 // no transform can be performed 3189 } 3190 else { 3191 IOFixedPoint64 scratch; 3192 if ((boundsWidth == cursorPinWidth) && (boundsHeight == cursorPinHeight)) { 3193 // translation only 3194 location += scratch.fromIntFloor(bounds->minx - cursorPin.minx, 3195 bounds->miny - cursorPin.miny); 3196 } 3197 else { 3198 // full transform 3199 IOFixed64 x_scale; 3200 IOFixed64 y_scale; 3201 x_scale.fromIntFloor(cursorPinWidth) /= boundsWidth; 3202 y_scale.fromIntFloor(cursorPinHeight) /= boundsHeight; 3203 location -= scratch.fromIntFloor(bounds->minx, bounds->miny); 3204 location *= scratch.fromFixed64(x_scale, y_scale); 3205 location += scratch.fromIntFloor(cursorPin.minx, cursorPin.miny); 3206 } 3207 } 3208 } 3209 } 3210 return; 3211} 3212 3213// 3214// Process a mouse status change. The driver should sign extend 3215// it's deltas and perform any bit flipping needed there. 3216// 3217// We take the state as presented and turn it into events. 3218// 3219void IOHIDSystem::_relativePointerEvent(IOHIDSystem * self, 3220 int buttons, 3221 /* deltaX */ int dx, 3222 /* deltaY */ int dy, 3223 /* atTime */ AbsoluteTime ts, 3224 OSObject * sender, 3225 void * refcon __unused) 3226{ 3227 self->relativePointerEvent(buttons, dx, dy, ts, sender); 3228} 3229 3230void IOHIDSystem::relativePointerEvent(int buttons, 3231 /* deltaX */ int dx, 3232 /* deltaY */ int dy, 3233 /* atTime */ AbsoluteTime ts) 3234{ 3235 relativePointerEvent(buttons, dx, dy, ts, 0); 3236} 3237 3238void IOHIDSystem::relativePointerEvent(int buttons, 3239 /* deltaX */ int dx, 3240 /* deltaY */ int dy, 3241 /* atTime */ AbsoluteTime ts, 3242 /* sender */ OSObject * sender) 3243{ 3244 IOHIDCmdGateActionArgs args; 3245 args.arg0 = &buttons; 3246 args.arg1 = &dx; 3247 args.arg2 = &dy; 3248 args.arg3 = &ts; 3249 args.arg4 = sender; 3250 3251 cmdGate->runAction((IOCommandGate::Action)doRelativePointerEvent, &args); 3252} 3253 3254 3255IOReturn IOHIDSystem::doRelativePointerEvent(IOHIDSystem *self, void * args) 3256 /* IOCommandGate::Action */ 3257{ 3258 int buttons = *(int *)((IOHIDCmdGateActionArgs *)args)->arg0; 3259 int dx = *(int *)((IOHIDCmdGateActionArgs *)args)->arg1; 3260 int dy = *(int *)((IOHIDCmdGateActionArgs *)args)->arg2; 3261 SInt64 ts = *(SInt64 *)((IOHIDCmdGateActionArgs *)args)->arg3; 3262 OSObject * sender = (OSObject *)((IOHIDCmdGateActionArgs *)args)->arg4; 3263 3264 self->relativePointerEventGated(buttons, dx, dy, ts, sender); 3265 3266 return kIOReturnSuccess; 3267} 3268 3269//************************************************************ 3270static bool vblForScreen(IOGraphicsDevice *io_gd_I, uint64_t &delta_O) 3271{ 3272 uint64_t nextVBL = 0; 3273 static UInt64 minVBLdelta = 0; 3274 static UInt64 maxVBLdelta = 0; 3275 3276 // rdar://5565815 Capping VBL interval 3277 if (!minVBLdelta) { 3278 // A screen refresh of more than 50ms (20Hz) is not acceptable. 3279 nanoseconds_to_absolutetime(50000000, (&maxVBLdelta)); 3280 // A screen refresh of less than 5ms (200Hz) is not necessary. 3281 nanoseconds_to_absolutetime(5000000, (&minVBLdelta)); 3282 } 3283 3284 if (io_gd_I) { 3285 io_gd_I->getVBLTime( &nextVBL, &delta_O ); 3286 if (delta_O < minVBLdelta) { 3287 delta_O = minVBLdelta; 3288 } 3289 else if (delta_O > maxVBLdelta) { 3290 delta_O = maxVBLdelta; 3291 } 3292 } 3293 else { 3294 delta_O = maxVBLdelta; 3295 } 3296 3297 return (nextVBL != 0); 3298} 3299 3300void IOHIDSystem::relativePointerEventGated(int buttons, int dx_I, int dy_I, SInt64 ts, OSObject * sender) 3301{ 3302 bool movementEvent = false; 3303 3304 PROFILE_TRACE(1); 3305 3306 if( eventsOpen == false ) 3307 return; 3308 3309 // Compare relative mouse deltas against thresholds to determine if the 3310 // movement should generate a tickle. This will prevent chatty mice from 3311 // tickling without user input. 3312 CachedMouseEventStruct *cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender); 3313 if (cachedMouseEvent) { 3314 UInt64 ts_nano; 3315 absolutetime_to_nanoseconds(ts, &ts_nano); 3316 3317 if (ts_nano > cachedMouseEvent->eventDeadline) { 3318 cachedMouseEvent->eventDeadline = ts_nano + kIOHIDChattyMouseSuppressionDelayNS; 3319 cachedMouseEvent->accumX = 0; 3320 cachedMouseEvent->accumY = 0; 3321 } 3322 3323 cachedMouseEvent->accumX += dx_I; 3324 cachedMouseEvent->accumY += dy_I; 3325 3326 if ((abs(cachedMouseEvent->accumX) >= kIOHIDRelativeTickleThresholdPixel) || 3327 (abs(cachedMouseEvent->accumY) >= kIOHIDRelativeTickleThresholdPixel)) 3328 { 3329 movementEvent = true; 3330 } 3331 3332 cachedMouseEvent->lastButtons = buttons; 3333 cachedMouseEvent->eventDeadline = ts_nano; 3334 3335 // Fake up pressure changes from button state changes 3336 if( (buttons & EV_LB) != (evg->buttons & EV_LB) ){ 3337 cachedMouseEvent->lastPressure = ( buttons & EV_LB ) ? MAXPRESSURE : MINPRESSURE; 3338 } 3339 } 3340 3341 // do not tickle on movement if the screen is dark (some restrictions apply) 3342 if (buttons & EV_LB) { 3343 // always tickle on left button down 3344 TICKLE_DISPLAY(NX_LMOUSEDOWN); 3345 } 3346 else if (buttons & EV_RB) { 3347 // always tickle on right button down 3348 TICKLE_DISPLAY(NX_RMOUSEDOWN); 3349 } 3350 else if (buttons) { 3351 // always tickle on other buttons down 3352 TICKLE_DISPLAY(NX_OMOUSEDOWN); 3353 } 3354 else if (movementEvent) { 3355 if (DISPLAY_IS_ENABLED) { 3356 // the display is on. send a moved tickle. 3357 TICKLE_DISPLAY(NX_MOUSEMOVED); 3358 } 3359 else 3360 { 3361 // the display is off... 3362 if (CMP_ABSOLUTETIME(&ts, &displaySleepWakeupDeadline) <= 0) { 3363 // but not too much time has passed. send a moved tickle. 3364 TICKLE_DISPLAY(NX_MOUSEMOVED); 3365 } 3366 return; 3367 } 3368 } 3369 3370 if (ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline)) { 3371 return; 3372 } 3373 3374 _setButtonState(buttons, /* atTime */ ts, sender); 3375 3376 _cursorHelper.incrementEventCount(); 3377 IOFixedPoint64 scratch; 3378 if ( scratch.fromIntFloor(dx_I, dy_I) ) { 3379 UInt64 uptime = 0; 3380 bool haveVBL = vblForScreen(((EvScreen*)evScreen)[cursorPinScreen].instance, _cursorMoveDelta); 3381 3382 clock_get_uptime(&uptime); 3383 3384 if (((scratch.xValue() > 0LL) && (_cursorHelper.desktopLocationAccumulated().xValue() < 0LL)) || 3385 ((scratch.xValue() < 0LL) && (_cursorHelper.desktopLocationAccumulated().xValue() > 0LL))) { 3386 _cursorHelper.desktopLocationAccumulated().xValue().fromIntFloor(0); 3387 } 3388 if (((scratch.yValue() > 0LL) && (_cursorHelper.desktopLocationAccumulated().yValue() < 0LL)) || 3389 ((scratch.yValue() < 0LL) && (_cursorHelper.desktopLocationAccumulated().yValue() > 0LL))) { 3390 _cursorHelper.desktopLocationAccumulated().yValue().fromIntFloor(0); 3391 } 3392 3393 IOHID_DEBUG(kIOHIDDebugCode_RelativePointerEventTiming, _cursorMoveDelta, 0, 3394 dx_I, dy_I); 3395 3396 _cursorHelper.desktopLocationAccumulated() += scratch; 3397 3398 scratch = _cursorHelper.desktopLocationAccumulated(); // for ease of reference 3399 _cursorEventLast = uptime; 3400 3401 if (!haveVBL) { 3402 // no VBL 3403 // post immediatly 3404 periodicEvents(NULL); 3405 } 3406 else { 3407 // see rdar://7675662 3408 if (cachedMouseEvent && (cachedMouseEvent->reportInterval_ns > 0)) { 3409 uint64_t cursorMoveDelta_ns; 3410 absolutetime_to_nanoseconds(_cursorMoveDelta, &cursorMoveDelta_ns); 3411 _cursorHelper.expectedCount().fromIntFloor(cursorMoveDelta_ns); 3412 _cursorHelper.expectedCount() /= cachedMouseEvent->reportInterval_ns; 3413 IOHID_DEBUG(kIOHIDDebugCode_RelativePointerEventScaling, 3414 scratch.xValue().asFixed(), scratch.yValue().asFixed(), 3415 _cursorHelper.expectedCount().asFixed(), 3416 _cursorHelper.getEventCountPosting() * 65536); 3417 } 3418 else { 3419 _cursorHelper.expectedCount().fromIntFloor(0); 3420 } 3421 3422 if (sender) 3423 sender->retain(); 3424 OSSafeReleaseNULL(lastSender); 3425 lastSender = sender; 3426 3427 if (uptime > _cursorMoveLast + 2 * _cursorMoveDelta) { 3428 // either we are not posting currently or this event is overdue. 3429 // post immediately 3430 periodicEvents(periodicES); // handles scheduling 3431 } 3432 else { 3433 scheduleNextPeriodicEvent(); 3434 } 3435 } 3436 _cursorLog(AbsoluteTime_to_scalar(&ts)); 3437 } 3438 PROFILE_TRACE(2); 3439} 3440 3441void IOHIDSystem::_absolutePointerEvent( 3442 IOHIDSystem * self, 3443 int buttons, 3444 /* at */ IOGPoint * newLoc, 3445 /* withBounds */ IOGBounds * bounds, 3446 /* inProximity */ bool proximity, 3447 /* withPressure */ int pressure, 3448 /* withAngle */ int stylusAngle, 3449 /* atTime */ AbsoluteTime ts, 3450 OSObject * sender, 3451 void * refcon __unused) 3452{ 3453 self->absolutePointerEvent(buttons, newLoc, bounds, proximity, 3454 pressure, stylusAngle, ts, sender); 3455} 3456 3457void IOHIDSystem::absolutePointerEvent( 3458 int buttons, 3459 /* at */ IOGPoint * newLoc, 3460 /* withBounds */ IOGBounds * bounds, 3461 /* inProximity */ bool proximity, 3462 /* withPressure */ int pressure, 3463 /* withAngle */ int stylusAngle, 3464 /* atTime */ AbsoluteTime ts) 3465{ 3466 absolutePointerEvent(buttons, newLoc, bounds, proximity, 3467 pressure, stylusAngle, ts, 0); 3468} 3469 3470void IOHIDSystem::absolutePointerEvent( 3471 int buttons, 3472 /* at */ IOGPoint * newLoc, 3473 /* withBounds */ IOGBounds * bounds, 3474 /* inProximity */ bool proximity, 3475 /* withPressure */ int pressure, 3476 /* withAngle */ int stylusAngle, 3477 /* atTime */ AbsoluteTime ts, 3478 /* sender */ OSObject * sender) 3479{ 3480 IOHIDCmdGateActionArgs args; 3481 3482 args.arg0 = &buttons; 3483 args.arg1 = (void *)newLoc; 3484 args.arg2 = (void *)bounds; 3485 args.arg3 = &proximity; 3486 args.arg4 = &pressure; 3487 args.arg5 = &stylusAngle; 3488 args.arg6 = &ts; 3489 args.arg7 = sender; 3490 3491 cmdGate->runAction((IOCommandGate::Action)doAbsolutePointerEvent, &args); 3492} 3493 3494IOReturn IOHIDSystem::doAbsolutePointerEvent(IOHIDSystem *self, void * args) 3495 /* IOCommandGate::Action */ 3496{ 3497 int buttons = *(int *) ((IOHIDCmdGateActionArgs *)args)->arg0; 3498 IOGPoint * newLoc = (IOGPoint *) ((IOHIDCmdGateActionArgs *)args)->arg1; 3499 IOGBounds * bounds = (IOGBounds *) ((IOHIDCmdGateActionArgs *)args)->arg2; 3500 bool proximity = *(bool *) ((IOHIDCmdGateActionArgs *)args)->arg3; 3501 int pressure = *(int *) ((IOHIDCmdGateActionArgs *)args)->arg4; 3502 int stylusAngle = *(int *) ((IOHIDCmdGateActionArgs *)args)->arg5; 3503 AbsoluteTime ts = *(AbsoluteTime *) ((IOHIDCmdGateActionArgs *)args)->arg6; 3504 OSObject * sender = (OSObject *)((IOHIDCmdGateActionArgs *)args)->arg7; 3505 3506 3507 self->absolutePointerEventGated(buttons, newLoc, bounds, proximity, pressure, stylusAngle, ts, sender); 3508 3509 return kIOReturnSuccess; 3510} 3511 3512void IOHIDSystem::absolutePointerEventGated( 3513 int buttons, 3514 /* at */ IOGPoint * newLocGPoint, 3515 /* withBounds */ IOGBounds * bounds __unused, 3516 /* inProximity */ bool proximity, 3517 /* withPressure */ int pressure, 3518 /* withAngle */ int stylusAngle __unused, 3519 /* atTime */ AbsoluteTime ts, 3520 /* sender */ OSObject * sender) 3521{ 3522 3523 /* 3524 * If you don't know what to pass for the following fields, pass the 3525 * default values below: 3526 * pressure = MINPRESSURE or MAXPRESSURE 3527 * stylusAngle = 90 3528 */ 3529 NXEventData outData; /* dummy data */ 3530 bool proximityChange = false; 3531 3532 PROFILE_TRACE(5); 3533 3534 if ( !eventsOpen ) 3535 return; 3536 3537 if (ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline)) { 3538 TICKLE_DISPLAY(NX_MOUSEMOVED); 3539 return; 3540 } 3541 3542 if (!DISPLAY_IS_ENABLED) { 3543#if !WAKE_DISPLAY_ON_MOVEMENT 3544 if ( CMP_ABSOLUTETIME(&ts, &displaySleepWakeupDeadline) <= 0 ) 3545 { 3546 TICKLE_DISPLAY(NX_MOUSEMOVED); 3547 return; 3548 } 3549 3550 if (buttons) 3551#endif 3552 { 3553 TICKLE_DISPLAY(NX_LMOUSEDOWN); 3554 } 3555 return; 3556 } 3557 3558 TICKLE_DISPLAY(NX_MOUSEMOVED); 3559 3560 IOFixedPoint64 newLoc; 3561 newLoc.fromIntFloor(newLocGPoint->x, newLocGPoint->y); 3562 _scaleLocationToCurrentScreen(newLoc, bounds); 3563 3564 // RY: Attempt to add basic tablet support to absolute pointing devices 3565 // Basically, we will fill in the tablet support portions of both the 3566 // mouse and mouseMove of NXEventData. Pending tablet events are stored 3567 // in the CachedMouseEventStruct and then later picked off in 3568 // _setButtonState and _postMouseMoveEvent 3569 CachedMouseEventStruct *cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender); 3570 if (cachedMouseEvent) 3571 { 3572 cachedMouseEvent->pointerFractionX = newLoc.xValue().fraction(); 3573 cachedMouseEvent->pointerFractionY = newLoc.yValue().fraction(); 3574 3575 proximityChange = (cachedMouseEvent->proximity != proximity); 3576 3577 cachedMouseEvent->state |= kCachedMousePointingEventDispFlag; 3578 cachedMouseEvent->proximity = proximity; 3579 cachedMouseEvent->lastPressure = ScalePressure(pressure); 3580 3581 if ( !(cachedMouseEvent->state & kCachedMouseTabletEventDispFlag) ) 3582 { 3583 // initialize the proximity and tablet event structs 3584 if ( !(cachedMouseEvent->state & kCachedMousePointingTabletEventDispFlag) ) 3585 { 3586 cachedMouseEvent->state |= kCachedMousePointingTabletEventDispFlag; 3587 cachedMouseEvent->proximityData.proximity.capabilityMask = ( 3588 NX_TABLET_CAPABILITY_DEVICEIDMASK | 3589 NX_TABLET_CAPABILITY_ABSXMASK | 3590 NX_TABLET_CAPABILITY_ABSYMASK | 3591 NX_TABLET_CAPABILITY_BUTTONSMASK | 3592 NX_TABLET_CAPABILITY_PRESSUREMASK); 3593 cachedMouseEvent->proximityData.proximity.pointerType = NX_TABLET_POINTER_PEN; 3594 cachedMouseEvent->proximityData.proximity.systemTabletID = IOHITablet::generateTabletID(); 3595 cachedMouseEvent->proximityData.proximity.deviceID = 3596 cachedMouseEvent->tabletData.tablet.deviceID = IOHIDPointing::generateDeviceID(); 3597 } 3598 3599 if ( proximityChange ) 3600 { 3601 cachedMouseEvent->proximityData.proximity.enterProximity = proximity; 3602 cachedMouseEvent->subType = NX_SUBTYPE_TABLET_PROXIMITY; 3603 3604 cachedMouseEvent->state |= kCachedMousePointingTabletEventPendFlag; 3605 proximityEventGated(&(cachedMouseEvent->proximityData), ts, sender); 3606 cachedMouseEvent->state &= ~kCachedMousePointingTabletEventPendFlag; 3607 } 3608 else if ( proximity ) 3609 { 3610 // RY: revert the button state 3611 // The window server requires that the lower 3 bits of 3612 // the buttons bit field be mangled for interpretation 3613 // when handling a button event. Unfortunately, 3614 // applications that make use of the tablet events 3615 // require that the buttons field not be mangled. Thus 3616 // the button state should be reverted. 3617 cachedMouseEvent->tabletData.tablet.buttons = buttons & ~0x7; 3618 if (buttons & 2) 3619 cachedMouseEvent->tabletData.tablet.buttons |= 4; 3620 if (buttons & EV_RB) 3621 cachedMouseEvent->tabletData.tablet.buttons |= 2; 3622 if (buttons & EV_LB) 3623 cachedMouseEvent->tabletData.tablet.buttons |= 1; 3624 3625 cachedMouseEvent->tabletData.tablet.x = newLoc.xValue().as32(); 3626 cachedMouseEvent->tabletData.tablet.y = newLoc.yValue().as32(); 3627 cachedMouseEvent->tabletData.tablet.pressure = pressure; 3628 cachedMouseEvent->subType = NX_SUBTYPE_TABLET_POINT; 3629 } 3630 } 3631 } 3632 3633 clock_get_uptime(&_cursorEventLast); 3634 if ( (newLoc != _cursorHelper.desktopLocation()) || proximityChange) 3635 { 3636 _cursorHelper.desktopLocationDelta() = newLoc - _cursorHelper.desktopLocation(); 3637 _cursorHelper.desktopLocation() = newLoc; 3638 _cursorLog(_cursorEventLast); 3639 3640 _setCursorPosition(false, proximityChange, sender); 3641 vblForScreen(((EvScreen*)evScreen)[cursorPinScreen].instance, _cursorMoveDelta); 3642 _cursorMoveLast = _cursorEventLast; 3643 } 3644 3645 if ( proximityChange && proximity == true ) 3646 { 3647 evg->eventFlags |= NX_STYLUSPROXIMITYMASK; 3648 bzero( (char *)&outData, sizeof outData ); 3649 postEvent( NX_FLAGSCHANGED, 3650 /* at */ &_cursorHelper.desktopLocation(), 3651 /* atTime */ ts, 3652 /* withData */ &outData, 3653 /* sender */ sender); 3654 } 3655 if ( proximityChange || proximity == true ) 3656 _setButtonState(buttons, /* atTime */ ts, sender); 3657 if ( proximityChange && proximity == false ) 3658 { 3659 evg->eventFlags &= ~NX_STYLUSPROXIMITYMASK; 3660 bzero( (char *)&outData, sizeof outData ); 3661 postEvent( NX_FLAGSCHANGED, 3662 /* at */ &_cursorHelper.desktopLocation(), 3663 /* atTime */ ts, 3664 /* withData */ &outData, 3665 /* sender */ sender); 3666 } 3667 3668 // RY: Clean it off 3669 if (cachedMouseEvent) 3670 { 3671 cachedMouseEvent->subType = NX_SUBTYPE_DEFAULT; 3672 cachedMouseEvent->pointerFractionX = cachedMouseEvent->pointerFractionY = 0; 3673 } 3674 3675 scheduleNextPeriodicEvent(); 3676 PROFILE_TRACE(6); 3677} 3678 3679void IOHIDSystem::_scrollWheelEvent(IOHIDSystem * self, 3680 short deltaAxis1, 3681 short deltaAxis2, 3682 short deltaAxis3, 3683 IOFixed fixedDelta1, 3684 IOFixed fixedDelta2, 3685 IOFixed fixedDelta3, 3686 SInt32 pointDeltaAxis1, 3687 SInt32 pointDeltaAxis2, 3688 SInt32 pointDeltaAxis3, 3689 UInt32 options, 3690 /* atTime */ AbsoluteTime ts, 3691 OSObject * sender, 3692 void * refcon __unused) 3693{ 3694 self->scrollWheelEvent(deltaAxis1, deltaAxis2, deltaAxis3, fixedDelta1, fixedDelta2, fixedDelta3, pointDeltaAxis1, pointDeltaAxis2, pointDeltaAxis3, options, ts, sender); 3695} 3696 3697void IOHIDSystem::scrollWheelEvent(short deltaAxis1, 3698 short deltaAxis2, 3699 short deltaAxis3, 3700 /* atTime */ AbsoluteTime ts) 3701 3702{ 3703 scrollWheelEvent(deltaAxis1, deltaAxis2, deltaAxis3, deltaAxis1<<16, deltaAxis2<<16, deltaAxis3<<16, 0, 0, 0, 0, ts, 0); 3704} 3705 3706void IOHIDSystem::scrollWheelEvent(short deltaAxis1, 3707 short deltaAxis2, 3708 short deltaAxis3, 3709 IOFixed fixedDelta1, 3710 IOFixed fixedDelta2, 3711 IOFixed fixedDelta3, 3712 SInt32 pointDeltaAxis1, 3713 SInt32 pointDeltaAxis2, 3714 SInt32 pointDeltaAxis3, 3715 UInt32 options, 3716 /* atTime */ AbsoluteTime ts, 3717 OSObject * sender) 3718 3719{ 3720 IOHIDCmdGateActionArgs args; 3721 3722 args.arg0 = &deltaAxis1; 3723 args.arg1 = &deltaAxis2; 3724 args.arg2 = &deltaAxis3; 3725 args.arg3 = &fixedDelta1; 3726 args.arg4 = &fixedDelta2; 3727 args.arg5 = &fixedDelta3; 3728 args.arg6 = &pointDeltaAxis1; 3729 args.arg7 = &pointDeltaAxis2; 3730 args.arg8 = &pointDeltaAxis3; 3731 args.arg9 = &options; 3732 args.arg10 = &ts; 3733 args.arg11 = sender; 3734 3735 cmdGate->runAction((IOCommandGate::Action)doScrollWheelEvent, (void *)&args); 3736} 3737 3738IOReturn IOHIDSystem::doScrollWheelEvent(IOHIDSystem *self, void * args) 3739 /* IOCommandGate::Action */ 3740{ 3741 short deltaAxis1 = *(short *)((IOHIDCmdGateActionArgs *)args)->arg0; 3742 short deltaAxis2 = *(short *)((IOHIDCmdGateActionArgs *)args)->arg1; 3743 short deltaAxis3 = *(short *)((IOHIDCmdGateActionArgs *)args)->arg2; 3744 IOFixed fixedDelta1 = *(IOFixed *)((IOHIDCmdGateActionArgs *)args)->arg3; 3745 IOFixed fixedDelta2 = *(IOFixed *)((IOHIDCmdGateActionArgs *)args)->arg4; 3746 IOFixed fixedDelta3 = *(IOFixed *)((IOHIDCmdGateActionArgs *)args)->arg5; 3747 SInt32 pointDeltaAxis1 = *(IOFixed *)((IOHIDCmdGateActionArgs *)args)->arg6; 3748 SInt32 pointDeltaAxis2 = *(IOFixed *)((IOHIDCmdGateActionArgs *)args)->arg7; 3749 SInt32 pointDeltaAxis3 = *(IOFixed *)((IOHIDCmdGateActionArgs *)args)->arg8; 3750 UInt32 options = *(UInt32 *)((IOHIDCmdGateActionArgs *)args)->arg9; 3751 AbsoluteTime ts = *(AbsoluteTime *)((IOHIDCmdGateActionArgs *)args)->arg10; 3752 OSObject * sender= (OSObject *)((IOHIDCmdGateActionArgs *)args)->arg11; 3753 3754 self->scrollWheelEventGated(deltaAxis1, deltaAxis2, deltaAxis3, fixedDelta1, fixedDelta2, fixedDelta3, pointDeltaAxis1, pointDeltaAxis2, pointDeltaAxis3, options, ts, sender); 3755 3756 return kIOReturnSuccess; 3757} 3758 3759#if 0 3760# define log_event_phase(s, ...) kprintf("%s:%d " s, __FILE__, __LINE__, __VA_ARGS__) 3761#else 3762# define log_event_phase(s, ...) 3763#endif 3764 3765void IOHIDSystem::scrollWheelEventGated(short deltaAxis1, 3766 short deltaAxis2, 3767 short deltaAxis3, 3768 IOFixed fixedDelta1, 3769 IOFixed fixedDelta2, 3770 IOFixed fixedDelta3, 3771 SInt32 pointDeltaAxis1, 3772 SInt32 pointDeltaAxis2, 3773 SInt32 pointDeltaAxis3, 3774 UInt32 options, 3775 /* atTime */ AbsoluteTime ts, 3776 OSObject * sender) 3777{ 3778 NXEventData wheelData; 3779 bool moved = (deltaAxis1 || pointDeltaAxis1 || 3780 deltaAxis2 || pointDeltaAxis2 || 3781 deltaAxis3 || pointDeltaAxis3); 3782 UInt32 momentum = (options & kScrollTypeMomentumAny); 3783 3784 if (!eventsOpen) 3785 return; 3786 3787 if (ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline)) { 3788 return; 3789 } 3790 3791#if !WAKE_DISPLAY_ON_MOVEMENT 3792 if (!DISPLAY_IS_ENABLED) { 3793 if (CMP_ABSOLUTETIME(&ts, &displaySleepWakeupDeadline) <= 0) 3794 { 3795 TICKLE_DISPLAY(NX_SCROLLWHEELMOVED); 3796 } 3797 return; 3798 } 3799#endif 3800 3801 /*********************************************************************************************** 3802 BEGIN PHASE SUPPRESSION STATE MACHINE 3803 Quiet: (start) 3804 on May Begin: 3805 post May Begin 3806 goto Suspended 3807 on Began: 3808 if moved 3809 post Begin 3810 goto Begun 3811 else 3812 post May Begin 3813 goto Suspended 3814 on Continue: 3815 on Ended: 3816 on Canceled: 3817 log and post? 3818 3819 Suspended: 3820 on Began: 3821 on Continue: 3822 if moved: 3823 post Begin 3824 goto Begun 3825 on Ended: 3826 on Canceled: 3827 post Canceled 3828 goto Quiet 3829 on May Begin: 3830 log and post? 3831 3832 3833 Begun: 3834 on Ended 3835 on Canceled: 3836 post Ended or Cancelled 3837 goto Quiet 3838 on Continue: 3839 post Continue 3840 on Began: 3841 on May Begin: 3842 log and post? 3843 3844 */ 3845 UInt32 phase = (options & kScrollTypeOptionPhaseAny); 3846 UInt32 oldDelayedPhase = 0; 3847 UInt32 newDelayedPhase = 0; 3848 if (_devicePhaseState && _devicePhaseState->getObject((OSSymbol*)sender)) { 3849 newDelayedPhase = oldDelayedPhase = ((OSNumber*)_devicePhaseState->getObject((OSSymbol*)sender))->unsigned32BitValue(); 3850 } 3851 // phaseAnnotation = |32 supplied phase |24 original state |16 new state |8 empty | 3852 UInt32 phaseAnnotation = (phase << 16) | (oldDelayedPhase << 8); 3853 3854 switch (oldDelayedPhase) { 3855 default: // quiet 3856 switch (phase) { 3857 case kScrollTypeOptionPhaseMayBegin: 3858 newDelayedPhase = kScrollTypeOptionPhaseMayBegin; 3859 break; 3860 case kScrollTypeOptionPhaseBegan: 3861 if (moved) { 3862 newDelayedPhase = kScrollTypeOptionPhaseBegan; 3863 } 3864 else { 3865 newDelayedPhase = kScrollTypeOptionPhaseMayBegin; 3866 options &= ~kScrollTypeOptionPhaseAny; 3867 options |= kScrollTypeOptionPhaseMayBegin; 3868 phase = kScrollTypeOptionPhaseMayBegin; 3869 } 3870 break; 3871 case kScrollTypeOptionPhaseChanged: 3872 case kScrollTypeOptionPhaseEnded: 3873 case kScrollTypeOptionPhaseCanceled: 3874 log_event_phase("unexpected phase (%04x) state (%04x) combination\n", phase, oldDelayedPhase); 3875 break; 3876 } 3877 break; 3878 3879 case kScrollTypeOptionPhaseMayBegin: // suspended 3880 switch (phase) { 3881 case kScrollTypeOptionPhaseMayBegin: 3882 case kScrollTypeOptionPhaseBegan: 3883 case kScrollTypeOptionPhaseChanged: 3884 if (moved) { 3885 newDelayedPhase = kScrollTypeOptionPhaseBegan; 3886 options &= ~kScrollTypeOptionPhaseAny; 3887 options |= kScrollTypeOptionPhaseBegan; 3888 phase = kScrollTypeOptionPhaseBegan; 3889 } 3890 else { 3891 options &= ~kScrollTypeOptionPhaseAny; 3892 phase = 0; 3893 } 3894 break; 3895 case kScrollTypeOptionPhaseEnded: 3896 case kScrollTypeOptionPhaseCanceled: 3897 newDelayedPhase = 0; 3898 options &= ~kScrollTypeOptionPhaseAny; 3899 options |= kScrollTypeOptionPhaseCanceled; 3900 phase = kScrollTypeOptionPhaseCanceled; 3901 break; 3902 } 3903 break; 3904 3905 case kScrollTypeOptionPhaseBegan: // Begun 3906 switch (phase) { 3907 case kScrollTypeOptionPhaseMayBegin: 3908 case kScrollTypeOptionPhaseBegan: 3909 log_event_phase("unexpected phase (%04x) state (%04x) combination\n", phase, oldDelayedPhase); 3910 break; 3911 case kScrollTypeOptionPhaseChanged: 3912 break; 3913 case kScrollTypeOptionPhaseEnded: 3914 case kScrollTypeOptionPhaseCanceled: 3915 newDelayedPhase = 0; 3916 break; 3917 } 3918 break; 3919 } 3920 phaseAnnotation |= phase | (newDelayedPhase >> 8); 3921 if (oldDelayedPhase != newDelayedPhase) { 3922 log_event_phase("updating phase from %04x to %04x for %p\n", oldDelayedPhase, newDelayedPhase, sender); 3923 if (newDelayedPhase) { 3924 if (!_devicePhaseState) 3925 _devicePhaseState = OSDictionary::withCapacity(0); 3926 if (_devicePhaseState) { 3927 OSNumber *newDelayedPhaseNumber = OSNumber::withNumber(newDelayedPhase, 32); 3928 _devicePhaseState->setObject((OSSymbol*)sender, newDelayedPhaseNumber); 3929 newDelayedPhaseNumber->release(); 3930 } 3931 else { 3932 IOLog("%s unable to create _devicePhaseState dictionary\n", __func__); 3933 } 3934 } 3935 else { 3936 if (_devicePhaseState) { 3937 _devicePhaseState->removeObject((OSSymbol*)sender); 3938 } 3939 } 3940 } 3941 /* 3942 END PHASE SUPPRESSION STATE MACHINE 3943 **********************************************************************************************/ 3944 3945 switch (momentum) { 3946 case kScrollTypeMomentumStart: 3947 if (!moved) { 3948 // suppress the start until we get a changed with movement 3949 _delayedScrollMomentum = momentum; 3950 momentum = 0; 3951 options &= ~kScrollTypeMomentumAny; 3952 } 3953 else { 3954 // clear state and let go 3955 _delayedScrollMomentum = 0; 3956 } 3957 break; 3958 3959 case kScrollTypeMomentumContinue: 3960 if (_delayedScrollMomentum) { 3961 // we suppressed a start 3962 options &= ~kScrollTypeMomentumAny; 3963 if (!moved) { 3964 // continue suppressing it 3965 momentum = 0; 3966 } 3967 else { 3968 // make this the start 3969 momentum = _delayedScrollMomentum; 3970 options |= momentum; 3971 // clear the state 3972 _delayedScrollMomentum = 0; 3973 } 3974 } 3975 else { 3976 if (!moved) { 3977 // if there is phase, we will allow this event to go through 3978 // without changing it. if there isn't, it will get suppressed below. 3979 momentum = 0; 3980 } 3981 } 3982 break; 3983 3984 case kScrollTypeMomentumEnd: 3985 if (_delayedScrollMomentum) { 3986 // we have a suppressed start. the whole scroll needs to be suppressed. 3987 options &= ~kScrollTypeMomentumAny; 3988 momentum = 0; 3989 _delayedScrollMomentum = 0; 3990 } 3991 else { 3992 // do nothing 3993 } 3994 3995 break; 3996 3997 case 0: 3998 // no momentum. do nothing. 3999 break; 4000 4001 default: 4002 kprintf("IOHIDSystem::scrollWheelEventGated called with unknown momentum state: %08x\n", (unsigned)momentum); 4003 break; 4004 } 4005 4006 /*********************************************************************************************** 4007 BEGIN SCROLL COUNT STATE MACHINE 4008 */ 4009 UInt32 phase_momentum = options & (_scIgnoreMomentum ? kScrollTypeOptionPhaseAny : (kScrollTypeOptionPhaseAny | kScrollTypeMomentumAny)); 4010 if (phase_momentum) { 4011 UInt64 axis1squared = (pointDeltaAxis1 * pointDeltaAxis1); 4012 UInt64 axis2squared = (pointDeltaAxis2 * pointDeltaAxis2); 4013 UInt64 axis3squared = (pointDeltaAxis3 * pointDeltaAxis3); 4014 UInt64 scrollMagnitudeSquared = axis1squared + axis2squared + axis3squared; 4015 UInt8 newDirection = kScrollDirectionInvalid; 4016 bool checkSustain = false; 4017 4018 if ((axis1squared > axis2squared) && (axis1squared > axis3squared)) { 4019 if (pointDeltaAxis1 > 0) { 4020 newDirection = kScrollDirectionXPositive; 4021 } 4022 else if (pointDeltaAxis1 < 0) { 4023 newDirection = kScrollDirectionXNegative; 4024 } 4025 } 4026 else if ((axis2squared > axis1squared) && (axis2squared > axis3squared)) { 4027 if (pointDeltaAxis2 > 0) { 4028 newDirection = kScrollDirectionYPositive; 4029 } 4030 else if (pointDeltaAxis2 < 0) { 4031 newDirection = kScrollDirectionYNegative; 4032 } 4033 } 4034 else if ((axis3squared > axis1squared) && (axis3squared > axis2squared)) { 4035 if (pointDeltaAxis3 > 0) { 4036 newDirection = kScrollDirectionZPositive; 4037 } 4038 else if (pointDeltaAxis3 < 0) { 4039 newDirection = kScrollDirectionZNegative; 4040 } 4041 } 4042 if ((newDirection != kScrollDirectionInvalid) && (newDirection != _scDirection)) { 4043 if (_scCount) { 4044 log_scroll_state("Resetting _scCount on change from %d to %d\n", _scDirection, newDirection); 4045 _scCount = 0; 4046 } 4047 _scDirection = newDirection; 4048 } 4049 4050 if (_scCount && _scMouseCanReset) { 4051 IOFixedPoint64 thresh = IOFixedPoint64().fromIntFloor(clickSpaceThresh.x, clickSpaceThresh.y); 4052 IOFixedPoint64 min = _scLastScrollLocation - thresh; 4053 IOFixedPoint64 max = _scLastScrollLocation + thresh; 4054 IOFixedPoint64 location = _cursorHelper.desktopLocation(); 4055 if ( (location > max) || (location < min) ) { 4056 log_scroll_state("Resetting _scCount on mouse move [%d, %d] vs [%d, %d]\n", 4057 location.xValue().as32(), location.yValue().as32(), 4058 _scLastScrollLocation.xValue().as32(), _scLastScrollLocation.yValue().as32()); 4059 _scCount = 0; 4060 } 4061 } 4062 4063 switch (phase_momentum) { 4064 case kScrollTypeOptionPhaseBegan: { 4065 if (_scCount > 0) { 4066 if ((_scLastScrollEndTime + _scMaxTimeDeltaBetween) > ts) { 4067 if (!_scIncrementedThisPhrase) { 4068 log_scroll_state("Incrementing _scCount: %lld\n", ts); 4069 _scCount++; 4070 _scIncrementedThisPhrase = 1; 4071 } 4072 _scLastScrollSustainTime = ts; 4073 } 4074 else { 4075 _scCount = 0; 4076 log_scroll_state("Resetting _scCount due to delay: %lld + %lld < %lld\n", _scLastScrollEndTime, _scMaxTimeDeltaBetween, ts); 4077 } 4078 } 4079 break; 4080 } 4081 case kScrollTypeOptionPhaseChanged: { 4082 if (_scCount == 0) { 4083 if (scrollMagnitudeSquared >= _scMinDeltaSqToStart) { 4084 log_scroll_state("_scCount to 1 on %lld > %lld\n", scrollMagnitudeSquared, _scMinDeltaSqToStart); 4085 _scCount = 1; 4086 _scLastScrollSustainTime = ts; 4087 } 4088 } 4089 else { 4090 if (_scCount > 2) { 4091 IOFixed64 temp; 4092 temp.fromIntFloor(llsqrt(scrollMagnitudeSquared)); 4093 temp /= _scAccelerationFactor; 4094 _scCount += temp.as32(); 4095 log_scroll_state("_scCount to %d on (llsqrt(%lld) * 65536 / %lld)\n", _scCount, scrollMagnitudeSquared, _scAccelerationFactor.asFixed64()); 4096 if (_scCount > _scCountMax) { 4097 _scCount = _scCountMax; 4098 } 4099 } 4100 checkSustain = true; 4101 } 4102 break; 4103 } 4104 case kScrollTypeOptionPhaseEnded: { 4105 if (_scCount > 0) { 4106 _scLastScrollEndTime = ts; 4107 _scIncrementedThisPhrase = 0; 4108 } 4109 break; 4110 } 4111 case kScrollTypeOptionPhaseCanceled: { 4112 log_scroll_state("Resetting _scCount cancelled: %lld\n", ts); 4113 _scIncrementedThisPhrase = false; 4114 _scCount = 0; 4115 break; 4116 } 4117 case kScrollTypeOptionPhaseMayBegin: { 4118 if (_scCount > 0) { 4119 if (((_scLastScrollEndTime + _scMaxTimeDeltaBetween) > ts) && !_scIncrementedThisPhrase) { 4120 log_scroll_state("Incrementing _scCount: %lld\n", ts); 4121 _scCount++; 4122 _scIncrementedThisPhrase = 1; 4123 _scLastScrollSustainTime = ts; 4124 } 4125 else { 4126 log_scroll_state("Resetting _scCount due to delay: %lld + %lld < %lld\n", _scLastScrollEndTime, _scMaxTimeDeltaBetween, ts); 4127 _scCount = 0; 4128 _scIncrementedThisPhrase = 0; 4129 } 4130 } 4131 break; 4132 } 4133 case kScrollTypeMomentumStart: { 4134 // do nothing 4135 break; 4136 } 4137 case kScrollTypeMomentumContinue: { 4138 checkSustain = true; 4139 break; 4140 } 4141 case kScrollTypeMomentumEnd: { 4142 if (_scCount > 0) { 4143 _scLastScrollEndTime = ts; 4144 _scIncrementedThisPhrase = 0; 4145 } 4146 break; 4147 } 4148 } 4149 4150 if (checkSustain) { 4151 if (scrollMagnitudeSquared > _scMinDeltaSqToSustain) { 4152 _scLastScrollSustainTime = ts; 4153 } 4154 else if (_scLastScrollSustainTime + _scMaxTimeDeltaToSustain < ts) { 4155 log_scroll_state("Resetting _scCount due to sustain delay: %lld + %lld < %lld\n", _scLastScrollSustainTime, _scMaxTimeDeltaToSustain, ts); 4156 _scCount = 0; 4157 } 4158 } 4159 _scLastScrollLocation = _cursorHelper.desktopLocation(); 4160 } 4161 /* 4162 END SCROLL COUNT STATE MACHINE 4163 **********************************************************************************************/ 4164 4165 if (!moved && !momentum && !phase) { 4166 log_event_phase("annotation %08x suppressed\n", phaseAnnotation); 4167 return; 4168 } 4169 else { 4170 log_event_phase("annotation %08x posted with %08x\n", phaseAnnotation, options); 4171 } 4172 4173 TICKLE_DISPLAY(NX_SCROLLWHEELMOVED); 4174 4175 bzero((char *)&wheelData, sizeof wheelData); 4176 wheelData.scrollWheel.deltaAxis1 = deltaAxis1; 4177 wheelData.scrollWheel.deltaAxis2 = deltaAxis2; 4178 wheelData.scrollWheel.deltaAxis3 = deltaAxis3; 4179 wheelData.scrollWheel.fixedDeltaAxis1 = fixedDelta1; 4180 wheelData.scrollWheel.fixedDeltaAxis2 = fixedDelta2; 4181 wheelData.scrollWheel.fixedDeltaAxis3 = fixedDelta3; 4182 wheelData.scrollWheel.pointDeltaAxis1 = pointDeltaAxis1; 4183 wheelData.scrollWheel.pointDeltaAxis2 = pointDeltaAxis2; 4184 wheelData.scrollWheel.pointDeltaAxis3 = pointDeltaAxis3; 4185 wheelData.scrollWheel.reserved1 = (UInt16)options & (kScrollTypeContinuous | kScrollTypeMomentumAny | kScrollTypeOptionPhaseAny); 4186 updateScrollEventForSender(sender, &wheelData); 4187 4188 if (options & (kScrollTypeMomentumAny | kScrollTypeOptionPhaseAny)) { 4189 wheelData.scrollWheel.reserved8[0] = phaseAnnotation; 4190 wheelData.scrollWheel.reserved8[1] = _scCount; 4191 log_scroll_state("posting scroll: (%d, %d, %d) %d %d, %lld %lld, %lld\n", 4192 pointDeltaAxis1, pointDeltaAxis2, pointDeltaAxis3, _scCount, _scDirection, 4193 _scLastScrollEndTime, _scLastScrollSustainTime, ts); 4194 wheelData.scrollWheel.reserved8[2] = IOHIDevice::GenerateKey(sender); 4195 } 4196 4197 postEvent( (options & kScrollTypeZoom) ? NX_ZOOM : NX_SCROLLWHEELMOVED, 4198 /* at */ &_cursorHelper.desktopLocation(), 4199 /* atTime */ ts, 4200 /* withData */ &wheelData, 4201 /* sender */ sender); 4202 4203 return; 4204} 4205 4206void IOHIDSystem::_tabletEvent(IOHIDSystem *self, 4207 NXEventData *tabletData, 4208 AbsoluteTime ts, 4209 OSObject * sender, 4210 void * refcon __unused) 4211{ 4212 self->tabletEvent(tabletData, ts, sender); 4213} 4214 4215void IOHIDSystem::tabletEvent(NXEventData *tabletData, 4216 AbsoluteTime ts) 4217{ 4218 tabletEvent(tabletData, ts, 0); 4219} 4220 4221void IOHIDSystem::tabletEvent(NXEventData *tabletData, 4222 AbsoluteTime ts, 4223 OSObject * sender) 4224{ 4225 cmdGate->runAction((IOCommandGate::Action)doTabletEvent, tabletData, &ts, sender); 4226} 4227 4228IOReturn IOHIDSystem::doTabletEvent(IOHIDSystem *self, void * arg0, void * arg1, void * arg2) 4229 /* IOCommandGate::Action */ 4230{ 4231 NXEventData *tabletData = (NXEventData *) arg0; 4232 AbsoluteTime ts = *(AbsoluteTime *) arg1; 4233 OSObject * sender = (OSObject *) arg2; 4234 4235 self->tabletEventGated(tabletData, ts, sender); 4236 4237 return kIOReturnSuccess; 4238} 4239 4240void IOHIDSystem::tabletEventGated(NXEventData *tabletData, 4241 AbsoluteTime ts, 4242 OSObject * sender) 4243{ 4244 CachedMouseEventStruct *cachedMouseEvent; 4245 4246 if (!eventsOpen) 4247 return; 4248 4249 if(ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline)) 4250 return; 4251 4252 if ((cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender)) && 4253 !(cachedMouseEvent->state & kCachedMousePointingTabletEventPendFlag)) 4254 { 4255 4256 cachedMouseEvent->state |= kCachedMouseTabletEventDispFlag; 4257 cachedMouseEvent->subType = NX_SUBTYPE_TABLET_POINT; 4258 bcopy( tabletData, &(cachedMouseEvent->tabletData), sizeof(NXEventData)); 4259 4260 // Don't dispatch an event if they can be embedded in pointing events 4261 if ( cachedMouseEvent->state & kCachedMousePointingEventDispFlag ) 4262 return; 4263 } 4264 4265 postEvent(NX_TABLETPOINTER, 4266 &_cursorHelper.desktopLocation(), 4267 ts, 4268 tabletData, 4269 sender); 4270 4271 return; 4272} 4273 4274void IOHIDSystem::_proximityEvent(IOHIDSystem *self, 4275 NXEventData *proximityData, 4276 AbsoluteTime ts, 4277 OSObject * sender, 4278 void * refcon __unused) 4279{ 4280 self->proximityEvent(proximityData, ts, sender); 4281} 4282 4283void IOHIDSystem::proximityEvent(NXEventData *proximityData, 4284 AbsoluteTime ts) 4285{ 4286 4287 proximityEvent(proximityData, ts, 0); 4288} 4289 4290void IOHIDSystem::proximityEvent(NXEventData *proximityData, 4291 AbsoluteTime ts, 4292 OSObject * sender) 4293{ 4294 cmdGate->runAction((IOCommandGate::Action)doProximityEvent, proximityData, &ts, sender); 4295} 4296 4297IOReturn IOHIDSystem::doProximityEvent(IOHIDSystem *self, void * arg0, void *arg1, void * arg2) 4298 /* IOCommandGate::Action */ 4299{ 4300 4301 NXEventData *proximityData = (NXEventData *)arg0; 4302 AbsoluteTime ts = *(AbsoluteTime *)arg1; 4303 OSObject * sender = (OSObject *)arg2; 4304 4305 self->proximityEventGated(proximityData, ts, sender); 4306 4307 return kIOReturnSuccess; 4308} 4309 4310void IOHIDSystem::proximityEventGated(NXEventData *proximityData, 4311 AbsoluteTime ts, 4312 OSObject * sender) 4313{ 4314 CachedMouseEventStruct *cachedMouseEvent; 4315 4316 if (!eventsOpen) 4317 return; 4318 4319 if(ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline)) 4320 return; 4321 4322 if ((cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender)) && 4323 !(cachedMouseEvent->state & kCachedMousePointingTabletEventPendFlag)) 4324 { 4325 cachedMouseEvent->state |= kCachedMouseTabletEventDispFlag; 4326 cachedMouseEvent->subType = NX_SUBTYPE_TABLET_PROXIMITY; 4327 bcopy( proximityData, &(cachedMouseEvent->proximityData), sizeof(NXEventData)); 4328 } 4329 4330 postEvent(NX_TABLETPROXIMITY, 4331 &_cursorHelper.desktopLocation(), 4332 ts, 4333 proximityData, 4334 sender); 4335 4336 return; 4337} 4338 4339void IOHIDSystem::doProcessKeyboardEQ(IOHIDSystem * self) 4340{ 4341 processKeyboardEQ(self); 4342} 4343 4344void IOHIDSystem::processKeyboardEQ(IOHIDSystem * self, AbsoluteTime * deadline) 4345{ 4346 KeyboardEQElement * keyboardEQElement; 4347 4348 KEYBOARD_EQ_LOCK; 4349 4350 while ( ((keyboardEQElement = (KeyboardEQElement *)dequeue_head(&gKeyboardEQ)) != NULL) 4351 && !(deadline && (CMP_ABSOLUTETIME(&(keyboardEQElement->ts), deadline) > 0))) 4352 { 4353 KEYBOARD_EQ_UNLOCK; 4354 4355 if (keyboardEQElement->action) 4356 (*(keyboardEQElement->action))(self, keyboardEQElement); 4357 OSSafeReleaseNULL(keyboardEQElement->sender); // NOTE: This is the matching release 4358 4359 IOFree(keyboardEQElement, sizeof(KeyboardEQElement)); 4360 4361 KEYBOARD_EQ_LOCK; 4362 } 4363 4364 KEYBOARD_EQ_UNLOCK; 4365} 4366 4367 4368// 4369// Process a keyboard state change. 4370// 4371void IOHIDSystem::_keyboardEvent(IOHIDSystem * self, 4372 unsigned eventType, 4373 /* flags */ unsigned flags, 4374 /* keyCode */ unsigned key, 4375 /* charCode */ unsigned charCode, 4376 /* charSet */ unsigned charSet, 4377 /* originalCharCode */ unsigned origCharCode, 4378 /* originalCharSet */ unsigned origCharSet, 4379 /* keyboardType */ unsigned keyboardType, 4380 /* repeat */ bool repeat, 4381 /* atTime */ AbsoluteTime ts, 4382 OSObject * sender, 4383 void * refcon __unused) 4384{ 4385 self->keyboardEvent(eventType, flags, key, charCode, charSet, 4386 origCharCode, origCharSet, keyboardType, repeat, ts, sender); 4387} 4388 4389void IOHIDSystem::keyboardEvent(unsigned eventType, 4390 /* flags */ unsigned flags, 4391 /* keyCode */ unsigned key, 4392 /* charCode */ unsigned charCode, 4393 /* charSet */ unsigned charSet, 4394 /* originalCharCode */ unsigned origCharCode, 4395 /* originalCharSet */ unsigned origCharSet, 4396 /* keyboardType */ unsigned keyboardType, 4397 /* repeat */ bool repeat, 4398 /* atTime */ AbsoluteTime ts) 4399{ 4400 keyboardEvent(eventType, flags, key, charCode, charSet, 4401 origCharCode, origCharSet, keyboardType, repeat, ts, 0); 4402} 4403 4404void IOHIDSystem::keyboardEvent(unsigned eventType, 4405 /* flags */ unsigned flags, 4406 /* keyCode */ unsigned key, 4407 /* charCode */ unsigned charCode, 4408 /* charSet */ unsigned charSet, 4409 /* originalCharCode */ unsigned origCharCode, 4410 /* originalCharSet */ unsigned origCharSet, 4411 /* keyboardType */ unsigned keyboardType, 4412 /* repeat */ bool repeat, 4413 /* atTime */ AbsoluteTime ts, 4414 /* sender */ OSObject * sender) 4415{ 4416 KeyboardEQElement * keyboardEQElement = (KeyboardEQElement *)IOMalloc(sizeof(KeyboardEQElement)); 4417 4418 if ( !keyboardEQElement ) 4419 return; 4420 4421 bzero(keyboardEQElement, sizeof(KeyboardEQElement)); 4422 4423 keyboardEQElement->action = IOHIDSystem::doKeyboardEvent; 4424 keyboardEQElement->ts = ts; 4425 keyboardEQElement->sender = sender; 4426 if (sender) sender->retain(); // NOTE: Matching release is in IOHIDSystem::processKeyboardEQ 4427 4428 4429 keyboardEQElement->event.keyboard.eventType = eventType; 4430 keyboardEQElement->event.keyboard.flags = flags; 4431 keyboardEQElement->event.keyboard.key = key; 4432 keyboardEQElement->event.keyboard.charCode = charCode; 4433 keyboardEQElement->event.keyboard.charSet = charSet; 4434 keyboardEQElement->event.keyboard.origCharCode = origCharCode; 4435 keyboardEQElement->event.keyboard.origCharSet = origCharSet; 4436 keyboardEQElement->event.keyboard.keyboardType = keyboardType; 4437 keyboardEQElement->event.keyboard.repeat = repeat; 4438 4439 KEYBOARD_EQ_LOCK; 4440 enqueue_tail(&gKeyboardEQ, (queue_entry_t)keyboardEQElement); 4441 KEYBOARD_EQ_UNLOCK; 4442 4443 keyboardEQES->interruptOccurred(0, 0, 0); 4444} 4445 4446IOReturn IOHIDSystem::doKeyboardEvent(IOHIDSystem *self, void * args) 4447 /* IOCommandGate::Action */ 4448{ 4449 KeyboardEQElement * keyboardEQElement = (KeyboardEQElement *)args; 4450 4451 AbsoluteTime ts = keyboardEQElement->ts; 4452 OSObject * sender = keyboardEQElement->sender; 4453 4454 unsigned eventType = keyboardEQElement->event.keyboard.eventType; 4455 unsigned flags = keyboardEQElement->event.keyboard.flags; 4456 unsigned key = keyboardEQElement->event.keyboard.key; 4457 unsigned charCode = keyboardEQElement->event.keyboard.charCode; 4458 unsigned charSet = keyboardEQElement->event.keyboard.charSet; 4459 unsigned origCharCode = keyboardEQElement->event.keyboard.origCharCode; 4460 unsigned origCharSet = keyboardEQElement->event.keyboard.origCharSet; 4461 unsigned keyboardType = keyboardEQElement->event.keyboard.keyboardType; 4462 bool repeat = keyboardEQElement->event.keyboard.repeat; 4463 4464 self->keyboardEventGated(eventType, flags, key, charCode, charSet, 4465 origCharCode, origCharSet, keyboardType, repeat, ts, sender); 4466 4467 return kIOReturnSuccess; 4468} 4469 4470/* This method adds a key press to the consumedKeys array, indicating that a 4471 * key down event was consumed and its corresponding key up must be consumed. 4472 * It returns true if the key was added successfully, and false if the key 4473 * couldn't be allocated or was already in the array. 4474 */ 4475bool IOHIDSystem::addConsumedKey(unsigned key) 4476{ 4477 bool result = false; 4478 OSNumber *keyCodeNumber; 4479 unsigned int index; 4480 4481 keyCodeNumber = OSNumber::withNumber(key, sizeof(key) * 8); 4482 if ( !keyCodeNumber ) goto finish; 4483 4484 index = getArrayIndexForObject(consumedKeys, keyCodeNumber); 4485 if ( index != kObjectNotFound ) goto finish; 4486 4487 consumedKeys->setObject(keyCodeNumber); 4488 result = true; 4489finish: 4490 if (keyCodeNumber) keyCodeNumber->release(); 4491 return result; 4492} 4493 4494/* This method removes a key press from the consumed keys array, indicating 4495 * that a key down / key up pair have been consumed. It returns true when the 4496 * key is successfully removed from the array, and false if the key was not in 4497 * the array. 4498 */ 4499bool IOHIDSystem::removeConsumedKey(unsigned key) 4500{ 4501 bool result = false; 4502 OSNumber *keyCodeNumber; 4503 unsigned int index; 4504 4505 keyCodeNumber = OSNumber::withNumber(key, sizeof(key) * 8); 4506 if ( !keyCodeNumber ) goto finish; 4507 4508 index = getArrayIndexForObject(consumedKeys, keyCodeNumber); 4509 if ( index == kObjectNotFound ) goto finish; 4510 4511 consumedKeys->removeObject(index); 4512 result = true; 4513finish: 4514 if (keyCodeNumber) keyCodeNumber->release(); 4515 return result; 4516} 4517 4518void IOHIDSystem::keyboardEventGated(unsigned eventType, 4519 /* flags */ unsigned flags, 4520 /* keyCode */ unsigned key, 4521 /* charCode */ unsigned charCode, 4522 /* charSet */ unsigned charSet, 4523 /* originalCharCode */ unsigned origCharCode, 4524 /* originalCharSet */ unsigned origCharSet, 4525 /* keyboardType */ unsigned keyboardType, 4526 /* repeat */ bool repeat, 4527 /* atTime */ AbsoluteTime ts, 4528 /* sender */ OSObject * sender) 4529{ 4530 UInt32 rootDomainConsumeCause; 4531 UInt32 displayConsumeCause; 4532 NXEventData outData; 4533 static unsigned prevFlags = 0; 4534 4535 /* If we get a key up event, check the consumedKeys array to see if it 4536 * needs to be consumed. 4537 */ 4538 if ( eventType == NX_KEYUP && consumedKeys->getCount() ) { 4539 if (removeConsumedKey(key)) { 4540 return; 4541 } 4542 } 4543 4544 /* The goal here is to ignore the key presses that woke the system, and for 4545 * that purpose we are interested in two deadlines. First, we want to 4546 * consume the first key press that occurs within a second of the 4547 * rootDomain domain powering on, which will prevent the key press that 4548 * wakes the machine from posting event. Second, we want to consume any key 4549 * presses that occur within 50ms of that first key press or of the 4550 * displayWrangler powering on. This prevents a hand smashing the keyboard 4551 * from generating lots of spurious events both on wake from sleep and 4552 * display sleep. 4553 */ 4554 rootDomainConsumeCause = ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline); 4555 displayConsumeCause = ShouldConsumeHIDEvent(ts, displayStateChangeDeadline); 4556 if (rootDomainConsumeCause || displayConsumeCause) { 4557 TICKLE_DISPLAY(NX_KEYDOWN); 4558 if (eventType != NX_KEYDOWN) return; 4559 4560 (void) addConsumedKey(key); 4561 4562 if (rootDomainConsumeCause) { 4563 AbsoluteTime_to_scalar(&rootDomainStateChangeDeadline) = 0; 4564 4565 clock_get_uptime(&displayStateChangeDeadline); 4566 ADD_ABSOLUTETIME(&displayStateChangeDeadline, 4567 &gIOHIDRelativeTickleThresholdAbsoluteTime); 4568 } 4569 4570 return; 4571 } 4572 4573 // Notify stackshotd for CMD-OPT-CTRL-ALT-(COMMA|SLASH|PERIOD) 4574 if( !repeat && ((flags & NORMAL_MODIFIER_MASK) == NORMAL_MODIFIER_MASK) ) 4575 { 4576 UInt32 keycode = UINT_MAX; 4577 switch (key) { 4578 case 0x2f: // kHIDUsage_KeyboardPeriod 4579 case 0x41: // kHIDUsage_KeypadPeriod 4580 keycode = kHIDUsage_KeyboardPeriod; 4581 break; 4582 case 0x2b: // kHIDUsage_KeyboardComma 4583 case 0x5f: // kHIDUsage_KeypadComma 4584 keycode = kHIDUsage_KeyboardComma; 4585 break; 4586 case 0x2c: // kHIDUsage_KeyboardSlash 4587 case 0x4b: // kHIDUsage_KeypadSlash 4588 keycode = kHIDUsage_KeyboardSlash; 4589 break; 4590 default: 4591 // do nothing 4592 break; 4593 } 4594 if (keycode != UINT_MAX) { 4595 if (eventType == NX_KEYDOWN) { 4596 sendStackShotMessage(keycode); 4597 IOLog("IOHIDSystem posted stackshot event 0x%02x\n", (unsigned)keycode); 4598 } 4599 return; 4600 } 4601 } 4602 4603 /* If the display is off, we consume a key down event and send a tickle to 4604 * wake the displays. Key up events are also consumed on the rare chance 4605 * they aren't in the consumedKeys array, but they don't cause a tickle. 4606 */ 4607 if ( !DISPLAY_IS_ENABLED ) { 4608 if ( eventType == NX_KEYDOWN ) { 4609 (void) addConsumedKey(key); 4610 } 4611 else if ( eventType == NX_KEYUP) { 4612 return; 4613 } 4614 else if ( eventType == NX_FLAGSCHANGED ) { 4615 unsigned kbFlagChanges = (flags & KEYBOARD_FLAGSMASK) ^ (prevFlags & KEYBOARD_FLAGSMASK); 4616 4617 /* Flag changes due to key release shouldn't tickle display */ 4618 if (!(kbFlagChanges & flags)) { 4619 prevFlags = flags; 4620 return; 4621 } 4622 } 4623 TICKLE_DISPLAY(eventType); 4624 return; 4625 } 4626 prevFlags = flags; 4627 4628 TICKLE_DISPLAY(NX_KEYDOWN); 4629 4630 // RY: trigger NMI for CMD-OPT-CTRL-ALT-ESC 4631 if( !repeat && (key == 0x35) && 4632 (eventType == NX_KEYDOWN) && 4633 ((flags & NORMAL_MODIFIER_MASK) == NORMAL_MODIFIER_MASK)) 4634 { 4635 PE_enter_debugger("USB Programmer Key"); 4636 } 4637 4638 if ( eventsOpen ) { 4639 UInt32 usage = 0; 4640 UInt32 usagePage = 0; 4641 if ((flags & NX_HIGHCODE_ENCODING_MASK) == NX_HIGHCODE_ENCODING_MASK) { 4642 usage = (origCharCode & 0xffff0000) >> 16; 4643 usagePage = (origCharSet & 0xffff0000) >> 16; 4644 origCharCode &= 0xffff; 4645 origCharSet &= 0xffff; 4646 } 4647 4648 outData.key.repeat = repeat; 4649 outData.key.keyCode = key; 4650 outData.key.charSet = charSet; 4651 outData.key.charCode = charCode; 4652 outData.key.origCharSet = origCharSet; 4653 outData.key.origCharCode = origCharCode; 4654 outData.key.keyboardType = keyboardType; 4655 outData.key.reserved2 = usage; 4656 outData.key.reserved3 = usagePage; 4657 4658 evg->eventFlags = (evg->eventFlags & ~KEYBOARD_FLAGSMASK) 4659 | (flags & KEYBOARD_FLAGSMASK); 4660 4661 if (cachedEventFlags != evg->eventFlags) { 4662 cachedEventFlags = evg->eventFlags; 4663 4664 // RY: Reset the clickTime as well on modifier 4665 // change to prevent double click from occuring 4666 nanoseconds_to_absolutetime(0, &clickTime); 4667 } 4668 4669 postEvent( eventType, 4670 /* at */ &_cursorHelper.desktopLocation(), 4671 /* atTime */ ts, 4672 /* withData */ &outData, 4673 /* sender */ sender, 4674 /* extPID */ 0, 4675 /* processKEQ*/false); 4676 } else { 4677 // Take on BSD console duties and dispatch the keyboardEvents. 4678 static const char cursorCodes[] = { 'D', 'A', 'C', 'B' }; 4679 if( (eventType == NX_KEYDOWN) && ((flags & NX_ALTERNATEMASK) != NX_ALTERNATEMASK)) { 4680 if( (charSet == NX_SYMBOLSET) 4681 && (charCode >= 0xac) && (charCode <= 0xaf)) { 4682 cons_cinput( '\033'); 4683 cons_cinput( 'O'); 4684 charCode = cursorCodes[ charCode - 0xac ]; 4685 } 4686 cons_cinput( charCode ); 4687 } 4688 } 4689} 4690 4691void IOHIDSystem::_keyboardSpecialEvent( IOHIDSystem * self, 4692 unsigned eventType, 4693 /* flags */ unsigned flags, 4694 /* keyCode */ unsigned key, 4695 /* specialty */ unsigned flavor, 4696 /* guid */ UInt64 guid, 4697 /* repeat */ bool repeat, 4698 /* atTime */ AbsoluteTime ts, 4699 OSObject * sender, 4700 void * refcon __unused) 4701{ 4702 self->keyboardSpecialEvent(eventType, flags, key, flavor, guid, repeat, ts, sender); 4703} 4704 4705void IOHIDSystem::keyboardSpecialEvent( unsigned eventType, 4706 /* flags */ unsigned flags, 4707 /* keyCode */ unsigned key, 4708 /* specialty */ unsigned flavor, 4709 /* guid */ UInt64 guid, 4710 /* repeat */ bool repeat, 4711 /* atTime */ AbsoluteTime ts) 4712{ 4713 keyboardSpecialEvent(eventType, flags, key, flavor, guid, repeat, ts, 0); 4714} 4715 4716void IOHIDSystem::keyboardSpecialEvent( unsigned eventType, 4717 /* flags */ unsigned flags, 4718 /* keyCode */ unsigned key, 4719 /* specialty */ unsigned flavor, 4720 /* guid */ UInt64 guid, 4721 /* repeat */ bool repeat, 4722 /* atTime */ AbsoluteTime ts, 4723 /* sender */ OSObject * sender) 4724{ 4725 KeyboardEQElement * keyboardEQElement = NULL; 4726 4727 keyboardEQElement = (KeyboardEQElement *)IOMalloc(sizeof(KeyboardEQElement)); 4728 4729 if ( !keyboardEQElement ) 4730 return; 4731 4732 bzero(keyboardEQElement, sizeof(KeyboardEQElement)); 4733 4734 keyboardEQElement->action = IOHIDSystem::doKeyboardSpecialEvent; 4735 keyboardEQElement->ts = ts; 4736 keyboardEQElement->sender = sender; 4737 if (sender) sender->retain(); // NOTE: Matching release is in IOHIDSystem::processKeyboardEQ 4738 4739 keyboardEQElement->event.keyboardSpecial.eventType = eventType; 4740 keyboardEQElement->event.keyboardSpecial.flags = flags; 4741 keyboardEQElement->event.keyboardSpecial.key = key; 4742 keyboardEQElement->event.keyboardSpecial.flavor = flavor; 4743 keyboardEQElement->event.keyboardSpecial.guid = guid; 4744 keyboardEQElement->event.keyboardSpecial.repeat = repeat; 4745 4746 KEYBOARD_EQ_LOCK; 4747 enqueue_tail(&gKeyboardEQ, (queue_entry_t)keyboardEQElement); 4748 KEYBOARD_EQ_UNLOCK; 4749 4750 keyboardEQES->interruptOccurred(0, 0, 0); 4751} 4752 4753 4754IOReturn IOHIDSystem::doKeyboardSpecialEvent(IOHIDSystem *self, void * args) 4755 /* IOCommandGate::Action */ 4756{ 4757 KeyboardEQElement * keyboardEQElement = (KeyboardEQElement *)args; 4758 4759 AbsoluteTime ts = keyboardEQElement->ts; 4760 OSObject * sender = keyboardEQElement->sender; 4761 4762 unsigned eventType = keyboardEQElement->event.keyboardSpecial.eventType; 4763 unsigned flags = keyboardEQElement->event.keyboardSpecial.flags; 4764 unsigned key = keyboardEQElement->event.keyboardSpecial.key; 4765 unsigned flavor = keyboardEQElement->event.keyboardSpecial.flavor; 4766 UInt64 guid = keyboardEQElement->event.keyboardSpecial.guid; 4767 bool repeat = keyboardEQElement->event.keyboardSpecial.repeat; 4768 4769 self->keyboardSpecialEventGated(eventType, flags, key, flavor, guid, repeat, ts, sender); 4770 4771 return kIOReturnSuccess; 4772} 4773 4774void IOHIDSystem::keyboardSpecialEventGated( 4775 /* event */ unsigned eventType, 4776 /* flags */ unsigned flags, 4777 /* keyCode */ unsigned key, 4778 /* specialty */ unsigned flavor, 4779 /* guid */ UInt64 guid, 4780 /* repeat */ bool repeat, 4781 /* atTime */ AbsoluteTime ts, 4782 /* sender */ OSObject * sender) 4783{ 4784 NXEventData outData; 4785 int level = -1; 4786 4787 if ((key != NX_NOSPECIALKEY) || (flavor != NX_SUBTYPE_STICKYKEYS_RELEASE)) { 4788 /* Key up events shouldn't tickle when display is off */ 4789 if (DISPLAY_IS_ENABLED || eventType == NX_KEYDOWN) 4790 TICKLE_DISPLAY(NX_SYSDEFINED); 4791 } 4792 4793 if (ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline) || 4794 !DISPLAY_IS_ENABLED) 4795 { 4796 return; 4797 } 4798 4799 // Since the HIDSystem will now take on BSD Console duty, 4800 // we need to make sure to process the programmer key info 4801 // prior to doing the eventsOpen check 4802 if ( eventType == NX_KEYDOWN && flavor == NX_POWER_KEY && !repeat) { 4803 if ( (flags & (NORMAL_MODIFIER_MASK | NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK)) == 4804 (NX_COMMANDMASK | NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK) ) 4805 PE_enter_debugger("Programmer Key"); 4806 else if ( (flags & NORMAL_MODIFIER_MASK) == ( NX_COMMANDMASK | NX_CONTROLMASK ) ) 4807 PEHaltRestart(kPERestartCPU); 4808 } 4809 4810 if ( !eventsOpen ) 4811 return; 4812 4813 // clear event record 4814 bzero( (void *)&outData, sizeof outData ); 4815 4816 // Update flags. 4817 evg->eventFlags = (evg->eventFlags & ~KEYBOARD_FLAGSMASK) 4818 | (flags & KEYBOARD_FLAGSMASK); 4819 4820 // was this a keydown event 4821 if ( eventType == NX_KEYDOWN ) 4822 { 4823 notifyHIDevices(this, ioHIDevices, kIOHIDSystem508SpecialKeyDownMessage); 4824 4825 // which special key went down 4826 switch ( flavor ) 4827 { 4828 case NX_KEYTYPE_EJECT: 4829 4830 // Special key handlers: 4831 // 4832 // Command = invoke macsbug 4833 // Command+option = sleep now 4834 // Command+option+control = shutdown now 4835 // Control = logout dialog 4836 4837 if( (evg->eventFlags & NX_COMMANDMASK) && 4838 !(evg->eventFlags & NX_CONTROLMASK) && 4839 !(evg->eventFlags & NX_SHIFTMASK) && 4840 !(evg->eventFlags & NX_ALTERNATEMASK) ) 4841 { 4842 // Post a power key event, Classic should pick this up and 4843 // drop into MacsBug. 4844 // 4845 outData.compound.subType = NX_SUBTYPE_POWER_KEY; 4846 postEvent( NX_SYSDEFINED, 4847 /* at */ &_cursorHelper.desktopLocation(), 4848 /* atTime */ ts, 4849 /* withData */ &outData, 4850 /* sender */ sender, 4851 /* extPID */ 0, 4852 /* processKEQ*/false); 4853 } 4854 else if( (evg->eventFlags & NX_COMMANDMASK) && 4855 !(evg->eventFlags & NX_CONTROLMASK) && 4856 !(evg->eventFlags & NX_SHIFTMASK) && 4857 (evg->eventFlags & NX_ALTERNATEMASK) ) 4858 { 4859 //IOLog( "IOHIDSystem -- sleep now!\n" ); 4860 4861 // The Key release events may not get delivered 4862 // to clients if they come late in sleep process. So, 4863 // clear the flags before heading to sleep. 4864 evg->eventFlags = 0; 4865 // Post the sleep now event. Someone else will handle the actual call. 4866 // 4867 outData.compound.subType = NX_SUBTYPE_SLEEP_EVENT; 4868 postEvent( NX_SYSDEFINED, 4869 /* at */ &_cursorHelper.desktopLocation(), 4870 /* atTime */ ts, 4871 /* withData */ &outData, 4872 /* sender */ sender, 4873 /* extPID */ 0, 4874 /* processKEQ*/false); 4875 4876 } 4877 else if( (evg->eventFlags & NX_COMMANDMASK) && 4878 (evg->eventFlags & NX_CONTROLMASK) && 4879 !(evg->eventFlags & NX_SHIFTMASK) && 4880 (evg->eventFlags & NX_ALTERNATEMASK) ) 4881 { 4882 //IOLog( "IOHIDSystem -- shutdown now!\n" ); 4883 4884 // Post the shutdown now event. Someone else will handle the actual call. 4885 // 4886 outData.compound.subType = NX_SUBTYPE_SHUTDOWN_EVENT; 4887 postEvent( NX_SYSDEFINED, 4888 /* at */ &_cursorHelper.desktopLocation(), 4889 /* atTime */ ts, 4890 /* withData */ &outData, 4891 /* sender */ sender, 4892 /* extPID */ 0, 4893 /* processKEQ*/false); 4894 4895 } 4896 else if( (evg->eventFlags & NX_COMMANDMASK) && 4897 (evg->eventFlags & NX_CONTROLMASK) && 4898 !(evg->eventFlags & NX_SHIFTMASK) && 4899 !(evg->eventFlags & NX_ALTERNATEMASK) ) 4900 { 4901 // Restart now! 4902 //IOLog( "IOHIDSystem -- Restart now!\n" ); 4903 4904 // Post the Restart now event. Someone else will handle the actual call. 4905 // 4906 outData.compound.subType = NX_SUBTYPE_RESTART_EVENT; 4907 postEvent( NX_SYSDEFINED, 4908 /* at */ &_cursorHelper.desktopLocation(), 4909 /* atTime */ ts, 4910 /* withData */ &outData, 4911 /* sender */ sender, 4912 /* extPID */ 0, 4913 /* processKEQ*/false); 4914 4915 } 4916 else if( !(evg->eventFlags & NX_COMMANDMASK) && 4917 (evg->eventFlags & NX_CONTROLMASK) && 4918 !(evg->eventFlags & NX_SHIFTMASK) && 4919 !(evg->eventFlags & NX_ALTERNATEMASK) ) 4920 { 4921 // Looks like we should put up the normal 'Power Key' dialog. 4922 // 4923 // Set the event flags to zero, because the system will not do the right 4924 // thing if we don't zero this out (it will ignore the power key event 4925 // we post, thinking that some modifiers are down). 4926 // 4927 evg->eventFlags = 0; 4928 4929 // Post the power keydown event. 4930 // 4931 outData.compound.subType = NX_SUBTYPE_POWER_KEY; 4932 postEvent( NX_SYSDEFINED, 4933 /* at */ &_cursorHelper.desktopLocation(), 4934 /* atTime */ ts, 4935 /* withData */ &outData, 4936 /* sender */ sender, 4937 /* extPID */ 0, 4938 /* processKEQ*/false); 4939 4940 } 4941 else 4942 { 4943 // After all that checking, no modifiers are down, so let's pump up a 4944 // system defined eject event. This way we can have anyone who's watching 4945 // for this event (aka LoginWindow) route this event to the right target 4946 // (aka AutoDiskMounter). 4947 4948 //IOLog( "IOHIDSystem--Normal Eject action!\n" ); 4949 4950 // Post the eject keydown event. 4951 // 4952 outData.compound.subType = NX_SUBTYPE_EJECT_KEY; 4953 postEvent( NX_SYSDEFINED, 4954 /* at */ &_cursorHelper.desktopLocation(), 4955 /* atTime */ ts, 4956 /* withData */ &outData, 4957 /* sender */ sender, 4958 /* extPID */ 0, 4959 /* processKEQ*/false); 4960 4961 } 4962 break; 4963 4964 case NX_POWER_KEY: 4965 // first issue a power key down event 4966 keyboardEventGated(eventType, 4967 flags, 4968 0x7f, 4969 0, 4970 0, 4971 0, 4972 0, 4973 0, 4974 0, 4975 ts, 4976 sender); 4977 // Now the special event 4978 outData.compound.subType = NX_SUBTYPE_POWER_KEY; 4979 postEvent( NX_SYSDEFINED, 4980 /* at */ &_cursorHelper.desktopLocation(), 4981 /* atTime */ ts, 4982 /* withData */ &outData, 4983 /* sender */ sender, 4984 /* extPID */ 0, 4985 /* processKEQ*/false); 4986 break; 4987 } 4988 } 4989 else if ( eventType == NX_KEYUP ) 4990 { 4991 switch ( flavor ) 4992 { 4993 case NX_POWER_KEY: 4994 keyboardEventGated(eventType, 4995 flags, 4996 0x7f, 4997 0, 4998 0, 4999 0, 5000 0, 5001 0, 5002 0, 5003 ts, 5004 sender); 5005 break; 5006 } 5007 } 5008 // if someone pases a sysdefined type in, then its ready to go already 5009 else if ( eventType == NX_SYSDEFINED ) 5010 { 5011 outData.compound.subType = flavor; 5012 postEvent( NX_SYSDEFINED, 5013 /* at */ &_cursorHelper.desktopLocation(), 5014 /* atTime */ ts, 5015 /* withData */ &outData, 5016 /* sender */ sender, 5017 /* extPID */ 0, 5018 /* processKEQ*/false); 5019 5020 } 5021 5022 // post keydowns and key ups if this flavor should be posted 5023 // note, we dont want to do this for events of type NX_SYSDEFINED 5024 // we probably _should_ just check for keydowns and keyups here 5025 // but the smallest change was to just make sure we didnt do this for 5026 // the new type, which is NX_SYSDEFINED (used for sticky keys feature) 5027 if ( eventType != NX_SYSDEFINED ) 5028 { 5029 if( (flags & SPECIALKEYS_MODIFIER_MASK) 5030 && (flavor == NX_POWER_KEY)) 5031 { 5032 //Should modifier + POWER ever be dispatched? Command-power 5033 // is used to get into debugger and MacsBug 5034 } 5035 else 5036 { 5037 outData.compound.subType = NX_SUBTYPE_AUX_CONTROL_BUTTONS; 5038 outData.compound.misc.L[0] = (flavor << 16) | (eventType << 8) | repeat; 5039 outData.compound.misc.L[1] = guid & 0xffffffff; 5040 outData.compound.misc.L[2] = guid >> 32; 5041 5042 postEvent( NX_SYSDEFINED, 5043 /* at */ &_cursorHelper.desktopLocation(), 5044 /* atTime */ ts, 5045 /* withData */ &outData, 5046 /* sender */ sender, 5047 /* extPID */ 0, 5048 /* processKEQ*/false); 5049 5050 } 5051 } 5052 5053 if ( level != -1 ) // An interesting special key event occurred 5054 { 5055 evSpecialKeyMsg( flavor, 5056 /* direction */ eventType, 5057 /* flags */ flags, 5058 /* level */ level); 5059 } 5060} 5061 5062/* 5063 * Update current event flags. Restricted to keyboard flags only, this 5064 * method is used to silently update the flags state for keys which both 5065 * generate characters and flag changes. The specs say we don't generate 5066 * a flags-changed event for such keys. This method is also used to clear 5067 * the keyboard flags on a keyboard subsystem reset. 5068 */ 5069void IOHIDSystem::_updateEventFlags(IOHIDSystem * self, 5070 unsigned flags, 5071 OSObject * sender, 5072 void * refcon __unused) 5073{ 5074 self->updateEventFlags(flags, sender); 5075} 5076 5077void IOHIDSystem::updateEventFlags(unsigned flags) 5078{ 5079 updateEventFlags(flags, 0); 5080} 5081 5082void IOHIDSystem::updateEventFlags(unsigned flags, OSObject * sender) 5083{ 5084 KeyboardEQElement * keyboardEQElement = (KeyboardEQElement *)IOMalloc(sizeof(KeyboardEQElement)); 5085 5086 if ( !keyboardEQElement ) 5087 return; 5088 5089 bzero(keyboardEQElement, sizeof(KeyboardEQElement)); 5090 5091 keyboardEQElement->action = IOHIDSystem::doUpdateEventFlags; 5092 keyboardEQElement->sender = sender; 5093 if (sender) sender->retain(); // NOTE: Matching release is in IOHIDSystem::processKeyboardEQ 5094 5095 keyboardEQElement->event.flagsChanged.flags = flags; 5096 5097 KEYBOARD_EQ_LOCK; 5098 enqueue_tail(&gKeyboardEQ, (queue_entry_t)keyboardEQElement); 5099 KEYBOARD_EQ_UNLOCK; 5100 5101 keyboardEQES->interruptOccurred(0, 0, 0); 5102} 5103 5104IOReturn IOHIDSystem::doUpdateEventFlags(IOHIDSystem *self, void * args) 5105 /* IOCommandGate::Action */ 5106{ 5107 KeyboardEQElement * keyboardEQElement = (KeyboardEQElement *)args; 5108 5109 OSObject * sender = keyboardEQElement->sender; 5110 unsigned flags = keyboardEQElement->event.flagsChanged.flags; 5111 5112 self->updateEventFlagsGated(flags, sender); 5113 5114 return kIOReturnSuccess; 5115} 5116 5117void IOHIDSystem::updateEventFlagsGated(unsigned flags, OSObject * sender __unused) 5118{ 5119 if ( eventsOpen ) { 5120 evg->eventFlags = (evg->eventFlags & ~KEYBOARD_FLAGSMASK) 5121 | (flags & KEYBOARD_FLAGSMASK); 5122 5123 // RY: Reset the clickTime as well on modifier 5124 // change to prevent double click from occuring 5125 nanoseconds_to_absolutetime(0, &clickTime); 5126 } 5127} 5128 5129// 5130// - _setButtonState:(int)buttons atTime:(int)t 5131// Update the button state. Generate button events as needed 5132// 5133void IOHIDSystem::_setButtonState(int buttons, 5134 /* atTime */ AbsoluteTime ts, 5135 OSObject * sender) 5136{ 5137 // *** HACK ALERT *** 5138 // Chache the sent button state and or it with the other button states. 5139 // This will prevent awkward behavior when two pointing devices are used 5140 // at the same time. 5141 CachedMouseEventStruct *cachedMouseEvent = NULL; 5142 5143 if ( cachedButtonStates ) { 5144 cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender); 5145 5146 if (cachedMouseEvent) { 5147 cachedMouseEvent->lastButtons = buttons; 5148 } 5149 5150 if (evg->buttons == buttons) 5151 return; 5152 5153 buttons = GetCachedMouseButtonStates(cachedButtonStates); 5154 } 5155 // *** END HACK *** 5156 5157 // Once again check if new button state differs 5158 if (evg->buttons == buttons) 5159 return; 5160 5161 if (_scMouseCanReset && _scCount) { 5162 log_scroll_state("Resetting _scCount due to click: %lld\n", ts); 5163 _scCount = 0; 5164 } 5165 5166 // Magic uber-mouse buttons changed event so we can get all of the buttons... 5167 NXEventData evData; 5168 unsigned long hwButtons, hwDelta; 5169 5170 /* I'd like to keep the event button mapping linear, so 5171 I have to "undo" the LB/RB mouse bit numbering funkiness 5172 before I pass the information down to the app. */ 5173 /* Ideally this would all go away if we fixed EV_LB and EV_RB 5174 to be bits 0 and 1 */ 5175 CONVERT_EV_TO_HW_BUTTONS(buttons, hwButtons); 5176 CONVERT_EV_TO_HW_DELTA((evg->buttons ^ buttons), hwDelta); 5177 5178 evData.compound.reserved = 0; 5179 evData.compound.subType = NX_SUBTYPE_AUX_MOUSE_BUTTONS; 5180 evData.compound.misc.L[0] = hwDelta; 5181 evData.compound.misc.L[1] = hwButtons; 5182 5183 postEvent( NX_SYSDEFINED, 5184 /* at */ &_cursorHelper.desktopLocation(), 5185 /* atTime */ ts, 5186 /* withData */ &evData, 5187 /* sender */ sender); 5188 5189 // End Magic uber-mouse buttons changed event 5190 5191 bzero(&evData, sizeof(NXEventData)); 5192 5193 // vtn3: This will update the data structure for touch devices 5194 updateMouseEventForSender(sender, &evData); 5195 5196 // RY: Roll in the tablet info we got from absolutePointerEventGated 5197 // into a button event. Prior to this we were sending null data to 5198 // post event. This won't be much different as the only non-zero 5199 // contents should be the tablet area of the event. 5200 if (cachedMouseEvent || 5201 (NULL != (cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender)))) { 5202 if (evData.mouse.subType != NX_SUBTYPE_MOUSE_TOUCH) 5203 evData.mouse.subType = cachedMouseEvent->subType; 5204 evData.mouse.pressure = cachedMouseEvent->lastPressure; 5205 5206 if (cachedMouseEvent->subType == NX_SUBTYPE_TABLET_POINT) { 5207 bcopy(&(cachedMouseEvent->tabletData), &(evData.mouse.tablet.point), sizeof(NXTabletPointData)); 5208 } 5209 else if (cachedMouseEvent->subType == NX_SUBTYPE_TABLET_PROXIMITY) { 5210 bcopy(&(cachedMouseEvent->proximityData), &(evData.mouse.tablet.proximity), sizeof(NXTabletProximityData)); 5211 } 5212 } 5213 evData.mouse.subx = _cursorHelper.desktopLocation().xValue().fraction() >> 8; 5214 evData.mouse.suby = _cursorHelper.desktopLocation().yValue().fraction() >> 8; 5215 5216 if ((evg->buttons & EV_LB) != (buttons & EV_LB)) { 5217 if (buttons & EV_LB) { 5218 postEvent( NX_LMOUSEDOWN, 5219 /* at */ &_cursorHelper.desktopLocation(), 5220 /* atTime */ ts, 5221 /* withData */ &evData, 5222 /* sender */ sender); 5223 } 5224 else { 5225 postEvent( NX_LMOUSEUP, 5226 /* at */ &_cursorHelper.desktopLocation(), 5227 /* atTime */ ts, 5228 /* withData */ &evData, 5229 /* sender */ sender); 5230 } 5231 // After entering initial up/down event, set up 5232 // coalescing state so drags will behave correctly 5233 evg->dontCoalesce = evg->dontWantCoalesce; 5234 if (evg->dontCoalesce) 5235 evg->eventFlags |= NX_NONCOALSESCEDMASK; 5236 else 5237 evg->eventFlags &= ~NX_NONCOALSESCEDMASK; 5238 } 5239 5240 if ((evg->buttons & EV_RB) != (buttons & EV_RB)) { 5241 if (buttons & EV_RB) { 5242 postEvent( NX_RMOUSEDOWN, 5243 /* at */ &_cursorHelper.desktopLocation(), 5244 /* atTime */ ts, 5245 /* withData */ &evData, 5246 /* sender */ sender); 5247 } 5248 else { 5249 postEvent( NX_RMOUSEUP, 5250 /* at */ &_cursorHelper.desktopLocation(), 5251 /* atTime */ ts, 5252 /* withData */ &evData, 5253 /* sender */ sender); 5254 } 5255 } 5256 5257 evg->buttons = buttons; 5258} 5259 5260// 5261// Sets the cursor position (evg->cursorLoc) to the new 5262// location. The location is clipped against the cursor pin rectangle, 5263// mouse moved/dragged events are generated using the given event mask, 5264// and a mouse-exited event may be generated. The cursor image is 5265// moved. 5266// This should be run from a command gate action. 5267// 5268void IOHIDSystem::setCursorPosition(IOGPoint * newLoc, bool external, OSObject * sender) 5269{ 5270 if ( eventsOpen == true ) 5271 { 5272 clock_get_uptime(&_cursorEventLast); 5273 _cursorHelper.desktopLocationDelta().xValue() += (newLoc->x - _cursorHelper.desktopLocation().xValue()); 5274 _cursorHelper.desktopLocationDelta().yValue() += (newLoc->y - _cursorHelper.desktopLocation().yValue()); 5275 _cursorHelper.desktopLocation().fromIntFloor(newLoc->x, newLoc->y); 5276 _setCursorPosition(external, false, sender); 5277 _cursorMoveLast = _cursorEventLast; 5278 scheduleNextPeriodicEvent(); 5279 } 5280} 5281 5282// 5283// This mechanism is used to update the cursor position, possibly generating 5284// messages to registered frame buffer devices and posting drag, tracking, and 5285// mouse motion events. 5286// 5287// This should be run from a command gate action. 5288// This can be called from setCursorPosition:(IOGPoint *)newLoc to set the 5289// position by a _IOSetParameterFromIntArray() call, directly from the absolute or 5290// relative pointer device routines, or on a timed event callback. 5291// 5292 5293void IOHIDSystem::enableContinuousCursor() 5294{ 5295 kprintf("%s called\n", __func__); 5296 5297 _continuousCursor = true; 5298} 5299 5300void IOHIDSystem::disableContinuousCursor() 5301{ 5302 kprintf("%s called\n", __func__); 5303 5304 _continuousCursor = false; 5305} 5306 5307void IOHIDSystem::_setCursorPosition(bool external, bool proximityChange, OSObject * sender) 5308{ 5309 bool cursorMoved = true; 5310 IOHID_DEBUG(kIOHIDDebugCode_SetCursorPosition, sender, 5311 _cursorHelper.desktopLocation().xValue().as64(), 5312 _cursorHelper.desktopLocation().yValue().as64(), 0); 5313 IOHID_DEBUG(kIOHIDDebugCode_SetCursorPosition, sender, proximityChange, external, 1); 5314 PROFILE_TRACE(9); 5315 5316 if (!screens) { 5317 return; 5318 } 5319 5320 if( OSSpinLockTry(&evg->cursorSema) == 0 ) { // host using shmem 5321 // try again later 5322 return; 5323 } 5324 5325 // Past here we hold the cursorSema lock. Make sure the lock is 5326 // cleared before returning or the system will be wedged. 5327 if (cursorCoupled || external) 5328 { 5329 UInt32 newScreens = 0; 5330 SInt32 pinScreen = -1L; 5331 EvScreen *screen = (EvScreen *)evScreen; 5332 5333 bool foundFirstScreen = false; // T => found first valid screen 5334 bool foundSecondScreen = false; // T => found second valid screen 5335 int leftScreen = 0; 5336 int rightScreen = 0; 5337 5338 if (cursorPinned) { 5339 _cursorHelper.desktopLocation().clipToRect(cursorPin); 5340 } 5341 else { 5342 /* Get mask of screens on which the cursor is present */ 5343 for (int i = 0; i < screens; i++ ) { 5344 if (!screen[i].desktopBounds) 5345 continue; 5346 if ((screen[i].desktopBounds->maxx - screen[i].desktopBounds->minx) < 128) 5347 continue; 5348 if (_continuousCursor) { 5349 if( !foundFirstScreen ) { 5350 foundFirstScreen = true; 5351 leftScreen = i; 5352 rightScreen = i; 5353 } 5354 else if( !foundSecondScreen ) { 5355 // I need this if I care about vertical stacks of displays 5356 // foundSecondScreen = 5357 // (screen[leftScreen].desktopBounds->minx != screen[i].desktopBounds->minx) || 5358 // (screen[leftScreen].desktopBounds->maxx != screen[i].desktopBounds->maxx) || 5359 // (screen[leftScreen].desktopBounds->miny != screen[i].desktopBounds->miny) || 5360 // (screen[leftScreen].desktopBounds->maxy != screen[i].desktopBounds->maxy); 5361 } 5362 5363 // if (screen[i].desktopBounds->minx < screen[leftScreen].desktopBounds->minx) { // overlaps can torroid 5364 if (screen[i].desktopBounds->maxx <= screen[leftScreen].desktopBounds->minx) { // non-overlaps torroid 5365 leftScreen = i; 5366 } 5367 // if (screen[rightScreen].desktopBounds->maxx < screen[i].desktopBounds->maxx ) // overlaps can torroid 5368 if (screen[rightScreen].desktopBounds->maxx <= screen[i].desktopBounds->minx ) // non-overlaps torroid 5369 { 5370 rightScreen = i; 5371 } 5372 } 5373 if (_cursorHelper.desktopLocation().inRect(*screen[i].desktopBounds)) { 5374 pinScreen = i; 5375 newScreens |= (1 << i); 5376 } 5377 } 5378 } 5379 5380 if (newScreens == 0) { 5381 /* At this point cursor has gone off all screens, 5382 clip it to the closest screen. */ 5383 IOFixedPoint64 aimLoc = _cursorHelper.desktopLocation(); 5384 int64_t dx; 5385 int64_t dy; 5386 uint64_t distance; 5387 uint64_t bestDistance = -1ULL; 5388 5389 const int64_t kHackMiniumWrapDistance = 0; // 22 * 22; 5390 const int64_t kHackUpperNoWrap = 40; // Amount of space at the top that does not wrap 5391 const int64_t kHackLowerNoWrap = 40; // Amount of space at the bottom that does not wrap 5392 // TODO: decide if menubar is special for wrap (and how) 5393 for (int i = 0; i < screens; i++ ) { 5394 if (!screen[i].desktopBounds) 5395 continue; 5396 if ((screen[i].desktopBounds->maxx - screen[i].desktopBounds->minx) < 128) 5397 continue; 5398 if (_continuousCursor && (screen[i].desktopBounds->maxy - screen[i].desktopBounds->miny) < 128) 5399 continue; 5400 5401 IOFixedPoint64 pinnedLoc = aimLoc; 5402 pinnedLoc.clipToRect(*screen[i].desktopBounds); 5403 dx = (pinnedLoc.xValue() - aimLoc.xValue()).as64(); 5404 dy = (pinnedLoc.yValue() - aimLoc.yValue()).as64(); 5405 distance = dx * dx + dy * dy; 5406 5407 if (distance <= bestDistance) { 5408 bestDistance = distance; 5409 5410 if (_continuousCursor && 5411 leftScreen != rightScreen && 5412 screen[i].desktopBounds->miny + kHackUpperNoWrap < pinnedLoc.yValue().as64() && 5413 pinnedLoc.yValue().as64() < screen[i].desktopBounds->maxy - kHackLowerNoWrap && 5414 kHackMiniumWrapDistance < bestDistance ) { 5415 5416 IOFixed64 targetX; 5417 IOFixed64 targetY; 5418 int targetDisplay = i; 5419 bool shouldWrap = true; // Assume we're wrapping (makes code below shorter) 5420 5421 if (aimLoc.xValue().as64() < screen[leftScreen].desktopBounds->minx ) { 5422 // Wrap to right side of right screen 5423 targetX.fromIntFloor(screen[rightScreen].desktopBounds->maxx); 5424 targetY.fromIntFloor(screen[rightScreen].desktopBounds->maxy - screen[rightScreen].desktopBounds->miny); 5425 targetDisplay = rightScreen; 5426 kprintf("IOHIDSystem::_setCursorPosition Wrap to right side of right screen\n"); 5427 } 5428 else if (screen[rightScreen].desktopBounds->maxx < aimLoc.xValue().as64()) { 5429 // Wrap to left side of left screen 5430 targetX.fromIntFloor(screen[leftScreen].desktopBounds->minx); 5431 targetY.fromIntFloor(screen[leftScreen].desktopBounds->maxy - screen[leftScreen].desktopBounds->miny); 5432 targetDisplay = leftScreen; 5433 kprintf("IOHIDSystem::_setCursorPosition Wrap to left side of left screen\n"); 5434 } 5435 else { 5436 shouldWrap = false; 5437 kprintf("IOHIDSystem::_setCursorPosition don't wrap\n"); 5438 } 5439 5440 if (shouldWrap) 5441 { 5442 IOFixed64 closestYFraction; 5443 closestYFraction.fromIntFloor(pinnedLoc.yValue().as64() - screen[i].desktopBounds->miny); 5444 closestYFraction /= (screen[i].desktopBounds->maxy - screen[i].desktopBounds->miny); 5445 targetY *= closestYFraction; 5446 5447 pinnedLoc.fromFixed64(targetX, targetY); 5448 pinnedLoc.clipToRect(*screen[targetDisplay].desktopBounds); // SHOULD NOT NEED - makes SURE we hit a screen 5449 5450 } 5451 } 5452 5453 _cursorHelper.desktopLocation() = pinnedLoc; 5454 } 5455 } 5456 IOHID_DEBUG(kIOHIDDebugCode_SetCursorPosition, sender, 5457 _cursorHelper.desktopLocation().xValue().as64(), 5458 _cursorHelper.desktopLocation().yValue().as64(), 2); 5459 5460 /* regenerate mask for new position */ 5461 for (int i = 0; i < screens; i++ ) { 5462 if (!screen[i].desktopBounds) 5463 continue; 5464 if ((screen[i].desktopBounds->maxx - screen[i].desktopBounds->minx) < 128) 5465 continue; 5466 if (_cursorHelper.desktopLocation().inRect(*screen[i].desktopBounds)) { 5467 pinScreen = i; 5468 newScreens |= (1 << i); 5469 } 5470 } 5471 } 5472 5473 /* Catch the no-move case */ 5474 if ((_cursorHelper.desktopLocation().xValue().asFixed24x8() == evg->desktopCursorFixed.x) && 5475 (_cursorHelper.desktopLocation().yValue().asFixed24x8() == evg->desktopCursorFixed.y) && 5476 (proximityChange == 0) && (!_cursorHelper.desktopLocationDelta())) { 5477 cursorMoved = false; // mouse moved, but cursor didn't 5478 } 5479 else { 5480 evg->cursorLoc.x = _cursorHelper.desktopLocation().xValue().as32(); 5481 evg->cursorLoc.y = _cursorHelper.desktopLocation().yValue().as32(); 5482 evg->desktopCursorFixed.x = _cursorHelper.desktopLocation().xValue().asFixed24x8(); 5483 evg->desktopCursorFixed.y = _cursorHelper.desktopLocation().yValue().asFixed24x8(); 5484 if (pinScreen >= 0) { 5485 _cursorHelper.updateScreenLocation(screen[pinScreen].desktopBounds, screen[pinScreen].displayBounds); 5486 } 5487 else { 5488 _cursorHelper.updateScreenLocation(NULL, NULL); 5489 } 5490 evg->screenCursorFixed.x = _cursorHelper.getScreenLocation().xValue().asFixed24x8(); 5491 evg->screenCursorFixed.y = _cursorHelper.getScreenLocation().yValue().asFixed24x8(); 5492 5493 /* If cursor changed screens */ 5494 if (newScreens != cursorScreens) { 5495 hideCursor(); /* hide cursor on old screens */ 5496 cursorScreens = newScreens; 5497 if (pinScreen >= 0) { 5498 cursorPin = *(((EvScreen*)evScreen)[pinScreen].desktopBounds); 5499 cursorPinScreen = pinScreen; 5500 showCursor(); 5501 } 5502 } else { 5503 /* cursor moved on same screens */ 5504 moveCursor(); 5505 } 5506 } 5507 } 5508 else { 5509 /* cursor uncoupled */ 5510 _cursorHelper.desktopLocation().xValue().fromFixed24x8(evg->desktopCursorFixed.x); 5511 _cursorHelper.desktopLocation().yValue().fromFixed24x8(evg->desktopCursorFixed.y); 5512 } 5513 5514 AbsoluteTime uptime; 5515 clock_get_uptime(&uptime); 5516 5517 _cursorLog(uptime); 5518 5519 /* See if anybody wants the mouse moved or dragged events */ 5520 // Note: extPostEvent clears evg->movedMask as a hack to prevent these events 5521 // so any change here should check to make sure it does not break that hack 5522 if (evg->movedMask) { 5523 if ((evg->movedMask & NX_LMOUSEDRAGGEDMASK) && (evg->buttons & EV_LB)) { 5524 _postMouseMoveEvent(NX_LMOUSEDRAGGED, uptime, sender); 5525 } 5526 else if ((evg->movedMask & NX_RMOUSEDRAGGEDMASK) && (evg->buttons & EV_RB)) { 5527 _postMouseMoveEvent(NX_RMOUSEDRAGGED, uptime, sender); 5528 } 5529 else if (evg->movedMask & NX_MOUSEMOVEDMASK) { 5530 _postMouseMoveEvent(NX_MOUSEMOVED, uptime, sender); 5531 } 5532 } 5533 5534 /* check new cursor position for leaving evg->mouseRect */ 5535 if (cursorMoved && evg->mouseRectValid && _cursorHelper.desktopLocation().inRect(evg->mouseRect)) 5536 { 5537 if (evg->mouseRectValid) 5538 { 5539 postEvent(/* what */ NX_MOUSEEXITED, 5540 /* at */ &_cursorHelper.desktopLocation(), 5541 /* atTime */ uptime, 5542 /* withData */ NULL, 5543 /* sender */ sender); 5544 evg->mouseRectValid = 0; 5545 } 5546 } 5547 OSSpinLockUnlock(&evg->cursorSema); 5548 PROFILE_TRACE(10); 5549} 5550 5551void IOHIDSystem::_postMouseMoveEvent(int what, 5552 AbsoluteTime ts, 5553 OSObject * sender) 5554{ 5555 NXEventData data; 5556 CachedMouseEventStruct *cachedMouseEvent = 0; 5557 PROFILE_TRACE(11); 5558 5559 bzero( &data, sizeof(data) ); 5560 data.mouseMove.dx = _cursorHelper.desktopLocationDelta().xValue().as32(); 5561 data.mouseMove.dy = _cursorHelper.desktopLocationDelta().yValue().as32(); 5562 data.mouseMove.subx = _cursorHelper.desktopLocation().xValue().fraction() >> 8; 5563 data.mouseMove.suby = _cursorHelper.desktopLocation().yValue().fraction() >> 8; 5564 5565 _cursorHelper.desktopLocationDelta() = IOFixedPoint64(); 5566 _cursorLog(AbsoluteTime_to_scalar(&ts)); 5567 5568 // vtn3: This will update the data structure for touch devices 5569 updateMouseMoveEventForSender(sender, &data); 5570 5571 // RY: Roll in the tablet info we got from absolutePointerEventGated 5572 // into the mouseMove event. 5573 if (sender && (cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender))) 5574 { 5575 if (data.mouse.subType != NX_SUBTYPE_MOUSE_TOUCH) 5576 data.mouseMove.subType = cachedMouseEvent->subType; 5577 data.mouseMove.reserved1 = cachedMouseEvent->lastPressure; 5578 5579 if (cachedMouseEvent->subType == NX_SUBTYPE_TABLET_PROXIMITY) 5580 { 5581 bcopy(&(cachedMouseEvent->proximityData), &(data.mouseMove.tablet.proximity), sizeof(NXTabletProximityData)); 5582 } 5583 else if (cachedMouseEvent->subType == NX_SUBTYPE_TABLET_POINT) 5584 { 5585 bcopy(&(cachedMouseEvent->tabletData), &(data.mouseMove.tablet.point), sizeof(NXTabletPointData)); 5586 } 5587 } 5588 5589 postEvent(what, &_cursorHelper.desktopLocation(), ts, &data, sender); 5590 PROFILE_TRACE(12); 5591} 5592 5593/** 5594 ** IOUserClient methods 5595 **/ 5596 5597IOReturn IOHIDSystem::newUserClient(task_t owningTask, 5598 /* withToken */ void * security_id, 5599 /* ofType */ UInt32 type, 5600 /* withProps*/ OSDictionary * properties, 5601 /* client */ IOUserClient ** handler) 5602{ 5603 IOHIDCmdGateActionArgs args; 5604 5605 args.arg0 = &owningTask; 5606 args.arg1 = security_id; 5607 args.arg2 = &type; 5608 args.arg3 = properties; 5609 args.arg4 = handler; 5610 5611 return cmdGate->runAction((IOCommandGate::Action)doNewUserClient, &args); 5612} 5613 5614IOReturn IOHIDSystem::doNewUserClient(IOHIDSystem *self, void * args) 5615 /* IOCommandGate::Action */ 5616{ 5617 task_t owningTask = *(task_t *) ((IOHIDCmdGateActionArgs *)args)->arg0; 5618 void * security_id = ((IOHIDCmdGateActionArgs *)args)->arg1; 5619 UInt32 type = *(UInt32 *) ((IOHIDCmdGateActionArgs *)args)->arg2; 5620 OSDictionary * properties = (OSDictionary *) ((IOHIDCmdGateActionArgs *)args)->arg3; 5621 IOUserClient ** handler = (IOUserClient **) ((IOHIDCmdGateActionArgs *)args)->arg4; 5622 5623 return self->newUserClientGated(owningTask, security_id, type, properties, handler); 5624} 5625 5626IOReturn IOHIDSystem::newUserClientGated(task_t owningTask, 5627 /* withToken */ void * security_id, 5628 /* ofType */ UInt32 type, 5629 /* withProps*/ OSDictionary * properties, 5630 /* client */ IOUserClient ** handler) 5631{ 5632 IOUserClient * newConnect = 0; 5633 IOReturn err = kIOReturnNoMemory; 5634 5635 do { 5636 if ( type == kIOHIDParamConnectType) { 5637 if ( paramConnect) { 5638 newConnect = paramConnect; 5639 newConnect->retain(); 5640 } 5641 else if ( eventsOpen) { 5642 newConnect = new IOHIDParamUserClient; 5643 } 5644 else { 5645 err = kIOReturnNotOpen; 5646 continue; 5647 } 5648 5649 } 5650 else if ( type == kIOHIDServerConnectType) { 5651 newConnect = new IOHIDUserClient; 5652 } 5653 else if ( type == kIOHIDStackShotConnectType ) { 5654 newConnect = new IOHIDStackShotUserClient; 5655 } 5656 else if ( type == kIOHIDEventSystemConnectType ) { 5657 newConnect = new IOHIDEventSystemUserClient; 5658 } 5659 else { 5660 err = kIOReturnUnsupported; 5661 } 5662 5663 if ( !newConnect) { 5664 continue; 5665 } 5666 5667 // initialization is getting out of hand 5668 5669 if ( (newConnect != paramConnect) && ( 5670 (false == newConnect->initWithTask(owningTask, security_id, type, properties)) 5671 || (false == newConnect->setProperty(kIOUserClientCrossEndianCompatibleKey, kOSBooleanTrue)) 5672 || (false == newConnect->attach( this )) 5673 || (false == newConnect->start( this )) 5674 || ((type == kIOHIDServerConnectType) 5675 && (err = evOpen())) 5676 )) { 5677 newConnect->detach( this ); 5678 newConnect->release(); 5679 newConnect = 0; 5680 continue; 5681 } 5682 if ( type == kIOHIDParamConnectType) 5683 paramConnect = newConnect; 5684 5685 err = kIOReturnSuccess; 5686 5687 } 5688 while( false ); 5689 5690#ifdef DEBUG 5691 int pid = -1; 5692 proc_t p = (proc_t)get_bsdtask_info(owningTask); 5693 pid = proc_pid(p); 5694 IOLog("%s (%d) %s returned %p\n", __func__, pid, 5695 type == kIOHIDParamConnectType ? "IOHIDParamUserClient" : 5696 type == kIOHIDServerConnectType ? "IOHIDUserClient" : 5697 type == kIOHIDStackShotConnectType ? "IOHIDStackShotUserClient" : 5698 type == kIOHIDEventSystemConnectType ? "IOHIDEventSystemUserClient" : 5699 "kIOReturnUnsupported", 5700 newConnect); 5701#endif 5702 5703 IOHID_DEBUG(kIOHIDDebugCode_NewUserClient, type, err, newConnect, 0); 5704 *handler = newConnect; 5705 return err; 5706} 5707 5708 5709IOReturn IOHIDSystem::setEventsEnable(void*p1,void*,void*,void*,void*,void*) 5710{ // IOMethod 5711 IOReturn ret; 5712 5713 if (mac_iokit_check_hid_control(kauth_cred_get())) 5714 return kIOReturnNotPermitted; 5715 5716 ret = cmdGate->runAction((IOCommandGate::Action)doSetEventsEnablePre, p1); 5717 if ( ret == kIOReturnSuccess ) { 5718 // reset outside gated context 5719 _resetMouseParameters(); 5720 } 5721 ret = cmdGate->runAction((IOCommandGate::Action)doSetEventsEnablePost, p1); 5722 5723 return ret; 5724} 5725 5726IOReturn IOHIDSystem::doSetEventsEnablePre(IOHIDSystem *self, void *p1) 5727 /* IOCommandGate::Action */ 5728{ 5729 return self->setEventsEnablePreGated(p1); 5730} 5731 5732IOReturn IOHIDSystem::setEventsEnablePreGated(void*p1) 5733{ 5734 bool enable = (bool)p1; 5735 5736 if( enable) { 5737 while ( evStateChanging ) 5738 cmdGate->commandSleep(&evStateChanging); 5739 5740 evStateChanging = true; 5741 attachDefaultEventSources(); 5742 } 5743 return( kIOReturnSuccess); 5744} 5745 5746IOReturn IOHIDSystem::doSetEventsEnablePost(IOHIDSystem *self, void *p1) 5747 /* IOCommandGate::Action */ 5748{ 5749 return self->setEventsEnablePostGated(p1); 5750} 5751 5752IOReturn IOHIDSystem::setEventsEnablePostGated(void*p1) 5753{ 5754 bool enable = (bool)p1; 5755 5756 if( enable) { 5757 evStateChanging = false; 5758 cmdGate->commandWakeup(&evStateChanging); 5759 } 5760 return( kIOReturnSuccess); 5761} 5762 5763 5764IOReturn IOHIDSystem::setCursorEnable(void*p1,void*,void*,void*,void*,void*) 5765{ // IOMethod 5766 if (mac_iokit_check_hid_control(kauth_cred_get())) 5767 return kIOReturnNotPermitted; 5768 5769 return cmdGate->runAction((IOCommandGate::Action)doSetCursorEnable, p1); 5770 5771} 5772 5773IOReturn IOHIDSystem::doSetCursorEnable(IOHIDSystem *self, void * arg0) 5774 /* IOCommandGate::Action */ 5775{ 5776 return self->setCursorEnableGated(arg0); 5777} 5778 5779IOReturn IOHIDSystem::setCursorEnableGated(void* p1) 5780{ 5781 bool enable = (bool)(intptr_t)p1; 5782 5783 if ( !eventsOpen ) { 5784 return kIOReturnNotOpen; 5785 } 5786 5787 if( !screens) { 5788 return kIOReturnNoDevice; 5789 } 5790 5791 if( enable ) { 5792 if( cursorStarted) { 5793 hideCursor(); 5794 cursorEnabled = resetCursor(); 5795 showCursor(); 5796 } 5797 else { 5798 cursorEnabled = startCursor(); 5799 } 5800 } 5801 else { 5802 cursorEnabled = enable; 5803 } 5804 5805 if (cursorCoupled != cursorEnabled) { 5806 _periodicEventNext = kIOHIDSystenDistantFuture; 5807 _cursorMoveDelta = 0; 5808 _cursorHelper.desktopLocationPosting().fromIntFloor(0, 0); 5809 _cursorHelper.clearEventCounts(); 5810 _cursorLogTimed(); 5811 scheduleNextPeriodicEvent(); 5812 cursorCoupled = cursorEnabled; 5813 } 5814 5815 return kIOReturnSuccess; 5816} 5817 5818IOReturn IOHIDSystem::setContinuousCursorEnable(void*p1,void*,void*,void*,void*,void*) 5819{ // IOMethod 5820 kprintf("%s called\n", __func__); 5821 5822 if (mac_iokit_check_hid_control(kauth_cred_get())) 5823 return kIOReturnNotPermitted; 5824 5825 return cmdGate->runAction((IOCommandGate::Action)doSetContinuousCursorEnable, p1); 5826 5827} 5828 5829IOReturn IOHIDSystem::doSetContinuousCursorEnable(IOHIDSystem *self, void * arg0) 5830 /* IOCommandGate::Action */ 5831{ 5832 kprintf("%s called\n", __func__); 5833 5834 return self->setContinuousCursorEnableGated(arg0); 5835} 5836 5837IOReturn IOHIDSystem::setContinuousCursorEnableGated(void* p1) 5838{ 5839 bool enable = (bool)(intptr_t)p1; 5840 5841 kprintf("%s called\n", __func__); 5842 5843 if ( !eventsOpen ) { 5844 return kIOReturnNotOpen; 5845 } 5846 5847 if( !screens) { 5848 return kIOReturnNoDevice; 5849 } 5850 5851 if( enable ) 5852 enableContinuousCursor(); 5853 else 5854 disableContinuousCursor(); 5855 5856 return kIOReturnSuccess; 5857} 5858 5859IOReturn IOHIDSystem::extSetBounds( IOGBounds * bounds ) 5860{ 5861 if (mac_iokit_check_hid_control(kauth_cred_get())) 5862 return kIOReturnNotPermitted; 5863 5864 if( bounds->minx != bounds->maxx) { 5865 cursorPin = *bounds; 5866 cursorPinned = true; 5867 } else 5868 cursorPinned = false; 5869 5870 return( kIOReturnSuccess ); 5871} 5872 5873IOReturn IOHIDSystem::extPostEvent(void*p1,void*p2,void*,void*,void*,void*) 5874{ // IOMethod 5875 AbsoluteTime ts; 5876 5877 clock_get_uptime(&ts); 5878 5879 return cmdGate->runAction((IOCommandGate::Action)doExtPostEvent, p1, p2, &ts); 5880} 5881 5882IOReturn IOHIDSystem::doExtPostEvent(IOHIDSystem *self, void * arg0, void * arg1, void * arg2, void * arg3 __unused) 5883 /* IOCommandGate::Action */ 5884{ 5885 return self->extPostEventGated(arg0, arg1, arg2); 5886} 5887 5888IOReturn IOHIDSystem::extPostEventGated(void *p1,void *p2 __unused, void *p3) 5889{ 5890 struct evioLLEvent * event = (struct evioLLEvent *)p1; 5891 bool isMoveOrDragEvent = false; 5892 bool isSeized = false; 5893 int oldMovedMask = 0; 5894 UInt32 buttonState = 0; 5895 UInt32 newFlags = 0; 5896 AbsoluteTime ts = *(AbsoluteTime *)p3; 5897 CachedMouseEventStruct *cachedMouseEvent = NULL; 5898 UInt32 typeMask = EventCodeMask(event->type); 5899 5900 // rdar://problem/8689199 5901 int extPID = proc_selfpid(); 5902 5903 IOHID_DEBUG(kIOHIDDebugCode_ExtPostEvent, event->type, *(UInt32*)&(event->location), event->setFlags, event->flags); 5904 5905 5906 if (event->type != NX_NULLEVENT && mac_iokit_check_hid_control(kauth_cred_get())) 5907 return kIOReturnNotPermitted; 5908 5909 if ( eventsOpen == false ) 5910 return kIOReturnNotOpen; 5911 5912 if (ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline, false)) { 5913 if (typeMask & NX_WAKEMASK) { 5914 TICKLE_DISPLAY(event->type); 5915 } 5916 return kIOReturnSuccess; 5917 } 5918 5919 if (!DISPLAY_IS_ENABLED) { 5920#if !WAKE_DISPLAY_ON_MOVEMENT 5921 if ( (typeMask & NX_WAKEMASK) || 5922 ((typeMask & MOVEDEVENTMASK) && (CMP_ABSOLUTETIME(&ts, &displaySleepWakeupDeadline) <= 0)) ) 5923#endif 5924 { 5925 TICKLE_DISPLAY(event->type); 5926 } 5927 return kIOReturnSuccess; 5928 } 5929 5930 TICKLE_DISPLAY(event->type); 5931 5932 // used in set cursor below 5933 if (typeMask & MOVEDEVENTMASK) 5934 { 5935 isMoveOrDragEvent = true; 5936 5937 // We have mouse move event without a specified pressure value and an embedded tablet event 5938 // We need to scale the tablet pressure to fit in mouseMove pressure 5939 if ((event->data.mouseMove.subType == NX_SUBTYPE_TABLET_POINT) && (event->data.mouseMove.reserved1 == 0)) 5940 { 5941 event->data.mouseMove.reserved1 = ScalePressure(event->data.mouseMove.tablet.point.pressure); 5942 } 5943 } 5944 // We have mouse event without a specified pressure value and an embedded tablet event 5945 // We need to scale the tablet pressure to fit in mouse pressure 5946 else if ((typeMask & MOUSEEVENTMASK) && 5947 (event->data.mouse.subType == NX_SUBTYPE_TABLET_POINT) && (event->data.mouse.pressure == 0)) 5948 { 5949 event->data.mouse.pressure = ScalePressure(event->data.mouse.tablet.point.pressure); 5950 } 5951 5952 if( event->setCursor) 5953 { 5954 // hack: clear evg->movedMask so setCursorPosition will not post 5955 // mouse moved events if this event is itself a mouse move event 5956 // this will prevent double events 5957 if (isMoveOrDragEvent) 5958 { 5959 oldMovedMask = evg->movedMask; 5960 evg->movedMask = 0; 5961 } 5962 5963 if (( event->type == NX_MOUSEMOVED ) && 5964 ( event->setCursor & kIOHIDSetRelativeCursorPosition )) 5965 { 5966 IOFixedPoint32 move; 5967 move.x = (event->data.mouseMove.dx * 256); 5968 move.y = (event->data.mouseMove.dy * 256); 5969 _cursorHelper.desktopLocation() += move; 5970 _cursorHelper.desktopLocationDelta() += move; 5971 5972 _cursorLog(AbsoluteTime_to_scalar(&ts)); 5973 5974 clock_get_uptime(&_cursorEventLast); 5975 _setCursorPosition(); 5976 _cursorMoveLast = _cursorEventLast; 5977 // scheduleNextPeriodicEvent() happens at the end. 5978 } 5979 else if ( event->setCursor & kIOHIDSetCursorPosition ) 5980 { 5981 setCursorPosition(&event->location, false); 5982 } 5983 5984 // other side of hack 5985 if (isMoveOrDragEvent) 5986 evg->movedMask = oldMovedMask; 5987 } 5988 // RY: This event is not moving the cursor, but we should 5989 // still determine if we need to click the location 5990 else 5991 { 5992 UInt32 newScreens = 0; 5993 EvScreen *screen = (EvScreen *)evScreen; 5994 5995 if (!cursorPinned) { 5996 /* Get mask of screens on which the cursor is present */ 5997 for (int i = 0; i < screens; i++ ) { 5998 if (!screen[i].desktopBounds) 5999 continue; 6000 if ((screen[i].desktopBounds->maxx - screen[i].desktopBounds->minx) < 128) 6001 continue; 6002 if (_cursorHelper.desktopLocation().inRect(*screen[i].desktopBounds)) { 6003 newScreens |= (1 << i); 6004 } 6005 } 6006 } 6007 6008 if (newScreens == 0) 6009 { 6010 /* At this point cursor has gone off all screens, 6011 just clip it to one of the previous screens. */ 6012 event->location.x = (event->location.x < cursorPin.minx) ? 6013 cursorPin.minx : ((event->location.x > cursorPin.maxx) ? 6014 cursorPin.maxx : event->location.x); 6015 event->location.y = (event->location.y < cursorPin.miny) ? 6016 cursorPin.miny : ((event->location.y > cursorPin.maxy) ? 6017 cursorPin.maxy : event->location.y); 6018 } 6019 } 6020 6021 if ((typeMask & (NX_LMOUSEDOWNMASK | NX_RMOUSEDOWNMASK | NX_LMOUSEUPMASK | NX_RMOUSEUPMASK)) || 6022 ((event->type == NX_SYSDEFINED) && (event->data.compound.subType == NX_SUBTYPE_AUX_MOUSE_BUTTONS))) 6023 { 6024 cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, 0); 6025 if (cachedMouseEvent) 6026 { 6027 buttonState = cachedMouseEvent->lastButtons; 6028 switch ( event->type ) 6029 { 6030 case NX_LMOUSEDOWN: 6031 buttonState |= EV_LB; 6032 break; 6033 case NX_RMOUSEDOWN: 6034 buttonState |= EV_RB; 6035 break; 6036 case NX_LMOUSEUP: 6037 buttonState &= ~EV_LB; 6038 break; 6039 case NX_RMOUSEUP: 6040 buttonState &= ~EV_RB; 6041 break; 6042 case NX_SYSDEFINED: 6043 CONVERT_HW_TO_WV_BUTTONS(event->data.compound.misc.L[1], buttonState); 6044 } 6045 cachedMouseEvent->lastButtons = buttonState; 6046 6047 evg->buttons = GetCachedMouseButtonStates(cachedButtonStates); 6048 } 6049 } 6050 6051 if( event->setFlags & kIOHIDSetGlobalEventFlags) 6052 { 6053 newFlags = evg->eventFlags = (evg->eventFlags & ~KEYBOARD_FLAGSMASK) 6054 | (event->flags & KEYBOARD_FLAGSMASK); 6055 } 6056 6057 if ( event->setFlags & kIOHIDPostHIDManagerEvent ) 6058 { 6059 if ((typeMask & (MOUSEEVENTMASK | MOVEDEVENTMASK | NX_SCROLLWHEELMOVEDMASK)) && 6060 (_hidPointingDevice || (_hidPointingDevice = IOHIDPointingDevice::newPointingDeviceAndStart(this, 8, 400, true, 2)))) 6061 { 6062 SInt32 dx = 0; 6063 SInt32 dy = 0; 6064 SInt32 wheel = 0; 6065 buttonState = 0; 6066 6067 if (typeMask & MOVEDEVENTMASK) 6068 { 6069 dx = event->data.mouseMove.dx; 6070 dy = event->data.mouseMove.dy; 6071 } 6072 else if ( event->type == NX_SCROLLWHEELMOVED ) 6073 { 6074 wheel = event->data.scrollWheel.deltaAxis1; 6075 } 6076 6077 // Button state should have already been taken care of by above. 6078 if (cachedMouseEvent || 6079 (NULL != (cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, 0)))) 6080 CONVERT_EV_TO_HW_BUTTONS((cachedMouseEvent->lastButtons), buttonState); 6081 6082 _hidPointingDevice->postMouseEvent(buttonState, dx, dy, wheel); 6083 isSeized |= _hidPointingDevice->isSeized(); 6084 } 6085 6086 if ((typeMask & (NX_KEYDOWNMASK | NX_KEYUPMASK | NX_FLAGSCHANGEDMASK)) && 6087 (_hidKeyboardDevice || (_hidKeyboardDevice = IOHIDKeyboardDevice::newKeyboardDeviceAndStart(this, 1)))) 6088 { 6089 _hidKeyboardDevice->postFlagKeyboardEvent(newFlags & KEYBOARD_FLAGSMASK); 6090 6091 if ((event->type != NX_FLAGSCHANGED) && (event->data.key.repeat == 0)) 6092 { 6093 _hidKeyboardDevice->postKeyboardEvent(event->data.key.keyCode, (event->type == NX_KEYDOWN)); 6094 } 6095 6096 isSeized |= _hidKeyboardDevice->isSeized(); 6097 } 6098 } 6099 6100 if ( !isSeized ) 6101 { 6102 postEvent( event->type, 6103 /* at */ &_cursorHelper.desktopLocation(), 6104 /* atTime */ ts, 6105 /* withData */ &event->data, 6106 /* sender */ 0, 6107 /* extPID */ extPID); 6108 } 6109 6110 scheduleNextPeriodicEvent(); 6111 6112 return kIOReturnSuccess; 6113} 6114 6115 6116IOReturn IOHIDSystem::extSetMouseLocation(void*p1,void*p2,void*,void*,void*,void*) 6117{ // IOMethod 6118 if (mac_iokit_check_hid_control(kauth_cred_get())) 6119 return kIOReturnNotPermitted; 6120 if ((sizeof(int32_t)*3) != (intptr_t)p2) { 6121 IOLog("IOHIDSystem::extSetMouseLocation called with inappropriate data size: %d\n", (int)(intptr_t)p2); 6122 return kIOReturnBadArgument; 6123 } 6124 6125 return cmdGate->runAction((IOCommandGate::Action)doExtSetMouseLocation, p1); 6126} 6127 6128IOReturn IOHIDSystem::doExtSetMouseLocation(IOHIDSystem *self, void * arg0) 6129 /* IOCommandGate::Action */ 6130{ 6131 return self->extSetMouseLocationGated(arg0); 6132} 6133 6134IOReturn IOHIDSystem::extSetMouseLocationGated(void *p1) 6135{ 6136 IOFixedPoint32 * loc = (IOFixedPoint32 *)p1; 6137 6138 IOHID_DEBUG(kIOHIDDebugCode_ExtSetLocation, loc ? loc->x : 0, loc ? loc->y : 0, loc, 0); 6139 6140 // setCursorPosition(loc, true); 6141 if ( eventsOpen == true ) 6142 { 6143 _cursorHelper.desktopLocationDelta() += *loc; 6144 _cursorHelper.desktopLocationDelta() -= _cursorHelper.desktopLocation(); 6145 _cursorHelper.desktopLocation() = *loc; 6146 _setCursorPosition(true); 6147 } 6148 6149 return kIOReturnSuccess; 6150} 6151 6152IOReturn IOHIDSystem::extGetStateForSelector(void*p1,void*p2,void*,void*,void*,void*) 6153{ // IOMethod 6154 return cmdGate->runAction((IOCommandGate::Action)doExtGetStateForSelector, p1, p2); 6155} 6156 6157IOReturn IOHIDSystem::extSetStateForSelector(void*p1,void*p2,void*,void*,void*,void*) 6158{ // IOMethod 6159 if (mac_iokit_check_hid_control(kauth_cred_get())) 6160 return kIOReturnNotPermitted; 6161 6162 return cmdGate->runAction((IOCommandGate::Action)doExtSetStateForSelector, p1, p2); 6163} 6164 6165IOReturn IOHIDSystem::doExtGetStateForSelector(IOHIDSystem *self, void *p1, void *p2) 6166/* IOCommandGate::Action */ 6167{ 6168 IOReturn result = kIOReturnSuccess; 6169 unsigned int selector = (uintptr_t)p1; 6170 unsigned int *state_O = (unsigned int*)p2; 6171 switch (selector) { 6172 case kIOHIDCapsLockState: 6173 result = self->getCapsLockState(state_O); 6174 break; 6175 6176 case kIOHIDNumLockState: 6177 result = self->getNumLockState(state_O); 6178 break; 6179 6180 case kIOHIDActivityUserIdle: 6181 *state_O = self->_privateData->hidActivityIdle ? 1 : 0; 6182 break; 6183 6184 case kIOHIDActivityDisplayOn: 6185 *state_O = self->displayState & IOPMDeviceUsable ? 1 : 0; 6186 break; 6187 6188 default: 6189 IOLog("IOHIDSystem::doExtGetStateForSelector recieved unexpected selector: %d\n", selector); 6190 result = kIOReturnBadArgument; 6191 break; 6192 } 6193 return result; 6194} 6195 6196IOReturn IOHIDSystem::doExtSetStateForSelector(IOHIDSystem *self, void *p1, void *p2) 6197/* IOCommandGate::Action */ 6198{ 6199 IOReturn result = kIOReturnSuccess; 6200 unsigned int selector = (uintptr_t)p1; 6201 unsigned int state_I = (uintptr_t)p2; 6202 6203 switch (selector) { 6204 case kIOHIDCapsLockState: 6205 result = self->setCapsLockState(state_I); 6206 break; 6207 6208 case kIOHIDNumLockState: 6209 result = self->setNumLockState(state_I); 6210 break; 6211 6212 case kIOHIDActivityUserIdle: // not settable 6213 case kIOHIDActivityDisplayOn: // not settable 6214 default: 6215 IOLog("IOHIDSystem::doExtGetStateForSelector recieved unexpected selector: %d\n", selector); 6216 result = kIOReturnBadArgument; 6217 break; 6218 6219 } 6220 return result; 6221} 6222 6223IOReturn IOHIDSystem::getCapsLockState(unsigned int *state_O) 6224{ 6225 IOReturn retVal = kIOReturnNoDevice; 6226 *state_O = false; 6227 OSIterator *itr = getProviderIterator(); 6228 if (itr) { 6229 bool done = false; 6230 while (!done) { 6231 OSObject *provider; 6232 while (!done && (NULL != (provider = itr->getNextObject()))) { 6233 IOHIDKeyboard *keyboard = OSDynamicCast(IOHIDKeyboard, provider); 6234 if (keyboard) { 6235 retVal = kIOReturnSuccess; 6236 if (keyboard->alphaLock()) { 6237 *state_O = true; 6238 done = true; 6239 } 6240 } 6241 } 6242 if (itr->isValid()) { 6243 done = true; 6244 } 6245 else { 6246 itr->reset(); 6247 } 6248 } 6249 itr->release(); 6250 } 6251 return retVal; 6252} 6253 6254IOReturn IOHIDSystem::setCapsLockState(unsigned int state_I) 6255{ 6256 IOReturn retVal = kIOReturnNoDevice; 6257 OSIterator *itr = getProviderIterator(); 6258 if (itr) { 6259 bool done = false; 6260 while (!done) { 6261 OSObject *provider; 6262 while (!done && (NULL != (provider = itr->getNextObject()))) { 6263 IOHIDKeyboard *keyboard = OSDynamicCast(IOHIDKeyboard, provider); 6264 if (keyboard) { 6265 if ((state_I && !keyboard->alphaLock()) || (!state_I && keyboard->alphaLock())) { 6266 AbsoluteTime timeStamp; 6267 UInt32 opts = (1<<31) /* kDelayedOption */; 6268 clock_get_uptime(&timeStamp); 6269 6270 keyboard->dispatchKeyboardEvent(timeStamp, kHIDPage_KeyboardOrKeypad, kHIDUsage_KeyboardCapsLock, 1, opts); 6271 keyboard->dispatchKeyboardEvent(timeStamp, kHIDPage_KeyboardOrKeypad, kHIDUsage_KeyboardCapsLock, 0, opts); 6272 } 6273 retVal = kIOReturnSuccess; 6274 } 6275 } 6276 if (itr->isValid()) { 6277 done = true; 6278 } 6279 else { 6280 itr->reset(); 6281 } 6282 } 6283 itr->release(); 6284 } 6285 return retVal; 6286} 6287 6288IOReturn IOHIDSystem::getNumLockState(unsigned int *state_O) 6289{ 6290 IOReturn retVal = kIOReturnNoDevice; 6291 *state_O = false; 6292 OSIterator *itr = getProviderIterator(); 6293 if (itr) { 6294 bool done = false; 6295 while (!done) { 6296 OSObject *provider; 6297 while (!done && (NULL != (provider = itr->getNextObject()))) { 6298 IOHIDKeyboard *keyboard = OSDynamicCast(IOHIDKeyboard, provider); 6299 if (keyboard) { 6300 retVal = kIOReturnSuccess; 6301 if (keyboard->numLock()) { 6302 *state_O = true; 6303 done = true; 6304 } 6305 } 6306 } 6307 if (itr->isValid()) { 6308 done = true; 6309 } 6310 else { 6311 itr->reset(); 6312 } 6313 } 6314 itr->release(); 6315 } 6316 return retVal; 6317} 6318 6319IOReturn IOHIDSystem::setNumLockState(unsigned int state_I) 6320{ 6321 IOReturn retVal = kIOReturnNoDevice; 6322 OSIterator *itr = getProviderIterator(); 6323 if (itr) { 6324 bool done = false; 6325 while (!done) { 6326 OSObject *provider; 6327 while (!done && (NULL != (provider = itr->getNextObject()))) { 6328 IOHIDKeyboard *keyboard = OSDynamicCast(IOHIDKeyboard, provider); 6329 if (keyboard) { 6330 if ((state_I && !keyboard->numLock()) || (!state_I && keyboard->numLock())) { 6331 AbsoluteTime timeStamp; 6332 UInt32 opts = 0; 6333 clock_get_uptime(&timeStamp); 6334 6335 keyboard->dispatchKeyboardEvent(timeStamp, kHIDPage_AppleVendorTopCase, kHIDUsage_AV_TopCase_KeyboardFn, 1, opts); 6336 keyboard->dispatchKeyboardEvent(timeStamp, kHIDPage_AppleVendorTopCase, kHIDUsage_AV_TopCase_KeyboardFn, 0, opts); 6337 } 6338 retVal = kIOReturnSuccess; 6339 } 6340 } 6341 if (itr->isValid()) { 6342 done = true; 6343 } 6344 else { 6345 itr->reset(); 6346 } 6347 } 6348 itr->release(); 6349 } 6350 return retVal; 6351} 6352 6353IOReturn IOHIDSystem::extGetButtonEventNum(void*p1,void*p2,void*,void*,void*,void*) 6354{ // IOMethod 6355 return cmdGate->runAction((IOCommandGate::Action)doExtGetButtonEventNum, p1, p2); 6356} 6357 6358IOReturn IOHIDSystem::doExtGetButtonEventNum(IOHIDSystem *self, void * arg0, void * arg1) 6359 /* IOCommandGate::Action */ 6360{ 6361 return self->extGetButtonEventNumGated(arg0, arg1); 6362} 6363 6364IOReturn IOHIDSystem::extGetButtonEventNumGated(void *p1, void* p2) 6365{ 6366 NXMouseButton button = (NXMouseButton)(uintptr_t)p1; 6367 int * eventNum = (int *)p2; 6368 IOReturn err = kIOReturnSuccess; 6369 6370 switch( button) { 6371 case NX_LeftButton: 6372 *eventNum = leftENum; 6373 break; 6374 case NX_RightButton: 6375 *eventNum = rightENum; 6376 break; 6377 default: 6378 err = kIOReturnBadArgument; 6379 } 6380 6381 return err; 6382} 6383 6384void IOHIDSystem::makeNumberParamProperty( OSDictionary * dict, const char * key, 6385 unsigned long long number, unsigned int bits ) 6386{ 6387 OSNumber * numberRef; 6388 numberRef = OSNumber::withNumber(number, bits); 6389 6390 if( numberRef) { 6391 dict->setObject( key, numberRef); 6392 numberRef->release(); 6393 } 6394} 6395 6396void IOHIDSystem::makeInt32ArrayParamProperty( OSDictionary * dict, const char * key, 6397 UInt32 * intArray, unsigned int count ) 6398{ 6399 OSArray * array; 6400 OSNumber * number; 6401 6402 array = OSArray::withCapacity(count); 6403 6404 if ( !array ) 6405 return; 6406 6407 for (unsigned i=0; i<count; i++) 6408 { 6409 number = OSNumber::withNumber(intArray[i], sizeof(UInt32) << 3); 6410 if (number) 6411 { 6412 array->setObject(number); 6413 number->release(); 6414 } 6415 } 6416 6417 dict->setObject( key, array); 6418 array->release(); 6419} 6420 6421void IOHIDSystem::createParameters( void ) 6422{ 6423 UInt64 nano; 6424 IOFixed fixed; 6425 UInt32 int32; 6426 6427 savedParameters->setObject(kIOHIDDefaultParametersKey, kOSBooleanTrue); 6428 6429 nano = EV_DCLICKTIME; 6430 makeNumberParamProperty( savedParameters, kIOHIDClickTimeKey, 6431 nano, 64 ); 6432 6433 UInt32 tempClickSpace[] = {clickSpaceThresh.x, clickSpaceThresh.y}; 6434 makeInt32ArrayParamProperty( savedParameters, kIOHIDClickSpaceKey, 6435 tempClickSpace, sizeof(tempClickSpace)/sizeof(UInt32) ); 6436 6437 nano = EV_DEFAULTKEYREPEAT; 6438 makeNumberParamProperty( savedParameters, kIOHIDKeyRepeatKey, 6439 nano, 64 ); 6440 nano = EV_DEFAULTINITIALREPEAT; 6441 makeNumberParamProperty( savedParameters, kIOHIDInitialKeyRepeatKey, 6442 nano, 64 ); 6443 6444 fixed = EV_DEFAULTPOINTERACCELLEVEL; 6445 makeNumberParamProperty( savedParameters, kIOHIDPointerAccelerationKey, 6446 fixed, sizeof(fixed) << 3); 6447 6448 fixed = EV_DEFAULTSCROLLACCELLEVEL; 6449 makeNumberParamProperty( savedParameters, kIOHIDScrollAccelerationKey, 6450 fixed, sizeof(fixed) << 3); 6451 6452 fixed = kIOHIDButtonMode_EnableRightClick; 6453 makeNumberParamProperty( savedParameters, kIOHIDPointerButtonMode, 6454 fixed, sizeof(fixed) << 3); 6455 6456 // set eject delay properties 6457 int32 = kEjectF12DelayMS; 6458 makeNumberParamProperty( savedParameters, kIOHIDF12EjectDelayKey, 6459 int32, 32 ); 6460 int32 = kEjectKeyDelayMS; 6461 makeNumberParamProperty( savedParameters, kIOHIDKeyboardEjectDelay, 6462 int32, 32 ); 6463 6464 // set slow keys delay property 6465 int32 = 0; 6466 makeNumberParamProperty( savedParameters, kIOHIDSlowKeysDelayKey, 6467 int32, 32 ); 6468 6469 // set disabled property 6470 int32 = 0; // not disabled 6471 makeNumberParamProperty( savedParameters, kIOHIDStickyKeysDisabledKey, 6472 int32, 32 ); 6473 6474 // set on/off property 6475 int32 = 0; // off 6476 makeNumberParamProperty( savedParameters, kIOHIDStickyKeysOnKey, 6477 int32, 32 ); 6478 6479 // set shift toggles property 6480 int32 = 0; // off, shift does not toggle 6481 makeNumberParamProperty( savedParameters, kIOHIDStickyKeysShiftTogglesKey, 6482 int32, 32 ); 6483 6484 // set option toggles property 6485 int32 = 0; // off, option does not toggle 6486 makeNumberParamProperty( savedParameters, kIOHIDMouseKeysOptionTogglesKey, 6487 int32, 32 ); 6488 6489 int32 = 0; 6490 makeNumberParamProperty( savedParameters, kIOHIDFKeyModeKey, 6491 int32, 32 ); 6492 6493 setProperty( kIOHIDParametersKey, savedParameters ); 6494 savedParameters->release(); 6495 6496 // RY: Set up idleTimeSerializer. This should generate the 6497 // current idle time when requested. 6498 OSSerializer * idleTimeSerializer = OSSerializer::forTarget(this, IOHIDSystem::_idleTimeSerializerCallback); 6499 6500 if (idleTimeSerializer) 6501 { 6502 setProperty( kIOHIDIdleTimeKey, idleTimeSerializer); 6503 idleTimeSerializer->release(); 6504 } 6505 6506#if 0 6507 OSSerializer * displaySerializer = OSSerializer::forTarget(this, IOHIDSystem::_displaySerializerCallback); 6508 6509 if (displaySerializer) 6510 { 6511 setProperty("DisplayState", displaySerializer); 6512 displaySerializer->release(); 6513 } 6514#endif 6515} 6516 6517bool IOHIDSystem::_idleTimeSerializerCallback(void * target, void * ref __unused, OSSerialize *s) 6518{ 6519 IOHIDSystem * self = (IOHIDSystem *) target; 6520 AbsoluteTime currentTime; 6521 OSNumber * number; 6522 UInt64 idleTimeNano = 0; 6523 bool retValue = false; 6524 6525 if( self->eventsOpen ) 6526 { 6527 clock_get_uptime( ¤tTime); 6528 SUB_ABSOLUTETIME( ¤tTime, &(self->lastUndimEvent)); 6529 absolutetime_to_nanoseconds( currentTime, &idleTimeNano); 6530 } 6531 6532 number = OSNumber::withNumber(idleTimeNano, 64); 6533 if (number) 6534 { 6535 retValue = number->serialize( s ); 6536 number->release(); 6537 } 6538 6539 return retValue; 6540} 6541 6542bool IOHIDSystem::_displaySerializerCallback(void * target, void * ref __unused, OSSerialize *s) 6543{ 6544 IOHIDSystem *self = (IOHIDSystem *) target; 6545 bool retValue = false; 6546 OSDictionary *mainDict = OSDictionary::withCapacity(4); 6547 require(mainDict, exit_early); 6548 6549#define IfNotNullAddNumToDictWithKey(x,y, w,z) \ 6550 if (x) { \ 6551 OSNumber *num = NULL; \ 6552 num = OSNumber::withNumber(y, 8*sizeof(y)); \ 6553 if (num) { \ 6554 w->setObject(z, num); \ 6555 num->release(); \ 6556 } \ 6557 } 6558 6559 for(int i = 0; i < self->screens; i++) { 6560 EvScreen &esp = ((EvScreen*)(self->evScreen))[i]; 6561 OSDictionary *thisDisplay = OSDictionary::withCapacity(4); 6562 char key[256]; 6563 6564 require(thisDisplay, next_display); 6565 snprintf(key, sizeof(key), "%d", i); 6566 mainDict->setObject(key, thisDisplay); 6567 6568 IfNotNullAddNumToDictWithKey(esp.instance, esp.instance->getRegistryEntryID(), thisDisplay, "io_fb_id"); 6569 IfNotNullAddNumToDictWithKey(esp.displayBounds, esp.displayBounds->minx, thisDisplay, "disp_min_x"); 6570 IfNotNullAddNumToDictWithKey(esp.displayBounds, esp.displayBounds->maxx, thisDisplay, "disp_max_x"); 6571 IfNotNullAddNumToDictWithKey(esp.displayBounds, esp.displayBounds->miny, thisDisplay, "disp_min_y"); 6572 IfNotNullAddNumToDictWithKey(esp.displayBounds, esp.displayBounds->maxy, thisDisplay, "disp_max_y"); 6573 IfNotNullAddNumToDictWithKey(esp.desktopBounds, esp.desktopBounds->minx, thisDisplay, "desk_min_x"); 6574 IfNotNullAddNumToDictWithKey(esp.desktopBounds, esp.desktopBounds->maxx, thisDisplay, "desk_max_x"); 6575 IfNotNullAddNumToDictWithKey(esp.desktopBounds, esp.desktopBounds->miny, thisDisplay, "desk_min_y"); 6576 IfNotNullAddNumToDictWithKey(esp.desktopBounds, esp.desktopBounds->maxy, thisDisplay, "desk_max_y"); 6577 IfNotNullAddNumToDictWithKey(esp.creator_pid, esp.creator_pid, thisDisplay, "creator_pid"); 6578 6579 next_display: 6580 OSSafeReleaseNULL(thisDisplay); 6581 } 6582 6583 { // safety scoping 6584 OSDictionary *workSpaceDict = OSDictionary::withCapacity(4); 6585 IfNotNullAddNumToDictWithKey(workSpaceDict, self->workSpace.minx, workSpaceDict, "minx"); 6586 IfNotNullAddNumToDictWithKey(workSpaceDict, self->workSpace.miny, workSpaceDict, "miny"); 6587 IfNotNullAddNumToDictWithKey(workSpaceDict, self->workSpace.maxx, workSpaceDict, "maxx"); 6588 IfNotNullAddNumToDictWithKey(workSpaceDict, self->workSpace.maxy, workSpaceDict, "maxy"); 6589 mainDict->setObject("workspace", workSpaceDict ? (OSObject*)workSpaceDict : (OSObject*)kOSBooleanFalse); 6590 OSSafeReleaseNULL(workSpaceDict); 6591 } 6592 6593 { // safety scoping 6594 OSDictionary *cursorPinDict = OSDictionary::withCapacity(4); 6595 IfNotNullAddNumToDictWithKey(cursorPinDict, self->cursorPin.minx, cursorPinDict, "minx"); 6596 IfNotNullAddNumToDictWithKey(cursorPinDict, self->cursorPin.miny, cursorPinDict, "miny"); 6597 IfNotNullAddNumToDictWithKey(cursorPinDict, self->cursorPin.maxx, cursorPinDict, "maxx"); 6598 IfNotNullAddNumToDictWithKey(cursorPinDict, self->cursorPin.maxy, cursorPinDict, "maxy"); 6599 mainDict->setObject("cursorPin", cursorPinDict ? (OSObject*)cursorPinDict : (OSObject*)kOSBooleanFalse); 6600 OSSafeReleaseNULL(cursorPinDict); 6601 } 6602 6603 retValue = mainDict->serialize( s ); 6604 6605exit_early: 6606 OSSafeReleaseNULL(mainDict); 6607 return retValue; 6608} 6609 6610IOReturn IOHIDSystem::setProperties( OSObject * properties ) 6611{ 6612 OSDictionary * dict; 6613 IOReturn err = kIOReturnSuccess; 6614 IOReturn ret; 6615 6616 dict = OSDynamicCast( OSDictionary, properties ); 6617 if( dict) { 6618 if (dict->getObject(kIOHIDUseKeyswitchKey) && 6619 ( IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator) != kIOReturnSuccess)) { 6620 dict->removeObject(kIOHIDUseKeyswitchKey); 6621 } 6622 ret = setParamProperties( dict ); 6623 } 6624 else 6625 err = kIOReturnBadArgument; 6626 6627 return( err ); 6628} 6629 6630IOReturn IOHIDSystem::setParamProperties( OSDictionary * dict ) 6631{ 6632 OSIterator * iter = NULL; 6633 IOReturn ret = kIOReturnSuccess; 6634 IOReturn err = kIOReturnSuccess; 6635 6636 // Tip off devices that these are default parameters 6637 dict->setObject(kIOHIDDefaultParametersKey, kOSBooleanTrue); 6638 6639 ret = cmdGate->runAction((IOCommandGate::Action)doSetParamPropertiesPre, dict, &iter); 6640 6641 if ( ret == kIOReturnSuccess ) { 6642 6643 // Do the following down calls outside of the gate 6644 if( iter) { 6645 IOService * eventSrc; 6646 OSDictionary * validParameters; 6647 while( (eventSrc = (IOService *) iter->getNextObject())) { 6648 6649 if ( OSDynamicCast(IOHIDKeyboard, eventSrc) || OSDynamicCast(IOHIDPointing, eventSrc) || OSDynamicCast(IOHIDConsumer, eventSrc)) 6650 continue; 6651 6652 // Use valid parameters per device. Basically if the IOHIDevice has a given property 6653 // in its registery we should NOT push it down via setParamProperties as properties 6654 // generated via the global IOHIDSystem::setParamProperties are defaults. 6655 validParameters = createFilteredParamPropertiesForService(eventSrc, dict); 6656 if ( validParameters ) { 6657 6658 if ( OSDynamicCast(IOHIDevice, eventSrc) ) 6659 ret = ((IOHIDevice *)eventSrc)->setParamProperties( validParameters ); 6660 else if ( OSDynamicCast( IOHIDEventService, eventSrc ) ) 6661 ret = ((IOHIDEventService *)eventSrc)->setSystemProperties( validParameters ); 6662 6663 if( (ret != kIOReturnSuccess) && (ret != kIOReturnBadArgument)) 6664 err = ret; 6665 6666 dict->merge(validParameters); 6667 6668 validParameters->release(); 6669 } 6670 } 6671 iter->release(); 6672 } 6673 6674 // Grab the gate again. 6675 cmdGate->runAction((IOCommandGate::Action)doSetParamPropertiesPost, dict); 6676 } 6677 6678 return err; 6679} 6680 6681OSDictionary * IOHIDSystem::createFilteredParamPropertiesForService(IOService * service, OSDictionary * dict) 6682{ 6683 OSDictionary * validParameters = OSDictionary::withCapacity(4); 6684 6685 if ( !validParameters ) 6686 return NULL; 6687 6688 OSDictionary * deviceParameters = NULL; 6689 6690 if ( OSDynamicCast(IOHIDevice, service) ) { 6691 deviceParameters = (OSDictionary*)service->copyProperty(kIOHIDParametersKey); 6692 } 6693 else if ( OSDynamicCast( IOHIDEventService, service ) ) { 6694 deviceParameters = (OSDictionary*)service->copyProperty(kIOHIDEventServicePropertiesKey); 6695 } 6696 if (!OSDynamicCast(OSDictionary, deviceParameters)) 6697 OSSafeReleaseNULL(deviceParameters); 6698 6699 OSCollectionIterator * iterator = OSCollectionIterator::withCollection(dict); 6700 if ( iterator ) { 6701 bool done = false; 6702 while (!done) { 6703 OSSymbol * key = NULL; 6704 while ((key = (OSSymbol*)iterator->getNextObject()) != NULL) { 6705 if ( !deviceParameters || !deviceParameters->getObject(key) ) { 6706 validParameters->setObject(key, dict->getObject(key)); 6707 } 6708 } 6709 if (iterator->isValid()) { 6710 done = true; 6711 } 6712 else { 6713 iterator->reset(); 6714 validParameters->flushCollection(); 6715 } 6716 } 6717 iterator->release(); 6718 } 6719 6720 if ( validParameters->getCount() == 0 ) { 6721 validParameters->release(); 6722 validParameters = NULL; 6723 } 6724 else { 6725 validParameters->setObject(kIOHIDDefaultParametersKey, kOSBooleanTrue); 6726 } 6727 6728 return validParameters; 6729} 6730 6731 6732IOReturn IOHIDSystem::doSetParamPropertiesPre(IOHIDSystem *self, void * arg0, void * arg1) 6733 /* IOCommandGate::Action */ 6734{ 6735 return self->setParamPropertiesPreGated((OSDictionary *)arg0, (OSIterator**)arg1); 6736} 6737 6738IOReturn IOHIDSystem::setParamPropertiesPreGated( OSDictionary * dict, OSIterator ** pOpenIter) 6739{ 6740 OSArray * array; 6741 OSNumber * number; 6742 6743 // check for null 6744 if (dict == NULL) 6745 return kIOReturnError; 6746 6747 // adding a pending flag here because we will be momentarily openning the gate 6748 // to make down calls into the client, before closing back up again to merge 6749 // the properties. 6750 while ( setParamPropertiesInProgress ) 6751 cmdGate->commandSleep(&setParamPropertiesInProgress); 6752 6753 setParamPropertiesInProgress = true; 6754 6755 if( (number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDUseKeyswitchKey)))) 6756 { 6757 gUseKeyswitch = number->unsigned32BitValue(); 6758 } 6759 6760 if( (number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDClickTimeKey)))) 6761 { 6762 UInt64 nano = number->unsigned64BitValue(); 6763 nanoseconds_to_absolutetime(nano, &clickTimeThresh); 6764 } 6765 6766 // check the reset before setting the other parameters 6767 if (dict->getObject(kIOHIDScrollCountResetKey)) { 6768 _setScrollCountParameters(); 6769 } 6770 6771 _setScrollCountParameters(dict); 6772 6773 if( (array = OSDynamicCast( OSArray, 6774 dict->getObject(kIOHIDClickSpaceKey)))) { 6775 6776 if ((number = OSDynamicCast( OSNumber, 6777 array->getObject(EVSIOSCS_X)))) 6778 { 6779 clickSpaceThresh.x = number->unsigned32BitValue(); 6780 } 6781 if ((number = OSDynamicCast( OSNumber, 6782 array->getObject(EVSIOSCS_Y)))) 6783 { 6784 clickSpaceThresh.y = number->unsigned32BitValue(); 6785 } 6786 } 6787 6788 if( (number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDWaitCursorFrameIntervalKey)))) { 6789 uint32_t value = number->unsigned32BitValue(); 6790 _cursorWaitDelta = value; 6791 if (_cursorWaitDelta < kTickScale) { 6792 _cursorWaitDelta = kTickScale; 6793 } 6794 scheduleNextPeriodicEvent(); 6795 } 6796 6797 if( (number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDStickyKeysOnKey)))) { 6798 if (number->unsigned32BitValue()) 6799 stickyKeysState |= (1 << 0); 6800 else 6801 stickyKeysState &= ~(1 << 0); 6802 6803 } 6804 6805 if( (number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDStickyKeysShiftTogglesKey)))) { 6806 if (number->unsigned32BitValue()) 6807 stickyKeysState |= (1 << 1); 6808 else 6809 stickyKeysState &= ~(1 << 1); 6810 6811 } 6812 6813 // save all params for new devices 6814 if ( dict->getObject(kIOHIDResetKeyboardKey) ) { 6815 UInt64 nano = EV_DEFAULTKEYREPEAT; 6816 makeNumberParamProperty( dict, kIOHIDKeyRepeatKey, nano, 64 ); 6817 6818 nano = EV_DEFAULTINITIALREPEAT; 6819 makeNumberParamProperty( dict, kIOHIDInitialKeyRepeatKey, nano, 64 ); 6820 } 6821 6822 if ( dict->getObject(kIOHIDResetPointerKey) ) { 6823 IOFixed fixed = EV_DEFAULTPOINTERACCELLEVEL; 6824 makeNumberParamProperty( dict, kIOHIDPointerAccelerationKey, fixed, sizeof(fixed) << 3); 6825 6826 fixed = kIOHIDButtonMode_EnableRightClick; 6827 makeNumberParamProperty( dict, kIOHIDPointerButtonMode, fixed, sizeof(fixed) << 3); 6828 6829 UInt64 nano = EV_DCLICKTIME; 6830 makeNumberParamProperty( dict, kIOHIDClickTimeKey, nano, 64 ); 6831 } 6832 6833 if ( dict->getObject(kIOHIDScrollResetKey) ) { 6834 IOFixed fixed = EV_DEFAULTSCROLLACCELLEVEL; 6835 makeNumberParamProperty( dict, kIOHIDScrollAccelerationKey, fixed, sizeof(fixed) << 3); 6836 } 6837 6838 // update connected input devices 6839 if ( pOpenIter ) 6840 *pOpenIter = getOpenProviderIterator(); 6841 6842 return kIOReturnSuccess; 6843} 6844 6845void IOHIDSystem::_setScrollCountParameters(OSDictionary *newSettings) 6846{ 6847 if (!newSettings) { 6848 newSettings = (OSDictionary*)copyProperty(kIOHIDScrollCountBootDefaultKey); 6849 if (!OSDynamicCast(OSDictionary, newSettings)) { 6850 newSettings->release(); 6851 newSettings = NULL; 6852 } 6853 } 6854 else { 6855 newSettings->retain(); 6856 } 6857 6858 if (newSettings) { 6859 OSNumber *number = NULL; 6860 OSBoolean *boolean = NULL; 6861 if((number = OSDynamicCast(OSNumber, newSettings->getObject(kIOHIDScrollCountMinDeltaToStartKey)))) 6862 { 6863 _scMinDeltaSqToStart = number->unsigned64BitValue(); 6864 _scMinDeltaSqToStart *= _scMinDeltaSqToStart; 6865 if (_scMinDeltaSqToSustain == kDefaultMinimumDelta) 6866 _scMinDeltaSqToSustain = _scMinDeltaSqToStart; 6867 setProperty(kIOHIDScrollCountMinDeltaToStartKey, number); 6868 } 6869 6870 if((number = OSDynamicCast(OSNumber, newSettings->getObject(kIOHIDScrollCountMinDeltaToSustainKey)))) 6871 { 6872 _scMinDeltaSqToSustain = number->unsigned64BitValue(); 6873 _scMinDeltaSqToSustain *= _scMinDeltaSqToSustain; 6874 if (_scMinDeltaSqToStart == kDefaultMinimumDelta) 6875 _scMinDeltaSqToStart = _scMinDeltaSqToSustain; 6876 setProperty(kIOHIDScrollCountMinDeltaToSustainKey, number); 6877 } 6878 6879 if((number = OSDynamicCast(OSNumber, newSettings->getObject(kIOHIDScrollCountMaxTimeDeltaBetweenKey)))) 6880 { 6881 UInt64 valueInMs = number->unsigned64BitValue(); 6882 nanoseconds_to_absolutetime(valueInMs * kMillisecondScale, &_scMaxTimeDeltaBetween); 6883 if (!_scMaxTimeDeltaToSustain) 6884 _scMaxTimeDeltaToSustain = _scMaxTimeDeltaBetween; 6885 setProperty(kIOHIDScrollCountMaxTimeDeltaBetweenKey, number); 6886 } 6887 6888 if((number = OSDynamicCast(OSNumber, newSettings->getObject(kIOHIDScrollCountMaxTimeDeltaToSustainKey)))) 6889 { 6890 UInt64 valueInMs = number->unsigned64BitValue(); 6891 nanoseconds_to_absolutetime(valueInMs * kMillisecondScale, &_scMaxTimeDeltaToSustain); 6892 if (!_scMaxTimeDeltaBetween) 6893 _scMaxTimeDeltaBetween = _scMaxTimeDeltaToSustain; 6894 setProperty(kIOHIDScrollCountMaxTimeDeltaToSustainKey, number); 6895 } 6896 6897 if((boolean = OSDynamicCast(OSBoolean, newSettings->getObject(kIOHIDScrollCountIgnoreMomentumScrollsKey)))) 6898 { 6899 _scIgnoreMomentum = (boolean == kOSBooleanTrue); 6900 setProperty(kIOHIDScrollCountIgnoreMomentumScrollsKey, boolean); 6901 } 6902 6903 if((boolean = OSDynamicCast(OSBoolean, newSettings->getObject(kIOHIDScrollCountMouseCanResetKey)))) 6904 { 6905 _scMouseCanReset = (boolean == kOSBooleanTrue); 6906 setProperty(kIOHIDScrollCountMouseCanResetKey, boolean); 6907 } 6908 6909 if((number = OSDynamicCast(OSNumber, newSettings->getObject(kIOHIDScrollCountMaxKey)))) 6910 { 6911 _scCountMax = number->unsigned16BitValue(); 6912 setProperty(kIOHIDScrollCountMaxKey, number); 6913 } 6914 6915 if((number = OSDynamicCast(OSNumber, newSettings->getObject(kIOHIDScrollCountAccelerationFactorKey)))) 6916 { 6917 if (number->unsigned32BitValue() > 0) { 6918 _scAccelerationFactor.fromFixed(number->unsigned32BitValue()); 6919 setProperty(kIOHIDScrollCountAccelerationFactorKey, number); 6920 } 6921 } 6922 6923 if((boolean = OSDynamicCast(OSBoolean, newSettings->getObject(kIOHIDScrollCountZeroKey)))) 6924 { 6925 if (boolean == kOSBooleanTrue) { 6926 log_scroll_state("Resetting _scCount on kIOHIDScrollCountZeroKey%s\n", ""); 6927 _scCount = 0; 6928 } 6929 } 6930 6931 newSettings->release(); 6932 } 6933} 6934 6935IOReturn IOHIDSystem::doSetParamPropertiesPost(IOHIDSystem *self, void * arg0) 6936 /* IOCommandGate::Action */ 6937{ 6938 return self->setParamPropertiesPostGated((OSDictionary *)arg0); 6939} 6940 6941IOReturn IOHIDSystem::setParamPropertiesPostGated( OSDictionary * dict) 6942{ 6943 if ( dict->getObject(kIOHIDTemporaryParametersKey) == NULL ) { 6944 bool resetKeyboard = dict->getObject(kIOHIDResetKeyboardKey) != NULL; 6945 bool resetPointer = dict->getObject(kIOHIDResetPointerKey) != NULL; 6946 bool resetScroll = dict->getObject(kIOHIDScrollResetKey) != NULL; 6947 6948 OSDictionary * newParams = OSDictionary::withDictionary( savedParameters ); 6949 if( newParams) { 6950 if ( resetKeyboard ) { 6951 dict->removeObject(kIOHIDResetKeyboardKey); 6952 } 6953 if ( resetPointer ) { 6954 dict->removeObject(kIOHIDResetPointerKey); 6955 newParams->removeObject(kIOHIDTrackpadAccelerationType); 6956 newParams->removeObject(kIOHIDMouseAccelerationType); 6957 } 6958 if ( resetScroll ) { 6959 dict->removeObject(kIOHIDScrollResetKey); 6960 newParams->removeObject(kIOHIDTrackpadScrollAccelerationKey); 6961 newParams->removeObject(kIOHIDMouseScrollAccelerationKey); 6962 } 6963 6964 newParams->merge( dict ); 6965 setProperty( kIOHIDParametersKey, newParams ); 6966 newParams->release(); 6967 savedParameters = newParams; 6968 } 6969 6970 // Send anevent notification that the properties changed. 6971 struct evioLLEvent event; 6972 AbsoluteTime ts; 6973 // clear event record 6974 bzero( (void *)&event, sizeof event); 6975 6976 event.data.compound.subType = NX_SUBTYPE_HIDPARAMETER_MODIFIED; 6977 clock_get_uptime(&ts); 6978 postEvent(NX_SYSDEFINED, &_cursorHelper.desktopLocation(), ts, &(event.data)); 6979 6980 } 6981 6982 // Wake any pending setParamProperties commands. They 6983 // still won't do much until we return out. 6984 setParamPropertiesInProgress = false; 6985 cmdGate->commandWakeup(&setParamPropertiesInProgress); 6986 6987 return kIOReturnSuccess; 6988} 6989 6990UInt8 IOHIDSystem::getSubtypeForSender(OSObject * sender) 6991{ 6992 UInt8 subtype = NX_SUBTYPE_DEFAULT; 6993 if (touchEventPosters->containsObject(sender)) { 6994 subtype = NX_SUBTYPE_MOUSE_TOUCH; 6995 } 6996 return subtype; 6997} 6998 6999void IOHIDSystem::updateMouseMoveEventForSender(OSObject * sender, NXEventData * evData) 7000{ 7001 if (sender && evData) { 7002 evData->mouse.subType = getSubtypeForSender(sender); 7003 } 7004} 7005 7006void IOHIDSystem::updateMouseEventForSender(OSObject * sender, NXEventData * evData) 7007{ 7008 if (sender && evData) { 7009 evData->mouseMove.subType = getSubtypeForSender(sender); 7010 } 7011} 7012 7013void IOHIDSystem::updateScrollEventForSender(OSObject * sender, NXEventData * evData) 7014{ 7015 if (sender && evData) { 7016 if (NX_SUBTYPE_MOUSE_TOUCH == getSubtypeForSender(sender)) { 7017 evData->scrollWheel.reserved1 |= kScrollTypeTouch; 7018 } 7019 } 7020} 7021 7022bool IOHIDSystem::attach( IOService * provider ) 7023{ 7024 IORegistryEntry *entry = provider; 7025 7026 if (!super::attach(provider)) return false; 7027 while(entry) { 7028 if (kOSBooleanTrue == entry->getProperty("MTEventSource")) { 7029 touchEventPosters->setObject(provider); 7030 entry = 0; 7031 } 7032 else { 7033 entry = entry->getParentEntry(gIOServicePlane); 7034 } 7035 } 7036 7037 return true; 7038} 7039 7040void IOHIDSystem::detach( IOService * provider ) 7041{ 7042 touchEventPosters->removeObject(provider); 7043 super::detach(provider); 7044} 7045