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