#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/IOHIDShared.h>
#include <IOKit/hidsystem/IOHIDParameter.h>
#include <IOKit/hid/IOHIDEvent.h>
#include <IOKit/usb/USB.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#include <kern/clock.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 "IOHIDKeys.h"
#include "IOHIDPrivate.h"
#include "IOHIDPrivateKeys.h"
#include "IOHIDEventServiceQueue.h"
#include "IOLLEvent.h"
#include <IOKit/hidsystem/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)
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", event, __LINE__); \
displayManager->activityTickle(IOHID_DEBUG_CODE(event)); \
} \
}
#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 1000000000ULL // 1 second
#define kIOHIDRelativeTickleThresholdNS 50000000ULL // 1/20 second
#define kIOHIDRelativeTickleThresholdPixel 3
#define kIOHIDDispaySleepAbortThresholdNS 5000000000ULL // 5 seconds
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) {
OSObject *reportInterval_obj = senderEntry->getProperty(kIOHIDReportIntervalKey, gIOServicePlane, kIORegistryIterateRecursively| kIORegistryIterateParents);
OSNumber *reportInterval_us = OSDynamicCast(OSNumber, reportInterval_obj);
if (reportInterval_us) {
mouseStruct->reportInterval_ns = reportInterval_us->unsigned64BitValue() * 1000;
}
else {
IOLog("No interval found for %s. Using %lld\n", senderEntry->getLocation(), mouseStruct->reportInterval_ns);
}
}
}
}
}
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;
}
#define super IOService
OSDefineMetaClassAndStructors(IOHIDSystem, IOService);
struct IOHIDSystem::ExpansionData
{
IOHIDSystemCursorHelper cursorHelper;
UInt32 delayedScrollPhase;
UInt32 delayedScrollMomentum;
};
#define _cursorHelper (_privateData->cursorHelper)
#define _delayedScrollPhase (_privateData->delayedScrollPhase)
#define _delayedScrollMomentum (_privateData->delayedScrollMomentum)
#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;
}
bool IOHIDSystem::init(OSDictionary * properties)
{
if (!super::init(properties))
return false;
_privateData = (ExpansionData*)IOMalloc(sizeof(ExpansionData));
if (!_privateData)
return false;
bzero(_privateData, sizeof(ExpansionData));
if (!_cursorHelper.init())
return false;
_cursorLogTimed();
evScreen = NULL;
timerES = 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;
OSDictionary *matchingDevice = serviceMatching("IOHIDevice");
OSDictionary *matchingService = serviceMatching("IOHIDEventService");
OSDictionary *matchingWrangler = serviceMatching("IODisplayWrangler");
OSDictionary *matchingKeyswitch = serviceMatching("AppleKeyswitch");
char provider_path[512];
int length = sizeof(provider_path);
provider->getPath( provider_path, &length, gIOServicePlane);
provider_path[length] = 0;
do {
if (!super::start(provider)) break;
evInstance = this;
_cursorHelper.desktopLocation().fromIntFloor(INIT_CURSOR_X, INIT_CURSOR_Y);
_cursorHelper.desktopLocationDelta().fromIntFloor(0, 0);
_cursorHelper.updateScreenLocation(NULL, NULL);
_cursorLogTimed();
evScreenSize = sizeof(EvScreen) * 32;
evScreen = (void *) IOMalloc(evScreenSize);
savedParameters = OSDictionary::withCapacity(4);
if (!evScreen || !savedParameters) break;
bzero(evScreen, evScreenSize);
firstWaitCursorFrame = EV_WAITCURSOR;
maxWaitCursorFrame = EV_MAXCURSOR;
createParameters();
workLoop = IOHIDWorkLoop::workLoop();
cmdGate = IOCommandGate::commandGate
(this);
timerES = IOTimerEventSource::timerEventSource
(this, (IOTimerEventSource::Action) &_periodicEvents );
eventConsumerES = IOInterruptEventSource::interruptEventSource
(this, (IOInterruptEventSource::Action) &doKickEventConsumer);
keyboardEQES = IOInterruptEventSource::interruptEventSource
(this, (IOInterruptEventSource::Action) &doProcessKeyboardEQ);
vblES = IOTimerEventSource::timerEventSource
(this, &_vblEvent );
if (!workLoop || !cmdGate || !timerES || !eventConsumerES || !keyboardEQES || !vblES)
break;
if ((workLoop->addEventSource(cmdGate) != kIOReturnSuccess)
|| (workLoop->addEventSource(timerES) != kIOReturnSuccess)
|| (workLoop->addEventSource(vblES) != kIOReturnSuccess)
|| (workLoop->addEventSource(eventConsumerES) != kIOReturnSuccess)
|| (workLoop->addEventSource(keyboardEQES) != kIOReturnSuccess))
break;
publishNotify = addMatchingNotification(gIOPublishNotification,
matchingDevice,
&IOHIDSystem::genericNotificationHandler,
this,
(void *)&IOHIDSystem::handlePublishNotification );
if (!publishNotify) break;
eventPublishNotify = addMatchingNotification(gIOPublishNotification,
matchingService,
&IOHIDSystem::genericNotificationHandler,
this,
(void *)&IOHIDSystem::handlePublishNotification );
if (!eventPublishNotify) break;
terminateNotify = addMatchingNotification(gIOTerminatedNotification,
matchingDevice,
&IOHIDSystem::genericNotificationHandler,
this,
(void *)&IOHIDSystem::handleTerminateNotification );
if (!terminateNotify) break;
eventTerminateNotify = addMatchingNotification(gIOTerminatedNotification,
matchingService,
&IOHIDSystem::genericNotificationHandler,
this,
(void *)&IOHIDSystem::handleTerminateNotification );
if (!eventTerminateNotify) break;
rootDomain = (IOService *)getPMRootDomain();
if (rootDomain)
rootDomain->registerInterestedDriver(this);
registerPrioritySleepWakeInterest(powerStateHandler, this, 0);
systemInfo = OSArray::withCapacity(4);
if (systemInfo) {
setProperty(kNXSystemInfoKey, systemInfo);
systemInfo->release();
}
registerService();
addMatchingNotification(gIOPublishNotification,
matchingWrangler,
&IOHIDSystem::genericNotificationHandler,
this,
(void *)&IOHIDSystem::handlePublishNotification );
gSwitchNotification = addMatchingNotification(gIOPublishNotification,
matchingKeyswitch,
keySwitchNotificationHandler,
this,
0);
iWasStarted = true;
registryName = getName();
}
while (false);
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) && !displaySleepDrivenByPM ) {
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 * target,
void * handler,
IOService * newService,
IONotifier * )
{
IOHIDSystem * self = (IOHIDSystem *) target;
return self->cmdGate->runAction((IOCommandGate::Action)handler, newService);
}
bool IOHIDSystem::handlePublishNotification(
void * target,
IOService * newService )
{
IOHIDSystem * self = (IOHIDSystem *) target;
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);
newSystemInfo->release();
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);
}
self->detach(service);
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);
newSystemInfo->release();
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 (workLoop) {
workLoop->disableAllEventSources();
}
if (_privateData) {
_cursorHelper.finalize();
IOFree((void*)_privateData, sizeof(ExpansionData));
}
if (evScreen) IOFree( (void *)evScreen, evScreenSize );
evScreen = (void *)0;
evScreenSize = 0;
if (timerES) {
timerES->cancelTimeout();
if ( workLoop )
workLoop->removeEventSource( timerES );
timerES->release();
timerES = 0;
}
if (vblES) {
vblES->cancelTimeout();
if ( workLoop )
workLoop->removeEventSource( vblES );
vblES->release();
vblES = 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 (cmdGate) {
evClose();
cmdGate->release();
cmdGate = 0;
}
if (workLoop) {
workLoop->release();
workLoop = 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 (ioHIDevices) {
ioHIDevices->release();
ioHIDevices = 0;
}
if (cachedButtonStates) {
cachedButtonStates->release();
cachedButtonStates = 0;
}
if (consumedKeys) {
consumedKeys->release();
consumedKeys = 0;
}
if ( gKeyboardEQLock ) {
IOLock * lock = gKeyboardEQLock;
IOLockLock(lock);
gKeyboardEQLock = 0;
IOLockUnlock(lock);
IOLockFree(lock);
}
if (_hidKeyboardDevice) {
_hidKeyboardDevice->release();
_hidKeyboardDevice = 0;
}
if (_hidPointingDevice) {
_hidPointingDevice->release();
_hidPointingDevice = 0;
}
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)
{
IOGPoint p;
if( !eventsOpen)
return;
for( int i = 0; i < screens; i++ ) {
EvScreen *esp = &((EvScreen*)evScreen)[i];
if ( esp->instance )
{
p.x = evg->screenCursorFixed.x / 256; p.y = evg->screenCursorFixed.y / 256;
bool onscreen = (0 != (cursorScreens & (1 << i)));
switch ( evcmd )
{
case EVMOVE:
if (onscreen)
esp->instance->moveCursor(&p, evg->frame);
break;
case EVSHOW:
if (onscreen)
esp->instance->showCursor(&p, evg->frame);
break;
case EVHIDE:
if (onscreen)
esp->instance->hideCursor();
break;
case EVLEVEL:
case EVNOP:
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();
}
}
int IOHIDSystem::registerScreen(IOGraphicsDevice * io_gd,
IOGBounds * boundsPtr,
IOGBounds * virtualBoundsPtr)
{
if( (false == eventsOpen) || (0 == boundsPtr) || (0 == virtualBoundsPtr) )
{
return -1;
}
workLoop->runAction((IOWorkLoop::Action)&IOHIDSystem::doRegisterScreen, this, io_gd, boundsPtr, virtualBoundsPtr);
return(SCREENTOKEN + screens);
}
IOReturn IOHIDSystem::doRegisterScreen(IOHIDSystem *self, IOGraphicsDevice *io_gd, IOGBounds *bounds, IOGBounds *virtualBounds, void *arg3 __unused)
{
self->registerScreenGated(io_gd, bounds, virtualBounds);
return kIOReturnSuccess;
}
void IOHIDSystem::registerScreenGated(IOGraphicsDevice *io_gd, IOGBounds *boundsPtr, IOGBounds *virtualBoundsPtr)
{
EvScreen *esp;
OSNumber *num;
if ( lastShmemPtr == (void *)0 )
lastShmemPtr = evs;
esp = &((EvScreen*)evScreen)[screens];
esp->instance = io_gd;
esp->displayBounds = boundsPtr;
esp->desktopBounds = virtualBoundsPtr;
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 ( esp->displayBounds->maxy < workSpace.maxy )
workSpace.maxy = boundsPtr->maxy;
if( (num = OSDynamicCast(OSNumber, io_gd->getProperty(kIOFBWaitCursorFramesKey)))
&& (num->unsigned32BitValue() > maxWaitCursorFrame)) {
firstWaitCursorFrame = 0;
maxWaitCursorFrame = num->unsigned32BitValue();
evg->lastFrame = maxWaitCursorFrame;
}
if( (num = OSDynamicCast(OSNumber, io_gd->getProperty(kIOFBWaitCursorPeriodKey)))) {
clock_interval_to_absolutetime_interval(num->unsigned32BitValue(), kNanosecondScale,
&waitFrameRate);
}
screens++;
}
void IOHIDSystem::unregisterScreen(int index) {
cmdGate->runAction((IOCommandGate::Action)doUnregisterScreen, (void *)index);
}
IOReturn IOHIDSystem::doUnregisterScreen (IOHIDSystem *self, void * arg0)
{
int index = (uintptr_t) arg0;
self->unregisterScreenGated(index);
return kIOReturnSuccess;
}
void IOHIDSystem::unregisterScreenGated(int index)
{
index -= SCREENTOKEN;
if ( eventsOpen == false || index < 0 || index >= screens )
return;
hideCursor();
((EvScreen*)evScreen)[index].instance = 0;
cursorScreens &= ~(1 << index);
setCursorPosition((IOGPoint *)&evg->cursorLoc, true);
showCursor();
}
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;
clock_interval_to_absolutetime_interval(DefaultWCFrameRate, kNanosecondScale, &waitFrameRate);
clock_interval_to_absolutetime_interval(DefaultWCSustain, kNanosecondScale, &waitSustain);
AbsoluteTime_to_scalar(&waitSusTime) = 0;
AbsoluteTime_to_scalar(&waitFrameTime) = 0;
EV_TICK_TO_NS(10,&periodicEventDelta);
evg->buttons = 0;
evg->eNum = INITEVENTNUM;
evg->eventFlags = oldFlags;
AbsoluteTime ts;
unsigned tick;
clock_get_uptime( &ts);
tick = EV_NS_TO_TICK(&ts);
if ( tick == 0 )
tick = 1; evg->VertRetraceClock = tick;
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;
_cursorLog(AbsoluteTime_to_scalar(&ts));
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();
}
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;
unsigned theClock = EV_NS_TO_TICK(&ts);
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;
}
if ( theClock > (unsigned)evg->VertRetraceClock && theClock < (unsigned)(evg->VertRetraceClock + (20 * EV_TICK_TIME)) )
evg->VertRetraceClock = theClock;
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 = (uintptr_t)sender;
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 (CMP_ABSOLUTETIME( &waitFrameTime, &thisPeriodicRun) > 0)
{
AbsoluteTime time_for_next_run;
clock_get_uptime(&time_for_next_run);
ADD_ABSOLUTETIME( &time_for_next_run, &periodicEventDelta);
if (CMP_ABSOLUTETIME( &waitFrameTime, &time_for_next_run) < 0) {
timerES->wakeAtTime(waitFrameTime);
return;
}
}
timerES->setTimeout(periodicEventDelta);
}
void IOHIDSystem::_periodicEvents(IOHIDSystem * self,
IOTimerEventSource *timer)
{
self->periodicEvents(timer);
}
void IOHIDSystem::periodicEvents(IOTimerEventSource * )
{
unsigned int tick;
if ( eventsOpen == false )
return;
clock_get_uptime(&thisPeriodicRun);
tick = EV_NS_TO_TICK(&thisPeriodicRun);
if ( tick == 0 )
tick = 1;
evg->VertRetraceClock = tick;
if ( needSetCursorPosition == true )
_setCursorPosition();
if ( OSSpinLockTry(&evg->waitCursorSema) )
{
if ( OSSpinLockTry(&evg->cursorSema) )
{
if ( (evg->AALastEventSent != evg->AALastEventConsumed)
&& ((evg->VertRetraceClock - evg->AALastEventSent >
evg->waitThreshold)))
evg->ctxtTimedOut = TRUE;
if (evg->waitCursorEnabled && evg->globalWaitCursorEnabled &&
evg->ctxtTimedOut)
{
if (!evg->waitCursorUp)
showWaitCursor();
} else
{
if (evg->waitCursorUp &&
CMP_ABSOLUTETIME(&waitSusTime, &thisPeriodicRun) <= 0)
hideWaitCursor();
}
if (evg->waitCursorUp &&
CMP_ABSOLUTETIME(&waitFrameTime, &thisPeriodicRun) <= 0)
animateWaitCursor();
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].instance)
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) {
cursorPin = *(((EvScreen*)evScreen)[pinScreen].desktopBounds);
cursorPin.maxx--;
cursorPin.maxy--;
cursorPinScreen = pinScreen;
}
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].instance)
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);
}
_cursorHelper.setOverdueTime(0);
_cursorHelper.desktopLocationPosting().fromIntFloor(0, 0);
_cursorHelper.clearEventCounts();
_cursorLogTimed();
vblES->cancelTimeout();
return( true );
}
bool IOHIDSystem::startCursor()
{
bool ok;
if (0 == screens) return( false );
cursorPinned = false;
resetCursor();
showCursor();
ok = (kIOReturnSuccess ==
cmdGate->runAction((IOCommandGate::Action)_periodicEvents, timerES));
cursorStarted = ok;
return( ok );
}
void IOHIDSystem::showWaitCursor()
{
xpr_ev_cursor("showWaitCursor\n",1,2,3,4,5);
evg->waitCursorUp = true;
hideCursor();
evg->frame = EV_WAITCURSOR;
showCursor();
waitSusTime = waitFrameTime = thisPeriodicRun;
ADD_ABSOLUTETIME( &waitFrameTime, &waitFrameRate);
ADD_ABSOLUTETIME( &waitSusTime, &waitSustain);
}
void IOHIDSystem::hideWaitCursor()
{
xpr_ev_cursor("hideWaitCursor\n",1,2,3,4,5);
evg->waitCursorUp = false;
hideCursor();
evg->frame = EV_STD_CURSOR;
showCursor();
AbsoluteTime_to_scalar(&waitFrameTime) = 0;
AbsoluteTime_to_scalar(&waitSusTime ) = 0;
}
void IOHIDSystem::animateWaitCursor()
{
xpr_ev_cursor("animateWaitCursor\n",1,2,3,4,5);
changeCursor(evg->frame + 1);
waitFrameTime = thisPeriodicRun;
ADD_ABSOLUTETIME( &waitFrameTime, &waitFrameRate);
}
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].instance != 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);
} 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);
}
} 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:
#ifdef DEBUG
kprintf("detachEventSource:%s\n", provider->getName());
#endif
provider->close( this );
case kIOMessageServiceWasClosed:
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 + 1;
int cursorPinHeight = cursorPin.maxy - cursorPin.miny + 1;
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;
AbsoluteTime ts = *(AbsoluteTime *)((IOHIDCmdGateActionArgs *)args)->arg3;
OSObject * sender = (OSObject *)((IOHIDCmdGateActionArgs *)args)->arg4;
self->relativePointerEventGated(buttons, dx, dy, ts, sender);
return kIOReturnSuccess;
}
void IOHIDSystem::relativePointerEventGated(int buttons, int dx_I, int dy_I, AbsoluteTime ts, OSObject * sender)
{
UnsignedWide nextVBL, vblDeltaTime, eventDeltaTime, moveDeltaTime;
bool haveVBL;
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 + kIOHIDPowerOnThresholdNS;
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 WAKE_DISPLAY_ON_MOVEMENT
if (buttons || movementEvent) {
TICKLE_DISPLAY(NX_MOUSEMOVED);
}
if (!DISPLAY_IS_ENABLED || ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline)) {
return;
}
#else
if (!DISPLAY_IS_ENABLED) {
if (buttons) {
TICKLE_DISPLAY(NX_LMOUSEDOWN);
}
if (movementEvent && (CMP_ABSOLUTETIME(&ts, &displaySleepWakeupDeadline) <= 0) ) {
TICKLE_DISPLAY(NX_MOUSEMOVED);
}
return;
}
if (ShouldConsumeHIDEvent(ts, rootDomainStateChangeDeadline)) {
return;
}
if (buttons || movementEvent) {
TICKLE_DISPLAY(movementEvent ? NX_MOUSEMOVED : NX_LMOUSEDOWN);
}
#endif
_setButtonState(buttons, ts, sender);
IOFixedPoint64 scratch;
_cursorHelper.incrementEventCount();
if ( scratch.fromIntFloor(dx_I, dy_I) ) {
eventDeltaTime = *((UnsignedWide *)(&ts));
SUB_ABSOLUTETIME( &eventDeltaTime, &lastRelativeEventTime );
lastRelativeEventTime = ts;
IOGraphicsDevice * io_gd = ((EvScreen*)evScreen)[cursorPinScreen].instance;
if( io_gd) {
io_gd->getVBLTime( (AbsoluteTime *)&nextVBL, (AbsoluteTime *)&vblDeltaTime );
}
else {
nextVBL.hi = nextVBL.lo = vblDeltaTime.hi = vblDeltaTime.lo = 0;
}
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);
#ifdef __LP64__
IOHID_DEBUG(kIOHIDDebugCode_RelativePointerEventTiming,
AbsoluteTime_to_scalar(&nextVBL),
AbsoluteTime_to_scalar(&lastRelativeEventTime),
dx_I, dy_I);
#else
IOHID_DEBUG(kIOHIDDebugCode_RelativePointerEventTiming,
nextVBL.hi, nextVBL.lo,
lastRelativeEventTime.hi, lastRelativeEventTime.lo);
#endif
haveVBL = (nextVBL.lo || nextVBL.hi);
_cursorHelper.desktopLocationAccumulated() += scratch;
if (haveVBL && _cursorHelper.isPosting(AbsoluteTime_to_scalar(&ts))) {
}
else {
scratch = _cursorHelper.desktopLocationAccumulated(); moveDeltaTime = *((UnsignedWide *)(&ts));
SUB_ABSOLUTETIME( &moveDeltaTime, &lastRelativeMoveTime );
lastRelativeMoveTime = ts;
if ( scratch ) {
if (((dx_I > 0) && (scratch.xValue() < 0LL)) || ((dx_I < 0) && (scratch.xValue() > 0LL))) {
IOLog("IOHIDSystem::relativePointerEventGated: unexpected Direction Change X: in=%d out=%d\n", dx_I, (int)scratch.xValue());
}
if (((dy_I > 0) && (scratch.yValue() < 0LL)) || ((dy_I < 0) && (scratch.yValue() > 0LL))) {
IOLog("IOHIDSystem::relativePointerEventGated: unexpected Direction Change Y: in=%d out=%d\n", dy_I, (int)scratch.yValue());
}
if( haveVBL ) {
static UInt64 resonableVBL = 0;
if (!resonableVBL) {
nanoseconds_to_absolutetime(50000000, (AbsoluteTime*)(&resonableVBL));
}
if (AbsoluteTime_to_scalar(&vblDeltaTime) > resonableVBL) {
AbsoluteTime_to_scalar(&vblDeltaTime) = resonableVBL;
}
_cursorHelper.startPosting(); if (cachedMouseEvent && (cachedMouseEvent->reportInterval_ns > 0)) {
uint64_t vblInterval_ns;
#ifdef __LP64__
absolutetime_to_nanoseconds(AbsoluteTime_to_scalar(&vblDeltaTime), &vblInterval_ns);
#else
absolutetime_to_nanoseconds(vblDeltaTime, &vblInterval_ns);
#endif
_cursorHelper.expectedCount().fromIntFloor(vblInterval_ns);
_cursorHelper.expectedCount() /= cachedMouseEvent->reportInterval_ns;
}
else {
_cursorHelper.expectedCount().fromIntFloor(0);
}
_cursorHelper.setOverdueTime(AbsoluteTime_to_scalar(&nextVBL) + AbsoluteTime_to_scalar(&resonableVBL));
_cursorLog(AbsoluteTime_to_scalar(&ts));
IOHID_DEBUG(kIOHIDDebugCode_RelativePointerEventScaling,
scratch.xValue().asFixed(), scratch.yValue().asFixed(),
_cursorHelper.expectedCount().asFixed(),
_cursorHelper.getEventCountPosting() * 65536);
lastSender = sender;
vblDeltaTime.lo += (vblDeltaTime.lo >> 4);
ADD_ABSOLUTETIME(&nextVBL, &vblDeltaTime);
vblES->wakeAtTime(*(AbsoluteTime *)&nextVBL);
}
else
{
_cursorHelper.desktopLocationAccumulated().fromIntFloor(0, 0);
_cursorHelper.desktopLocationPosting().fromIntFloor(0, 0);
_cursorHelper.clearEventCounts();
_cursorHelper.desktopLocation() += scratch;
_cursorHelper.desktopLocationDelta() += scratch;
_cursorLog(AbsoluteTime_to_scalar(&ts));
_setCursorPosition(false, false, sender);
}
}
}
}
PROFILE_TRACE(2);
}
void IOHIDSystem::vblEvent(void)
{
PROFILE_TRACE(3);
if (_cursorHelper.isPosting()) {
_cursorHelper.applyPostingDelta();
_setCursorPosition(false, false, lastSender);
}
PROFILE_TRACE(4);
}
void IOHIDSystem::_vblEvent(OSObject *self, IOTimerEventSource *sender __unused)
{
((IOHIDSystem *)self)->vblEvent();
}
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;
}
}
}
if ( (newLoc != _cursorHelper.desktopLocation()) || proximityChange)
{
_cursorHelper.desktopLocationDelta() += newLoc - _cursorHelper.desktopLocation();
_cursorHelper.desktopLocation() = newLoc;
_cursorLog(AbsoluteTime_to_scalar(&ts));
_setCursorPosition(false, proximityChange, sender);
}
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;
}
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;
}
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;
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
bool moved = (deltaAxis1 || pointDeltaAxis1 ||
deltaAxis2 || pointDeltaAxis2 ||
deltaAxis3 || pointDeltaAxis3);
UInt32 phase = (options & kScrollTypeOptionPhaseAny);
switch (phase) {
case kScrollTypeOptionPhaseBegan:
if (!moved) {
_delayedScrollPhase = phase;
phase = 0;
options &= ~kScrollTypeOptionPhaseAny;
}
else {
_delayedScrollPhase = 0;
}
break;
case kScrollTypeOptionPhaseChanged:
if (_delayedScrollPhase) {
options &= ~kScrollTypeOptionPhaseAny;
if (!moved) {
phase = 0;
}
else {
phase = _delayedScrollPhase;
options |= phase;
_delayedScrollPhase = 0;
}
}
else {
if (!moved) {
phase = 0;
}
}
break;
case kScrollTypeOptionPhaseEnded:
case kScrollTypeOptionPhaseCanceled:
if (_delayedScrollPhase) {
options &= ~kScrollTypeOptionPhaseAny;
phase = 0;
_delayedScrollPhase = 0;
}
else {
}
break;
case 0:
break;
default:
IOLog("IOHIDSystem::scrollWheelEventGated called with unknown phase state: %08x\n", (unsigned)phase);
break;
}
UInt32 momentum = (options & kScrollTypeMomentumAny);
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:
IOLog("IOHIDSystem::scrollWheelEventGated called with unknown momentum state: %08x\n", (unsigned)momentum);
break;
}
if (!moved && !momentum && !phase)
return;
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 (momentum)
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);
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;
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;
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 ( !DISPLAY_IS_ENABLED ) {
if ( eventType == NX_KEYDOWN ) {
(void) addConsumedKey(key);
}
TICKLE_DISPLAY(eventType);
return;
}
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( !repeat && ((flags & NORMAL_MODIFIER_MASK) == NORMAL_MODIFIER_MASK) )
{
UInt32 keycode = UINT32_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 != UINT32_MAX) {
if (eventType == NX_KEYDOWN) {
sendStackShotMessage(keycode);
IOLog("IOHIDSystem posted stackshot event 0x%02x\n", (unsigned)keycode);
}
return;
}
}
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;
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))
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_COMMANDMASK )
PE_enter_debugger("USB 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:
outData.compound.subType = NX_SUBTYPE_POWER_KEY;
postEvent( NX_SYSDEFINED,
&_cursorHelper.desktopLocation(),
ts,
&outData,
sender,
0,
false);
break;
}
}
#if 0
else if ( eventType == NX_KEYUP )
{
switch ( flavor )
{
case NX_KEYTYPE_SOUND_UP:
break;
case NX_KEYTYPE_SOUND_DOWN:
break;
case NX_KEYTYPE_MUTE:
break;
case NX_POWER_KEY:
break;
}
}
#endif
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;
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;
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.subx = (cachedMouseEvent->pointerFractionX >> 8) & 0xff;
evData.mouse.suby = (cachedMouseEvent->pointerFractionY >> 8) & 0xff;
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));
}
}
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 )
{
_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);
}
}
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 ) {
needSetCursorPosition = true; return;
}
needSetCursorPosition = false;
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].instance)
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].instance)
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].instance)
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);
cursorPin.maxx--;
cursorPin.maxy--;
cursorPinScreen = pinScreen;
showCursor();
}
} else {
moveCursor();
}
}
}
else {
_cursorHelper.desktopLocation().xValue().fromFixed24x8(evg->desktopCursorFixed.x);
_cursorHelper.desktopLocation().yValue().fromFixed24x8(evg->desktopCursorFixed.y);
}
AbsoluteTime ts;
clock_get_uptime(&ts);
_cursorLog(AbsoluteTime_to_scalar(&ts));
if (evg->movedMask) {
if ((evg->movedMask & NX_LMOUSEDRAGGEDMASK) && (evg->buttons & EV_LB)) {
_postMouseMoveEvent(NX_LMOUSEDRAGGED, ts, sender);
}
else if ((evg->movedMask & NX_RMOUSEDRAGGEDMASK) && (evg->buttons & EV_RB)) {
_postMouseMoveEvent(NX_RMOUSEDRAGGED, ts, sender);
}
else if (evg->movedMask & NX_MOUSEMOVEDMASK) {
_postMouseMoveEvent(NX_MOUSEMOVED, ts, sender);
}
}
if (cursorMoved && evg->mouseRectValid && _cursorHelper.desktopLocation().inRect(evg->mouseRect))
{
if (evg->mouseRectValid)
{
postEvent( NX_MOUSEEXITED,
&_cursorHelper.desktopLocation(),
ts,
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)p1;
if ( eventsOpen == false )
return kIOReturnNotOpen;
if( 0 == screens) return kIOReturnNoDevice;
if( enable) {
if( cursorStarted) {
hideCursor();
cursorEnabled = resetCursor();
showCursor();
}
else {
cursorEnabled = startCursor();
}
}
else {
cursorEnabled = enable;
}
if (cursorCoupled != cursorEnabled) {
_cursorHelper.setOverdueTime(0);
_cursorHelper.desktopLocationPosting().fromIntFloor(0, 0);
_cursorHelper.clearEventCounts();
_cursorLogTimed();
vblES->cancelTimeout();
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;
cursorPin.maxx--;
cursorPin.maxy--;
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)) {
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));
_setCursorPosition();
}
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].instance)
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);
}
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::extGetModifierLockState(void*p1,void*p2,void*,void*,void*,void*)
{ return cmdGate->runAction((IOCommandGate::Action)doExtGetToggleState, p1, p2);
}
IOReturn IOHIDSystem::extSetModifierLockState(void*p1,void*p2,void*,void*,void*,void*)
{ if (mac_iokit_check_hid_control(kauth_cred_get()))
return kIOReturnNotPermitted;
return cmdGate->runAction((IOCommandGate::Action)doExtSetToggleState, p1, p2);
}
IOReturn IOHIDSystem::doExtGetToggleState(IOHIDSystem *self, void *p1, void *p2)
{
unsigned int selector = (uintptr_t)p1;
unsigned int *state_O = (unsigned int*)p2;
switch (selector) {
case kIOHIDCapsLockState:
return self->getCapsLockState(state_O);
case kIOHIDNumLockState:
return self->getNumLockState(state_O);
}
return kIOReturnBadArgument;
}
IOReturn IOHIDSystem::doExtSetToggleState(IOHIDSystem *self, void *p1, void *p2)
{
unsigned int selector = (uintptr_t)p1;
unsigned int state_I = (uintptr_t)p2;
switch (selector) {
case kIOHIDCapsLockState:
return self->setCapsLockState(state_I);
case kIOHIDNumLockState:
return self->setNumLockState(state_I);
}
return kIOReturnBadArgument;
}
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();
}
}
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;
}
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 = OSDynamicCast(OSDictionary, service->getProperty(kIOHIDParametersKey));
else if ( OSDynamicCast( IOHIDEventService, service ) )
deviceParameters = OSDynamicCast(OSDictionary, service->getProperty(kIOHIDEventServicePropertiesKey));
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( (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))))
clock_interval_to_absolutetime_interval(number->unsigned32BitValue(), kNanosecondScale,
&waitFrameRate);
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;
}
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);
}