#define DEBUG_ASSERT_COMPONENT_NAME_STRING "IOHIDSystem"
#include <AssertMacros.h>
#include "IOHIDKeys.h"
#include "IOHIDEvent.h"
#include <IOKit/system.h>
#include <IOKit/assert.h>
#include <libkern/c++/OSContainers.h>
#include <libkern/c++/OSCollectionIterator.h>
#include <kern/queue.h>
#include <IOKit/IOTimerEventSource.h>
#include <IOKit/IOCommandGate.h>
#include <IOKit/IOMessage.h>
#include <IOKit/IOWorkLoop.h>
#include <IOKit/IOPlatformExpert.h>
#include <IOKit/hidsystem/IOHIDevice.h>
#include <IOKit/hidsystem/IOHIDParameter.h>
#include <IOKit/usb/USB.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#include <kern/clock.h>
#include "IOHIDShared.h"
#include "IOHIDSystem.h"
#include "IOHIDEventService.h"
#include "IOHIDPointing.h"
#include "IOHIDKeyboard.h"
#include "IOHIDConsumer.h"
#include "IOHITablet.h"
#include "IOHIDPointingDevice.h"
#include "IOHIDKeyboardDevice.h"
#include "IOHIDPrivate.h"
#include "IOHIDPrivateKeys.h"
#include "IOHIDEventServiceQueue.h"
#include "IOLLEvent.h"
#include "ev_private.h"
#include "IOHIDUserClient.h"
#include "AppleHIDUsageTables.h"
#include "IOHIDKeyboard.h"
#include "IOHIDFamilyTrace.h"
#include "IOHIDWorkLoop.h"
#include "IOHIDSystemCursorHelper.h"
#include <sys/kdebug.h>
#include <sys/proc.h>
#ifdef __cplusplus
extern "C"
{
#include <UserNotification/KUNCUserNotifications.h>
void cons_cinput( char c);
}
#endif
extern "C" {
#include <sys/kauth.h>
#define CONFIG_MACF 1
#include <security/mac_framework.h>
#undef CONFIG_MACF
};
bool displayWranglerUp( OSObject *, void *, IOService * );
#if 0
#define PROFILE_TRACE(X) IOHID_DEBUG(kIOHIDDebugCode_Profiling, X, __LINE__, 0, 0)
#else
#define PROFILE_TRACE(X)
#endif
static IOHIDSystem * evInstance = 0;
MasterAudioFunctions *masterAudioFunctions = 0;
#define xpr_ev_cursor(x, a, b, c, d, e)
#ifndef kIOFBWaitCursorFramesKey
#define kIOFBWaitCursorFramesKey "IOFBWaitCursorFrames"
#endif
#ifndef kIOFBWaitCursorPeriodKey
#define kIOFBWaitCursorPeriodKey "IOFBWaitCursorPeriod"
#endif
#ifndef kIOUserClientCrossEndianKey
#define kIOUserClientCrossEndianKey "IOUserClientCrossEndian"
#endif
#ifndef kIOUserClientCrossEndianCompatibleKey
#define kIOUserClientCrossEndianCompatibleKey "IOUserClientCrossEndianCompatible"
#endif
#ifndef abs
#define abs(_a) ((_a >= 0) ? _a : -_a)
#endif
#define NORMAL_MODIFIER_MASK (NX_COMMANDMASK | NX_CONTROLMASK | NX_SHIFTMASK | NX_ALTERNATEMASK)
#define EV_MAX_SCREENS 32
#define IDLE_HID_ACTIVITY_NSECS ((uint64_t)(5*60*NSEC_PER_SEC))
static inline unsigned AbsoluteTimeToTick( AbsoluteTime * ts )
{
UInt64 nano;
absolutetime_to_nanoseconds(*ts, &nano);
return( nano >> 24 );
}
static inline void TickToAbsoluteTime( unsigned tick, AbsoluteTime * ts )
{
UInt64 nano = ((UInt64) tick) << 24;
nanoseconds_to_absolutetime(nano, ts);
}
static UInt8 ScalePressure(unsigned pressure)
{
return ((pressure * (unsigned long long)EV_MAXPRESSURE) / (unsigned)(65535LL));
}
#define EV_NS_TO_TICK(ns) AbsoluteTimeToTick(ns)
#define EV_TICK_TO_NS(tick,ns) TickToAbsoluteTime(tick,ns)
typedef struct _IOHIDCmdGateActionArgs {
void* arg0;
void* arg1;
void* arg2;
void* arg3;
void* arg4;
void* arg5;
void* arg6;
void* arg7;
void* arg8;
void* arg9;
void* arg10;
void* arg11;
} IOHIDCmdGateActionArgs;
static bool gKeySwitchLocked = false;
static bool gUseKeyswitch = true;
static IONotifier * gSwitchNotification = 0;
static bool keySwitchNotificationHandler(void *target __unused, void *refCon __unused, IOService *service, IONotifier * )
{
gKeySwitchLocked = (service->getProperty("Keyswitch") == kOSBooleanTrue);
return true;
}
#define kHIDConsumeCauseNone 0x00
#define kHIDConsumeCauseKeyLock 0x01
#define kHIDConsumeCauseDeadline 0x02
static inline UInt32 ShouldConsumeHIDEvent(AbsoluteTime ts, AbsoluteTime deadline, bool checkKeySwitch = true )
{
if (checkKeySwitch && gKeySwitchLocked && gUseKeyswitch)
return kHIDConsumeCauseKeyLock;
if ( AbsoluteTime_to_scalar(&ts) == 0 )
clock_get_uptime(&ts);
if (CMP_ABSOLUTETIME(&ts, &deadline) <= 0)
{
return kHIDConsumeCauseDeadline;
}
return kHIDConsumeCauseNone;
}
#define WAKE_DISPLAY_ON_MOVEMENT (NX_WAKEMASK & MOVEDEVENTMASK)
#define DISPLAY_IS_ENABLED (displayState & IOPMDeviceUsable)
#define TICKLE_DISPLAY(event) \
{ \
if (!evStateChanging && displayManager) { \
IOHID_DEBUG(kIOHIDDebugCode_DisplayTickle, event, __LINE__, 0, 0); \
if (!DISPLAY_IS_ENABLED) kprintf("IOHIDSystem tickle when screen off for event %d at line %d\n", (int)event, __LINE__); \
displayManager->activityTickle(IOHID_DEBUG_CODE(event)); \
} \
updateHidActivity(); \
}
#define CONVERT_EV_TO_HW_BUTTONS(ev_buttons,hw_buttons) \
hw_buttons = ev_buttons & ~7; \
hw_buttons |= (ev_buttons & 3) << 1; \
hw_buttons |= (ev_buttons & 4) >> 2;
#define CONVERT_EV_TO_HW_DELTA(ev_buttons,hw_delta) \
hw_delta = ev_buttons & ~7; \
hw_delta |= (ev_buttons & 3) << 1; \
hw_delta |= (ev_buttons & 4) >> 2;
#define CONVERT_HW_TO_WV_BUTTONS(hw_buttons,ev_buttons) \
ev_buttons = hw_buttons & ~7; \
ev_buttons |= (hw_buttons & 6) >> 1; \
ev_buttons |= (hw_buttons & 1) << 2;
enum {
kIOHIDSetGlobalEventFlags = 0x00000001,
kIOHIDSetCursorPosition = 0x00000002,
kIOHIDSetRelativeCursorPosition = 0x00000004,
kIOHIDPostHIDManagerEvent = 0x00000008
};
#define kIOHIDPowerOnThresholdNS (500ULL * kMillisecondScale) // 1/2 second
#define kIOHIDRelativeTickleThresholdNS (50ULL * kMillisecondScale) // 1/20 second
#define kIOHIDRelativeTickleThresholdPixel 3
#define kIOHIDDispaySleepAbortThresholdNS (5ULL * kSecondScale) // 5 seconds
#define kIOHIDChattyMouseSuppressionDelayNS kSecondScale // 1 second
static AbsoluteTime gIOHIDPowerOnThresoldAbsoluteTime;
static AbsoluteTime gIOHIDRelativeTickleThresholdAbsoluteTime;
static AbsoluteTime gIOHIDDisplaySleepAbortThresholdAbsoluteTime;
static AbsoluteTime gIOHIDZeroAbsoluteTime;
typedef struct _stackShotMgs {
mach_msg_header_t header;
UInt32 flavor;
} _stackShotMessage;
enum {
kCachedMousePointingTabletEventDispFlag = 0x01,
kCachedMousePointingTabletEventPendFlag = 0x02,
kCachedMousePointingEventDispFlag = 0x04,
kCachedMouseTabletEventDispFlag = 0x08
};
typedef struct _CachedMouseEventStruct {
OSObject * service;
UInt64 eventDeadline;
UInt64 reportInterval_ns;
SInt32 lastButtons;
SInt32 accumX;
SInt32 accumY;
bool proximity;
UInt32 state;
UInt8 subType;
NXEventData tabletData;
NXEventData proximityData;
UInt16 pointerFractionX;
UInt16 pointerFractionY;
UInt8 lastPressure;
} CachedMouseEventStruct;
static void CalculateEventCountsForService(CachedMouseEventStruct *mouseStruct)
{
if ( mouseStruct ) {
mouseStruct->reportInterval_ns = 8000000; if ( mouseStruct->service ) {
IORegistryEntry *senderEntry = OSDynamicCast(IORegistryEntry, mouseStruct->service);
if (senderEntry) {
OSNumber *reportInterval_us = (OSNumber*)senderEntry->copyProperty(kIOHIDReportIntervalKey, gIOServicePlane, kIORegistryIterateRecursively| kIORegistryIterateParents);
if (OSDynamicCast(OSNumber, reportInterval_us)) {
mouseStruct->reportInterval_ns = reportInterval_us->unsigned64BitValue() * 1000;
}
else {
IOLog("No interval found for %s. Using %lld\n", senderEntry->getLocation(), mouseStruct->reportInterval_ns);
}
OSSafeReleaseNULL(reportInterval_us);
}
}
}
}
static void CalculateEventCountsForAllServices(OSArray *events)
{
if ( events )
{
int count = events->getCount();
int i;
for ( i=0; i<count; i++ )
{
OSData *data;
CachedMouseEventStruct *mouseEvent;
if ( (data = (OSData *)events->getObject(i) ) &&
(mouseEvent = (CachedMouseEventStruct *)data->getBytesNoCopy()) )
{
CalculateEventCountsForService(mouseEvent);
}
}
}
}
static SInt32 GetCachedMouseButtonStates(OSArray *events)
{
CachedMouseEventStruct * mouseEvent = 0;
OSData * data = 0;
SInt32 buttonState = 0;
UInt32 count = 0;
UInt32 i = 0;
if ( events )
{
count = events->getCount();
for ( i=0; i<count; i++ )
{
if ( (data = (OSData *)events->getObject(i)) &&
(mouseEvent = (CachedMouseEventStruct *)data->getBytesNoCopy()))
{
buttonState |= mouseEvent->lastButtons;
}
}
}
return buttonState;
}
static void ClearCachedMouseButtonStates(OSArray *events)
{
CachedMouseEventStruct * mouseEvent = 0;
OSData * data = 0;
UInt32 count = 0;
UInt32 i = 0;
if ( events )
{
count = events->getCount();
for ( i=0; i<count; i++ )
{
if ( (data = (OSData *)events->getObject(i)) &&
(mouseEvent = (CachedMouseEventStruct *)data->getBytesNoCopy()))
{
mouseEvent->lastButtons = 0;
CalculateEventCountsForService(mouseEvent);
}
}
}
}
static CachedMouseEventStruct * GetCachedMouseEventForService(OSArray *events, OSObject *service, UInt32 * index = 0)
{
CachedMouseEventStruct * mouseEvent = 0;
OSData * data = 0;
UInt32 count = 0;
UInt32 i = 0;
if ( events )
{
count = events->getCount();
for ( i=0; i<count; i++ )
{
if ( (data = (OSData *)events->getObject(i)) &&
(mouseEvent = (CachedMouseEventStruct *)data->getBytesNoCopy()) &&
(mouseEvent->service == service) )
{
if ( index ) *index = i;
return mouseEvent;
}
}
}
return NULL;
}
static void AppendNewCachedMouseEventForService(OSArray *events, OSObject *service)
{
CachedMouseEventStruct temp;
OSData * data;
bzero(&temp, sizeof(CachedMouseEventStruct));
temp.service = service;
data = OSData::withBytes(&temp, sizeof(CachedMouseEventStruct));
events->setObject(data);
data->release();
CalculateEventCountsForAllServices(events);
}
static void RemoveCachedMouseEventForService(OSArray *events, OSObject *service)
{
UInt32 index;
if ( events && GetCachedMouseEventForService(events, service, &index) )
{
events->removeObject(index);
}
CalculateEventCountsForAllServices(events);
}
#define kNXSystemInfoKey "NXSystemInfo"
static void AppendNewNXSystemInfoForService(OSArray *systemInfo, IOService *service)
{
OSDictionary * deviceInfo = NULL;
OSNumber * deviceID = NULL;
IOHIDevice * hiDevice = NULL;
OSObject * object = NULL;
if ( !systemInfo || !(hiDevice = OSDynamicCast(IOHIDevice, service)))
return;
deviceInfo = OSDictionary::withCapacity(4);
if ( !deviceInfo )
return;
deviceID = OSNumber::withNumber((uintptr_t)hiDevice, 64);
if (deviceID)
{
deviceInfo->setObject("serviceID", deviceID);
deviceID->release();
}
object = hiDevice->copyProperty(kIOHIDKindKey);
if ( object )
{
deviceInfo->setObject(kIOHIDKindKey, object);
object->release();
}
object = hiDevice->copyProperty(kIOHIDInterfaceIDKey);
if ( object )
{
deviceInfo->setObject(kIOHIDInterfaceIDKey, object);
object->release();
}
object = hiDevice->copyProperty(kIOHIDSubinterfaceIDKey);
if ( object )
{
deviceInfo->setObject(kIOHIDSubinterfaceIDKey, object);
object->release();
}
if ( hiDevice->metaCast("AppleADBKeyboard") || (hiDevice->getProvider() && hiDevice->getProvider()->metaCast("AppleEmbeddedKeyboard")) )
deviceInfo->setObject("built-in", kOSBooleanTrue);
OSDictionary * tempSystemInfo;
OSNumber * number;
if ( ((hiDevice->hidKind() == kHIKeyboardDevice) && (hiDevice->deviceType() != 0))&&
( (deviceInfo->getObject("built-in") == kOSBooleanTrue) ||
!((tempSystemInfo = OSDynamicCast(OSDictionary, systemInfo->getObject(0))) && (number = OSDynamicCast(OSNumber,tempSystemInfo->getObject(kIOHIDKindKey))) && (number->unsigned32BitValue() == kHIKeyboardDevice)) ||
((number = OSDynamicCast(OSNumber, hiDevice->getProperty(kIOHIDVendorIDKey))) && (number->unsigned32BitValue() == kIOUSBVendorIDAppleComputer) && (tempSystemInfo->getObject("built-in") != kOSBooleanTrue)) ) )
{
systemInfo->setObject(0, deviceInfo);
}
else
{
systemInfo->setObject(deviceInfo);
}
deviceInfo->release();
}
static void RemoveNXSystemInfoForService(OSArray *systemInfo, IOService *service)
{
OSDictionary * deviceInfo = NULL;
OSNumber * serviceID = NULL;
UInt32 i, count;
if ( !systemInfo || !OSDynamicCast(IOHIDevice, service))
return;
count = systemInfo->getCount();
for ( i=0; i<count; i++ )
{
if ( (deviceInfo = (OSDictionary *)systemInfo->getObject(i)) &&
(serviceID = (OSNumber *)deviceInfo->getObject("serviceID")) &&
(serviceID->unsigned64BitValue() == (uintptr_t)service) )
{
systemInfo->removeObject(i);
break;
}
}
}
static queue_head_t gKeyboardEQ;
static IOLock * gKeyboardEQLock = 0;
typedef IOReturn (*KeyboardEQAction)(IOHIDSystem * self, void *args);
typedef struct _KeyboardEQElement {
queue_chain_t link;
KeyboardEQAction action;
OSObject * sender;
AbsoluteTime ts;
union {
struct {
unsigned eventType;
unsigned flags;
unsigned key;
unsigned charCode;
unsigned charSet;
unsigned origCharCode;
unsigned origCharSet;
unsigned keyboardType;
bool repeat;
} keyboard;
struct {
unsigned eventType;
unsigned flags;
unsigned key;
unsigned flavor;
UInt64 guid;
bool repeat;
} keyboardSpecial;
struct {
unsigned flags;
} flagsChanged;
} event;
} KeyboardEQElement;
#define KEYBOARD_EQ_LOCK if (gKeyboardEQLock) IOLockLock(gKeyboardEQLock);
#define KEYBOARD_EQ_UNLOCK if (gKeyboardEQLock) IOLockUnlock(gKeyboardEQLock);
static UInt8 stickyKeysState = false;
static void notifyHIDevices(IOService *service, OSArray *hiDevices, UInt32 type)
{
IOHIKeyboard *keyboard;
if(!stickyKeysState || !hiDevices)
return;
switch ( type )
{
case kIOHIDSystem508MouseClickMessage:
case kIOHIDSystem508SpecialKeyDownMessage:
for(unsigned index=0; index<hiDevices->getCount(); index++)
{
keyboard = OSDynamicCast(IOHIKeyboard, hiDevices->getObject(index));
if (keyboard)
keyboard->IOHIKeyboard::message(type, service);
}
break;
}
}
#define kObjectNotFound ((unsigned int) -1)
static unsigned int
getArrayIndexForObject(OSArray *array, OSObject* object)
{
OSObject *tmp;
u_int i;
for (i = 0; i < array->getCount(); ++i) {
tmp = array->getObject(i);
if (tmp->isEqualTo(object)) {
return i;
}
}
return kObjectNotFound;
}
static void
hidActivityThread_cb(thread_call_param_t us, thread_call_param_t )
{
((IOHIDSystem *)us)->hidActivityChecker();
}
typedef struct {
IOCommandGate::Action handler;
IOService *newService;
}
IOHIDSystem_notificationData;
#define super IOService
OSDefineMetaClassAndStructors(IOHIDSystem, IOService);
struct IOHIDSystem::ExpansionData
{
IOHIDSystemCursorHelper cursorHelper;
UInt32 delayedScrollMomentum;
UInt8 scDirection;
UInt8 scIgnoreMomentum;
UInt8 scMouseCanReset;
UInt8 scIncrementedThisPhrase;
UInt16 scCount;
UInt16 scCountMax;
IOFixed64 scAccelerationFactor;
UInt64 scMinDeltaSqToStart;
UInt64 scMinDeltaSqToSustain;
UInt64 scLastScrollEndTime;
UInt64 scLastScrollSustainTime;
UInt64 scMaxTimeDeltaBetween;
UInt64 scMaxTimeDeltaToSustain;
IOFixedPoint64 scLastScrollLocation;
OSDictionary *devicePhaseState;
UInt64 periodicEventLast;
UInt64 periodicEventNext;
UInt64 cursorEventLast;
UInt64 cursorMoveLast;
UInt64 cursorMoveDelta;
UInt64 cursorWaitLast;
UInt64 cursorWaitDelta;
IONotifier * displayWranglerMatching;
bool hidActivityIdle; AbsoluteTime lastTickleTime;
thread_call_t hidActivityThread;
IOLock *delayedNotificationLock;
OSArray *delayedNotificationArray;
IOTimerEventSource *delayedNotificationSource;
};
#define _cursorHelper (_privateData->cursorHelper)
#define _devicePhaseState (_privateData->devicePhaseState)
#define _delayedScrollMomentum (_privateData->delayedScrollMomentum)
#define _scCount (_privateData->scCount)
#define _scCountMax (_privateData->scCountMax)
#define _scDirection (_privateData->scDirection)
#define _scIgnoreMomentum (_privateData->scIgnoreMomentum)
#define _scIncrementedThisPhrase (_privateData->scIncrementedThisPhrase)
#define _scMouseCanReset (_privateData->scMouseCanReset)
#define _scMinDeltaSqToStart (_privateData->scMinDeltaSqToStart)
#define _scMinDeltaSqToSustain (_privateData->scMinDeltaSqToSustain)
#define _scLastScrollEndTime (_privateData->scLastScrollEndTime)
#define _scLastScrollSustainTime (_privateData->scLastScrollSustainTime)
#define _scMaxTimeDeltaBetween (_privateData->scMaxTimeDeltaBetween)
#define _scMaxTimeDeltaToSustain (_privateData->scMaxTimeDeltaToSustain)
#define _scLastScrollLocation (_privateData->scLastScrollLocation)
#define _scAccelerationFactor (_privateData->scAccelerationFactor)
#define _periodicEventLast (_privateData->periodicEventLast)
#define _periodicEventNext (_privateData->periodicEventNext)
#define _cursorEventLast (_privateData->cursorEventLast)
#define _cursorMoveLast (_privateData->cursorMoveLast)
#define _cursorMoveDelta (_privateData->cursorMoveDelta)
#define _cursorWaitLast (_privateData->cursorWaitLast)
#define _cursorWaitDelta (_privateData->cursorWaitDelta)
#define _displayWranglerMatching (_privateData->displayWranglerMatching)
#define _hidActivityIdle (_privateData->hidActivityIdle)
#define _lastTickleTime (_privateData->lastTickleTime)
#define _hidActivityThread (_privateData->hidActivityThread)
#define _delayedNotificationLock (_privateData->delayedNotificationLock)
#define _delayedNotificationArray (_privateData->delayedNotificationArray)
#define _delayedNotificationSource (_privateData->delayedNotificationSource)
enum {
kScrollDirectionInvalid = 0,
kScrollDirectionXPositive,
kScrollDirectionXNegative,
kScrollDirectionYPositive,
kScrollDirectionYNegative,
kScrollDirectionZPositive,
kScrollDirectionZNegative,
};
#define _cursorLog(ts) do { \
if (evg != 0) \
if (evg->logCursorUpdates) { \
_cursorHelper.logPosition(__func__, ts); \
} \
} \
while(false)
#define _cursorLogTimed() do { \
if (evg != 0) \
if (evg->logCursorUpdates) { \
AbsoluteTime ts; \
clock_get_uptime(&ts); \
_cursorHelper.logPosition(__func__, AbsoluteTime_to_scalar(&ts)); \
} \
} \
while(false)
IOHIDSystem * IOHIDSystem::instance()
{
return evInstance;
}
#define kDefaultMinimumDelta 0x1ffffffffULL
bool IOHIDSystem::init(OSDictionary * properties)
{
if (!super::init(properties))
return false;
_privateData = (ExpansionData*)IOMalloc(sizeof(ExpansionData));
if (!_privateData)
return false;
bzero(_privateData, sizeof(ExpansionData));
_periodicEventNext = UINT64_MAX;
if (!_cursorHelper.init())
return false;
_cursorLogTimed();
_scMinDeltaSqToStart = _scMinDeltaSqToSustain = kDefaultMinimumDelta;
_scAccelerationFactor.fromIntFloor(5);
_scCountMax = 2000;
evScreen = NULL;
periodicES = 0;
eventConsumerES = 0;
keyboardEQES = 0;
cmdGate = 0;
workLoop = 0;
cachedEventFlags = 0;
displayState = IOPMDeviceUsable;
AbsoluteTime_to_scalar(&lastEventTime) = 0;
AbsoluteTime_to_scalar(&lastUndimEvent) = 0;
AbsoluteTime_to_scalar(&rootDomainStateChangeDeadline) = 0;
AbsoluteTime_to_scalar(&displayStateChangeDeadline) = 0;
AbsoluteTime_to_scalar(&displaySleepWakeupDeadline) = 0;
AbsoluteTime_to_scalar(&gIOHIDZeroAbsoluteTime) = 0;
displaySleepDrivenByPM = false;
ioHIDevices = OSArray::withCapacity(2);
cachedButtonStates = OSArray::withCapacity(3);
touchEventPosters = OSSet::withCapacity(2);
consumedKeys = OSArray::withCapacity(5);
AppendNewCachedMouseEventForService(cachedButtonStates, 0);
nanoseconds_to_absolutetime(kIOHIDPowerOnThresholdNS, &gIOHIDPowerOnThresoldAbsoluteTime);
nanoseconds_to_absolutetime(kIOHIDRelativeTickleThresholdNS, &gIOHIDRelativeTickleThresholdAbsoluteTime);
nanoseconds_to_absolutetime(kIOHIDDispaySleepAbortThresholdNS, &gIOHIDDisplaySleepAbortThresholdAbsoluteTime);
queue_init(&gKeyboardEQ);
gKeyboardEQLock = IOLockAlloc();
return true;
}
IOHIDSystem * IOHIDSystem::probe(IOService * provider,
SInt32 * score)
{
if (!super::probe(provider,score)) return 0;
return this;
}
IOWorkLoop * IOHIDSystem::getWorkLoop() const
{
return workLoop;
}
bool IOHIDSystem::start(IOService * provider)
{
bool iWasStarted = false;
OSObject *obj = NULL;
OSNumber *number = NULL;
OSDictionary *matchingDevice = serviceMatching("IOHIDevice");
OSDictionary *matchingService = serviceMatching("IOHIDEventService");
OSDictionary *matchingWrangler = serviceMatching("IODisplayWrangler");
OSDictionary *matchingKeyswitch = serviceMatching("AppleKeyswitch");
IOServiceMatchingNotificationHandler iohidNotificationHandler = OSMemberFunctionCast(IOServiceMatchingNotificationHandler, this, &IOHIDSystem::genericNotificationHandler);
require(super::start(provider), exit_early);
_setScrollCountParameters();
evInstance = this;
_cursorHelper.desktopLocation().fromIntFloor(INIT_CURSOR_X, INIT_CURSOR_Y);
_cursorHelper.desktopLocationDelta().fromIntFloor(0, 0);
_cursorHelper.updateScreenLocation(NULL, NULL);
_cursorLogTimed();
_delayedNotificationLock = IOLockAlloc();
_delayedNotificationArray = OSArray::withCapacity(2);
evScreenSize = sizeof(EvScreen) * EV_MAX_SCREENS;
evScreen = (void *) IOMalloc(evScreenSize);
bzero(evScreen, evScreenSize);
savedParameters = OSDictionary::withCapacity(4);
require(evScreen && savedParameters && _delayedNotificationLock && _delayedNotificationArray, exit_early);
bzero(evScreen, evScreenSize);
firstWaitCursorFrame = EV_WAITCURSOR;
maxWaitCursorFrame = EV_MAXCURSOR;
createParameters();
systemInfo = OSArray::withCapacity(4);
if (systemInfo) {
setProperty(kNXSystemInfoKey, systemInfo);
}
registryName = getName();
obj = copyProperty(kIOHIDPowerOnDelayNSKey, gIOServicePlane);
if (obj != NULL) {
number = OSDynamicCast(OSNumber, obj);
if (number != NULL) {
UInt64 value = number->unsigned64BitValue();
if (value < kMillisecondScale) {
}
else if (value > (10ULL * kSecondScale)) {
}
else {
setProperty(kIOHIDPowerOnDelayNSKey, number);
gIOHIDPowerOnThresoldAbsoluteTime = value;
}
}
obj->release();
}
workLoop = IOHIDWorkLoop::workLoop();
cmdGate = IOCommandGate::commandGate(this);
periodicES = IOTimerEventSource::timerEventSource(this, (IOTimerEventSource::Action) &_periodicEvents );
eventConsumerES = IOInterruptEventSource::interruptEventSource(this, (IOInterruptEventSource::Action) &doKickEventConsumer);
keyboardEQES = IOInterruptEventSource::interruptEventSource(this, (IOInterruptEventSource::Action) &doProcessKeyboardEQ);
_delayedNotificationSource = IOTimerEventSource::timerEventSource(this, OSMemberFunctionCast(IOTimerEventSource::Action, this, &IOHIDSystem::doProcessNotifications));
require(workLoop && cmdGate && periodicES && eventConsumerES && keyboardEQES && _delayedNotificationSource, exit_early);
require_noerr(workLoop->addEventSource(cmdGate), exit_early);
require_noerr(workLoop->addEventSource(periodicES), exit_early);
require_noerr(workLoop->addEventSource(eventConsumerES), exit_early);
require_noerr(workLoop->addEventSource(keyboardEQES), exit_early);
require_noerr(workLoop->addEventSource(_delayedNotificationSource), exit_early);
publishNotify = addMatchingNotification(gIOPublishNotification,
matchingDevice,
iohidNotificationHandler,
this,
(void *)&IOHIDSystem::handlePublishNotification );
require(publishNotify, exit_early);
eventPublishNotify = addMatchingNotification(gIOPublishNotification,
matchingService,
iohidNotificationHandler,
this,
(void *)&IOHIDSystem::handlePublishNotification );
require(eventPublishNotify, exit_early);
terminateNotify = addMatchingNotification(gIOTerminatedNotification,
matchingDevice,
iohidNotificationHandler,
this,
(void *)&IOHIDSystem::handleTerminateNotification );
require(terminateNotify, exit_early);
eventTerminateNotify = addMatchingNotification(gIOTerminatedNotification,
matchingService,
iohidNotificationHandler,
this,
(void *)&IOHIDSystem::handleTerminateNotification );
require(eventTerminateNotify, exit_early);
rootDomain = (IOService *)getPMRootDomain();
if (rootDomain)
rootDomain->registerInterestedDriver(this);
registerPrioritySleepWakeInterest(powerStateHandler, this, 0);
_displayWranglerMatching = addMatchingNotification(gIOPublishNotification,
matchingWrangler,
iohidNotificationHandler,
this,
(void *)&IOHIDSystem::handlePublishNotification);
require(_displayWranglerMatching, exit_early);
gSwitchNotification = addMatchingNotification(gIOPublishNotification,
matchingKeyswitch,
keySwitchNotificationHandler,
this,
0);
require(gSwitchNotification, exit_early);
#if !TARGET_OS_EMBEDDED
_hidActivityThread = thread_call_allocate(hidActivityThread_cb, (thread_call_param_t)this);
_hidActivityIdle = true;
require(_hidActivityThread, exit_early);
#endif
registerService();
iWasStarted = true;
exit_early:
matchingDevice->release();
matchingService->release();
matchingWrangler->release();
matchingKeyswitch->release();
if (!iWasStarted)
evInstance = 0;
return iWasStarted;
}
void IOHIDSystem::setDisplaySleepDrivenByPM(bool val)
{
displaySleepDrivenByPM = val;
}
IOReturn IOHIDSystem::powerStateHandler( void *target, void *refCon __unused,
UInt32 messageType, IOService *service __unused, void *messageArgs, vm_size_t argSize __unused)
{
IOPMSystemCapabilityChangeParameters * params;
IOHIDSystem* myThis = OSDynamicCast( IOHIDSystem, (OSObject*)target );
if ( messageType != kIOMessageSystemCapabilityChange ) {
return kIOReturnSuccess;
}
params = (IOPMSystemCapabilityChangeParameters *) messageArgs;
if ((params->changeFlags & kIOPMSystemCapabilityWillChange) &&
(params->fromCapabilities & kIOPMSystemCapabilityGraphics) &&
(params->toCapabilities & kIOPMSystemCapabilityGraphics) == 0) {
myThis->setDisplaySleepDrivenByPM(true);
}
return kIOReturnSuccess;
}
IOReturn IOHIDSystem::powerStateDidChangeTo( IOPMPowerFlags theFlags, unsigned long state, IOService * service)
{
IOHID_DEBUG(kIOHIDDebugCode_PowerStateChangeEvent, service, state, theFlags, 0);
if (service == displayManager)
{
displayState = theFlags;
if (theFlags & IOPMDeviceUsable) {
clock_get_uptime(&displayStateChangeDeadline);
ADD_ABSOLUTETIME(&displayStateChangeDeadline,
&gIOHIDRelativeTickleThresholdAbsoluteTime);
AbsoluteTime_to_scalar(&displaySleepWakeupDeadline) = 0;
updateEventFlags(0);
}
else {
if ( !CMP_ABSOLUTETIME(&displaySleepWakeupDeadline, &gIOHIDZeroAbsoluteTime) &&
(kOSBooleanFalse == rootDomain->copyProperty("DisplayIdleForDemandSleep"))) {
clock_get_uptime(&displaySleepWakeupDeadline);
ADD_ABSOLUTETIME(&displaySleepWakeupDeadline, &gIOHIDDisplaySleepAbortThresholdAbsoluteTime);
}
displaySleepDrivenByPM = false; }
}
else if (service == rootDomain)
{
if (theFlags & kIOPMPowerOn)
{
clock_get_uptime(&rootDomainStateChangeDeadline);
ADD_ABSOLUTETIME(&rootDomainStateChangeDeadline, &gIOHIDPowerOnThresoldAbsoluteTime);
ClearCachedMouseButtonStates(cachedButtonStates);
}
}
return IOPMNoErr;
}
bool IOHIDSystem::genericNotificationHandler(void * handler,
IOService * newService,
IONotifier * )
{
bool result = false;
if (handler && newService && _delayedNotificationSource) {
IOHIDSystem_notificationData rawData = {(IOCommandGate::Action)handler, newService};
OSData *data = OSData::withBytes(&rawData, sizeof(rawData));
if (data) {
newService->retain();
IOLockLock(_delayedNotificationLock);
_delayedNotificationArray->setObject(data);
IOLockUnlock(_delayedNotificationLock);
data->release();
_delayedNotificationSource->setTimeoutUS(1);
result = true;
}
}
return result;
}
void IOHIDSystem::doProcessNotifications(IOTimerEventSource *sender __unused)
{
bool reschedule = false;
while (_delayedNotificationArray->getCount() > 0) {
IOLockLock(_delayedNotificationLock);
OSData *notificationData = OSDynamicCast(OSData, _delayedNotificationArray->getObject(0));
if (notificationData) {
notificationData->retain();
}
_delayedNotificationArray->removeObject(0);
IOLockUnlock(_delayedNotificationLock);
if (notificationData) {
const IOHIDSystem_notificationData *data = (const IOHIDSystem_notificationData *)notificationData->getBytesNoCopy();
cmdGate->runAction(data->handler, data->newService);
data->newService->release();
notificationData->release();
}
}
if (reschedule) {
_delayedNotificationSource->setTimeoutUS(1);
}
}
bool IOHIDSystem::handlePublishNotification(
void * target,
IOService * newService )
{
IOHIDSystem * self = (IOHIDSystem *) target;
if (newService->isInactive()) {
return true;
}
if( newService->metaCast("IODisplayWrangler")) {
if( !self->displayManager) {
self->displayManager = newService;
self->displayState = newService->registerInterestedDriver(self);
}
return true;
}
self->attach( newService );
if( OSDynamicCast(IOHIDevice, newService) ||
OSDynamicCast(IOHIDEventService, newService)) {
if (self->ioHIDevices) {
if (self->ioHIDevices->getNextIndexOfObject(newService, 0) == (unsigned)-1)
self->ioHIDevices->setObject(newService);
}
if (OSDynamicCast(IOHIPointing, newService))
{
AppendNewCachedMouseEventForService(self->cachedButtonStates, newService);
}
OSArray * newSystemInfo = OSArray::withArray(self->systemInfo);
if ( newSystemInfo )
{
AppendNewNXSystemInfoForService(newSystemInfo, newService);
self->setProperty(kNXSystemInfoKey, newSystemInfo);
OSSafeReleaseNULL(self->systemInfo);
self->systemInfo = newSystemInfo;
}
if(self->eventsOpen || OSDynamicCast(IOHIKeyboard, newService))
self->registerEventSource( newService );
}
return true;
}
bool IOHIDSystem::handleTerminateNotification(
void * target,
IOService * service )
{
IOHIDSystem * self = (IOHIDSystem *) target;
int index;
if( self->eventsOpen && (
OSDynamicCast(IOHIDevice, service) ||
OSDynamicCast(IOHIDEventService, service)))
{
service->close(self);
}
if (self->ioHIDevices) {
if ((index = self->ioHIDevices->getNextIndexOfObject(service, 0)) != -1)
self->ioHIDevices->removeObject(index);
}
OSArray * newSystemInfo = OSArray::withArray(self->systemInfo);
if ( newSystemInfo )
{
RemoveNXSystemInfoForService(newSystemInfo, service);
self->setProperty(kNXSystemInfoKey, newSystemInfo);
OSSafeReleaseNULL(self->systemInfo);
self->systemInfo = newSystemInfo;
}
if (OSDynamicCast(IOHIPointing, service))
{
AbsoluteTime ts;
clock_get_uptime(&ts);
if ( (self->displayState & IOPMDeviceUsable) ) {
self->relativePointerEvent(0, 0, 0, ts, service);
}
CachedMouseEventStruct *cachedMouseEvent;
if ((cachedMouseEvent = GetCachedMouseEventForService(self->cachedButtonStates, service)) &&
(cachedMouseEvent->proximityData.proximity.enterProximity))
{
cachedMouseEvent->proximityData.proximity.enterProximity = false;
cachedMouseEvent->state |= kCachedMousePointingTabletEventPendFlag;
self->proximityEvent(&(cachedMouseEvent->proximityData), ts, service);
cachedMouseEvent->state &= ~kCachedMousePointingTabletEventPendFlag;
IOGBounds bounds = {0, 0, 0, 0};
IOGPoint newLoc = {0, 0};
self->absolutePointerEvent(0, &newLoc, &bounds, false, 0, 0, ts, service);
}
RemoveCachedMouseEventForService(self->cachedButtonStates, service);
}
return true;
}
void IOHIDSystem::free()
{
if (cmdGate) {
evClose();
}
if (workLoop) {
workLoop->disableAllEventSources();
}
if (periodicES) {
periodicES->cancelTimeout();
if ( workLoop )
workLoop->removeEventSource( periodicES );
periodicES->release();
periodicES = 0;
}
if (eventConsumerES) {
eventConsumerES->disable();
if ( workLoop )
workLoop->removeEventSource( eventConsumerES );
eventConsumerES->release();
eventConsumerES = 0;
}
if (keyboardEQES) {
keyboardEQES->disable();
if ( workLoop )
workLoop->removeEventSource( keyboardEQES );
keyboardEQES->release();
keyboardEQES = 0;
}
if (_privateData) {
if (_delayedNotificationSource) {
_delayedNotificationSource->cancelTimeout();
if ( workLoop )
workLoop->removeEventSource( _delayedNotificationSource );
_delayedNotificationSource->release();
}
if (_delayedNotificationLock) {
IOLockFree(_delayedNotificationLock);
_delayedNotificationLock = 0;
}
OSSafeReleaseNULL(_delayedNotificationArray);
}
if (evScreen) IOFree( (void *)evScreen, evScreenSize );
evScreen = (void *)0;
evScreenSize = 0;
if (publishNotify) {
publishNotify->remove();
publishNotify = 0;
}
if (gSwitchNotification) {
gSwitchNotification->remove();
gSwitchNotification = 0;
}
if (terminateNotify) {
terminateNotify->remove();
terminateNotify = 0;
}
if (eventPublishNotify) {
eventPublishNotify->remove();
eventPublishNotify = 0;
}
if (eventTerminateNotify) {
eventTerminateNotify->remove();
eventTerminateNotify = 0;
}
if (_displayWranglerMatching) {
_displayWranglerMatching->remove();
_displayWranglerMatching = 0;
}
OSSafeReleaseNULL(cmdGate); OSSafeReleaseNULL(workLoop);
OSSafeReleaseNULL(ioHIDevices);
OSSafeReleaseNULL(cachedButtonStates);
OSSafeReleaseNULL(consumedKeys);
OSSafeReleaseNULL(systemInfo);
if ( gKeyboardEQLock ) {
IOLock * lock = gKeyboardEQLock;
IOLockLock(lock);
gKeyboardEQLock = 0;
IOLockUnlock(lock);
IOLockFree(lock);
}
OSSafeReleaseNULL(_hidKeyboardDevice);
OSSafeReleaseNULL(_hidPointingDevice);
if (_privateData) {
_cursorHelper.finalize();
IOFree((void*)_privateData, sizeof(ExpansionData));
_privateData = NULL;
}
super::free();
}
IOReturn IOHIDSystem::evOpen(void)
{
IOReturn r = kIOReturnSuccess;
if ( evOpenCalled == true )
{
r = kIOReturnBusy;
goto done;
}
evOpenCalled = true;
if (!evInitialized)
{
evInitialized = true;
}
done:
return r;
}
IOReturn IOHIDSystem::evClose(void){
return cmdGate->runAction((IOCommandGate::Action)doEvClose);
}
IOReturn IOHIDSystem::doEvClose(IOHIDSystem *self)
{
return self->evCloseGated();
}
IOReturn IOHIDSystem::evCloseGated(void)
{
if ( evOpenCalled == false )
return kIOReturnBadArgument;
evStateChanging = true;
if( cursorEnabled)
hideCursor();
cursorStarted = false;
cursorEnabled = false;
detachEventSources();
if ( evScreen != (void *)0 )
{
screens = 0;
lastShmemPtr = (void *)0;
}
setEventPortGated(MACH_PORT_NULL);
evStateChanging = false;
evOpenCalled = false;
eventsOpen = false;
return kIOReturnSuccess;
}
void IOHIDSystem::evDispatch(
EvCmd evcmd)
{
if( !eventsOpen || (evcmd == EVLEVEL) || (evcmd == EVNOP))
return;
for( int i = 0; i < screens; i++ ) {
bool onscreen = (0 != (cursorScreens & (1 << i)));
if (onscreen) {
EvScreen *esp = &((EvScreen*)evScreen)[i];
if ( esp->instance ) {
IOGPoint p;
p.x = evg->screenCursorFixed.x / 256; p.y = evg->screenCursorFixed.y / 256;
switch ( evcmd )
{
case EVMOVE:
esp->instance->moveCursor(&p, evg->frame);
break;
case EVSHOW:
esp->instance->showCursor(&p, evg->frame);
break;
case EVHIDE:
esp->instance->hideCursor();
break;
default:
break;
}
}
}
}
}
void IOHIDSystem::evSpecialKeyMsg(unsigned key,
unsigned dir,
unsigned f,
unsigned l)
{
mach_port_t dst_port;
struct evioSpecialKeyMsg *msg;
static const struct evioSpecialKeyMsg init_msg =
{ { MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND), sizeof (struct evioSpecialKeyMsg), MACH_PORT_NULL, MACH_PORT_NULL, 0, EV_SPECIAL_KEY_MSG_ID },
0,
0,
0,
0
};
if ( (dst_port = specialKeyPort(key)) == MACH_PORT_NULL )
return;
msg = (struct evioSpecialKeyMsg *) IOMalloc(
sizeof (struct evioSpecialKeyMsg) );
if ( msg == NULL )
return;
bcopy( &init_msg, msg, sizeof (struct evioSpecialKeyMsg) );
msg->Head.msgh_remote_port = dst_port;
msg->key = key;
msg->direction = dir;
msg->flags = f;
msg->level = l;
cmdGate->runAction((IOCommandGate::Action)doSpecialKeyMsg,(void*)msg);
}
void IOHIDSystem::_resetMouseParameters(void)
{
if ( eventsOpen == false )
return;
OSDictionary *tempDict = OSDictionary::withCapacity(3);
UInt64 nano;
nanoseconds_to_absolutetime( EV_DCLICKTIME, &clickTimeThresh);
clickSpaceThresh.x = clickSpaceThresh.y = EV_DCLICKSPACE;
AbsoluteTime_to_scalar( &clickTime) = 0;
clickLoc.x = clickLoc.y = -EV_DCLICKSPACE;
clickState = 1;
if (tempDict) {
UInt32 tempClickSpace[] = {clickSpaceThresh.x, clickSpaceThresh.y};
makeInt32ArrayParamProperty( tempDict, kIOHIDClickSpaceKey,
tempClickSpace, sizeof(tempClickSpace)/sizeof(UInt32) );
nano = EV_DCLICKTIME;
makeNumberParamProperty( tempDict, kIOHIDClickTimeKey,
nano, 64 );
setParamProperties(tempDict);
tempDict->release();
}
}
#ifdef LOG_SCREEN_REGISTRATION
#warning LOG_SCREEN_REGISTRATION is defined
#define log_screen_reg(fmt, args...) kprintf(">>> " fmt, args)
#else
#define log_screen_reg(fmt, args...)
#endif
int
IOHIDSystem::registerScreen(IOGraphicsDevice * io_gd,
IOGBounds * boundsPtr,
IOGBounds * virtualBoundsPtr)
{
int result = -1;
if (eventsOpen) {
if (!io_gd || !boundsPtr || !virtualBoundsPtr) {
IOLog("%s invalid call %p %p %p\n", __PRETTY_FUNCTION__, io_gd, boundsPtr, virtualBoundsPtr);
}
else {
UInt32 index;
IOReturn ret = workLoop->runAction((IOWorkLoop::Action)&IOHIDSystem::doRegisterScreen,
this, io_gd, boundsPtr, virtualBoundsPtr, &index);
if (ret == kIOReturnSuccess) {
result = SCREENTOKEN + index;
}
else {
IOLog("%s failed %08x\n", __PRETTY_FUNCTION__, ret);
}
}
}
log_screen_reg("%s: registered token %d\n", __PRETTY_FUNCTION__, result);
return result;
}
IOReturn
IOHIDSystem::extRegisterVirtualDisplay(void* token_ptr,void*,void*,void*,void*,void*)
{
IOReturn result = kIOReturnBadArgument;
if (token_ptr) {
SInt32 index;
UInt64 *token = (UInt64 *)token_ptr;
result = workLoop->runAction((IOWorkLoop::Action)&IOHIDSystem::doRegisterScreen,
this, NULL, NULL, NULL, &index);
if ((index >= 0) && (index < EV_MAX_SCREENS)) {
*token = SCREENTOKEN + index;
}
else {
*token = 0;
if (result == kIOReturnSuccess) {
result = kIOReturnInternalError;
IOLog("IOHIDSystem tried to return an invalid token with no error\n");
}
}
log_screen_reg("%s: registered token %lld on %x\n", __PRETTY_FUNCTION__, *token, result);
}
return result;
}
IOReturn
IOHIDSystem::doRegisterScreen(IOHIDSystem *self,
IOGraphicsDevice *io_gd,
IOGBounds *bounds,
IOGBounds *virtualBounds,
void *index)
{
return self->registerScreenGated(io_gd, bounds, virtualBounds, (SInt32*)index);
}
#ifdef LOG_SCROLL_STATE
# define log_scroll_state(s, ...) kprintf(">>> %s:%d " s, "IOHIDSystem", __LINE__, __VA_ARGS__)
# define log_scroll_state_b(s, ...) kprintf(">>> %s:%d " s, "IOHIDSystem", __LINE__, __VA_ARGS__)
#else
# define log_scroll_state(s, ...)
# define log_scroll_state_b(s, ...)
#endif
IOReturn
IOHIDSystem::registerScreenGated(IOGraphicsDevice *io_gd,
IOGBounds *boundsPtr,
IOGBounds *virtualBoundsPtr,
SInt32 *index)
{
EvScreen *screen_ptr = NULL;
OSNumber *num = NULL;
IOReturn result = kIOReturnSuccess;
*index = -1;
if ( lastShmemPtr == (void *)0 )
lastShmemPtr = evs;
log_screen_reg("%s %p %p %p\n", __func__, io_gd, boundsPtr, virtualBoundsPtr);
for (int i = 0; (i < EV_MAX_SCREENS) && (screen_ptr == NULL); i++) {
screen_ptr = &((EvScreen*)evScreen)[i];
if (io_gd && (screen_ptr->instance == io_gd)) {
log_screen_reg("%s refound at index %d\n", __func__, i);
*index = i;
}
else if (screen_ptr->creator_pid) {
proc_t isStillAlive = proc_find(screen_ptr->creator_pid);
if (isStillAlive) {
screen_ptr = NULL;
proc_rele(isStillAlive);
}
else {
IOLog("IOHIDSystem::%s: Screen %d recycled from pid %d\n", __func__, i, screen_ptr->creator_pid);
*index = i;
screen_ptr->creator_pid = 0;
screen_ptr->displayBounds = NULL;
screen_ptr->desktopBounds = NULL;
}
}
else if (screen_ptr->instance) {
screen_ptr = NULL; }
else {
log_screen_reg("%s new index at %d\n", __func__, i);
*index = i;
}
}
if (!screen_ptr) {
IOLog("IOHIDSystem::%s: No space found for new screen\n", __func__);
result = kIOReturnNoResources;
}
else if (io_gd && boundsPtr && virtualBoundsPtr) {
screen_ptr->instance = io_gd;
screen_ptr->displayBounds = boundsPtr;
screen_ptr->desktopBounds = virtualBoundsPtr;
screen_ptr->creator_pid = 0;
if ( boundsPtr->minx < workSpace.minx )
workSpace.minx = boundsPtr->minx;
if ( boundsPtr->miny < workSpace.miny )
workSpace.miny = boundsPtr->miny;
if ( boundsPtr->maxx < workSpace.maxx )
workSpace.maxx = boundsPtr->maxx;
if ( screen_ptr->displayBounds->maxy < workSpace.maxy )
workSpace.maxy = boundsPtr->maxy;
num = (OSNumber*)io_gd->copyProperty(kIOFBWaitCursorFramesKey);
if(OSDynamicCast(OSNumber, num) &&
(num->unsigned32BitValue() > maxWaitCursorFrame)) {
firstWaitCursorFrame = 0;
maxWaitCursorFrame = num->unsigned32BitValue();
evg->lastFrame = maxWaitCursorFrame;
}
OSSafeReleaseNULL(num);
num = (OSNumber*)io_gd->copyProperty(kIOFBWaitCursorPeriodKey);
if( OSDynamicCast(OSNumber, num) ) {
clock_interval_to_absolutetime_interval(num->unsigned32BitValue(), kNanosecondScale, &_cursorWaitDelta);
}
OSSafeReleaseNULL(num);
}
else if (!io_gd && !boundsPtr && !virtualBoundsPtr) {
screen_ptr->displayBounds = (IOGBounds*)screen_ptr->scratch;
screen_ptr->desktopBounds = screen_ptr->displayBounds + 1;
screen_ptr->creator_pid = proc_selfpid();
screen_ptr->displayBounds->minx = screen_ptr->desktopBounds->minx = screen_ptr->displayBounds->miny = screen_ptr->desktopBounds->miny = -30001;
screen_ptr->displayBounds->maxx = screen_ptr->desktopBounds->maxx = screen_ptr->displayBounds->maxy = screen_ptr->desktopBounds->maxy = -30000;
}
else {
result = kIOReturnBadArgument;
}
if (result == kIOReturnSuccess) {
log_screen_reg(">>> display %d is for %d\n", *index, screen_ptr->creator_pid);
if (*index >= screens) {
screens = 1 + *index;
}
}
return result;
}
void IOHIDSystem::unregisterScreen(int token) {
uintptr_t index = token - SCREENTOKEN;
log_screen_reg("%s: unregistering token %d\n", __PRETTY_FUNCTION__, token);
if (index < EV_MAX_SCREENS) {
IOReturn ret = cmdGate->runAction((IOCommandGate::Action)doUnregisterScreen, (void *)index);
if (ret != kIOReturnSuccess) {
IOLog("%s recieved %08x for token %d.\n", __PRETTY_FUNCTION__, ret, token);
}
}
else {
IOLog("%s called with invalid token %d.\n", __PRETTY_FUNCTION__, token);
}
}
IOReturn
IOHIDSystem::extUnregisterVirtualDisplay(void* token_ptr,void*,void*,void*,void*,void*)
{
IOReturn result = kIOReturnSuccess;
uintptr_t token = (uintptr_t)token_ptr;
uintptr_t index = token - SCREENTOKEN;
if (index < EV_MAX_SCREENS) {
result = cmdGate->runAction((IOCommandGate::Action)doUnregisterScreen, (void *)index);
}
else {
IOLog("%s called with invalid token %d.\n", __PRETTY_FUNCTION__, (int)token);
result = kIOReturnBadArgument;
}
log_screen_reg("%s: unregistering token %lu on %x\n", __PRETTY_FUNCTION__, token, result);
return result;
}
IOReturn IOHIDSystem::doUnregisterScreen (IOHIDSystem *self, void * arg0, void *arg1)
{
uintptr_t index = (uintptr_t) arg0;
uintptr_t internal = (uintptr_t) arg1;
return self->unregisterScreenGated(index, internal);
}
IOReturn IOHIDSystem::unregisterScreenGated(int index, bool internal)
{
IOReturn result = kIOReturnSuccess;
log_screen_reg("%s %d %d %d\n", __func__, index, internal, screens);
if ( eventsOpen == false || index >= screens ) {
result = kIOReturnNoResources;
}
else {
EvScreen *screen_ptr = ((EvScreen*)evScreen)+index;
if (!screen_ptr->displayBounds) {
IOLog("%s called with invalid index %d\n", __PRETTY_FUNCTION__, index);
result = kIOReturnBadArgument;
}
else if (internal && !screen_ptr->instance) {
IOLog("%s called internally on an external device %d\n", __PRETTY_FUNCTION__, index);
result = kIOReturnNoDevice;
}
else if (!internal && screen_ptr->instance) {
IOLog("%s called externally on an internal device %d\n", __PRETTY_FUNCTION__, index);
result = kIOReturnNotPermitted;
}
else {
hideCursor();
screen_ptr->instance = NULL;
screen_ptr->desktopBounds = NULL;
screen_ptr->displayBounds = NULL;
screen_ptr->creator_pid = 0;
cursorScreens &= ~(1 << index);
setCursorPosition((IOGPoint *)&evg->cursorLoc, true);
showCursor();
}
}
return result;
}
IOReturn
IOHIDSystem::extSetVirtualDisplayBounds(void* token_ptr,void* minx,void* maxx,void* miny,void* maxy,void*)
{
IOReturn result = kIOReturnSuccess;
uintptr_t token = (uintptr_t)token_ptr;
uintptr_t index = token - SCREENTOKEN;
log_screen_reg("%s: set bounds on token %lu\n", __PRETTY_FUNCTION__, token);
if (index < EV_MAX_SCREENS) {
IOGBounds tempBounds = { (uintptr_t) minx, (uintptr_t) maxx, (uintptr_t) miny, (uintptr_t) maxy };
result = cmdGate->runAction((IOCommandGate::Action)doSetDisplayBounds, (void*) index, (void*) &tempBounds);
}
else {
IOLog("%s called with invalid token %d.\n", __PRETTY_FUNCTION__, (int)token);
result = kIOReturnBadArgument;
}
return result;
}
IOReturn
IOHIDSystem::doSetDisplayBounds (IOHIDSystem *self, void * arg0, void * arg1)
{
uintptr_t index = (uintptr_t) arg0;
IOGBounds *tempBounds = (IOGBounds*) arg1;
return self->setDisplayBoundsGated(index, tempBounds);
}
IOReturn
IOHIDSystem::setDisplayBoundsGated (UInt32 index, IOGBounds *tempBounds)
{
IOReturn result = kIOReturnSuccess;
log_screen_reg("%s ((%d,%d),(%d,%d))\n", __func__, tempBounds->minx, tempBounds->miny, tempBounds->maxx, tempBounds->maxy);
if ( eventsOpen == false || index >= (UInt32)screens ) {
result = kIOReturnNoResources;
}
else {
EvScreen *screen_ptr = ((EvScreen*)evScreen)+index;
if (screen_ptr->instance) {
IOLog("%s called on an internal device %d\n", __PRETTY_FUNCTION__, (int)index);
result = kIOReturnNotPermitted;
}
else if (!screen_ptr->displayBounds || !screen_ptr->desktopBounds) {
IOLog("%s called with invalid index %d\n", __PRETTY_FUNCTION__, (int)index);
result = kIOReturnBadArgument;
}
else {
hideCursor();
*(screen_ptr->displayBounds) = *(screen_ptr->desktopBounds) = *tempBounds;
cursorScreens &= ~(1 << index);
setCursorPosition((IOGPoint *)&evg->cursorLoc, true);
showCursor();
}
}
return result;
}
IOGBounds * IOHIDSystem::workspaceBounds()
{
return &workSpace;
}
IOReturn IOHIDSystem::registerEventQueue(IODataQueue * queue)
{
return cmdGate->runAction((IOCommandGate::Action)doRegisterEventQueue, (void *)queue);
}
IOReturn IOHIDSystem::doRegisterEventQueue (IOHIDSystem *self, void * arg0)
{
return self->registerEventQueueGated((IODataQueue *)arg0);
}
IOReturn IOHIDSystem::registerEventQueueGated(void * p1)
{
IODataQueue * queue = (IODataQueue *)p1;
if ( !queue )
return kIOReturnBadArgument;
if ( !dataQueueSet )
dataQueueSet = OSSet::withCapacity(4);
dataQueueSet->setObject(queue);
return kIOReturnSuccess;
}
IOReturn IOHIDSystem::unregisterEventQueue(IODataQueue * queue)
{
return cmdGate->runAction((IOCommandGate::Action)doUnregisterEventQueue, (void *)queue);
}
IOReturn IOHIDSystem::doUnregisterEventQueue (IOHIDSystem *self, void * arg0)
{
return self->unregisterEventQueueGated((IODataQueue *)arg0);
}
IOReturn IOHIDSystem::unregisterEventQueueGated(void * p1)
{
IODataQueue * queue = (IODataQueue *)p1;
if ( !queue )
return kIOReturnBadArgument;
if ( dataQueueSet )
dataQueueSet->removeObject(queue);
return kIOReturnSuccess;
}
IOReturn IOHIDSystem::createShmem(void* p1, void*, void*, void*, void*, void*)
{ return cmdGate->runAction((IOCommandGate::Action)doCreateShmem, p1);
}
IOReturn IOHIDSystem::doCreateShmem (IOHIDSystem *self, void * arg0)
{
return self->createShmemGated(arg0);
}
IOReturn IOHIDSystem::createShmemGated(void* p1)
{
int shmemVersion = (uintptr_t)p1;
IOByteCount size;
bool clean = false;
if ( shmemVersion < kIOHIDLastCompatibleShmemVersion ) {
IOLog("IOHIDSystem::createShmemGated called with low version: %d < %d\n", shmemVersion, kIOHIDLastCompatibleShmemVersion);
return kIOReturnUnsupported;
}
if ( shmemVersion > kIOHIDCurrentShmemVersion ) {
IOLog("IOHIDSystem::createShmemGated called with hi version: %d > %d\n", shmemVersion, kIOHIDCurrentShmemVersion);
return kIOReturnUnsupported;
}
if ( 0 == globalMemory) {
size = sizeof(EvOffsets) + sizeof(EvGlobals);
globalMemory = IOBufferMemoryDescriptor::withOptions( kIODirectionNone | kIOMemoryKernelUserShared, size );
if ( !globalMemory)
return kIOReturnNoMemory;
shmem_addr = (uintptr_t) globalMemory->getBytesNoCopy();
shmem_size = size;
clean = true;
}
initShmem(clean);
return kIOReturnSuccess;
}
void IOHIDSystem::initShmem(bool clean)
{
int i;
EvOffsets *eop;
int oldFlags = 0;
eop = (EvOffsets *) shmem_addr;
if (!clean) {
oldFlags = ((EvGlobals *)((char *)shmem_addr + sizeof(EvOffsets)))->eventFlags;
}
bzero( (void*)shmem_addr, shmem_size);
eop->evGlobalsOffset = sizeof(EvOffsets);
eop->evShmemOffset = eop->evGlobalsOffset + sizeof(EvGlobals);
evg = (EvGlobals *)((char *)shmem_addr + eop->evGlobalsOffset);
evs = (void *)((char *)shmem_addr + eop->evShmemOffset);
evg->version = kIOHIDCurrentShmemVersion;
evg->structSize = sizeof( EvGlobals);
evg->waitCursorEnabled = TRUE;
evg->globalWaitCursorEnabled = TRUE;
evg->lastFrame = maxWaitCursorFrame;
evg->waitThreshold = (12 * EV_TICKS_PER_SEC) / 10;
evg->buttons = 0;
evg->eNum = INITEVENTNUM;
evg->eventFlags = oldFlags;
evg->cursorLoc.x = _cursorHelper.desktopLocation().xValue().as32();
evg->cursorLoc.y = _cursorHelper.desktopLocation().yValue().as32();
evg->desktopCursorFixed.x = _cursorHelper.desktopLocation().xValue().asFixed24x8();
evg->desktopCursorFixed.y = _cursorHelper.desktopLocation().yValue().asFixed24x8();
evg->screenCursorFixed.x = _cursorHelper.getScreenLocation().xValue().asFixed24x8();
evg->screenCursorFixed.y = _cursorHelper.getScreenLocation().yValue().asFixed24x8();
evg->updateCursorPositionFromFixed = 0;
evg->logCursorUpdates = 0;
evg->dontCoalesce = 0;
evg->dontWantCoalesce = 0;
evg->wantPressure = 0;
evg->wantPrecision = 0;
evg->mouseRectValid = 0;
evg->movedMask = 0;
evg->cursorSema = OS_SPINLOCK_INIT;
evg->waitCursorSema = OS_SPINLOCK_INIT;
lleqSize = LLEQSIZE;
for (i=lleqSize; --i != -1; ) {
evg->lleq[i].event.type = 0;
AbsoluteTime_to_scalar(&evg->lleq[i].event.time) = 0;
evg->lleq[i].event.flags = 0;
evg->lleq[i].sema = OS_SPINLOCK_INIT;
evg->lleq[i].next = i+1;
}
evg->LLELast = 0;
evg->lleq[lleqSize-1].next = 0;
evg->LLEHead = evg->lleq[evg->LLELast].next;
evg->LLETail = evg->lleq[evg->LLELast].next;
_cursorLogTimed();
eventsOpen = true;
}
void IOHIDSystem::setEventPort(mach_port_t port)
{
if ((eventPort != port) && (workLoop))
workLoop->runAction((IOWorkLoop::Action)&IOHIDSystem::doSetEventPort, this, (void*)port);
}
IOReturn IOHIDSystem::doSetEventPort(IOHIDSystem *self, void *port_void, void *arg1 __unused, void *arg2 __unused, void *arg3 __unused)
{
self->setEventPortGated((mach_port_t)port_void);
return kIOReturnSuccess;
}
void IOHIDSystem::setEventPortGated(mach_port_t port)
{
static struct _eventMsg init_msg = { {
MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,0),
sizeof (struct _eventMsg),
MACH_PORT_NULL,
MACH_PORT_NULL,
0,
0
} };
init_msg.h.msgh_remote_port = port;
if ( eventMsg == NULL )
eventMsg = IOMalloc( sizeof (struct _eventMsg) );
*((struct _eventMsg *)eventMsg) = init_msg;
eventPort = port;
if (EventsInQueue())
kickEventConsumer();
}
IOReturn IOHIDSystem::setSpecialKeyPort(
int special_key,
mach_port_t key_port)
{
if ( special_key >= 0 && special_key < NX_NUM_SCANNED_SPECIALKEYS )
_specialKeyPort[special_key] = key_port;
return kIOReturnSuccess;
}
mach_port_t IOHIDSystem::specialKeyPort(int special_key)
{
if ( special_key >= 0 && special_key < NX_NUM_SCANNED_SPECIALKEYS )
return _specialKeyPort[special_key];
return MACH_PORT_NULL;
}
void IOHIDSystem::setStackShotPort(mach_port_t port)
{
stackShotPort = port;
static _stackShotMessage init_msg =
{
{ MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,0), sizeof (init_msg), MACH_PORT_NULL, MACH_PORT_NULL, 0, 0 },
0 };
if ( stackShotMsg ) {
IOFree(stackShotMsg, sizeof(_stackShotMessage));
stackShotMsg = NULL;
}
if ( stackShotPort ) {
if ( !(stackShotMsg = IOMalloc(sizeof(_stackShotMessage))) )
return;
init_msg.header.msgh_remote_port = stackShotPort;
*((_stackShotMessage*)stackShotMsg) = init_msg;
}
}
UInt32 IOHIDSystem::eventFlags()
{
return evg ? (evg->eventFlags) : 0;
}
void IOHIDSystem::dispatchEvent(IOHIDEvent *event, IOOptionBits options __unused)
{
if ( !event || !dataQueueSet)
return;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection(dataQueueSet);
IOHIDEventServiceQueue * dataQueue = NULL;
if ( !iterator )
return;
while ((dataQueue = OSDynamicCast(IOHIDEventServiceQueue, iterator->getNextObject()))) {
dataQueue->enqueueEvent(event);
}
iterator->release();
}
void IOHIDSystem::updateHidActivity()
{
#if !TARGET_OS_EMBEDDED
clock_get_uptime(&_lastTickleTime);
if (_hidActivityIdle)
thread_call_enter(_hidActivityThread);
#endif
}
void IOHIDSystem::hidActivityChecker( )
{
cmdGate->runAction((IOCommandGate::Action)reportUserHidActivity, NULL);
}
void IOHIDSystem::reportUserHidActivity(IOHIDSystem *self, void *args )
{
self->reportUserHidActivityGated(args);
}
void IOHIDSystem::reportUserHidActivityGated(void *args __unused)
{
AbsoluteTime deadline = 0;
AbsoluteTime ts;
static AbsoluteTime idleHidActivity = 0;
if (!idleHidActivity)
nanoseconds_to_absolutetime(IDLE_HID_ACTIVITY_NSECS, &idleHidActivity);
clock_get_uptime(&ts);
if ((ts-_lastTickleTime) < idleHidActivity) {
if (_hidActivityIdle) {
_hidActivityIdle = false;
messageClients(kIOHIDSystemUserHidActivity, (void *)_hidActivityIdle );
}
clock_absolutetime_interval_to_deadline((idleHidActivity+_lastTickleTime-ts), &deadline);
thread_call_enter_delayed(_hidActivityThread, deadline);
}
else if ( !_hidActivityIdle ) {
_hidActivityIdle = true;
messageClients(kIOHIDSystemUserHidActivity, (void *)_hidActivityIdle );
}
}
IOReturn IOHIDSystem::extGetUserHidActivityState(void *arg0,void*,void*,void*,void*,void*)
{
return cmdGate->runAction((IOCommandGate::Action)getUserHidActivityState, arg0);
}
IOReturn IOHIDSystem::getUserHidActivityState(IOHIDSystem *self, void *arg0)
{
return self->getUserHidActivityStateGated(arg0);
}
IOReturn IOHIDSystem::getUserHidActivityStateGated(void *state)
{
if (state) {
*((uint64_t*)state) = _hidActivityIdle ? 1 : 0;
return kIOReturnSuccess;
}
return kIOReturnBadArgument;
}
static inline int myAbs(int a) { return(a > 0 ? a : -a); }
short IOHIDSystem::getUniqueEventNum()
{
while (++evg->eNum == NULLEVENTNUM)
;
return(evg->eNum);
}
void IOHIDSystem::postEvent(int what,
IOFixedPoint64 *location,
AbsoluteTime ts,
NXEventData * myData,
OSObject * sender,
UInt32 extPID,
bool processKEQ)
{
PROFILE_TRACE(7);
if ( processKEQ )
processKeyboardEQ(this, &ts);
NXEQElement * theHead = (NXEQElement *) &evg->lleq[evg->LLEHead];
NXEQElement * theLast = (NXEQElement *) &evg->lleq[evg->LLELast];
NXEQElement * theTail = (NXEQElement *) &evg->lleq[evg->LLETail];
int wereEvents;
if (CMP_ABSOLUTETIME(&ts, &lastEventTime) < 0) {
ts = lastEventTime;
}
lastEventTime = ts;
IOHIDEvent * event = IOHIDEvent::withEventData(ts, what, myData);
if ( event ) {
dispatchEvent(event);
event->release();
}
if (EventCodeMask(what) & NX_UNDIMMASK) {
lastUndimEvent = ts;
}
wereEvents = EventsInQueue();
xpr_ev_post("postEvent: what %d, X %d Y %d Q %d, needKick %d\n", what,location->x,location->y, EventsInQueue(), needToKickEventConsumer);
IOHID_DEBUG(kIOHIDDebugCode_PostEvent, what, theHead, theTail, sender);
if ((!evg->dontCoalesce)
&& (theHead != theTail)
&& (theLast->event.type == what)
&& (EventCodeMask(what) & COALESCEEVENTMASK)
&& OSSpinLockTry(&theLast->sema)) {
theLast->event.location.x = location->xValue().as64();
theLast->event.location.y = location->yValue().as64();
absolutetime_to_nanoseconds(ts, &theLast->event.time);
if (myData != NULL)
theLast->event.data = *myData;
OSSpinLockUnlock(&theLast->sema);
}
else if (theTail->next != evg->LLEHead) {
theTail->event.type = what;
theTail->event.service_id = 0;
if (sender) {
IORegistryEntry *entry = OSDynamicCast(IORegistryEntry, sender);
if (entry) {
theTail->event.service_id = (uintptr_t)entry->getRegistryEntryID();
}
}
theTail->event.ext_pid = extPID;
theTail->event.location.x = location->xValue().as64();
theTail->event.location.y = location->yValue().as64();
theTail->event.flags = evg->eventFlags;
absolutetime_to_nanoseconds(ts, &theLast->event.time);
theTail->event.window = 0;
if (myData != NULL)
theTail->event.data = *myData;
switch (what) {
case NX_LMOUSEDOWN:
theTail->event.data.mouse.eventNum =
leftENum = getUniqueEventNum();
break;
case NX_RMOUSEDOWN:
theTail->event.data.mouse.eventNum =
rightENum = getUniqueEventNum();
break;
case NX_LMOUSEUP:
theTail->event.data.mouse.eventNum = leftENum;
leftENum = NULLEVENTNUM;
notifyHIDevices(this, ioHIDevices, kIOHIDSystem508MouseClickMessage);
break;
case NX_RMOUSEUP:
theTail->event.data.mouse.eventNum = rightENum;
rightENum = NULLEVENTNUM;
notifyHIDevices(this, ioHIDevices, kIOHIDSystem508MouseClickMessage);
break;
}
if (EventCodeMask(what) & PRESSUREEVENTMASK) {
if (!((EventCodeMask(what) & MOUSEEVENTMASK) || (EventCodeMask(what) & MOVEDEVENTMASK)))
IOLog("%s: postEvent unknown pressure event, cannot fill pressure.\n", registryName);
}
if (EventCodeMask(what) & MOUSEEVENTMASK) {
AbsoluteTime delta = ts;
SUB_ABSOLUTETIME( &delta, &clickTime);
if ((CMP_ABSOLUTETIME(&delta, &clickTimeThresh) <= 0)
&& (myAbs(location->xValue().as64() - clickLoc.x) <= clickSpaceThresh.x)
&& (myAbs(location->yValue().as64() - clickLoc.y) <= clickSpaceThresh.y)) {
if ((what == NX_LMOUSEDOWN)||(what == NX_RMOUSEDOWN)) {
clickTime = ts;
theTail->event.data.mouse.click = ++clickState;
}
else {
theTail->event.data.mouse.click = clickState;
}
}
else if ((what == NX_LMOUSEDOWN)||(what == NX_RMOUSEDOWN)) {
clickLoc = *location;
clickTime = ts;
clickState = 1;
theTail->event.data.mouse.click = clickState;
}
else
theTail->event.data.mouse.click = 0;
}
#if PMON
pmon_log_event(PMON_SOURCE_EV,
KP_EV_POST_EVENT,
what,
evg->eventFlags,
theClock);
#endif
evg->LLETail = theTail->next;
evg->LLELast = theLast->next;
if ( ! wereEvents ) kickEventConsumer();
}
else {
static uint64_t next_log = 0;
if (AbsoluteTime_to_scalar(&ts) > next_log)
{
IOLog("%s: postEvent LLEventQueue overflow.\n", registryName);
nanoseconds_to_absolutetime(60000000000LL, (AbsoluteTime*)&next_log);
next_log += AbsoluteTime_to_scalar(&ts);
}
kickEventConsumer();
#if PMON
pmon_log_event( PMON_SOURCE_EV,
KP_EV_QUEUE_FULL,
what,
evg->eventFlags,
theClock);
#endif
}
PROFILE_TRACE(8);
}
void IOHIDSystem::kickEventConsumer()
{
xpr_ev_post("kickEventConsumer (need == %d)\n",
needToKickEventConsumer,2,3,4,5);
if ( needToKickEventConsumer == true )
return;
needToKickEventConsumer = true;
eventConsumerES->interruptOccurred(0, 0, 0);
}
void IOHIDSystem::sendStackShotMessage(UInt32 flavor)
{
kern_return_t r;
mach_msg_header_t *msgh;
xpr_ev_post("sendStackShotMessage\n", 1,2,3,4,5);
if (stackShotMsg) {
((_stackShotMessage*)stackShotMsg)->flavor = flavor;
msgh = (mach_msg_header_t *)stackShotMsg;
if( msgh) {
r = mach_msg_send_from_kernel( msgh, msgh->msgh_size);
switch ( r ) {
case MACH_SEND_TIMED_OUT:
case MACH_MSG_SUCCESS:
break;
default:
IOLog("%s: sendStackShotMessage msg_send returned %d\n", registryName, r);
break;
}
}
}
}
void IOHIDSystem::doSpecialKeyMsg(IOHIDSystem * self,
struct evioSpecialKeyMsg *msg)
{
kern_return_t r;
xpr_ev_post("doSpecialKeyMsg 0x%x\n", msg,2,3,4,5);
r = mach_msg_send_from_kernel( &msg->Head, msg->Head.msgh_size);
xpr_ev_post("doSpecialKeyMsg: msg_send() == %d\n",r,2,3,4,5);
if ( r != MACH_MSG_SUCCESS )
{
IOLog("%s: doSpecialKeyMsg msg_send returned %d\n",
self->registryName, r);
}
if ( r == MACH_SEND_INVALID_DEST )
{
self->setSpecialKeyPort(
msg->key,
MACH_PORT_NULL);
}
IOFree( (void *)msg, sizeof (struct evioSpecialKeyMsg) );
}
void IOHIDSystem::doKickEventConsumer(IOHIDSystem * self)
{
kern_return_t r;
mach_msg_header_t *msgh;
self->needToKickEventConsumer = false;
if ( self->eventPort == MACH_PORT_NULL )
return;
xpr_ev_post("doKickEventConsumer\n", 1,2,3,4,5);
msgh = (mach_msg_header_t *)self->eventMsg;
if( msgh) {
r = mach_msg_send_from_kernel( msgh, msgh->msgh_size);
switch ( r )
{
case MACH_SEND_TIMED_OUT:
case MACH_MSG_SUCCESS:
break;
default:
IOLog("%s: doKickEventConsumer msg_send returned %d\n",
self->registryName, r);
break;
}
}
}
void IOHIDSystem::scheduleNextPeriodicEvent()
{
if ( !eventsOpen ) {
IOHID_DEBUG(kIOHIDDebugCode_Scheduling, 0, 0, 0, 0);
}
else {
uint64_t soon; uint64_t scheduledEvent = _periodicEventNext;
clock_interval_to_deadline(1, kMillisecondScale, &soon);
if ((scheduledEvent > _periodicEventLast) && (scheduledEvent < soon)) {
}
else {
if (scheduledEvent <= _periodicEventLast) {
scheduledEvent = UINT64_MAX;
}
if (screens && (kIOPMDeviceUsable | displayState)) {
uint64_t nextMove = _cursorMoveLast + _cursorMoveDelta;
uint64_t nextWait = _cursorWaitLast + _cursorWaitDelta;
if (_cursorMoveDelta) {
if (_cursorEventLast > _cursorMoveLast) {
scheduledEvent = nextMove;
}
}
if (_cursorWaitDelta && evg->waitCursorEnabled && evg->globalWaitCursorEnabled) {
if (scheduledEvent > nextWait) {
scheduledEvent = nextWait;
}
}
IOHID_DEBUG(kIOHIDDebugCode_Scheduling, scheduledEvent, nextMove, nextWait, 0);
}
else {
clock_interval_to_deadline(30, kMillisecondScale, &scheduledEvent);
IOHID_DEBUG(kIOHIDDebugCode_Scheduling, scheduledEvent, 0, 0, 0);
}
if (UINT64_MAX == scheduledEvent) {
periodicES->cancelTimeout();
}
else {
_periodicEventNext = scheduledEvent;
IOReturn err = periodicES->wakeAtTime(_periodicEventNext);
if (err) {
IOLog("%s:%d wakeAtTime failed for %lld: %08x (%s)\n", __func__, __LINE__, _periodicEventNext, err, stringFromReturn(err));
}
}
}
}
}
void IOHIDSystem::_periodicEvents(IOHIDSystem * self,
IOTimerEventSource *timer)
{
self->periodicEvents(timer);
}
void IOHIDSystem::periodicEvents(IOTimerEventSource * timer __unused)
{
if ( !eventsOpen )
return;
clock_get_uptime(&_periodicEventLast); _periodicEventNext = UINT64_MAX;
if (_periodicEventLast >= _cursorMoveLast + _cursorMoveDelta) {
_cursorHelper.startPosting();
_cursorHelper.applyPostingDelta();
_setCursorPosition(false, false, lastSender);
OSSafeReleaseNULL(lastSender);
_cursorMoveLast = _periodicEventLast;
}
if ( OSSpinLockTry(&evg->waitCursorSema) )
{
if ( OSSpinLockTry(&evg->cursorSema) )
{
if (evg->waitCursorEnabled && evg->globalWaitCursorEnabled)
{
if (!evg->waitCursorUp) {
showWaitCursor();
_cursorWaitLast = _periodicEventLast;
}
}
else {
if (evg->waitCursorUp && ((_cursorWaitLast + _cursorWaitDelta) < _periodicEventLast)) {
hideWaitCursor();
_cursorWaitLast = _periodicEventLast;
}
}
if (evg->waitCursorUp && ((_cursorWaitLast + _cursorWaitDelta) < _periodicEventLast)) {
animateWaitCursor();
_cursorWaitLast = _periodicEventLast;
}
OSSpinLockUnlock(&evg->cursorSema);
}
OSSpinLockUnlock(&evg->waitCursorSema);
}
scheduleNextPeriodicEvent();
return;
}
bool IOHIDSystem::resetCursor()
{
volatile IOGPoint * p;
UInt32 newScreens = 0;
SInt32 candidate = 0;
SInt32 pinScreen = -1L;
p = &evg->cursorLoc;
EvScreen *screen = (EvScreen *)evScreen;
for (int i = 0; i < screens; i++ ) {
if (!screen[i].desktopBounds)
continue;
if ((screen[i].desktopBounds->maxx - screen[i].desktopBounds->minx) < 128)
continue;
candidate = i;
if (_cursorHelper.desktopLocation().inRect(*screen[i].desktopBounds)) {
pinScreen = i;
newScreens |= (1 << i);
}
}
if (newScreens == 0)
pinScreen = candidate;
if (!cursorPinned) {
if (((EvScreen*)evScreen)[pinScreen].desktopBounds) {
cursorPin = *(((EvScreen*)evScreen)[pinScreen].desktopBounds);
cursorPin.maxx--;
cursorPin.maxy--;
cursorPinScreen = pinScreen;
}
else {
}
}
if (newScreens == 0) {
p->x = (p->x < cursorPin.minx) ?
cursorPin.minx : ((p->x > cursorPin.maxx) ?
cursorPin.maxx : p->x);
p->y = (p->y < cursorPin.miny) ?
cursorPin.miny : ((p->y > cursorPin.maxy) ?
cursorPin.maxy : p->y);
for (int i = 0; i < screens; i++ ) {
if (!screen[i].desktopBounds)
continue;
if ((screen[i].desktopBounds->maxx - screen[i].desktopBounds->minx) < 128)
continue;
if (_cursorHelper.desktopLocation().inRect(*screen[i].desktopBounds)){
pinScreen = i;
newScreens |= (1 << i);
}
}
}
cursorScreens = newScreens;
IOFixedPoint64 tempLoc;
if (evg->updateCursorPositionFromFixed) {
tempLoc.fromFixed24x8(evg->desktopCursorFixed.x, evg->desktopCursorFixed.y);
}
else {
tempLoc.fromIntFloor(evg->cursorLoc.x, evg->cursorLoc.y);
}
_cursorHelper.desktopLocationDelta() += tempLoc - _cursorHelper.desktopLocation();
_cursorHelper.desktopLocation() = tempLoc;
if (pinScreen >= 0) {
_cursorHelper.updateScreenLocation(screen[pinScreen].desktopBounds, screen[pinScreen].displayBounds);
}
else {
_cursorHelper.updateScreenLocation(NULL, NULL);
}
_cursorMoveDelta = _cursorWaitDelta = 0;
_cursorHelper.desktopLocationPosting().fromIntFloor(0, 0);
_cursorHelper.clearEventCounts();
_cursorLogTimed();
scheduleNextPeriodicEvent();
return( true );
}
bool IOHIDSystem::startCursor()
{
if (0 == screens) {
}
else {
cursorPinned = false;
resetCursor();
showCursor();
scheduleNextPeriodicEvent();
cursorStarted = true;
}
return( cursorStarted );
}
void IOHIDSystem::showWaitCursor()
{
xpr_ev_cursor("showWaitCursor\n",1,2,3,4,5);
evg->waitCursorUp = true;
hideCursor();
evg->frame = EV_WAITCURSOR;
showCursor();
}
void IOHIDSystem::hideWaitCursor()
{
xpr_ev_cursor("hideWaitCursor\n",1,2,3,4,5);
evg->waitCursorUp = false;
hideCursor();
evg->frame = EV_STD_CURSOR;
showCursor();
}
void IOHIDSystem::animateWaitCursor()
{
xpr_ev_cursor("animateWaitCursor\n",1,2,3,4,5);
changeCursor(evg->frame + 1);
}
void IOHIDSystem::changeCursor(int frame)
{
evg->frame = ((frame > (int)maxWaitCursorFrame) || (frame > evg->lastFrame)) ? firstWaitCursorFrame : frame;
xpr_ev_cursor("changeCursor %d\n",evg->frame,2,3,4,5);
moveCursor();
}
int IOHIDSystem::pointToScreen(IOGPoint * p)
{
int i;
EvScreen *screen = (EvScreen *)evScreen;
for (i=screens; --i != -1; ) {
if ((screen[i].desktopBounds != 0)
&& (p->x >= screen[i].desktopBounds->minx)
&& (p->x < screen[i].desktopBounds->maxx)
&& (p->y >= screen[i].desktopBounds->miny)
&& (p->y < screen[i].desktopBounds->maxy))
return i;
}
return(-1);
}
inline void IOHIDSystem::showCursor()
{
evDispatch( EVSHOW);
}
inline void IOHIDSystem::hideCursor()
{
evDispatch( EVHIDE);
}
inline void IOHIDSystem::moveCursor()
{
evDispatch( EVMOVE);
}
void IOHIDSystem::attachDefaultEventSources()
{
IOService * source;
OSIterator * sources;
sources = getProviderIterator();
if (!sources) return;
while( (source = (IOService *)sources->getNextObject())) {
if ((OSDynamicCast(IOHIDevice, source) && !OSDynamicCast(IOHIKeyboard, source))
|| OSDynamicCast(IOHIDEventService, source)) {
registerEventSource(source);
}
}
sources->release();
}
void IOHIDSystem::detachEventSources()
{
OSIterator * iter;
IOService * srcInstance;
iter = getOpenProviderIterator();
if( iter) {
while( (srcInstance = (IOService *) iter->getNextObject())) {
if ( ! OSDynamicCast(IOHIKeyboard, srcInstance) ) {
#ifdef DEBUG
kprintf("detachEventSource:%s\n", srcInstance->getName());
#endif
srcInstance->close(this);
}
}
iter->release();
}
}
bool IOHIDSystem::registerEventSource(IOService * source)
{
bool success = false;
#ifdef DEBUG
kprintf("registerEventSource:%s\n", source->getName());
#endif
if ( OSDynamicCast(IOHIKeyboard, source) ) {
success = ((IOHIKeyboard*)source)->open(this, kIOServiceSeize,0,
(KeyboardEventCallback) _keyboardEvent,
(KeyboardSpecialEventCallback) _keyboardSpecialEvent,
(UpdateEventFlagsCallback) _updateEventFlags);
source->setProperty(kIOHIDResetKeyboardKey, kOSBooleanTrue);
} else if ( OSDynamicCast(IOHIPointing, source) ) {
if ( OSDynamicCast(IOHITablet, source) ) {
success = ((IOHITablet*)source)->open(this, kIOServiceSeize,0,
(RelativePointerEventCallback) _relativePointerEvent,
(AbsolutePointerEventCallback) _absolutePointerEvent,
(ScrollWheelEventCallback) _scrollWheelEvent,
(TabletEventCallback) _tabletEvent,
(ProximityEventCallback) _proximityEvent);
} else {
success = ((IOHIPointing*)source)->open(this, kIOServiceSeize,0,
(RelativePointerEventCallback) _relativePointerEvent,
(AbsolutePointerEventCallback) _absolutePointerEvent,
(ScrollWheelEventCallback) _scrollWheelEvent);
}
source->setProperty(kIOHIDResetPointerKey, kOSBooleanTrue);
} else {
success = source->open(this, kIOServiceSeize, 0);
}
if ( success )
{
OSDictionary * newParams = OSDictionary::withDictionary( savedParameters );
if( newParams) {
if ( OSDynamicCast(IOHIDevice, source) )
((IOHIDevice *)source)->setParamProperties( newParams );
else if ( OSDynamicCast(IOHIDEventService, source) )
((IOHIDEventService *)source)->setSystemProperties( newParams );
setProperty( kIOHIDParametersKey, newParams );
newParams->release();
savedParameters = newParams;
}
}
else
IOLog("%s: Seize of %s failed.\n", registryName, source->getName());
return success;
}
IOReturn IOHIDSystem::message(UInt32 type, IOService * provider,
void * argument)
{
IOReturn status = kIOReturnSuccess;
switch (type)
{
case kIOMessageServiceIsTerminated:
provider->close( this );
case kIOMessageServiceWasClosed:
break;
case kIOHIDSystemActivityTickle: {
intptr_t nxEvent = (intptr_t) argument;
if ((nxEvent >= 0) && (nxEvent <= NX_LASTEVENT)) {
if (!evStateChanging && displayManager) {
IOHID_DEBUG(kIOHIDDebugCode_DisplayTickle, nxEvent, __LINE__, displayState,
provider ? provider->getRegistryEntryID() : 0);
if (DISPLAY_IS_ENABLED || (NX_WAKEMASK & EventCodeMask(nxEvent))) {
if (!DISPLAY_IS_ENABLED) {
kprintf("IOHIDSystem tickle when screen off for event %ld\n", nxEvent);
}
displayManager->activityTickle(IOHID_DEBUG_CODE(nxEvent));
}
}
}
else if (nxEvent == NX_HARDWARE_TICKLE) {
if (!evStateChanging && displayManager) {
IOHID_DEBUG(kIOHIDDebugCode_DisplayTickle, nxEvent, __LINE__, displayState,
provider ? provider->getRegistryEntryID() : 0);
if (!DISPLAY_IS_ENABLED) {
kprintf("IOHIDSystem tickle when screen off for hardware event from %08llx\n",
provider ? provider->getRegistryEntryID() : 0);
}
displayManager->activityTickle(IOHID_DEBUG_CODE(nxEvent));
}
}
else {
IOLog("kIOHIDSystemActivityTickle message for unsupported event %ld sent from %08llx\n",
nxEvent, provider ? provider->getRegistryEntryID() : 0);
}
break;
}
default:
status = super::message(type, provider, argument);
break;
}
return status;
}
void IOHIDSystem::scaleLocationToCurrentScreen(IOGPoint *location, IOGBounds *bounds __unused)
{
IOHIDSystem * hidsystem = instance();
if ( hidsystem ) {
IOFixedPoint64 temp;
temp.fromIntFloor(location->x, location->y);
hidsystem->_scaleLocationToCurrentScreen(temp, bounds);
*location = (IOGPoint)temp;
}
}
void IOHIDSystem::_scaleLocationToCurrentScreen(IOFixedPoint64 &location, IOGBounds *bounds)
{
if (!bounds) {
}
else {
if (*(UInt64*)&cursorPin == *(UInt64*)bounds) {
}
else {
int boundsWidth = bounds->maxx - bounds->minx;
int boundsHeight = bounds->maxy - bounds->miny;
int cursorPinWidth = cursorPin.maxx - cursorPin.minx;
int cursorPinHeight = cursorPin.maxy - cursorPin.miny;
if ((boundsWidth <= 0) || (boundsHeight <= 0) || (cursorPinWidth <= 0) || (cursorPinHeight <= 0)) {
}
else {
IOFixedPoint64 scratch;
if ((boundsWidth == cursorPinWidth) && (boundsHeight == cursorPinHeight)) {
location += scratch.fromIntFloor(bounds->minx - cursorPin.minx,
bounds->miny - cursorPin.miny);
}
else {
IOFixed64 x_scale;
IOFixed64 y_scale;
x_scale.fromIntFloor(cursorPinWidth) /= boundsWidth;
y_scale.fromIntFloor(cursorPinHeight) /= boundsHeight;
location -= scratch.fromIntFloor(bounds->minx, bounds->miny);
location *= scratch.fromFixed64(x_scale, y_scale);
location += scratch.fromIntFloor(cursorPin.minx, cursorPin.miny);
}
}
}
}
return;
}
void IOHIDSystem::_relativePointerEvent(IOHIDSystem * self,
int buttons,
int dx,
int dy,
AbsoluteTime ts,
OSObject * sender,
void * refcon __unused)
{
self->relativePointerEvent(buttons, dx, dy, ts, sender);
}
void IOHIDSystem::relativePointerEvent(int buttons,
int dx,
int dy,
AbsoluteTime ts)
{
relativePointerEvent(buttons, dx, dy, ts, 0);
}
void IOHIDSystem::relativePointerEvent(int buttons,
int dx,
int dy,
AbsoluteTime ts,
OSObject * sender)
{
IOHIDCmdGateActionArgs args;
args.arg0 = &buttons;
args.arg1 = &dx;
args.arg2 = &dy;
args.arg3 = &ts;
args.arg4 = sender;
cmdGate->runAction((IOCommandGate::Action)doRelativePointerEvent, &args);
}
IOReturn IOHIDSystem::doRelativePointerEvent(IOHIDSystem *self, void * args)
{
int buttons = *(int *)((IOHIDCmdGateActionArgs *)args)->arg0;
int dx = *(int *)((IOHIDCmdGateActionArgs *)args)->arg1;
int dy = *(int *)((IOHIDCmdGateActionArgs *)args)->arg2;
SInt64 ts = *(SInt64 *)((IOHIDCmdGateActionArgs *)args)->arg3;
OSObject * sender = (OSObject *)((IOHIDCmdGateActionArgs *)args)->arg4;
self->relativePointerEventGated(buttons, dx, dy, ts, sender);
return kIOReturnSuccess;
}
static bool vblForScreen(IOGraphicsDevice *io_gd_I, uint64_t &delta_O)
{
uint64_t nextVBL = 0;
static UInt64 minVBLdelta = 0;
static UInt64 maxVBLdelta = 0;
if (!minVBLdelta) {
nanoseconds_to_absolutetime(50000000, (&maxVBLdelta));
nanoseconds_to_absolutetime(5000000, (&minVBLdelta));
}
if (io_gd_I) {
io_gd_I->getVBLTime( &nextVBL, &delta_O );
if (delta_O < minVBLdelta) {
delta_O = minVBLdelta;
}
else if (delta_O > maxVBLdelta) {
delta_O = maxVBLdelta;
}
}
else {
delta_O = maxVBLdelta;
}
return (nextVBL != 0);
}
void IOHIDSystem::relativePointerEventGated(int buttons, int dx_I, int dy_I, SInt64 ts, OSObject * sender)
{
bool movementEvent = false;
PROFILE_TRACE(1);
if( eventsOpen == false )
return;
CachedMouseEventStruct *cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender);
if (cachedMouseEvent) {
UInt64 ts_nano;
absolutetime_to_nanoseconds(ts, &ts_nano);
if (ts_nano > cachedMouseEvent->eventDeadline) {
cachedMouseEvent->eventDeadline = ts_nano + kIOHIDChattyMouseSuppressionDelayNS;
cachedMouseEvent->accumX = 0;
cachedMouseEvent->accumY = 0;
}
cachedMouseEvent->accumX += dx_I;
cachedMouseEvent->accumY += dy_I;
if ((abs(cachedMouseEvent->accumX) >= kIOHIDRelativeTickleThresholdPixel) ||
(abs(cachedMouseEvent->accumY) >= kIOHIDRelativeTickleThresholdPixel))
{
movementEvent = true;
}
cachedMouseEvent->lastButtons = buttons;
cachedMouseEvent->eventDeadline = ts_nano;
if( (buttons & EV_LB) != (evg->buttons & EV_LB) ){
cachedMouseEvent->lastPressure = ( buttons & EV_LB ) ? MAXPRESSURE : MINPRESSURE;
}
}
if (buttons & EV_LB) {
TICKLE_DISPLAY(NX_LMOUSEDOWN);
}
else if (buttons & EV_RB) {
TICKLE_DISPLAY(NX_RMOUSEDOWN);
}
else if (buttons) {
TICKLE_DISPLAY(NX_OMOUSEDOWN);
}
else if (movementEvent) {
if (DISPLAY_IS_ENABLED) {
TICKLE_DISPLAY(NX_MOUSEMOVED);
}
else
{
if (CMP_ABSOLUTETIME(&ts, &displaySleepWakeupDeadline) <= 0) {
TICKLE_DISPLAY(NX_MOUSEMOVED);
}
return;
}
}
if (ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline)) {
return;
}
_setButtonState(buttons, ts, sender);
_cursorHelper.incrementEventCount();
IOFixedPoint64 scratch;
if ( scratch.fromIntFloor(dx_I, dy_I) ) {
UInt64 uptime = 0;
bool haveVBL = vblForScreen(((EvScreen*)evScreen)[cursorPinScreen].instance, _cursorMoveDelta);
clock_get_uptime(&uptime);
if (((scratch.xValue() > 0LL) && (_cursorHelper.desktopLocationAccumulated().xValue() < 0LL)) ||
((scratch.xValue() < 0LL) && (_cursorHelper.desktopLocationAccumulated().xValue() > 0LL))) {
_cursorHelper.desktopLocationAccumulated().xValue().fromIntFloor(0);
}
if (((scratch.yValue() > 0LL) && (_cursorHelper.desktopLocationAccumulated().yValue() < 0LL)) ||
((scratch.yValue() < 0LL) && (_cursorHelper.desktopLocationAccumulated().yValue() > 0LL))) {
_cursorHelper.desktopLocationAccumulated().yValue().fromIntFloor(0);
}
IOHID_DEBUG(kIOHIDDebugCode_RelativePointerEventTiming, _cursorMoveDelta, 0,
dx_I, dy_I);
_cursorHelper.desktopLocationAccumulated() += scratch;
scratch = _cursorHelper.desktopLocationAccumulated(); _cursorEventLast = uptime;
if (!haveVBL) {
periodicEvents(NULL);
}
else {
if (cachedMouseEvent && (cachedMouseEvent->reportInterval_ns > 0)) {
uint64_t cursorMoveDelta_ns;
absolutetime_to_nanoseconds(_cursorMoveDelta, &cursorMoveDelta_ns);
_cursorHelper.expectedCount().fromIntFloor(cursorMoveDelta_ns);
_cursorHelper.expectedCount() /= cachedMouseEvent->reportInterval_ns;
IOHID_DEBUG(kIOHIDDebugCode_RelativePointerEventScaling,
scratch.xValue().asFixed(), scratch.yValue().asFixed(),
_cursorHelper.expectedCount().asFixed(),
_cursorHelper.getEventCountPosting() * 65536);
}
else {
_cursorHelper.expectedCount().fromIntFloor(0);
}
if (sender)
sender->retain();
OSSafeReleaseNULL(lastSender);
lastSender = sender;
if (uptime > _cursorMoveLast + 2 * _cursorMoveDelta) {
periodicEvents(periodicES); }
else {
scheduleNextPeriodicEvent();
}
}
_cursorLog(AbsoluteTime_to_scalar(&ts));
}
PROFILE_TRACE(2);
}
void IOHIDSystem::_absolutePointerEvent(
IOHIDSystem * self,
int buttons,
IOGPoint * newLoc,
IOGBounds * bounds,
bool proximity,
int pressure,
int stylusAngle,
AbsoluteTime ts,
OSObject * sender,
void * refcon __unused)
{
self->absolutePointerEvent(buttons, newLoc, bounds, proximity,
pressure, stylusAngle, ts, sender);
}
void IOHIDSystem::absolutePointerEvent(
int buttons,
IOGPoint * newLoc,
IOGBounds * bounds,
bool proximity,
int pressure,
int stylusAngle,
AbsoluteTime ts)
{
absolutePointerEvent(buttons, newLoc, bounds, proximity,
pressure, stylusAngle, ts, 0);
}
void IOHIDSystem::absolutePointerEvent(
int buttons,
IOGPoint * newLoc,
IOGBounds * bounds,
bool proximity,
int pressure,
int stylusAngle,
AbsoluteTime ts,
OSObject * sender)
{
IOHIDCmdGateActionArgs args;
args.arg0 = &buttons;
args.arg1 = (void *)newLoc;
args.arg2 = (void *)bounds;
args.arg3 = &proximity;
args.arg4 = &pressure;
args.arg5 = &stylusAngle;
args.arg6 = &ts;
args.arg7 = sender;
cmdGate->runAction((IOCommandGate::Action)doAbsolutePointerEvent, &args);
}
IOReturn IOHIDSystem::doAbsolutePointerEvent(IOHIDSystem *self, void * args)
{
int buttons = *(int *) ((IOHIDCmdGateActionArgs *)args)->arg0;
IOGPoint * newLoc = (IOGPoint *) ((IOHIDCmdGateActionArgs *)args)->arg1;
IOGBounds * bounds = (IOGBounds *) ((IOHIDCmdGateActionArgs *)args)->arg2;
bool proximity = *(bool *) ((IOHIDCmdGateActionArgs *)args)->arg3;
int pressure = *(int *) ((IOHIDCmdGateActionArgs *)args)->arg4;
int stylusAngle = *(int *) ((IOHIDCmdGateActionArgs *)args)->arg5;
AbsoluteTime ts = *(AbsoluteTime *) ((IOHIDCmdGateActionArgs *)args)->arg6;
OSObject * sender = (OSObject *)((IOHIDCmdGateActionArgs *)args)->arg7;
self->absolutePointerEventGated(buttons, newLoc, bounds, proximity, pressure, stylusAngle, ts, sender);
return kIOReturnSuccess;
}
void IOHIDSystem::absolutePointerEventGated(
int buttons,
IOGPoint * newLocGPoint,
IOGBounds * bounds __unused,
bool proximity,
int pressure,
int stylusAngle __unused,
AbsoluteTime ts,
OSObject * sender)
{
NXEventData outData;
bool proximityChange = false;
PROFILE_TRACE(5);
if ( !eventsOpen )
return;
if (ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline)) {
TICKLE_DISPLAY(NX_MOUSEMOVED);
return;
}
if (!DISPLAY_IS_ENABLED) {
#if !WAKE_DISPLAY_ON_MOVEMENT
if ( CMP_ABSOLUTETIME(&ts, &displaySleepWakeupDeadline) <= 0 )
{
TICKLE_DISPLAY(NX_MOUSEMOVED);
return;
}
if (buttons)
#endif
{
TICKLE_DISPLAY(NX_LMOUSEDOWN);
}
return;
}
TICKLE_DISPLAY(NX_MOUSEMOVED);
IOFixedPoint64 newLoc;
newLoc.fromIntFloor(newLocGPoint->x, newLocGPoint->y);
_scaleLocationToCurrentScreen(newLoc, bounds);
CachedMouseEventStruct *cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender);
if (cachedMouseEvent)
{
cachedMouseEvent->pointerFractionX = newLoc.xValue().fraction();
cachedMouseEvent->pointerFractionY = newLoc.yValue().fraction();
proximityChange = (cachedMouseEvent->proximity != proximity);
cachedMouseEvent->state |= kCachedMousePointingEventDispFlag;
cachedMouseEvent->proximity = proximity;
cachedMouseEvent->lastPressure = ScalePressure(pressure);
if ( !(cachedMouseEvent->state & kCachedMouseTabletEventDispFlag) )
{
if ( !(cachedMouseEvent->state & kCachedMousePointingTabletEventDispFlag) )
{
cachedMouseEvent->state |= kCachedMousePointingTabletEventDispFlag;
cachedMouseEvent->proximityData.proximity.capabilityMask = (
NX_TABLET_CAPABILITY_DEVICEIDMASK |
NX_TABLET_CAPABILITY_ABSXMASK |
NX_TABLET_CAPABILITY_ABSYMASK |
NX_TABLET_CAPABILITY_BUTTONSMASK |
NX_TABLET_CAPABILITY_PRESSUREMASK);
cachedMouseEvent->proximityData.proximity.pointerType = NX_TABLET_POINTER_PEN;
cachedMouseEvent->proximityData.proximity.systemTabletID = IOHITablet::generateTabletID();
cachedMouseEvent->proximityData.proximity.deviceID =
cachedMouseEvent->tabletData.tablet.deviceID = IOHIDPointing::generateDeviceID();
}
if ( proximityChange )
{
cachedMouseEvent->proximityData.proximity.enterProximity = proximity;
cachedMouseEvent->subType = NX_SUBTYPE_TABLET_PROXIMITY;
cachedMouseEvent->state |= kCachedMousePointingTabletEventPendFlag;
proximityEventGated(&(cachedMouseEvent->proximityData), ts, sender);
cachedMouseEvent->state &= ~kCachedMousePointingTabletEventPendFlag;
}
else if ( proximity )
{
cachedMouseEvent->tabletData.tablet.buttons = buttons & ~0x7;
if (buttons & 2)
cachedMouseEvent->tabletData.tablet.buttons |= 4;
if (buttons & EV_RB)
cachedMouseEvent->tabletData.tablet.buttons |= 2;
if (buttons & EV_LB)
cachedMouseEvent->tabletData.tablet.buttons |= 1;
cachedMouseEvent->tabletData.tablet.x = newLoc.xValue().as32();
cachedMouseEvent->tabletData.tablet.y = newLoc.yValue().as32();
cachedMouseEvent->tabletData.tablet.pressure = pressure;
cachedMouseEvent->subType = NX_SUBTYPE_TABLET_POINT;
}
}
}
clock_get_uptime(&_cursorEventLast);
if ( (newLoc != _cursorHelper.desktopLocation()) || proximityChange)
{
_cursorHelper.desktopLocationDelta() = newLoc - _cursorHelper.desktopLocation();
_cursorHelper.desktopLocation() = newLoc;
_cursorLog(_cursorEventLast);
_setCursorPosition(false, proximityChange, sender);
vblForScreen(((EvScreen*)evScreen)[cursorPinScreen].instance, _cursorMoveDelta);
_cursorMoveLast = _cursorEventLast;
}
if ( proximityChange && proximity == true )
{
evg->eventFlags |= NX_STYLUSPROXIMITYMASK;
bzero( (char *)&outData, sizeof outData );
postEvent( NX_FLAGSCHANGED,
&_cursorHelper.desktopLocation(),
ts,
&outData,
sender);
}
if ( proximityChange || proximity == true )
_setButtonState(buttons, ts, sender);
if ( proximityChange && proximity == false )
{
evg->eventFlags &= ~NX_STYLUSPROXIMITYMASK;
bzero( (char *)&outData, sizeof outData );
postEvent( NX_FLAGSCHANGED,
&_cursorHelper.desktopLocation(),
ts,
&outData,
sender);
}
if (cachedMouseEvent)
{
cachedMouseEvent->subType = NX_SUBTYPE_DEFAULT;
cachedMouseEvent->pointerFractionX = cachedMouseEvent->pointerFractionY = 0;
}
scheduleNextPeriodicEvent();
PROFILE_TRACE(6);
}
void IOHIDSystem::_scrollWheelEvent(IOHIDSystem * self,
short deltaAxis1,
short deltaAxis2,
short deltaAxis3,
IOFixed fixedDelta1,
IOFixed fixedDelta2,
IOFixed fixedDelta3,
SInt32 pointDeltaAxis1,
SInt32 pointDeltaAxis2,
SInt32 pointDeltaAxis3,
UInt32 options,
AbsoluteTime ts,
OSObject * sender,
void * refcon __unused)
{
self->scrollWheelEvent(deltaAxis1, deltaAxis2, deltaAxis3, fixedDelta1, fixedDelta2, fixedDelta3, pointDeltaAxis1, pointDeltaAxis2, pointDeltaAxis3, options, ts, sender);
}
void IOHIDSystem::scrollWheelEvent(short deltaAxis1,
short deltaAxis2,
short deltaAxis3,
AbsoluteTime ts)
{
scrollWheelEvent(deltaAxis1, deltaAxis2, deltaAxis3, deltaAxis1<<16, deltaAxis2<<16, deltaAxis3<<16, 0, 0, 0, 0, ts, 0);
}
void IOHIDSystem::scrollWheelEvent(short deltaAxis1,
short deltaAxis2,
short deltaAxis3,
IOFixed fixedDelta1,
IOFixed fixedDelta2,
IOFixed fixedDelta3,
SInt32 pointDeltaAxis1,
SInt32 pointDeltaAxis2,
SInt32 pointDeltaAxis3,
UInt32 options,
AbsoluteTime ts,
OSObject * sender)
{
IOHIDCmdGateActionArgs args;
args.arg0 = &deltaAxis1;
args.arg1 = &deltaAxis2;
args.arg2 = &deltaAxis3;
args.arg3 = &fixedDelta1;
args.arg4 = &fixedDelta2;
args.arg5 = &fixedDelta3;
args.arg6 = &pointDeltaAxis1;
args.arg7 = &pointDeltaAxis2;
args.arg8 = &pointDeltaAxis3;
args.arg9 = &options;
args.arg10 = &ts;
args.arg11 = sender;
cmdGate->runAction((IOCommandGate::Action)doScrollWheelEvent, (void *)&args);
}
IOReturn IOHIDSystem::doScrollWheelEvent(IOHIDSystem *self, void * args)
{
short deltaAxis1 = *(short *)((IOHIDCmdGateActionArgs *)args)->arg0;
short deltaAxis2 = *(short *)((IOHIDCmdGateActionArgs *)args)->arg1;
short deltaAxis3 = *(short *)((IOHIDCmdGateActionArgs *)args)->arg2;
IOFixed fixedDelta1 = *(IOFixed *)((IOHIDCmdGateActionArgs *)args)->arg3;
IOFixed fixedDelta2 = *(IOFixed *)((IOHIDCmdGateActionArgs *)args)->arg4;
IOFixed fixedDelta3 = *(IOFixed *)((IOHIDCmdGateActionArgs *)args)->arg5;
SInt32 pointDeltaAxis1 = *(IOFixed *)((IOHIDCmdGateActionArgs *)args)->arg6;
SInt32 pointDeltaAxis2 = *(IOFixed *)((IOHIDCmdGateActionArgs *)args)->arg7;
SInt32 pointDeltaAxis3 = *(IOFixed *)((IOHIDCmdGateActionArgs *)args)->arg8;
UInt32 options = *(UInt32 *)((IOHIDCmdGateActionArgs *)args)->arg9;
AbsoluteTime ts = *(AbsoluteTime *)((IOHIDCmdGateActionArgs *)args)->arg10;
OSObject * sender= (OSObject *)((IOHIDCmdGateActionArgs *)args)->arg11;
self->scrollWheelEventGated(deltaAxis1, deltaAxis2, deltaAxis3, fixedDelta1, fixedDelta2, fixedDelta3, pointDeltaAxis1, pointDeltaAxis2, pointDeltaAxis3, options, ts, sender);
return kIOReturnSuccess;
}
#if 0
# define log_event_phase(s, ...) kprintf("%s:%d " s, __FILE__, __LINE__, __VA_ARGS__)
#else
# define log_event_phase(s, ...)
#endif
void IOHIDSystem::scrollWheelEventGated(short deltaAxis1,
short deltaAxis2,
short deltaAxis3,
IOFixed fixedDelta1,
IOFixed fixedDelta2,
IOFixed fixedDelta3,
SInt32 pointDeltaAxis1,
SInt32 pointDeltaAxis2,
SInt32 pointDeltaAxis3,
UInt32 options,
AbsoluteTime ts,
OSObject * sender)
{
NXEventData wheelData;
bool moved = (deltaAxis1 || pointDeltaAxis1 ||
deltaAxis2 || pointDeltaAxis2 ||
deltaAxis3 || pointDeltaAxis3);
UInt32 momentum = (options & kScrollTypeMomentumAny);
if (!eventsOpen)
return;
if (ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline)) {
return;
}
#if !WAKE_DISPLAY_ON_MOVEMENT
if (!DISPLAY_IS_ENABLED) {
if (CMP_ABSOLUTETIME(&ts, &displaySleepWakeupDeadline) <= 0)
{
TICKLE_DISPLAY(NX_SCROLLWHEELMOVED);
}
return;
}
#endif
UInt32 phase = (options & kScrollTypeOptionPhaseAny);
UInt32 oldDelayedPhase = 0;
UInt32 newDelayedPhase = 0;
if (_devicePhaseState && _devicePhaseState->getObject((OSSymbol*)sender)) {
newDelayedPhase = oldDelayedPhase = ((OSNumber*)_devicePhaseState->getObject((OSSymbol*)sender))->unsigned32BitValue();
}
UInt32 phaseAnnotation = (phase << 16) | (oldDelayedPhase << 8);
switch (oldDelayedPhase) {
default: switch (phase) {
case kScrollTypeOptionPhaseMayBegin:
newDelayedPhase = kScrollTypeOptionPhaseMayBegin;
break;
case kScrollTypeOptionPhaseBegan:
if (moved) {
newDelayedPhase = kScrollTypeOptionPhaseBegan;
}
else {
newDelayedPhase = kScrollTypeOptionPhaseMayBegin;
options &= ~kScrollTypeOptionPhaseAny;
options |= kScrollTypeOptionPhaseMayBegin;
phase = kScrollTypeOptionPhaseMayBegin;
}
break;
case kScrollTypeOptionPhaseChanged:
case kScrollTypeOptionPhaseEnded:
case kScrollTypeOptionPhaseCanceled:
log_event_phase("unexpected phase (%04x) state (%04x) combination\n", phase, oldDelayedPhase);
break;
}
break;
case kScrollTypeOptionPhaseMayBegin: switch (phase) {
case kScrollTypeOptionPhaseMayBegin:
case kScrollTypeOptionPhaseBegan:
case kScrollTypeOptionPhaseChanged:
if (moved) {
newDelayedPhase = kScrollTypeOptionPhaseBegan;
options &= ~kScrollTypeOptionPhaseAny;
options |= kScrollTypeOptionPhaseBegan;
phase = kScrollTypeOptionPhaseBegan;
}
else {
options &= ~kScrollTypeOptionPhaseAny;
phase = 0;
}
break;
case kScrollTypeOptionPhaseEnded:
case kScrollTypeOptionPhaseCanceled:
newDelayedPhase = 0;
options &= ~kScrollTypeOptionPhaseAny;
options |= kScrollTypeOptionPhaseCanceled;
phase = kScrollTypeOptionPhaseCanceled;
break;
}
break;
case kScrollTypeOptionPhaseBegan: switch (phase) {
case kScrollTypeOptionPhaseMayBegin:
case kScrollTypeOptionPhaseBegan:
log_event_phase("unexpected phase (%04x) state (%04x) combination\n", phase, oldDelayedPhase);
break;
case kScrollTypeOptionPhaseChanged:
break;
case kScrollTypeOptionPhaseEnded:
case kScrollTypeOptionPhaseCanceled:
newDelayedPhase = 0;
break;
}
break;
}
phaseAnnotation |= phase | (newDelayedPhase >> 8);
if (oldDelayedPhase != newDelayedPhase) {
log_event_phase("updating phase from %04x to %04x for %p\n", oldDelayedPhase, newDelayedPhase, sender);
if (newDelayedPhase) {
if (!_devicePhaseState)
_devicePhaseState = OSDictionary::withCapacity(0);
if (_devicePhaseState) {
OSNumber *newDelayedPhaseNumber = OSNumber::withNumber(newDelayedPhase, 32);
_devicePhaseState->setObject((OSSymbol*)sender, newDelayedPhaseNumber);
newDelayedPhaseNumber->release();
}
else {
IOLog("%s unable to create _devicePhaseState dictionary\n", __func__);
}
}
else {
if (_devicePhaseState) {
_devicePhaseState->removeObject((OSSymbol*)sender);
}
}
}
switch (momentum) {
case kScrollTypeMomentumStart:
if (!moved) {
_delayedScrollMomentum = momentum;
momentum = 0;
options &= ~kScrollTypeMomentumAny;
}
else {
_delayedScrollMomentum = 0;
}
break;
case kScrollTypeMomentumContinue:
if (_delayedScrollMomentum) {
options &= ~kScrollTypeMomentumAny;
if (!moved) {
momentum = 0;
}
else {
momentum = _delayedScrollMomentum;
options |= momentum;
_delayedScrollMomentum = 0;
}
}
else {
if (!moved) {
momentum = 0;
}
}
break;
case kScrollTypeMomentumEnd:
if (_delayedScrollMomentum) {
options &= ~kScrollTypeMomentumAny;
momentum = 0;
_delayedScrollMomentum = 0;
}
else {
}
break;
case 0:
break;
default:
kprintf("IOHIDSystem::scrollWheelEventGated called with unknown momentum state: %08x\n", (unsigned)momentum);
break;
}
UInt32 phase_momentum = options & (_scIgnoreMomentum ? kScrollTypeOptionPhaseAny : (kScrollTypeOptionPhaseAny | kScrollTypeMomentumAny));
if (phase_momentum) {
UInt64 axis1squared = (pointDeltaAxis1 * pointDeltaAxis1);
UInt64 axis2squared = (pointDeltaAxis2 * pointDeltaAxis2);
UInt64 axis3squared = (pointDeltaAxis3 * pointDeltaAxis3);
UInt64 scrollMagnitudeSquared = axis1squared + axis2squared + axis3squared;
UInt8 newDirection = kScrollDirectionInvalid;
bool checkSustain = false;
if ((axis1squared > axis2squared) && (axis1squared > axis3squared)) {
if (pointDeltaAxis1 > 0) {
newDirection = kScrollDirectionXPositive;
}
else if (pointDeltaAxis1 < 0) {
newDirection = kScrollDirectionXNegative;
}
}
else if ((axis2squared > axis1squared) && (axis2squared > axis3squared)) {
if (pointDeltaAxis2 > 0) {
newDirection = kScrollDirectionYPositive;
}
else if (pointDeltaAxis2 < 0) {
newDirection = kScrollDirectionYNegative;
}
}
else if ((axis3squared > axis1squared) && (axis3squared > axis2squared)) {
if (pointDeltaAxis3 > 0) {
newDirection = kScrollDirectionZPositive;
}
else if (pointDeltaAxis3 < 0) {
newDirection = kScrollDirectionZNegative;
}
}
if ((newDirection != kScrollDirectionInvalid) && (newDirection != _scDirection)) {
if (_scCount) {
log_scroll_state("Resetting _scCount on change from %d to %d\n", _scDirection, newDirection);
_scCount = 0;
}
_scDirection = newDirection;
}
if (_scCount && _scMouseCanReset) {
IOFixedPoint64 thresh = IOFixedPoint64().fromIntFloor(clickSpaceThresh.x, clickSpaceThresh.y);
IOFixedPoint64 min = _scLastScrollLocation - thresh;
IOFixedPoint64 max = _scLastScrollLocation + thresh;
IOFixedPoint64 location = _cursorHelper.desktopLocation();
if ( (location > max) || (location < min) ) {
log_scroll_state("Resetting _scCount on mouse move [%d, %d] vs [%d, %d]\n",
location.xValue().as32(), location.yValue().as32(),
_scLastScrollLocation.xValue().as32(), _scLastScrollLocation.yValue().as32());
_scCount = 0;
}
}
switch (phase_momentum) {
case kScrollTypeOptionPhaseBegan: {
if (_scCount > 0) {
if ((_scLastScrollEndTime + _scMaxTimeDeltaBetween) > ts) {
if (!_scIncrementedThisPhrase) {
log_scroll_state("Incrementing _scCount: %lld\n", ts);
_scCount++;
_scIncrementedThisPhrase = 1;
}
_scLastScrollSustainTime = ts;
}
else {
_scCount = 0;
log_scroll_state("Resetting _scCount due to delay: %lld + %lld < %lld\n", _scLastScrollEndTime, _scMaxTimeDeltaBetween, ts);
}
}
break;
}
case kScrollTypeOptionPhaseChanged: {
if (_scCount == 0) {
if (scrollMagnitudeSquared >= _scMinDeltaSqToStart) {
log_scroll_state("_scCount to 1 on %lld > %lld\n", scrollMagnitudeSquared, _scMinDeltaSqToStart);
_scCount = 1;
_scLastScrollSustainTime = ts;
}
}
else {
if (_scCount > 2) {
IOFixed64 temp;
temp.fromIntFloor(llsqrt(scrollMagnitudeSquared));
temp /= _scAccelerationFactor;
_scCount += temp.as32();
log_scroll_state("_scCount to %d on (llsqrt(%lld) * 65536 / %lld)\n", _scCount, scrollMagnitudeSquared, _scAccelerationFactor.asFixed64());
if (_scCount > _scCountMax) {
_scCount = _scCountMax;
}
}
checkSustain = true;
}
break;
}
case kScrollTypeOptionPhaseEnded: {
if (_scCount > 0) {
_scLastScrollEndTime = ts;
_scIncrementedThisPhrase = 0;
}
break;
}
case kScrollTypeOptionPhaseCanceled: {
log_scroll_state("Resetting _scCount cancelled: %lld\n", ts);
_scIncrementedThisPhrase = false;
_scCount = 0;
break;
}
case kScrollTypeOptionPhaseMayBegin: {
if (_scCount > 0) {
if (((_scLastScrollEndTime + _scMaxTimeDeltaBetween) > ts) && !_scIncrementedThisPhrase) {
log_scroll_state("Incrementing _scCount: %lld\n", ts);
_scCount++;
_scIncrementedThisPhrase = 1;
_scLastScrollSustainTime = ts;
}
else {
log_scroll_state("Resetting _scCount due to delay: %lld + %lld < %lld\n", _scLastScrollEndTime, _scMaxTimeDeltaBetween, ts);
_scCount = 0;
_scIncrementedThisPhrase = 0;
}
}
break;
}
case kScrollTypeMomentumStart: {
break;
}
case kScrollTypeMomentumContinue: {
checkSustain = true;
break;
}
case kScrollTypeMomentumEnd: {
if (_scCount > 0) {
_scLastScrollEndTime = ts;
_scIncrementedThisPhrase = 0;
}
break;
}
}
if (checkSustain) {
if (scrollMagnitudeSquared > _scMinDeltaSqToSustain) {
_scLastScrollSustainTime = ts;
}
else if (_scLastScrollSustainTime + _scMaxTimeDeltaToSustain < ts) {
log_scroll_state("Resetting _scCount due to sustain delay: %lld + %lld < %lld\n", _scLastScrollSustainTime, _scMaxTimeDeltaToSustain, ts);
_scCount = 0;
}
}
_scLastScrollLocation = _cursorHelper.desktopLocation();
}
if (!moved && !momentum && !phase) {
log_event_phase("annotation %08x suppressed\n", phaseAnnotation);
return;
}
else {
log_event_phase("annotation %08x posted with %08x\n", phaseAnnotation, options);
}
TICKLE_DISPLAY(NX_SCROLLWHEELMOVED);
bzero((char *)&wheelData, sizeof wheelData);
wheelData.scrollWheel.deltaAxis1 = deltaAxis1;
wheelData.scrollWheel.deltaAxis2 = deltaAxis2;
wheelData.scrollWheel.deltaAxis3 = deltaAxis3;
wheelData.scrollWheel.fixedDeltaAxis1 = fixedDelta1;
wheelData.scrollWheel.fixedDeltaAxis2 = fixedDelta2;
wheelData.scrollWheel.fixedDeltaAxis3 = fixedDelta3;
wheelData.scrollWheel.pointDeltaAxis1 = pointDeltaAxis1;
wheelData.scrollWheel.pointDeltaAxis2 = pointDeltaAxis2;
wheelData.scrollWheel.pointDeltaAxis3 = pointDeltaAxis3;
wheelData.scrollWheel.reserved1 = (UInt16)options & (kScrollTypeContinuous | kScrollTypeMomentumAny | kScrollTypeOptionPhaseAny);
updateScrollEventForSender(sender, &wheelData);
if (options & (kScrollTypeMomentumAny | kScrollTypeOptionPhaseAny)) {
wheelData.scrollWheel.reserved8[0] = phaseAnnotation;
wheelData.scrollWheel.reserved8[1] = _scCount;
log_scroll_state("posting scroll: (%d, %d, %d) %d %d, %lld %lld, %lld\n",
pointDeltaAxis1, pointDeltaAxis2, pointDeltaAxis3, _scCount, _scDirection,
_scLastScrollEndTime, _scLastScrollSustainTime, ts);
wheelData.scrollWheel.reserved8[2] = IOHIDevice::GenerateKey(sender);
}
postEvent( (options & kScrollTypeZoom) ? NX_ZOOM : NX_SCROLLWHEELMOVED,
&_cursorHelper.desktopLocation(),
ts,
&wheelData,
sender);
return;
}
void IOHIDSystem::_tabletEvent(IOHIDSystem *self,
NXEventData *tabletData,
AbsoluteTime ts,
OSObject * sender,
void * refcon __unused)
{
self->tabletEvent(tabletData, ts, sender);
}
void IOHIDSystem::tabletEvent(NXEventData *tabletData,
AbsoluteTime ts)
{
tabletEvent(tabletData, ts, 0);
}
void IOHIDSystem::tabletEvent(NXEventData *tabletData,
AbsoluteTime ts,
OSObject * sender)
{
cmdGate->runAction((IOCommandGate::Action)doTabletEvent, tabletData, &ts, sender);
}
IOReturn IOHIDSystem::doTabletEvent(IOHIDSystem *self, void * arg0, void * arg1, void * arg2)
{
NXEventData *tabletData = (NXEventData *) arg0;
AbsoluteTime ts = *(AbsoluteTime *) arg1;
OSObject * sender = (OSObject *) arg2;
self->tabletEventGated(tabletData, ts, sender);
return kIOReturnSuccess;
}
void IOHIDSystem::tabletEventGated(NXEventData *tabletData,
AbsoluteTime ts,
OSObject * sender)
{
CachedMouseEventStruct *cachedMouseEvent;
if (!eventsOpen)
return;
if(ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline))
return;
if ((cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender)) &&
!(cachedMouseEvent->state & kCachedMousePointingTabletEventPendFlag))
{
cachedMouseEvent->state |= kCachedMouseTabletEventDispFlag;
cachedMouseEvent->subType = NX_SUBTYPE_TABLET_POINT;
bcopy( tabletData, &(cachedMouseEvent->tabletData), sizeof(NXEventData));
if ( cachedMouseEvent->state & kCachedMousePointingEventDispFlag )
return;
}
postEvent(NX_TABLETPOINTER,
&_cursorHelper.desktopLocation(),
ts,
tabletData,
sender);
return;
}
void IOHIDSystem::_proximityEvent(IOHIDSystem *self,
NXEventData *proximityData,
AbsoluteTime ts,
OSObject * sender,
void * refcon __unused)
{
self->proximityEvent(proximityData, ts, sender);
}
void IOHIDSystem::proximityEvent(NXEventData *proximityData,
AbsoluteTime ts)
{
proximityEvent(proximityData, ts, 0);
}
void IOHIDSystem::proximityEvent(NXEventData *proximityData,
AbsoluteTime ts,
OSObject * sender)
{
cmdGate->runAction((IOCommandGate::Action)doProximityEvent, proximityData, &ts, sender);
}
IOReturn IOHIDSystem::doProximityEvent(IOHIDSystem *self, void * arg0, void *arg1, void * arg2)
{
NXEventData *proximityData = (NXEventData *)arg0;
AbsoluteTime ts = *(AbsoluteTime *)arg1;
OSObject * sender = (OSObject *)arg2;
self->proximityEventGated(proximityData, ts, sender);
return kIOReturnSuccess;
}
void IOHIDSystem::proximityEventGated(NXEventData *proximityData,
AbsoluteTime ts,
OSObject * sender)
{
CachedMouseEventStruct *cachedMouseEvent;
if (!eventsOpen)
return;
if(ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline))
return;
if ((cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender)) &&
!(cachedMouseEvent->state & kCachedMousePointingTabletEventPendFlag))
{
cachedMouseEvent->state |= kCachedMouseTabletEventDispFlag;
cachedMouseEvent->subType = NX_SUBTYPE_TABLET_PROXIMITY;
bcopy( proximityData, &(cachedMouseEvent->proximityData), sizeof(NXEventData));
}
postEvent(NX_TABLETPROXIMITY,
&_cursorHelper.desktopLocation(),
ts,
proximityData,
sender);
return;
}
void IOHIDSystem::doProcessKeyboardEQ(IOHIDSystem * self)
{
processKeyboardEQ(self);
}
void IOHIDSystem::processKeyboardEQ(IOHIDSystem * self, AbsoluteTime * deadline)
{
KeyboardEQElement * keyboardEQElement;
KEYBOARD_EQ_LOCK;
while ( ((keyboardEQElement = (KeyboardEQElement *)dequeue_head(&gKeyboardEQ)) != NULL)
&& !(deadline && (CMP_ABSOLUTETIME(&(keyboardEQElement->ts), deadline) > 0)))
{
KEYBOARD_EQ_UNLOCK;
if (keyboardEQElement->action)
(*(keyboardEQElement->action))(self, keyboardEQElement);
OSSafeReleaseNULL(keyboardEQElement->sender);
IOFree(keyboardEQElement, sizeof(KeyboardEQElement));
KEYBOARD_EQ_LOCK;
}
KEYBOARD_EQ_UNLOCK;
}
void IOHIDSystem::_keyboardEvent(IOHIDSystem * self,
unsigned eventType,
unsigned flags,
unsigned key,
unsigned charCode,
unsigned charSet,
unsigned origCharCode,
unsigned origCharSet,
unsigned keyboardType,
bool repeat,
AbsoluteTime ts,
OSObject * sender,
void * refcon __unused)
{
self->keyboardEvent(eventType, flags, key, charCode, charSet,
origCharCode, origCharSet, keyboardType, repeat, ts, sender);
}
void IOHIDSystem::keyboardEvent(unsigned eventType,
unsigned flags,
unsigned key,
unsigned charCode,
unsigned charSet,
unsigned origCharCode,
unsigned origCharSet,
unsigned keyboardType,
bool repeat,
AbsoluteTime ts)
{
keyboardEvent(eventType, flags, key, charCode, charSet,
origCharCode, origCharSet, keyboardType, repeat, ts, 0);
}
void IOHIDSystem::keyboardEvent(unsigned eventType,
unsigned flags,
unsigned key,
unsigned charCode,
unsigned charSet,
unsigned origCharCode,
unsigned origCharSet,
unsigned keyboardType,
bool repeat,
AbsoluteTime ts,
OSObject * sender)
{
KeyboardEQElement * keyboardEQElement = (KeyboardEQElement *)IOMalloc(sizeof(KeyboardEQElement));
if ( !keyboardEQElement )
return;
bzero(keyboardEQElement, sizeof(KeyboardEQElement));
keyboardEQElement->action = IOHIDSystem::doKeyboardEvent;
keyboardEQElement->ts = ts;
keyboardEQElement->sender = sender;
if (sender) sender->retain();
keyboardEQElement->event.keyboard.eventType = eventType;
keyboardEQElement->event.keyboard.flags = flags;
keyboardEQElement->event.keyboard.key = key;
keyboardEQElement->event.keyboard.charCode = charCode;
keyboardEQElement->event.keyboard.charSet = charSet;
keyboardEQElement->event.keyboard.origCharCode = origCharCode;
keyboardEQElement->event.keyboard.origCharSet = origCharSet;
keyboardEQElement->event.keyboard.keyboardType = keyboardType;
keyboardEQElement->event.keyboard.repeat = repeat;
KEYBOARD_EQ_LOCK;
enqueue_tail(&gKeyboardEQ, (queue_entry_t)keyboardEQElement);
KEYBOARD_EQ_UNLOCK;
keyboardEQES->interruptOccurred(0, 0, 0);
}
IOReturn IOHIDSystem::doKeyboardEvent(IOHIDSystem *self, void * args)
{
KeyboardEQElement * keyboardEQElement = (KeyboardEQElement *)args;
AbsoluteTime ts = keyboardEQElement->ts;
OSObject * sender = keyboardEQElement->sender;
unsigned eventType = keyboardEQElement->event.keyboard.eventType;
unsigned flags = keyboardEQElement->event.keyboard.flags;
unsigned key = keyboardEQElement->event.keyboard.key;
unsigned charCode = keyboardEQElement->event.keyboard.charCode;
unsigned charSet = keyboardEQElement->event.keyboard.charSet;
unsigned origCharCode = keyboardEQElement->event.keyboard.origCharCode;
unsigned origCharSet = keyboardEQElement->event.keyboard.origCharSet;
unsigned keyboardType = keyboardEQElement->event.keyboard.keyboardType;
bool repeat = keyboardEQElement->event.keyboard.repeat;
self->keyboardEventGated(eventType, flags, key, charCode, charSet,
origCharCode, origCharSet, keyboardType, repeat, ts, sender);
return kIOReturnSuccess;
}
bool IOHIDSystem::addConsumedKey(unsigned key)
{
bool result = false;
OSNumber *keyCodeNumber;
unsigned int index;
keyCodeNumber = OSNumber::withNumber(key, sizeof(key) * 8);
if ( !keyCodeNumber ) goto finish;
index = getArrayIndexForObject(consumedKeys, keyCodeNumber);
if ( index != kObjectNotFound ) goto finish;
consumedKeys->setObject(keyCodeNumber);
result = true;
finish:
if (keyCodeNumber) keyCodeNumber->release();
return result;
}
bool IOHIDSystem::removeConsumedKey(unsigned key)
{
bool result = false;
OSNumber *keyCodeNumber;
unsigned int index;
keyCodeNumber = OSNumber::withNumber(key, sizeof(key) * 8);
if ( !keyCodeNumber ) goto finish;
index = getArrayIndexForObject(consumedKeys, keyCodeNumber);
if ( index == kObjectNotFound ) goto finish;
consumedKeys->removeObject(index);
result = true;
finish:
if (keyCodeNumber) keyCodeNumber->release();
return result;
}
void IOHIDSystem::keyboardEventGated(unsigned eventType,
unsigned flags,
unsigned key,
unsigned charCode,
unsigned charSet,
unsigned origCharCode,
unsigned origCharSet,
unsigned keyboardType,
bool repeat,
AbsoluteTime ts,
OSObject * sender)
{
UInt32 rootDomainConsumeCause;
UInt32 displayConsumeCause;
NXEventData outData;
static unsigned prevFlags = 0;
if ( eventType == NX_KEYUP && consumedKeys->getCount() ) {
if (removeConsumedKey(key)) {
return;
}
}
rootDomainConsumeCause = ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline);
displayConsumeCause = ShouldConsumeHIDEvent(ts, displayStateChangeDeadline);
if (rootDomainConsumeCause || displayConsumeCause) {
TICKLE_DISPLAY(NX_KEYDOWN);
if (eventType != NX_KEYDOWN) return;
(void) addConsumedKey(key);
if (rootDomainConsumeCause) {
AbsoluteTime_to_scalar(&rootDomainStateChangeDeadline) = 0;
clock_get_uptime(&displayStateChangeDeadline);
ADD_ABSOLUTETIME(&displayStateChangeDeadline,
&gIOHIDRelativeTickleThresholdAbsoluteTime);
}
return;
}
if( !repeat && ((flags & NORMAL_MODIFIER_MASK) == NORMAL_MODIFIER_MASK) )
{
UInt32 keycode = UINT_MAX;
switch (key) {
case 0x2f: case 0x41: keycode = kHIDUsage_KeyboardPeriod;
break;
case 0x2b: case 0x5f: keycode = kHIDUsage_KeyboardComma;
break;
case 0x2c: case 0x4b: keycode = kHIDUsage_KeyboardSlash;
break;
default:
break;
}
if (keycode != UINT_MAX) {
if (eventType == NX_KEYDOWN) {
sendStackShotMessage(keycode);
IOLog("IOHIDSystem posted stackshot event 0x%02x\n", (unsigned)keycode);
}
return;
}
}
if ( !DISPLAY_IS_ENABLED ) {
if ( eventType == NX_KEYDOWN ) {
(void) addConsumedKey(key);
}
else if ( eventType == NX_KEYUP) {
return;
}
else if ( eventType == NX_FLAGSCHANGED ) {
unsigned kbFlagChanges = (flags & KEYBOARD_FLAGSMASK) ^ (prevFlags & KEYBOARD_FLAGSMASK);
if (!(kbFlagChanges & flags)) {
prevFlags = flags;
return;
}
}
TICKLE_DISPLAY(eventType);
return;
}
prevFlags = flags;
TICKLE_DISPLAY(NX_KEYDOWN);
if( !repeat && (key == 0x35) &&
(eventType == NX_KEYDOWN) &&
((flags & NORMAL_MODIFIER_MASK) == NORMAL_MODIFIER_MASK))
{
PE_enter_debugger("USB Programmer Key");
}
if ( eventsOpen ) {
UInt32 usage = 0;
UInt32 usagePage = 0;
if ((flags & NX_HIGHCODE_ENCODING_MASK) == NX_HIGHCODE_ENCODING_MASK) {
usage = (origCharCode & 0xffff0000) >> 16;
usagePage = (origCharSet & 0xffff0000) >> 16;
origCharCode &= 0xffff;
origCharSet &= 0xffff;
}
outData.key.repeat = repeat;
outData.key.keyCode = key;
outData.key.charSet = charSet;
outData.key.charCode = charCode;
outData.key.origCharSet = origCharSet;
outData.key.origCharCode = origCharCode;
outData.key.keyboardType = keyboardType;
outData.key.reserved2 = usage;
outData.key.reserved3 = usagePage;
evg->eventFlags = (evg->eventFlags & ~KEYBOARD_FLAGSMASK)
| (flags & KEYBOARD_FLAGSMASK);
if (cachedEventFlags != evg->eventFlags) {
cachedEventFlags = evg->eventFlags;
nanoseconds_to_absolutetime(0, &clickTime);
}
postEvent( eventType,
&_cursorHelper.desktopLocation(),
ts,
&outData,
sender,
0,
false);
} else {
static const char cursorCodes[] = { 'D', 'A', 'C', 'B' };
if( (eventType == NX_KEYDOWN) && ((flags & NX_ALTERNATEMASK) != NX_ALTERNATEMASK)) {
if( (charSet == NX_SYMBOLSET)
&& (charCode >= 0xac) && (charCode <= 0xaf)) {
cons_cinput( '\033');
cons_cinput( 'O');
charCode = cursorCodes[ charCode - 0xac ];
}
cons_cinput( charCode );
}
}
}
void IOHIDSystem::_keyboardSpecialEvent( IOHIDSystem * self,
unsigned eventType,
unsigned flags,
unsigned key,
unsigned flavor,
UInt64 guid,
bool repeat,
AbsoluteTime ts,
OSObject * sender,
void * refcon __unused)
{
self->keyboardSpecialEvent(eventType, flags, key, flavor, guid, repeat, ts, sender);
}
void IOHIDSystem::keyboardSpecialEvent( unsigned eventType,
unsigned flags,
unsigned key,
unsigned flavor,
UInt64 guid,
bool repeat,
AbsoluteTime ts)
{
keyboardSpecialEvent(eventType, flags, key, flavor, guid, repeat, ts, 0);
}
void IOHIDSystem::keyboardSpecialEvent( unsigned eventType,
unsigned flags,
unsigned key,
unsigned flavor,
UInt64 guid,
bool repeat,
AbsoluteTime ts,
OSObject * sender)
{
KeyboardEQElement * keyboardEQElement = NULL;
keyboardEQElement = (KeyboardEQElement *)IOMalloc(sizeof(KeyboardEQElement));
if ( !keyboardEQElement )
return;
bzero(keyboardEQElement, sizeof(KeyboardEQElement));
keyboardEQElement->action = IOHIDSystem::doKeyboardSpecialEvent;
keyboardEQElement->ts = ts;
keyboardEQElement->sender = sender;
if (sender) sender->retain();
keyboardEQElement->event.keyboardSpecial.eventType = eventType;
keyboardEQElement->event.keyboardSpecial.flags = flags;
keyboardEQElement->event.keyboardSpecial.key = key;
keyboardEQElement->event.keyboardSpecial.flavor = flavor;
keyboardEQElement->event.keyboardSpecial.guid = guid;
keyboardEQElement->event.keyboardSpecial.repeat = repeat;
KEYBOARD_EQ_LOCK;
enqueue_tail(&gKeyboardEQ, (queue_entry_t)keyboardEQElement);
KEYBOARD_EQ_UNLOCK;
keyboardEQES->interruptOccurred(0, 0, 0);
}
IOReturn IOHIDSystem::doKeyboardSpecialEvent(IOHIDSystem *self, void * args)
{
KeyboardEQElement * keyboardEQElement = (KeyboardEQElement *)args;
AbsoluteTime ts = keyboardEQElement->ts;
OSObject * sender = keyboardEQElement->sender;
unsigned eventType = keyboardEQElement->event.keyboardSpecial.eventType;
unsigned flags = keyboardEQElement->event.keyboardSpecial.flags;
unsigned key = keyboardEQElement->event.keyboardSpecial.key;
unsigned flavor = keyboardEQElement->event.keyboardSpecial.flavor;
UInt64 guid = keyboardEQElement->event.keyboardSpecial.guid;
bool repeat = keyboardEQElement->event.keyboardSpecial.repeat;
self->keyboardSpecialEventGated(eventType, flags, key, flavor, guid, repeat, ts, sender);
return kIOReturnSuccess;
}
void IOHIDSystem::keyboardSpecialEventGated(
unsigned eventType,
unsigned flags,
unsigned key,
unsigned flavor,
UInt64 guid,
bool repeat,
AbsoluteTime ts,
OSObject * sender)
{
NXEventData outData;
int level = -1;
if ((key != NX_NOSPECIALKEY) || (flavor != NX_SUBTYPE_STICKYKEYS_RELEASE)) {
if (DISPLAY_IS_ENABLED || eventType == NX_KEYDOWN)
TICKLE_DISPLAY(NX_SYSDEFINED);
}
if (ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline) ||
!DISPLAY_IS_ENABLED)
{
return;
}
if ( eventType == NX_KEYDOWN && flavor == NX_POWER_KEY && !repeat) {
if ( (flags & (NORMAL_MODIFIER_MASK | NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK)) ==
(NX_COMMANDMASK | NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK) )
PE_enter_debugger("Programmer Key");
else if ( (flags & NORMAL_MODIFIER_MASK) == ( NX_COMMANDMASK | NX_CONTROLMASK ) )
PEHaltRestart(kPERestartCPU);
}
if ( !eventsOpen )
return;
bzero( (void *)&outData, sizeof outData );
evg->eventFlags = (evg->eventFlags & ~KEYBOARD_FLAGSMASK)
| (flags & KEYBOARD_FLAGSMASK);
if ( eventType == NX_KEYDOWN )
{
notifyHIDevices(this, ioHIDevices, kIOHIDSystem508SpecialKeyDownMessage);
switch ( flavor )
{
case NX_KEYTYPE_EJECT:
if( (evg->eventFlags & NX_COMMANDMASK) &&
!(evg->eventFlags & NX_CONTROLMASK) &&
!(evg->eventFlags & NX_SHIFTMASK) &&
!(evg->eventFlags & NX_ALTERNATEMASK) )
{
outData.compound.subType = NX_SUBTYPE_POWER_KEY;
postEvent( NX_SYSDEFINED,
&_cursorHelper.desktopLocation(),
ts,
&outData,
sender,
0,
false);
}
else if( (evg->eventFlags & NX_COMMANDMASK) &&
!(evg->eventFlags & NX_CONTROLMASK) &&
!(evg->eventFlags & NX_SHIFTMASK) &&
(evg->eventFlags & NX_ALTERNATEMASK) )
{
evg->eventFlags = 0;
outData.compound.subType = NX_SUBTYPE_SLEEP_EVENT;
postEvent( NX_SYSDEFINED,
&_cursorHelper.desktopLocation(),
ts,
&outData,
sender,
0,
false);
}
else if( (evg->eventFlags & NX_COMMANDMASK) &&
(evg->eventFlags & NX_CONTROLMASK) &&
!(evg->eventFlags & NX_SHIFTMASK) &&
(evg->eventFlags & NX_ALTERNATEMASK) )
{
outData.compound.subType = NX_SUBTYPE_SHUTDOWN_EVENT;
postEvent( NX_SYSDEFINED,
&_cursorHelper.desktopLocation(),
ts,
&outData,
sender,
0,
false);
}
else if( (evg->eventFlags & NX_COMMANDMASK) &&
(evg->eventFlags & NX_CONTROLMASK) &&
!(evg->eventFlags & NX_SHIFTMASK) &&
!(evg->eventFlags & NX_ALTERNATEMASK) )
{
outData.compound.subType = NX_SUBTYPE_RESTART_EVENT;
postEvent( NX_SYSDEFINED,
&_cursorHelper.desktopLocation(),
ts,
&outData,
sender,
0,
false);
}
else if( !(evg->eventFlags & NX_COMMANDMASK) &&
(evg->eventFlags & NX_CONTROLMASK) &&
!(evg->eventFlags & NX_SHIFTMASK) &&
!(evg->eventFlags & NX_ALTERNATEMASK) )
{
evg->eventFlags = 0;
outData.compound.subType = NX_SUBTYPE_POWER_KEY;
postEvent( NX_SYSDEFINED,
&_cursorHelper.desktopLocation(),
ts,
&outData,
sender,
0,
false);
}
else
{
outData.compound.subType = NX_SUBTYPE_EJECT_KEY;
postEvent( NX_SYSDEFINED,
&_cursorHelper.desktopLocation(),
ts,
&outData,
sender,
0,
false);
}
break;
case NX_POWER_KEY:
keyboardEventGated(eventType,
flags,
0x7f,
0,
0,
0,
0,
0,
0,
ts,
sender);
outData.compound.subType = NX_SUBTYPE_POWER_KEY;
postEvent( NX_SYSDEFINED,
&_cursorHelper.desktopLocation(),
ts,
&outData,
sender,
0,
false);
break;
}
}
else if ( eventType == NX_KEYUP )
{
switch ( flavor )
{
case NX_POWER_KEY:
keyboardEventGated(eventType,
flags,
0x7f,
0,
0,
0,
0,
0,
0,
ts,
sender);
break;
}
}
else if ( eventType == NX_SYSDEFINED )
{
outData.compound.subType = flavor;
postEvent( NX_SYSDEFINED,
&_cursorHelper.desktopLocation(),
ts,
&outData,
sender,
0,
false);
}
if ( eventType != NX_SYSDEFINED )
{
if( (flags & SPECIALKEYS_MODIFIER_MASK)
&& (flavor == NX_POWER_KEY))
{
}
else
{
outData.compound.subType = NX_SUBTYPE_AUX_CONTROL_BUTTONS;
outData.compound.misc.L[0] = (flavor << 16) | (eventType << 8) | repeat;
outData.compound.misc.L[1] = guid & 0xffffffff;
outData.compound.misc.L[2] = guid >> 32;
postEvent( NX_SYSDEFINED,
&_cursorHelper.desktopLocation(),
ts,
&outData,
sender,
0,
false);
}
}
if ( level != -1 ) {
evSpecialKeyMsg( flavor,
eventType,
flags,
level);
}
}
void IOHIDSystem::_updateEventFlags(IOHIDSystem * self,
unsigned flags,
OSObject * sender,
void * refcon __unused)
{
self->updateEventFlags(flags, sender);
}
void IOHIDSystem::updateEventFlags(unsigned flags)
{
updateEventFlags(flags, 0);
}
void IOHIDSystem::updateEventFlags(unsigned flags, OSObject * sender)
{
KeyboardEQElement * keyboardEQElement = (KeyboardEQElement *)IOMalloc(sizeof(KeyboardEQElement));
if ( !keyboardEQElement )
return;
bzero(keyboardEQElement, sizeof(KeyboardEQElement));
keyboardEQElement->action = IOHIDSystem::doUpdateEventFlags;
keyboardEQElement->sender = sender;
if (sender) sender->retain();
keyboardEQElement->event.flagsChanged.flags = flags;
KEYBOARD_EQ_LOCK;
enqueue_tail(&gKeyboardEQ, (queue_entry_t)keyboardEQElement);
KEYBOARD_EQ_UNLOCK;
keyboardEQES->interruptOccurred(0, 0, 0);
}
IOReturn IOHIDSystem::doUpdateEventFlags(IOHIDSystem *self, void * args)
{
KeyboardEQElement * keyboardEQElement = (KeyboardEQElement *)args;
OSObject * sender = keyboardEQElement->sender;
unsigned flags = keyboardEQElement->event.flagsChanged.flags;
self->updateEventFlagsGated(flags, sender);
return kIOReturnSuccess;
}
void IOHIDSystem::updateEventFlagsGated(unsigned flags, OSObject * sender __unused)
{
if ( eventsOpen ) {
evg->eventFlags = (evg->eventFlags & ~KEYBOARD_FLAGSMASK)
| (flags & KEYBOARD_FLAGSMASK);
nanoseconds_to_absolutetime(0, &clickTime);
}
}
void IOHIDSystem::_setButtonState(int buttons,
AbsoluteTime ts,
OSObject * sender)
{
CachedMouseEventStruct *cachedMouseEvent = NULL;
if ( cachedButtonStates ) {
cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender);
if (cachedMouseEvent) {
cachedMouseEvent->lastButtons = buttons;
}
if (evg->buttons == buttons)
return;
buttons = GetCachedMouseButtonStates(cachedButtonStates);
}
if (evg->buttons == buttons)
return;
if (_scMouseCanReset && _scCount) {
log_scroll_state("Resetting _scCount due to click: %lld\n", ts);
_scCount = 0;
}
NXEventData evData;
unsigned long hwButtons, hwDelta;
CONVERT_EV_TO_HW_BUTTONS(buttons, hwButtons);
CONVERT_EV_TO_HW_DELTA((evg->buttons ^ buttons), hwDelta);
evData.compound.reserved = 0;
evData.compound.subType = NX_SUBTYPE_AUX_MOUSE_BUTTONS;
evData.compound.misc.L[0] = hwDelta;
evData.compound.misc.L[1] = hwButtons;
postEvent( NX_SYSDEFINED,
&_cursorHelper.desktopLocation(),
ts,
&evData,
sender);
bzero(&evData, sizeof(NXEventData));
updateMouseEventForSender(sender, &evData);
if (cachedMouseEvent ||
(NULL != (cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender)))) {
if (evData.mouse.subType != NX_SUBTYPE_MOUSE_TOUCH)
evData.mouse.subType = cachedMouseEvent->subType;
evData.mouse.pressure = cachedMouseEvent->lastPressure;
if (cachedMouseEvent->subType == NX_SUBTYPE_TABLET_POINT) {
bcopy(&(cachedMouseEvent->tabletData), &(evData.mouse.tablet.point), sizeof(NXTabletPointData));
}
else if (cachedMouseEvent->subType == NX_SUBTYPE_TABLET_PROXIMITY) {
bcopy(&(cachedMouseEvent->proximityData), &(evData.mouse.tablet.proximity), sizeof(NXTabletProximityData));
}
}
evData.mouse.subx = _cursorHelper.desktopLocation().xValue().fraction() >> 8;
evData.mouse.suby = _cursorHelper.desktopLocation().yValue().fraction() >> 8;
if ((evg->buttons & EV_LB) != (buttons & EV_LB)) {
if (buttons & EV_LB) {
postEvent( NX_LMOUSEDOWN,
&_cursorHelper.desktopLocation(),
ts,
&evData,
sender);
}
else {
postEvent( NX_LMOUSEUP,
&_cursorHelper.desktopLocation(),
ts,
&evData,
sender);
}
evg->dontCoalesce = evg->dontWantCoalesce;
if (evg->dontCoalesce)
evg->eventFlags |= NX_NONCOALSESCEDMASK;
else
evg->eventFlags &= ~NX_NONCOALSESCEDMASK;
}
if ((evg->buttons & EV_RB) != (buttons & EV_RB)) {
if (buttons & EV_RB) {
postEvent( NX_RMOUSEDOWN,
&_cursorHelper.desktopLocation(),
ts,
&evData,
sender);
}
else {
postEvent( NX_RMOUSEUP,
&_cursorHelper.desktopLocation(),
ts,
&evData,
sender);
}
}
evg->buttons = buttons;
}
void IOHIDSystem::setCursorPosition(IOGPoint * newLoc, bool external, OSObject * sender)
{
if ( eventsOpen == true )
{
clock_get_uptime(&_cursorEventLast);
_cursorHelper.desktopLocationDelta().xValue() += (newLoc->x - _cursorHelper.desktopLocation().xValue());
_cursorHelper.desktopLocationDelta().yValue() += (newLoc->y - _cursorHelper.desktopLocation().yValue());
_cursorHelper.desktopLocation().fromIntFloor(newLoc->x, newLoc->y);
_setCursorPosition(external, false, sender);
_cursorMoveLast = _cursorEventLast;
scheduleNextPeriodicEvent();
}
}
void IOHIDSystem::_setCursorPosition(bool external, bool proximityChange, OSObject * sender)
{
bool cursorMoved = true;
IOHID_DEBUG(kIOHIDDebugCode_SetCursorPosition, sender,
_cursorHelper.desktopLocation().xValue().as64(),
_cursorHelper.desktopLocation().yValue().as64(), 0);
IOHID_DEBUG(kIOHIDDebugCode_SetCursorPosition, sender, proximityChange, external, 1);
PROFILE_TRACE(9);
if (!screens) {
return;
}
if( OSSpinLockTry(&evg->cursorSema) == 0 ) { return;
}
if (cursorCoupled || external)
{
UInt32 newScreens = 0;
SInt32 pinScreen = -1L;
EvScreen *screen = (EvScreen *)evScreen;
if (cursorPinned) {
_cursorHelper.desktopLocation().clipToRect(cursorPin);
}
else {
for (int i = 0; i < screens; i++ ) {
if (!screen[i].desktopBounds)
continue;
if ((screen[i].desktopBounds->maxx - screen[i].desktopBounds->minx) < 128)
continue;
if (_cursorHelper.desktopLocation().inRect(*screen[i].desktopBounds)) {
pinScreen = i;
newScreens |= (1 << i);
}
}
}
if (newScreens == 0) {
IOFixedPoint64 aimLoc = _cursorHelper.desktopLocation();
int64_t dx;
int64_t dy;
uint64_t distance;
uint64_t bestDistance = -1ULL;
for (int i = 0; i < screens; i++ ) {
if (!screen[i].desktopBounds)
continue;
if ((screen[i].desktopBounds->maxx - screen[i].desktopBounds->minx) < 128)
continue;
IOFixedPoint64 pinnedLoc = aimLoc;
pinnedLoc.clipToRect(*screen[i].desktopBounds);
dx = (pinnedLoc.xValue() - aimLoc.xValue()).as64();
dy = (pinnedLoc.yValue() - aimLoc.yValue()).as64();
distance = dx * dx + dy * dy;
if (distance <= bestDistance) {
bestDistance = distance;
_cursorHelper.desktopLocation() = pinnedLoc;
}
}
IOHID_DEBUG(kIOHIDDebugCode_SetCursorPosition, sender,
_cursorHelper.desktopLocation().xValue().as64(),
_cursorHelper.desktopLocation().yValue().as64(), 2);
for (int i = 0; i < screens; i++ ) {
if (!screen[i].desktopBounds)
continue;
if ((screen[i].desktopBounds->maxx - screen[i].desktopBounds->minx) < 128)
continue;
if (_cursorHelper.desktopLocation().inRect(*screen[i].desktopBounds)) {
pinScreen = i;
newScreens |= (1 << i);
}
}
}
if ((_cursorHelper.desktopLocation().xValue().asFixed24x8() == evg->desktopCursorFixed.x) &&
(_cursorHelper.desktopLocation().yValue().asFixed24x8() == evg->desktopCursorFixed.y) &&
(proximityChange == 0) && (!_cursorHelper.desktopLocationDelta())) {
cursorMoved = false; }
else {
evg->cursorLoc.x = _cursorHelper.desktopLocation().xValue().as32();
evg->cursorLoc.y = _cursorHelper.desktopLocation().yValue().as32();
evg->desktopCursorFixed.x = _cursorHelper.desktopLocation().xValue().asFixed24x8();
evg->desktopCursorFixed.y = _cursorHelper.desktopLocation().yValue().asFixed24x8();
if (pinScreen >= 0) {
_cursorHelper.updateScreenLocation(screen[pinScreen].desktopBounds, screen[pinScreen].displayBounds);
}
else {
_cursorHelper.updateScreenLocation(NULL, NULL);
}
evg->screenCursorFixed.x = _cursorHelper.getScreenLocation().xValue().asFixed24x8();
evg->screenCursorFixed.y = _cursorHelper.getScreenLocation().yValue().asFixed24x8();
if (newScreens != cursorScreens) {
hideCursor();
cursorScreens = newScreens;
if (pinScreen >= 0) {
cursorPin = *(((EvScreen*)evScreen)[pinScreen].desktopBounds);
cursorPinScreen = pinScreen;
showCursor();
}
} else {
moveCursor();
}
}
}
else {
_cursorHelper.desktopLocation().xValue().fromFixed24x8(evg->desktopCursorFixed.x);
_cursorHelper.desktopLocation().yValue().fromFixed24x8(evg->desktopCursorFixed.y);
}
AbsoluteTime uptime;
clock_get_uptime(&uptime);
_cursorLog(uptime);
if (evg->movedMask) {
if ((evg->movedMask & NX_LMOUSEDRAGGEDMASK) && (evg->buttons & EV_LB)) {
_postMouseMoveEvent(NX_LMOUSEDRAGGED, uptime, sender);
}
else if ((evg->movedMask & NX_RMOUSEDRAGGEDMASK) && (evg->buttons & EV_RB)) {
_postMouseMoveEvent(NX_RMOUSEDRAGGED, uptime, sender);
}
else if (evg->movedMask & NX_MOUSEMOVEDMASK) {
_postMouseMoveEvent(NX_MOUSEMOVED, uptime, sender);
}
}
if (cursorMoved && evg->mouseRectValid && _cursorHelper.desktopLocation().inRect(evg->mouseRect))
{
if (evg->mouseRectValid)
{
postEvent( NX_MOUSEEXITED,
&_cursorHelper.desktopLocation(),
uptime,
NULL,
sender);
evg->mouseRectValid = 0;
}
}
OSSpinLockUnlock(&evg->cursorSema);
PROFILE_TRACE(10);
}
void IOHIDSystem::_postMouseMoveEvent(int what,
AbsoluteTime ts,
OSObject * sender)
{
NXEventData data;
CachedMouseEventStruct *cachedMouseEvent = 0;
PROFILE_TRACE(11);
bzero( &data, sizeof(data) );
data.mouseMove.dx = _cursorHelper.desktopLocationDelta().xValue().as32();
data.mouseMove.dy = _cursorHelper.desktopLocationDelta().yValue().as32();
data.mouseMove.subx = _cursorHelper.desktopLocation().xValue().fraction() >> 8;
data.mouseMove.suby = _cursorHelper.desktopLocation().yValue().fraction() >> 8;
_cursorHelper.desktopLocationDelta() = IOFixedPoint64();
_cursorLog(AbsoluteTime_to_scalar(&ts));
updateMouseMoveEventForSender(sender, &data);
if (sender && (cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, sender)))
{
if (data.mouse.subType != NX_SUBTYPE_MOUSE_TOUCH)
data.mouseMove.subType = cachedMouseEvent->subType;
data.mouseMove.reserved1 = cachedMouseEvent->lastPressure;
if (cachedMouseEvent->subType == NX_SUBTYPE_TABLET_PROXIMITY)
{
bcopy(&(cachedMouseEvent->proximityData), &(data.mouseMove.tablet.proximity), sizeof(NXTabletProximityData));
}
else if (cachedMouseEvent->subType == NX_SUBTYPE_TABLET_POINT)
{
bcopy(&(cachedMouseEvent->tabletData), &(data.mouseMove.tablet.point), sizeof(NXTabletPointData));
}
}
postEvent(what, &_cursorHelper.desktopLocation(), ts, &data, sender);
PROFILE_TRACE(12);
}
IOReturn IOHIDSystem::newUserClient(task_t owningTask,
void * security_id,
UInt32 type,
OSDictionary * properties,
IOUserClient ** handler)
{
IOHIDCmdGateActionArgs args;
args.arg0 = &owningTask;
args.arg1 = security_id;
args.arg2 = &type;
args.arg3 = properties;
args.arg4 = handler;
return cmdGate->runAction((IOCommandGate::Action)doNewUserClient, &args);
}
IOReturn IOHIDSystem::doNewUserClient(IOHIDSystem *self, void * args)
{
task_t owningTask = *(task_t *) ((IOHIDCmdGateActionArgs *)args)->arg0;
void * security_id = ((IOHIDCmdGateActionArgs *)args)->arg1;
UInt32 type = *(UInt32 *) ((IOHIDCmdGateActionArgs *)args)->arg2;
OSDictionary * properties = (OSDictionary *) ((IOHIDCmdGateActionArgs *)args)->arg3;
IOUserClient ** handler = (IOUserClient **) ((IOHIDCmdGateActionArgs *)args)->arg4;
return self->newUserClientGated(owningTask, security_id, type, properties, handler);
}
IOReturn IOHIDSystem::newUserClientGated(task_t owningTask,
void * security_id,
UInt32 type,
OSDictionary * properties,
IOUserClient ** handler)
{
IOUserClient * newConnect = 0;
IOReturn err = kIOReturnNoMemory;
do {
if ( type == kIOHIDParamConnectType) {
if ( paramConnect) {
newConnect = paramConnect;
newConnect->retain();
}
else if ( eventsOpen) {
newConnect = new IOHIDParamUserClient;
}
else {
err = kIOReturnNotOpen;
continue;
}
}
else if ( type == kIOHIDServerConnectType) {
newConnect = new IOHIDUserClient;
}
else if ( type == kIOHIDStackShotConnectType ) {
newConnect = new IOHIDStackShotUserClient;
}
else if ( type == kIOHIDEventSystemConnectType ) {
newConnect = new IOHIDEventSystemUserClient;
}
else {
err = kIOReturnUnsupported;
}
if ( !newConnect) {
continue;
}
if ( (newConnect != paramConnect) && (
(false == newConnect->initWithTask(owningTask, security_id, type, properties))
|| (false == newConnect->setProperty(kIOUserClientCrossEndianCompatibleKey, kOSBooleanTrue))
|| (false == newConnect->attach( this ))
|| (false == newConnect->start( this ))
|| ((type == kIOHIDServerConnectType)
&& (err = evOpen()))
)) {
newConnect->detach( this );
newConnect->release();
newConnect = 0;
continue;
}
if ( type == kIOHIDParamConnectType)
paramConnect = newConnect;
err = kIOReturnSuccess;
}
while( false );
#ifdef DEBUG
int pid = -1;
proc_t p = (proc_t)get_bsdtask_info(owningTask);
pid = proc_pid(p);
IOLog("%s (%d) %s returned %p\n", __func__, pid,
type == kIOHIDParamConnectType ? "IOHIDParamUserClient" :
type == kIOHIDServerConnectType ? "IOHIDUserClient" :
type == kIOHIDStackShotConnectType ? "IOHIDStackShotUserClient" :
type == kIOHIDEventSystemConnectType ? "IOHIDEventSystemUserClient" :
"kIOReturnUnsupported",
newConnect);
#endif
IOHID_DEBUG(kIOHIDDebugCode_NewUserClient, type, err, newConnect, 0);
*handler = newConnect;
return err;
}
IOReturn IOHIDSystem::setEventsEnable(void*p1,void*,void*,void*,void*,void*)
{ IOReturn ret;
if (mac_iokit_check_hid_control(kauth_cred_get()))
return kIOReturnNotPermitted;
ret = cmdGate->runAction((IOCommandGate::Action)doSetEventsEnablePre, p1);
if ( ret == kIOReturnSuccess ) {
_resetMouseParameters();
}
ret = cmdGate->runAction((IOCommandGate::Action)doSetEventsEnablePost, p1);
return ret;
}
IOReturn IOHIDSystem::doSetEventsEnablePre(IOHIDSystem *self, void *p1)
{
return self->setEventsEnablePreGated(p1);
}
IOReturn IOHIDSystem::setEventsEnablePreGated(void*p1)
{
bool enable = (bool)p1;
if( enable) {
while ( evStateChanging )
cmdGate->commandSleep(&evStateChanging);
evStateChanging = true;
attachDefaultEventSources();
}
return( kIOReturnSuccess);
}
IOReturn IOHIDSystem::doSetEventsEnablePost(IOHIDSystem *self, void *p1)
{
return self->setEventsEnablePostGated(p1);
}
IOReturn IOHIDSystem::setEventsEnablePostGated(void*p1)
{
bool enable = (bool)p1;
if( enable) {
evStateChanging = false;
cmdGate->commandWakeup(&evStateChanging);
}
return( kIOReturnSuccess);
}
IOReturn IOHIDSystem::setCursorEnable(void*p1,void*,void*,void*,void*,void*)
{ if (mac_iokit_check_hid_control(kauth_cred_get()))
return kIOReturnNotPermitted;
return cmdGate->runAction((IOCommandGate::Action)doSetCursorEnable, p1);
}
IOReturn IOHIDSystem::doSetCursorEnable(IOHIDSystem *self, void * arg0)
{
return self->setCursorEnableGated(arg0);
}
IOReturn IOHIDSystem::setCursorEnableGated(void* p1)
{
bool enable = (bool)(intptr_t)p1;
if ( !eventsOpen ) {
return kIOReturnNotOpen;
}
if( !screens) {
return kIOReturnNoDevice;
}
if( enable ) {
if( cursorStarted) {
hideCursor();
cursorEnabled = resetCursor();
showCursor();
}
else {
cursorEnabled = startCursor();
}
}
else {
cursorEnabled = enable;
}
if (cursorCoupled != cursorEnabled) {
_periodicEventNext = UINT64_MAX;
_cursorMoveDelta = 0;
_cursorHelper.desktopLocationPosting().fromIntFloor(0, 0);
_cursorHelper.clearEventCounts();
_cursorLogTimed();
scheduleNextPeriodicEvent();
cursorCoupled = cursorEnabled;
}
return kIOReturnSuccess;
}
IOReturn IOHIDSystem::extSetBounds( IOGBounds * bounds )
{
if (mac_iokit_check_hid_control(kauth_cred_get()))
return kIOReturnNotPermitted;
if( bounds->minx != bounds->maxx) {
cursorPin = *bounds;
cursorPinned = true;
} else
cursorPinned = false;
return( kIOReturnSuccess );
}
IOReturn IOHIDSystem::extPostEvent(void*p1,void*p2,void*,void*,void*,void*)
{ AbsoluteTime ts;
clock_get_uptime(&ts);
return cmdGate->runAction((IOCommandGate::Action)doExtPostEvent, p1, p2, &ts);
}
IOReturn IOHIDSystem::doExtPostEvent(IOHIDSystem *self, void * arg0, void * arg1, void * arg2, void * arg3 __unused)
{
return self->extPostEventGated(arg0, arg1, arg2);
}
IOReturn IOHIDSystem::extPostEventGated(void *p1,void *p2 __unused, void *p3)
{
struct evioLLEvent * event = (struct evioLLEvent *)p1;
bool isMoveOrDragEvent = false;
bool isSeized = false;
int oldMovedMask = 0;
UInt32 buttonState = 0;
UInt32 newFlags = 0;
AbsoluteTime ts = *(AbsoluteTime *)p3;
CachedMouseEventStruct *cachedMouseEvent = NULL;
UInt32 typeMask = EventCodeMask(event->type);
int extPID = proc_selfpid();
IOHID_DEBUG(kIOHIDDebugCode_ExtPostEvent, event->type, *(UInt32*)&(event->location), event->setFlags, event->flags);
if (event->type != NX_NULLEVENT && mac_iokit_check_hid_control(kauth_cred_get()))
return kIOReturnNotPermitted;
if ( eventsOpen == false )
return kIOReturnNotOpen;
if (ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline, false)) {
if (typeMask & NX_WAKEMASK) {
TICKLE_DISPLAY(event->type);
}
return kIOReturnSuccess;
}
if (!DISPLAY_IS_ENABLED) {
#if !WAKE_DISPLAY_ON_MOVEMENT
if ( (typeMask & NX_WAKEMASK) ||
((typeMask & MOVEDEVENTMASK) && (CMP_ABSOLUTETIME(&ts, &displaySleepWakeupDeadline) <= 0)) )
#endif
{
TICKLE_DISPLAY(event->type);
}
return kIOReturnSuccess;
}
TICKLE_DISPLAY(event->type);
if (typeMask & MOVEDEVENTMASK)
{
isMoveOrDragEvent = true;
if ((event->data.mouseMove.subType == NX_SUBTYPE_TABLET_POINT) && (event->data.mouseMove.reserved1 == 0))
{
event->data.mouseMove.reserved1 = ScalePressure(event->data.mouseMove.tablet.point.pressure);
}
}
else if ((typeMask & MOUSEEVENTMASK) &&
(event->data.mouse.subType == NX_SUBTYPE_TABLET_POINT) && (event->data.mouse.pressure == 0))
{
event->data.mouse.pressure = ScalePressure(event->data.mouse.tablet.point.pressure);
}
if( event->setCursor)
{
if (isMoveOrDragEvent)
{
oldMovedMask = evg->movedMask;
evg->movedMask = 0;
}
if (( event->type == NX_MOUSEMOVED ) &&
( event->setCursor & kIOHIDSetRelativeCursorPosition ))
{
IOFixedPoint32 move;
move.x = (event->data.mouseMove.dx * 256);
move.y = (event->data.mouseMove.dy * 256);
_cursorHelper.desktopLocation() += move;
_cursorHelper.desktopLocationDelta() += move;
_cursorLog(AbsoluteTime_to_scalar(&ts));
clock_get_uptime(&_cursorEventLast);
_setCursorPosition();
_cursorMoveLast = _cursorEventLast;
}
else if ( event->setCursor & kIOHIDSetCursorPosition )
{
setCursorPosition(&event->location, false);
}
if (isMoveOrDragEvent)
evg->movedMask = oldMovedMask;
}
else
{
UInt32 newScreens = 0;
EvScreen *screen = (EvScreen *)evScreen;
if (!cursorPinned) {
for (int i = 0; i < screens; i++ ) {
if (!screen[i].desktopBounds)
continue;
if ((screen[i].desktopBounds->maxx - screen[i].desktopBounds->minx) < 128)
continue;
if (_cursorHelper.desktopLocation().inRect(*screen[i].desktopBounds)) {
newScreens |= (1 << i);
}
}
}
if (newScreens == 0)
{
event->location.x = (event->location.x < cursorPin.minx) ?
cursorPin.minx : ((event->location.x > cursorPin.maxx) ?
cursorPin.maxx : event->location.x);
event->location.y = (event->location.y < cursorPin.miny) ?
cursorPin.miny : ((event->location.y > cursorPin.maxy) ?
cursorPin.maxy : event->location.y);
}
}
if ((typeMask & (NX_LMOUSEDOWNMASK | NX_RMOUSEDOWNMASK | NX_LMOUSEUPMASK | NX_RMOUSEUPMASK)) ||
((event->type == NX_SYSDEFINED) && (event->data.compound.subType == NX_SUBTYPE_AUX_MOUSE_BUTTONS)))
{
cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, 0);
if (cachedMouseEvent)
{
buttonState = cachedMouseEvent->lastButtons;
switch ( event->type )
{
case NX_LMOUSEDOWN:
buttonState |= EV_LB;
break;
case NX_RMOUSEDOWN:
buttonState |= EV_RB;
break;
case NX_LMOUSEUP:
buttonState &= ~EV_LB;
break;
case NX_RMOUSEUP:
buttonState &= ~EV_RB;
break;
case NX_SYSDEFINED:
CONVERT_HW_TO_WV_BUTTONS(event->data.compound.misc.L[1], buttonState);
}
cachedMouseEvent->lastButtons = buttonState;
evg->buttons = GetCachedMouseButtonStates(cachedButtonStates);
}
}
if( event->setFlags & kIOHIDSetGlobalEventFlags)
{
newFlags = evg->eventFlags = (evg->eventFlags & ~KEYBOARD_FLAGSMASK)
| (event->flags & KEYBOARD_FLAGSMASK);
}
if ( event->setFlags & kIOHIDPostHIDManagerEvent )
{
if ((typeMask & (MOUSEEVENTMASK | MOVEDEVENTMASK | NX_SCROLLWHEELMOVEDMASK)) &&
(_hidPointingDevice || (_hidPointingDevice = IOHIDPointingDevice::newPointingDeviceAndStart(this, 8, 400, true, 2))))
{
SInt32 dx = 0;
SInt32 dy = 0;
SInt32 wheel = 0;
buttonState = 0;
if (typeMask & MOVEDEVENTMASK)
{
dx = event->data.mouseMove.dx;
dy = event->data.mouseMove.dy;
}
else if ( event->type == NX_SCROLLWHEELMOVED )
{
wheel = event->data.scrollWheel.deltaAxis1;
}
if (cachedMouseEvent ||
(NULL != (cachedMouseEvent = GetCachedMouseEventForService(cachedButtonStates, 0))))
CONVERT_EV_TO_HW_BUTTONS((cachedMouseEvent->lastButtons), buttonState);
_hidPointingDevice->postMouseEvent(buttonState, dx, dy, wheel);
isSeized |= _hidPointingDevice->isSeized();
}
if ((typeMask & (NX_KEYDOWNMASK | NX_KEYUPMASK | NX_FLAGSCHANGEDMASK)) &&
(_hidKeyboardDevice || (_hidKeyboardDevice = IOHIDKeyboardDevice::newKeyboardDeviceAndStart(this, 1))))
{
_hidKeyboardDevice->postFlagKeyboardEvent(newFlags & KEYBOARD_FLAGSMASK);
if ((event->type != NX_FLAGSCHANGED) && (event->data.key.repeat == 0))
{
_hidKeyboardDevice->postKeyboardEvent(event->data.key.keyCode, (event->type == NX_KEYDOWN));
}
isSeized |= _hidKeyboardDevice->isSeized();
}
}
if ( !isSeized )
{
postEvent( event->type,
&_cursorHelper.desktopLocation(),
ts,
&event->data,
0,
extPID);
}
scheduleNextPeriodicEvent();
return kIOReturnSuccess;
}
IOReturn IOHIDSystem::extSetMouseLocation(void*p1,void*p2,void*,void*,void*,void*)
{ if (mac_iokit_check_hid_control(kauth_cred_get()))
return kIOReturnNotPermitted;
if ((sizeof(int32_t)*3) != (intptr_t)p2) {
IOLog("IOHIDSystem::extSetMouseLocation called with inappropriate data size: %d\n", (int)(intptr_t)p2);
return kIOReturnBadArgument;
}
return cmdGate->runAction((IOCommandGate::Action)doExtSetMouseLocation, p1);
}
IOReturn IOHIDSystem::doExtSetMouseLocation(IOHIDSystem *self, void * arg0)
{
return self->extSetMouseLocationGated(arg0);
}
IOReturn IOHIDSystem::extSetMouseLocationGated(void *p1)
{
IOFixedPoint32 * loc = (IOFixedPoint32 *)p1;
IOHID_DEBUG(kIOHIDDebugCode_ExtSetLocation, loc ? loc->x : 0, loc ? loc->y : 0, loc, 0);
if ( eventsOpen == true )
{
_cursorHelper.desktopLocationDelta() += *loc;
_cursorHelper.desktopLocationDelta() -= _cursorHelper.desktopLocation();
_cursorHelper.desktopLocation() = *loc;
_setCursorPosition(true);
}
return kIOReturnSuccess;
}
IOReturn IOHIDSystem::extGetStateForSelector(void*p1,void*p2,void*,void*,void*,void*)
{ return cmdGate->runAction((IOCommandGate::Action)doExtGetStateForSelector, p1, p2);
}
IOReturn IOHIDSystem::extSetStateForSelector(void*p1,void*p2,void*,void*,void*,void*)
{ if (mac_iokit_check_hid_control(kauth_cred_get()))
return kIOReturnNotPermitted;
return cmdGate->runAction((IOCommandGate::Action)doExtSetStateForSelector, p1, p2);
}
IOReturn IOHIDSystem::doExtGetStateForSelector(IOHIDSystem *self, void *p1, void *p2)
{
IOReturn result = kIOReturnSuccess;
unsigned int selector = (uintptr_t)p1;
unsigned int *state_O = (unsigned int*)p2;
switch (selector) {
case kIOHIDCapsLockState:
result = self->getCapsLockState(state_O);
break;
case kIOHIDNumLockState:
result = self->getNumLockState(state_O);
break;
case kIOHIDActivityUserIdle:
*state_O = self->_privateData->hidActivityIdle ? 1 : 0;
break;
case kIOHIDActivityDisplayOn:
*state_O = self->displayState & IOPMDeviceUsable ? 1 : 0;
break;
default:
IOLog("IOHIDSystem::doExtGetStateForSelector recieved unexpected selector: %d\n", selector);
result = kIOReturnBadArgument;
break;
}
return result;
}
IOReturn IOHIDSystem::doExtSetStateForSelector(IOHIDSystem *self, void *p1, void *p2)
{
IOReturn result = kIOReturnSuccess;
unsigned int selector = (uintptr_t)p1;
unsigned int state_I = (uintptr_t)p2;
switch (selector) {
case kIOHIDCapsLockState:
result = self->setCapsLockState(state_I);
break;
case kIOHIDNumLockState:
result = self->setNumLockState(state_I);
break;
case kIOHIDActivityUserIdle: case kIOHIDActivityDisplayOn: default:
IOLog("IOHIDSystem::doExtGetStateForSelector recieved unexpected selector: %d\n", selector);
result = kIOReturnBadArgument;
break;
}
return result;
}
IOReturn IOHIDSystem::getCapsLockState(unsigned int *state_O)
{
IOReturn retVal = kIOReturnNoDevice;
*state_O = false;
OSIterator *itr = getProviderIterator();
if (itr) {
bool done = false;
while (!done) {
OSObject *provider;
while (!done && (NULL != (provider = itr->getNextObject()))) {
IOHIDKeyboard *keyboard = OSDynamicCast(IOHIDKeyboard, provider);
if (keyboard) {
retVal = kIOReturnSuccess;
if (keyboard->alphaLock()) {
*state_O = true;
done = true;
}
}
}
if (itr->isValid()) {
done = true;
}
else {
itr->reset();
}
}
itr->release();
}
return retVal;
}
IOReturn IOHIDSystem::setCapsLockState(unsigned int state_I)
{
IOReturn retVal = kIOReturnNoDevice;
OSIterator *itr = getProviderIterator();
if (itr) {
bool done = false;
while (!done) {
OSObject *provider;
while (!done && (NULL != (provider = itr->getNextObject()))) {
IOHIDKeyboard *keyboard = OSDynamicCast(IOHIDKeyboard, provider);
if (keyboard) {
if ((state_I && !keyboard->alphaLock()) || (!state_I && keyboard->alphaLock())) {
AbsoluteTime timeStamp;
UInt32 opts = (1<<31) ;
clock_get_uptime(&timeStamp);
keyboard->dispatchKeyboardEvent(timeStamp, kHIDPage_KeyboardOrKeypad, kHIDUsage_KeyboardCapsLock, 1, opts);
keyboard->dispatchKeyboardEvent(timeStamp, kHIDPage_KeyboardOrKeypad, kHIDUsage_KeyboardCapsLock, 0, opts);
}
retVal = kIOReturnSuccess;
}
}
if (itr->isValid()) {
done = true;
}
else {
itr->reset();
}
}
itr->release();
}
return retVal;
}
IOReturn IOHIDSystem::getNumLockState(unsigned int *state_O)
{
IOReturn retVal = kIOReturnNoDevice;
*state_O = false;
OSIterator *itr = getProviderIterator();
if (itr) {
bool done = false;
while (!done) {
OSObject *provider;
while (!done && (NULL != (provider = itr->getNextObject()))) {
IOHIDKeyboard *keyboard = OSDynamicCast(IOHIDKeyboard, provider);
if (keyboard) {
retVal = kIOReturnSuccess;
if (keyboard->numLock()) {
*state_O = true;
done = true;
}
}
}
if (itr->isValid()) {
done = true;
}
else {
itr->reset();
}
}
itr->release();
}
return retVal;
}
IOReturn IOHIDSystem::setNumLockState(unsigned int state_I)
{
IOReturn retVal = kIOReturnNoDevice;
OSIterator *itr = getProviderIterator();
if (itr) {
bool done = false;
while (!done) {
OSObject *provider;
while (!done && (NULL != (provider = itr->getNextObject()))) {
IOHIDKeyboard *keyboard = OSDynamicCast(IOHIDKeyboard, provider);
if (keyboard) {
if ((state_I && !keyboard->numLock()) || (!state_I && keyboard->numLock())) {
AbsoluteTime timeStamp;
UInt32 opts = 0;
clock_get_uptime(&timeStamp);
keyboard->dispatchKeyboardEvent(timeStamp, kHIDPage_AppleVendorTopCase, kHIDUsage_AV_TopCase_KeyboardFn, 1, opts);
keyboard->dispatchKeyboardEvent(timeStamp, kHIDPage_AppleVendorTopCase, kHIDUsage_AV_TopCase_KeyboardFn, 0, opts);
}
retVal = kIOReturnSuccess;
}
}
if (itr->isValid()) {
done = true;
}
else {
itr->reset();
}
}
itr->release();
}
return retVal;
}
IOReturn IOHIDSystem::extGetButtonEventNum(void*p1,void*p2,void*,void*,void*,void*)
{ return cmdGate->runAction((IOCommandGate::Action)doExtGetButtonEventNum, p1, p2);
}
IOReturn IOHIDSystem::doExtGetButtonEventNum(IOHIDSystem *self, void * arg0, void * arg1)
{
return self->extGetButtonEventNumGated(arg0, arg1);
}
IOReturn IOHIDSystem::extGetButtonEventNumGated(void *p1, void* p2)
{
NXMouseButton button = (NXMouseButton)(uintptr_t)p1;
int * eventNum = (int *)p2;
IOReturn err = kIOReturnSuccess;
switch( button) {
case NX_LeftButton:
*eventNum = leftENum;
break;
case NX_RightButton:
*eventNum = rightENum;
break;
default:
err = kIOReturnBadArgument;
}
return err;
}
void IOHIDSystem::makeNumberParamProperty( OSDictionary * dict, const char * key,
unsigned long long number, unsigned int bits )
{
OSNumber * numberRef;
numberRef = OSNumber::withNumber(number, bits);
if( numberRef) {
dict->setObject( key, numberRef);
numberRef->release();
}
}
void IOHIDSystem::makeInt32ArrayParamProperty( OSDictionary * dict, const char * key,
UInt32 * intArray, unsigned int count )
{
OSArray * array;
OSNumber * number;
array = OSArray::withCapacity(count);
if ( !array )
return;
for (unsigned i=0; i<count; i++)
{
number = OSNumber::withNumber(intArray[i], sizeof(UInt32) << 3);
if (number)
{
array->setObject(number);
number->release();
}
}
dict->setObject( key, array);
array->release();
}
void IOHIDSystem::createParameters( void )
{
UInt64 nano;
IOFixed fixed;
UInt32 int32;
savedParameters->setObject(kIOHIDDefaultParametersKey, kOSBooleanTrue);
nano = EV_DCLICKTIME;
makeNumberParamProperty( savedParameters, kIOHIDClickTimeKey,
nano, 64 );
UInt32 tempClickSpace[] = {clickSpaceThresh.x, clickSpaceThresh.y};
makeInt32ArrayParamProperty( savedParameters, kIOHIDClickSpaceKey,
tempClickSpace, sizeof(tempClickSpace)/sizeof(UInt32) );
nano = EV_DEFAULTKEYREPEAT;
makeNumberParamProperty( savedParameters, kIOHIDKeyRepeatKey,
nano, 64 );
nano = EV_DEFAULTINITIALREPEAT;
makeNumberParamProperty( savedParameters, kIOHIDInitialKeyRepeatKey,
nano, 64 );
fixed = EV_DEFAULTPOINTERACCELLEVEL;
makeNumberParamProperty( savedParameters, kIOHIDPointerAccelerationKey,
fixed, sizeof(fixed) << 3);
fixed = EV_DEFAULTSCROLLACCELLEVEL;
makeNumberParamProperty( savedParameters, kIOHIDScrollAccelerationKey,
fixed, sizeof(fixed) << 3);
fixed = kIOHIDButtonMode_EnableRightClick;
makeNumberParamProperty( savedParameters, kIOHIDPointerButtonMode,
fixed, sizeof(fixed) << 3);
int32 = kEjectF12DelayMS;
makeNumberParamProperty( savedParameters, kIOHIDF12EjectDelayKey,
int32, 32 );
int32 = kEjectKeyDelayMS;
makeNumberParamProperty( savedParameters, kIOHIDKeyboardEjectDelay,
int32, 32 );
int32 = 0;
makeNumberParamProperty( savedParameters, kIOHIDSlowKeysDelayKey,
int32, 32 );
int32 = 0; makeNumberParamProperty( savedParameters, kIOHIDStickyKeysDisabledKey,
int32, 32 );
int32 = 0; makeNumberParamProperty( savedParameters, kIOHIDStickyKeysOnKey,
int32, 32 );
int32 = 0; makeNumberParamProperty( savedParameters, kIOHIDStickyKeysShiftTogglesKey,
int32, 32 );
int32 = 0; makeNumberParamProperty( savedParameters, kIOHIDMouseKeysOptionTogglesKey,
int32, 32 );
int32 = 0;
makeNumberParamProperty( savedParameters, kIOHIDFKeyModeKey,
int32, 32 );
setProperty( kIOHIDParametersKey, savedParameters );
savedParameters->release();
OSSerializer * idleTimeSerializer = OSSerializer::forTarget(this, IOHIDSystem::_idleTimeSerializerCallback);
if (idleTimeSerializer)
{
setProperty( kIOHIDIdleTimeKey, idleTimeSerializer);
idleTimeSerializer->release();
}
#if 0
OSSerializer * displaySerializer = OSSerializer::forTarget(this, IOHIDSystem::_displaySerializerCallback);
if (displaySerializer)
{
setProperty("DisplayState", displaySerializer);
displaySerializer->release();
}
#endif
}
bool IOHIDSystem::_idleTimeSerializerCallback(void * target, void * ref __unused, OSSerialize *s)
{
IOHIDSystem * self = (IOHIDSystem *) target;
AbsoluteTime currentTime;
OSNumber * number;
UInt64 idleTimeNano = 0;
bool retValue = false;
if( self->eventsOpen )
{
clock_get_uptime( ¤tTime);
SUB_ABSOLUTETIME( ¤tTime, &(self->lastUndimEvent));
absolutetime_to_nanoseconds( currentTime, &idleTimeNano);
}
number = OSNumber::withNumber(idleTimeNano, 64);
if (number)
{
retValue = number->serialize( s );
number->release();
}
return retValue;
}
bool IOHIDSystem::_displaySerializerCallback(void * target, void * ref __unused, OSSerialize *s)
{
IOHIDSystem *self = (IOHIDSystem *) target;
bool retValue = false;
OSDictionary *mainDict = OSDictionary::withCapacity(4);
require(mainDict, exit_early);
#define IfNotNullAddNumToDictWithKey(x,y, w,z) \
if (x) { \
OSNumber *num = NULL; \
num = OSNumber::withNumber(y, 8*sizeof(y)); \
if (num) { \
w->setObject(z, num); \
num->release(); \
} \
}
for(int i = 0; i < self->screens; i++) {
EvScreen &esp = ((EvScreen*)(self->evScreen))[i];
OSDictionary *thisDisplay = OSDictionary::withCapacity(4);
char key[256];
require(thisDisplay, next_display);
snprintf(key, sizeof(key), "%d", i);
mainDict->setObject(key, thisDisplay);
IfNotNullAddNumToDictWithKey(esp.instance, esp.instance->getRegistryEntryID(), thisDisplay, "io_fb_id");
IfNotNullAddNumToDictWithKey(esp.displayBounds, esp.displayBounds->minx, thisDisplay, "disp_min_x");
IfNotNullAddNumToDictWithKey(esp.displayBounds, esp.displayBounds->maxx, thisDisplay, "disp_max_x");
IfNotNullAddNumToDictWithKey(esp.displayBounds, esp.displayBounds->miny, thisDisplay, "disp_min_y");
IfNotNullAddNumToDictWithKey(esp.displayBounds, esp.displayBounds->maxy, thisDisplay, "disp_max_y");
IfNotNullAddNumToDictWithKey(esp.desktopBounds, esp.desktopBounds->minx, thisDisplay, "desk_min_x");
IfNotNullAddNumToDictWithKey(esp.desktopBounds, esp.desktopBounds->maxx, thisDisplay, "desk_max_x");
IfNotNullAddNumToDictWithKey(esp.desktopBounds, esp.desktopBounds->miny, thisDisplay, "desk_min_y");
IfNotNullAddNumToDictWithKey(esp.desktopBounds, esp.desktopBounds->maxy, thisDisplay, "desk_max_y");
IfNotNullAddNumToDictWithKey(esp.creator_pid, esp.creator_pid, thisDisplay, "creator_pid");
next_display:
OSSafeReleaseNULL(thisDisplay);
}
{ OSDictionary *workSpaceDict = OSDictionary::withCapacity(4);
IfNotNullAddNumToDictWithKey(workSpaceDict, self->workSpace.minx, workSpaceDict, "minx");
IfNotNullAddNumToDictWithKey(workSpaceDict, self->workSpace.miny, workSpaceDict, "miny");
IfNotNullAddNumToDictWithKey(workSpaceDict, self->workSpace.maxx, workSpaceDict, "maxx");
IfNotNullAddNumToDictWithKey(workSpaceDict, self->workSpace.maxy, workSpaceDict, "maxy");
mainDict->setObject("workspace", workSpaceDict ? (OSObject*)workSpaceDict : (OSObject*)kOSBooleanFalse);
OSSafeReleaseNULL(workSpaceDict);
}
{ OSDictionary *cursorPinDict = OSDictionary::withCapacity(4);
IfNotNullAddNumToDictWithKey(cursorPinDict, self->cursorPin.minx, cursorPinDict, "minx");
IfNotNullAddNumToDictWithKey(cursorPinDict, self->cursorPin.miny, cursorPinDict, "miny");
IfNotNullAddNumToDictWithKey(cursorPinDict, self->cursorPin.maxx, cursorPinDict, "maxx");
IfNotNullAddNumToDictWithKey(cursorPinDict, self->cursorPin.maxy, cursorPinDict, "maxy");
mainDict->setObject("cursorPin", cursorPinDict ? (OSObject*)cursorPinDict : (OSObject*)kOSBooleanFalse);
OSSafeReleaseNULL(cursorPinDict);
}
retValue = mainDict->serialize( s );
exit_early:
OSSafeReleaseNULL(mainDict);
return retValue;
}
IOReturn IOHIDSystem::setProperties( OSObject * properties )
{
OSDictionary * dict;
IOReturn err = kIOReturnSuccess;
IOReturn ret;
dict = OSDynamicCast( OSDictionary, properties );
if( dict) {
if (dict->getObject(kIOHIDUseKeyswitchKey) &&
( IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator) != kIOReturnSuccess)) {
dict->removeObject(kIOHIDUseKeyswitchKey);
}
ret = setParamProperties( dict );
}
else
err = kIOReturnBadArgument;
return( err );
}
IOReturn IOHIDSystem::setParamProperties( OSDictionary * dict )
{
OSIterator * iter = NULL;
IOReturn ret = kIOReturnSuccess;
IOReturn err = kIOReturnSuccess;
dict->setObject(kIOHIDDefaultParametersKey, kOSBooleanTrue);
ret = cmdGate->runAction((IOCommandGate::Action)doSetParamPropertiesPre, dict, &iter);
if ( ret == kIOReturnSuccess ) {
if( iter) {
IOService * eventSrc;
OSDictionary * validParameters;
while( (eventSrc = (IOService *) iter->getNextObject())) {
if ( OSDynamicCast(IOHIDKeyboard, eventSrc) || OSDynamicCast(IOHIDPointing, eventSrc) || OSDynamicCast(IOHIDConsumer, eventSrc))
continue;
validParameters = createFilteredParamPropertiesForService(eventSrc, dict);
if ( validParameters ) {
if ( OSDynamicCast(IOHIDevice, eventSrc) )
ret = ((IOHIDevice *)eventSrc)->setParamProperties( validParameters );
else if ( OSDynamicCast( IOHIDEventService, eventSrc ) )
ret = ((IOHIDEventService *)eventSrc)->setSystemProperties( validParameters );
if( (ret != kIOReturnSuccess) && (ret != kIOReturnBadArgument))
err = ret;
dict->merge(validParameters);
validParameters->release();
}
}
iter->release();
}
cmdGate->runAction((IOCommandGate::Action)doSetParamPropertiesPost, dict);
}
return err;
}
OSDictionary * IOHIDSystem::createFilteredParamPropertiesForService(IOService * service, OSDictionary * dict)
{
OSDictionary * validParameters = OSDictionary::withCapacity(4);
if ( !validParameters )
return NULL;
OSDictionary * deviceParameters = NULL;
if ( OSDynamicCast(IOHIDevice, service) ) {
deviceParameters = (OSDictionary*)service->copyProperty(kIOHIDParametersKey);
}
else if ( OSDynamicCast( IOHIDEventService, service ) ) {
deviceParameters = (OSDictionary*)service->copyProperty(kIOHIDEventServicePropertiesKey);
}
if (!OSDynamicCast(OSDictionary, deviceParameters))
OSSafeReleaseNULL(deviceParameters);
OSCollectionIterator * iterator = OSCollectionIterator::withCollection(dict);
if ( iterator ) {
bool done = false;
while (!done) {
OSSymbol * key = NULL;
while ((key = (OSSymbol*)iterator->getNextObject()) != NULL) {
if ( !deviceParameters || !deviceParameters->getObject(key) ) {
validParameters->setObject(key, dict->getObject(key));
}
}
if (iterator->isValid()) {
done = true;
}
else {
iterator->reset();
validParameters->flushCollection();
}
}
iterator->release();
}
if ( validParameters->getCount() == 0 ) {
validParameters->release();
validParameters = NULL;
}
else {
validParameters->setObject(kIOHIDDefaultParametersKey, kOSBooleanTrue);
}
return validParameters;
}
IOReturn IOHIDSystem::doSetParamPropertiesPre(IOHIDSystem *self, void * arg0, void * arg1)
{
return self->setParamPropertiesPreGated((OSDictionary *)arg0, (OSIterator**)arg1);
}
IOReturn IOHIDSystem::setParamPropertiesPreGated( OSDictionary * dict, OSIterator ** pOpenIter)
{
OSArray * array;
OSNumber * number;
if (dict == NULL)
return kIOReturnError;
while ( setParamPropertiesInProgress )
cmdGate->commandSleep(&setParamPropertiesInProgress);
setParamPropertiesInProgress = true;
if( (number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDUseKeyswitchKey))))
{
gUseKeyswitch = number->unsigned32BitValue();
}
if( (number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDClickTimeKey))))
{
UInt64 nano = number->unsigned64BitValue();
nanoseconds_to_absolutetime(nano, &clickTimeThresh);
}
if (dict->getObject(kIOHIDScrollCountResetKey)) {
_setScrollCountParameters();
}
_setScrollCountParameters(dict);
if( (array = OSDynamicCast( OSArray,
dict->getObject(kIOHIDClickSpaceKey)))) {
if ((number = OSDynamicCast( OSNumber,
array->getObject(EVSIOSCS_X))))
{
clickSpaceThresh.x = number->unsigned32BitValue();
}
if ((number = OSDynamicCast( OSNumber,
array->getObject(EVSIOSCS_Y))))
{
clickSpaceThresh.y = number->unsigned32BitValue();
}
}
if( (number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDWaitCursorFrameIntervalKey)))) {
uint32_t value = number->unsigned32BitValue();
_cursorWaitDelta = value;
if (_cursorWaitDelta < kTickScale) {
_cursorWaitDelta = kTickScale;
}
scheduleNextPeriodicEvent();
}
if( (number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDStickyKeysOnKey)))) {
if (number->unsigned32BitValue())
stickyKeysState |= (1 << 0);
else
stickyKeysState &= ~(1 << 0);
}
if( (number = OSDynamicCast( OSNumber, dict->getObject(kIOHIDStickyKeysShiftTogglesKey)))) {
if (number->unsigned32BitValue())
stickyKeysState |= (1 << 1);
else
stickyKeysState &= ~(1 << 1);
}
if ( dict->getObject(kIOHIDResetKeyboardKey) ) {
UInt64 nano = EV_DEFAULTKEYREPEAT;
makeNumberParamProperty( dict, kIOHIDKeyRepeatKey, nano, 64 );
nano = EV_DEFAULTINITIALREPEAT;
makeNumberParamProperty( dict, kIOHIDInitialKeyRepeatKey, nano, 64 );
}
if ( dict->getObject(kIOHIDResetPointerKey) ) {
IOFixed fixed = EV_DEFAULTPOINTERACCELLEVEL;
makeNumberParamProperty( dict, kIOHIDPointerAccelerationKey, fixed, sizeof(fixed) << 3);
fixed = kIOHIDButtonMode_EnableRightClick;
makeNumberParamProperty( dict, kIOHIDPointerButtonMode, fixed, sizeof(fixed) << 3);
UInt64 nano = EV_DCLICKTIME;
makeNumberParamProperty( dict, kIOHIDClickTimeKey, nano, 64 );
}
if ( dict->getObject(kIOHIDScrollResetKey) ) {
IOFixed fixed = EV_DEFAULTSCROLLACCELLEVEL;
makeNumberParamProperty( dict, kIOHIDScrollAccelerationKey, fixed, sizeof(fixed) << 3);
}
if ( pOpenIter )
*pOpenIter = getOpenProviderIterator();
return kIOReturnSuccess;
}
void IOHIDSystem::_setScrollCountParameters(OSDictionary *newSettings)
{
if (!newSettings) {
newSettings = (OSDictionary*)copyProperty(kIOHIDScrollCountBootDefaultKey);
if (!OSDynamicCast(OSDictionary, newSettings)) {
newSettings->release();
newSettings = NULL;
}
}
else {
newSettings->retain();
}
if (newSettings) {
OSNumber *number = NULL;
OSBoolean *boolean = NULL;
if((number = OSDynamicCast(OSNumber, newSettings->getObject(kIOHIDScrollCountMinDeltaToStartKey))))
{
_scMinDeltaSqToStart = number->unsigned64BitValue();
_scMinDeltaSqToStart *= _scMinDeltaSqToStart;
if (_scMinDeltaSqToSustain == kDefaultMinimumDelta)
_scMinDeltaSqToSustain = _scMinDeltaSqToStart;
setProperty(kIOHIDScrollCountMinDeltaToStartKey, number);
}
if((number = OSDynamicCast(OSNumber, newSettings->getObject(kIOHIDScrollCountMinDeltaToSustainKey))))
{
_scMinDeltaSqToSustain = number->unsigned64BitValue();
_scMinDeltaSqToSustain *= _scMinDeltaSqToSustain;
if (_scMinDeltaSqToStart == kDefaultMinimumDelta)
_scMinDeltaSqToStart = _scMinDeltaSqToSustain;
setProperty(kIOHIDScrollCountMinDeltaToSustainKey, number);
}
if((number = OSDynamicCast(OSNumber, newSettings->getObject(kIOHIDScrollCountMaxTimeDeltaBetweenKey))))
{
UInt64 valueInMs = number->unsigned64BitValue();
nanoseconds_to_absolutetime(valueInMs * kMillisecondScale, &_scMaxTimeDeltaBetween);
if (!_scMaxTimeDeltaToSustain)
_scMaxTimeDeltaToSustain = _scMaxTimeDeltaBetween;
setProperty(kIOHIDScrollCountMaxTimeDeltaBetweenKey, number);
}
if((number = OSDynamicCast(OSNumber, newSettings->getObject(kIOHIDScrollCountMaxTimeDeltaToSustainKey))))
{
UInt64 valueInMs = number->unsigned64BitValue();
nanoseconds_to_absolutetime(valueInMs * kMillisecondScale, &_scMaxTimeDeltaToSustain);
if (!_scMaxTimeDeltaBetween)
_scMaxTimeDeltaBetween = _scMaxTimeDeltaToSustain;
setProperty(kIOHIDScrollCountMaxTimeDeltaToSustainKey, number);
}
if((boolean = OSDynamicCast(OSBoolean, newSettings->getObject(kIOHIDScrollCountIgnoreMomentumScrollsKey))))
{
_scIgnoreMomentum = (boolean == kOSBooleanTrue);
setProperty(kIOHIDScrollCountIgnoreMomentumScrollsKey, boolean);
}
if((boolean = OSDynamicCast(OSBoolean, newSettings->getObject(kIOHIDScrollCountMouseCanResetKey))))
{
_scMouseCanReset = (boolean == kOSBooleanTrue);
setProperty(kIOHIDScrollCountMouseCanResetKey, boolean);
}
if((number = OSDynamicCast(OSNumber, newSettings->getObject(kIOHIDScrollCountMaxKey))))
{
_scCountMax = number->unsigned16BitValue();
setProperty(kIOHIDScrollCountMaxKey, number);
}
if((number = OSDynamicCast(OSNumber, newSettings->getObject(kIOHIDScrollCountAccelerationFactorKey))))
{
if (number->unsigned32BitValue() > 0) {
_scAccelerationFactor.fromFixed(number->unsigned32BitValue());
setProperty(kIOHIDScrollCountAccelerationFactorKey, number);
}
}
if((boolean = OSDynamicCast(OSBoolean, newSettings->getObject(kIOHIDScrollCountZeroKey))))
{
if (boolean == kOSBooleanTrue) {
log_scroll_state("Resetting _scCount on kIOHIDScrollCountZeroKey%s\n", "");
_scCount = 0;
}
}
newSettings->release();
}
}
IOReturn IOHIDSystem::doSetParamPropertiesPost(IOHIDSystem *self, void * arg0)
{
return self->setParamPropertiesPostGated((OSDictionary *)arg0);
}
IOReturn IOHIDSystem::setParamPropertiesPostGated( OSDictionary * dict)
{
if ( dict->getObject(kIOHIDTemporaryParametersKey) == NULL ) {
bool resetKeyboard = dict->getObject(kIOHIDResetKeyboardKey) != NULL;
bool resetPointer = dict->getObject(kIOHIDResetPointerKey) != NULL;
bool resetScroll = dict->getObject(kIOHIDScrollResetKey) != NULL;
OSDictionary * newParams = OSDictionary::withDictionary( savedParameters );
if( newParams) {
if ( resetKeyboard ) {
dict->removeObject(kIOHIDResetKeyboardKey);
}
if ( resetPointer ) {
dict->removeObject(kIOHIDResetPointerKey);
newParams->removeObject(kIOHIDTrackpadAccelerationType);
newParams->removeObject(kIOHIDMouseAccelerationType);
}
if ( resetScroll ) {
dict->removeObject(kIOHIDScrollResetKey);
newParams->removeObject(kIOHIDTrackpadScrollAccelerationKey);
newParams->removeObject(kIOHIDMouseScrollAccelerationKey);
}
newParams->merge( dict );
setProperty( kIOHIDParametersKey, newParams );
newParams->release();
savedParameters = newParams;
}
struct evioLLEvent event;
AbsoluteTime ts;
bzero( (void *)&event, sizeof event);
event.data.compound.subType = NX_SUBTYPE_HIDPARAMETER_MODIFIED;
clock_get_uptime(&ts);
postEvent(NX_SYSDEFINED, &_cursorHelper.desktopLocation(), ts, &(event.data));
}
setParamPropertiesInProgress = false;
cmdGate->commandWakeup(&setParamPropertiesInProgress);
return kIOReturnSuccess;
}
UInt8 IOHIDSystem::getSubtypeForSender(OSObject * sender)
{
UInt8 subtype = NX_SUBTYPE_DEFAULT;
if (touchEventPosters->containsObject(sender)) {
subtype = NX_SUBTYPE_MOUSE_TOUCH;
}
return subtype;
}
void IOHIDSystem::updateMouseMoveEventForSender(OSObject * sender, NXEventData * evData)
{
if (sender && evData) {
evData->mouse.subType = getSubtypeForSender(sender);
}
}
void IOHIDSystem::updateMouseEventForSender(OSObject * sender, NXEventData * evData)
{
if (sender && evData) {
evData->mouseMove.subType = getSubtypeForSender(sender);
}
}
void IOHIDSystem::updateScrollEventForSender(OSObject * sender, NXEventData * evData)
{
if (sender && evData) {
if (NX_SUBTYPE_MOUSE_TOUCH == getSubtypeForSender(sender)) {
evData->scrollWheel.reserved1 |= kScrollTypeTouch;
}
}
}
bool IOHIDSystem::attach( IOService * provider )
{
IORegistryEntry *entry = provider;
if (!super::attach(provider)) return false;
while(entry) {
if (kOSBooleanTrue == entry->getProperty("MTEventSource")) {
touchEventPosters->setObject(provider);
entry = 0;
}
else {
entry = entry->getParentEntry(gIOServicePlane);
}
}
return true;
}
void IOHIDSystem::detach( IOService * provider )
{
touchEventPosters->removeObject(provider);
super::detach(provider);
}