IOHIDPointerEventTranslation.c [plain text]
#include <AssertMacros.h>
#include <dispatch/dispatch.h>
#include <CoreFoundation/CFRuntime.h>
#include <IOKit/hid/IOHIDServiceClient.h>
#include <IOKit/hid/IOHIDService.h>
#include <IOKit/hid/IOHIDUsageTables.h>
#include "AppleHIDUsageTables.h"
#include "IOHIDFamilyPrivate.h"
#include <IOKit/usb/USB.h>
#include "IOHIDEventData.h"
#include "IOHIDPointerEventTranslation.h"
#include "IOHIDevicePrivateKeys.h"
#include "IOHIDDebug.h"
#include <mach/mach_time.h>
#define kPhaseMask (kIOHIDEventPhaseBegan | kIOHIDEventPhaseChanged | kIOHIDEventPhaseEnded | kIOHIDEventPhaseCancelled | kIOHIDEventPhaseMayBegin)
#define ABS_TO_NS(t,b) ((t * (b).numer)/ (b).denom)
#define NS_TO_ABS(t,b) ((t * (b).denom)/ (b).numer)
#define FIXED_TO_DOUBLE(x) (((double)x)/65536.0)
#define EV_DCLICKTIME 500000000
#define EV_DCLICKSPACE 3
#define kAbsoluteToPixelTranslation 1024
#define SIGN(x) ((x > 0) - (x < 0))
#define TRANSLATE_SCROLL_MOMENTUM(scrollEvent) \
(((IOHIDEventGetPhase (scrollEvent) & kPhaseMask) << 8) | \
((IOHIDEventGetPhase (scrollEvent) >> 2) & kScrollTypeMomentumContinue) | \
((IOHIDEventGetPhase (scrollEvent) >> 1) & \
(kScrollTypeMomentumStart | kScrollTypeMomentumEnd)))
#define kIOHIDScrollPixelToWheelScale FIXED_TO_DOUBLE(0x0000199a)
#define kIOFixedOne 0x10000ULL
#define kIOHIDScrollDefaultResolution FIXED_TO_DOUBLE (9 * kIOFixedOne)
#define kIOHIDScrollConsumeResolution FIXED_TO_DOUBLE (100 * kIOFixedOne)
#define kIOHIDScrollConsumeCountMultiplier 3
#define kIOHIDScrollCountMaxTimeDeltaBetween 600
#define kIOHIDScrollCountMaxTimeDeltaToSustain 250
#define kIOHIDScrollCountMinDeltaToStart (30)
#define kIOHIDScrollCountMinDeltaToSustain (20)
#define kIOHIDScrollCountIgnoreMomentumScrolls true
#define kIOHIDScrollCountMouseCanReset true
#define kIOHIDScrollCountMax 2000
#define kIOHIDScrollCountAccelerationFactor FIXED_TO_DOUBLE(163840)
#define NULLEVENTNUM 0
#define INITEVENTNUM 13
#define kZoomModifierMask (NX_COMMANDMASK| NX_ALTERNATEMASK | NX_CONTROLMASK | NX_SHIFTMASK)
#define kLegacyMouseEventsMask (NX_LMOUSEDOWNMASK|NX_RMOUSEDOWNMASK|NX_LMOUSEUPMASK|NX_RMOUSEUPMASK|NX_OMOUSEDOWNMASK|NX_OMOUSEUPMASK)
typedef struct {
boolean_t direction;
double accumulator;
uint32_t count;
uint32_t clearThreshold;
uint32_t countThreshold;
boolean_t hiResolution;
} CONSUME_RECORD;
typedef struct {
uint32_t buttons;
boolean_t isMultiTouchService;
boolean_t isContinuousScroll;
uint32_t buttonCount;
boolean_t clickRemappingDisable;
CFTypeRef service;
IOHIDFloat lastAbsoluteX;
IOHIDFloat lastAbsoluteY;
CONSUME_RECORD scrollConsume[3];
} SERVICE_RECORD;
typedef struct {
uint32_t globalButtons;
uint32_t flags;
uint64_t timestamp;
uint64_t serviceid;
SERVICE_RECORD *serviceRecord;
CFMutableArrayRef eventCollection;
IOHIDEventRef event;
} EVENT_TRANSLATOR_CONTEXT;
static uint64_t __IOHIDEventTranslatorGetServiceIDForObject (CFTypeRef service);
CFTypeRef __IOHIDEventTranslatorCopyServiceProperty (CFTypeRef service, CFStringRef key);
void __IOHIDPointerEventTranslatorCreateMouseUpDownEvent (IOHIDPointerEventTranslatorRef translator, EVENT_TRANSLATOR_CONTEXT *context, IOHIDEventRef pointerEvent);
void __IOHIDPointerEventTranslatorCreateSysdefineEvent (IOHIDPointerEventTranslatorRef translator, EVENT_TRANSLATOR_CONTEXT *context);
static void __IOHIDPointerEventTranslatorFree( CFTypeRef object );
static CFStringRef __IOHIDPointerEventTranslatorCopyDebugDescription(CFTypeRef cf);
IOHIDPointerEventTranslatorRef __IOHIDPointerEventTranslatorCreatePrivate(CFAllocatorRef allocator, CFAllocatorContext * context __unused);
IOHIDEventRef __IOHIDPointerEventTranslatorCreateMouseMoveEvent (IOHIDPointerEventTranslatorRef translator, EVENT_TRANSLATOR_CONTEXT *context, IOHIDEventRef pointerEvent);
void __IOHIDPointerEventTranslatorInitNxEvent (EVENT_TRANSLATOR_CONTEXT *context, NXEventExt *nxEvent, uint8_t type);
void __IOHIDPointerEventTranslatorProcessButtonState (IOHIDPointerEventTranslatorRef translator, EVENT_TRANSLATOR_CONTEXT *context, IOHIDEventRef pointerEvent);
void __IOHIDPointerEventTranslatorProcessClickState (IOHIDPointerEventTranslatorRef translator, EVENT_TRANSLATOR_CONTEXT *context, IOHIDEventRef pointerEvent, IOHIDEventRef buttonEvent);
void __IOHIDPointerEventTranslatorProcessScrollCount (IOHIDPointerEventTranslatorRef translator, EVENT_TRANSLATOR_CONTEXT *context, IOHIDEventRef scrollEvent);
IOHIDEventRef __IOHIDPointerEventTranslatorCreateScrollEvent (IOHIDPointerEventTranslatorRef translator, EVENT_TRANSLATOR_CONTEXT *context, IOHIDEventRef scrollEvent, IOHIDEventRef accellScrollEvent);
boolean_t __IOHIDEventTranslatorGetBooleanProperty (CFTypeRef service, CFStringRef key, boolean_t defaultValue);
uint64_t __IOHIDEventTranslatorGetIntegerProperty (CFTypeRef service, CFStringRef key, uint64_t defaultValue);
SERVICE_RECORD * __IOHIDEventTranslatorGetServiceRecordForServiceID (IOHIDPointerEventTranslatorRef translator, uint64_t serviceID);
static uint32_t __IOHIDPointerEventTranslatorGetUniqueEventNumber (IOHIDPointerEventTranslatorRef translator);
uint32_t __IOHIDPointerEventTranslatorRemapButtons (IOHIDPointerEventTranslatorRef translator, EVENT_TRANSLATOR_CONTEXT *context, uint32_t buttons);
void __IOHIDPointerEventTranslatorProcessLegacyEvent (IOHIDPointerEventTranslatorRef translator,EVENT_TRANSLATOR_CONTEXT *context, IOHIDEventRef legacyMouseEvent);
NXEventExt * __IOHIDPointerEventTranslatorGetNxMouseEvents (IOHIDEventRef event);
double __IOHIDPointerEventTranslatorGetScrollDelta (SERVICE_RECORD *record, int axisIndex, double value, double accelValue);
uint32_t __IOHIDPointerEventTranslatorInitScrollResolution (CFTypeRef service, int axisIndex);
void __IOHIDPointerEventTranslatorInitScrollConsumeRecords (SERVICE_RECORD * serviceRecord);
static const CFRuntimeClass __IOHIDPointerEventTranslatorClass = {
0, "IOHIDPointerEventTranslator", NULL, NULL, __IOHIDPointerEventTranslatorFree, NULL, NULL, NULL, __IOHIDPointerEventTranslatorCopyDebugDescription,
NULL,
NULL
};
typedef struct __IOHIDPointerEventTranslator {
CFRuntimeBase cfBase; uint32_t globalButtons;
CFMutableDictionaryRef serviceRecord;
mach_timebase_info_data_t timebaseInfo;
uint32_t flags;
uint8_t clickCount;
uint64_t lastClickTime;
uint64_t clickCountTimeTreshold;
uint32_t clickCountPixelTreshold;
IOHIDFloat clickCountDeltaX;
IOHIDFloat clickCountDeltaY;
uint16_t scrollCount;
uint32_t scrollDicrection;
uint64_t lastScrollTime;
uint64_t lastScrollSustainTime;
IOHIDFloat scrollCountDeltaX;
IOHIDFloat scrollCountDeltaY;
boolean_t scrollIncrementThisPhase;
uint64_t scrollCountMaxTimeDeltaBetween;
uint32_t scrollCountMaxTimeDeltaToSustain;
uint32_t scrollCountMinDeltaToStartPow2;
uint32_t scrollCountMinDeltaToSustainPow2;
boolean_t scrollCountIgnoreMomentumScrolls;
boolean_t scrollCountMouseCanReset;
uint32_t scrollCountMax;
double scrollCountAccelerationFactor;
uint32_t zoomModifierMask;
boolean_t zoomLastScrollWasZoom;
uint32_t eventNumber;
uint32_t lastLeftEventNum;
uint32_t lastRightEventNum;
uint32_t buttonMode;
} __IOHIDPointerEventTranslator;
static dispatch_once_t __pointerTranslatorTypeInit = 0;
static CFTypeID __pointerTranslatorTypeID = _kCFRuntimeNotATypeID;
CFTypeID IOHIDPointerEventTranslatorGetTypeID(void)
{
if ( _kCFRuntimeNotATypeID == __pointerTranslatorTypeID ) {
dispatch_once(&__pointerTranslatorTypeInit, ^{
__pointerTranslatorTypeID = _CFRuntimeRegisterClass(&__IOHIDPointerEventTranslatorClass);
});
}
return __pointerTranslatorTypeID;
}
IOHIDPointerEventTranslatorRef IOHIDPointerEventTranslatorCreate (CFAllocatorRef allocator, uint32_t options)
{
(void)options;
IOHIDPointerEventTranslatorRef translator = __IOHIDPointerEventTranslatorCreatePrivate(allocator, NULL);
if (!translator) {
return translator;
}
translator->serviceRecord = CFDictionaryCreateMutable (CFGetAllocator(translator), 0, NULL, &kCFTypeDictionaryValueCallBacks);
require(translator->serviceRecord, error_exit);
mach_timebase_info(&(translator->timebaseInfo));
translator->clickCountTimeTreshold = EV_DCLICKTIME;
translator->clickCountPixelTreshold = EV_DCLICKSPACE;
translator->scrollCountMaxTimeDeltaBetween = NS_TO_ABS (kIOHIDScrollCountMaxTimeDeltaBetween*kMillisecondScale,translator->timebaseInfo);
translator->scrollCountMaxTimeDeltaToSustain = NS_TO_ABS (kIOHIDScrollCountMaxTimeDeltaToSustain*kMillisecondScale,translator->timebaseInfo);
translator->scrollCountMinDeltaToStartPow2 = kIOHIDScrollCountMinDeltaToStart * kIOHIDScrollCountMinDeltaToStart;
translator->scrollCountMinDeltaToSustainPow2 = kIOHIDScrollCountMinDeltaToSustain * kIOHIDScrollCountMinDeltaToSustain;
translator->scrollCountIgnoreMomentumScrolls = kIOHIDScrollCountIgnoreMomentumScrolls;
translator->scrollCountMouseCanReset = kIOHIDScrollCountMouseCanReset;
translator->scrollCountMax = kIOHIDScrollCountMax;
translator->scrollCountAccelerationFactor = kIOHIDScrollCountAccelerationFactor;
translator->eventNumber = INITEVENTNUM;
translator->buttonMode = NX_RightButton;
return translator;
error_exit:
CFRelease (translator);
translator = NULL;
return translator;
}
uint32_t __IOHIDPointerEventTranslatorInitScrollResolution (CFTypeRef service, int axisIndex) {
static CFStringRef scrollRes [] = {CFSTR(kIOHIDScrollResolutionYKey), CFSTR(kIOHIDScrollResolutionXKey), CFSTR(kIOHIDScrollResolutionZKey)};
uint32_t resolution = (uint32_t)__IOHIDEventTranslatorGetIntegerProperty (service, scrollRes[axisIndex], 0);
if (!resolution) {
resolution = (uint32_t)__IOHIDEventTranslatorGetIntegerProperty (service, CFSTR(kIOHIDScrollResolutionKey), 0);
}
return resolution;
}
void __IOHIDPointerEventTranslatorInitScrollConsumeRecords (SERVICE_RECORD * serviceRecord) {
for (int index = 0; index < 3; index++) {
uint32_t resolution = __IOHIDPointerEventTranslatorInitScrollResolution (serviceRecord->service, index);
if (!resolution) {
continue;
}
serviceRecord->scrollConsume[index].hiResolution = ((FIXED_TO_DOUBLE(resolution) * 2) > kIOHIDScrollDefaultResolution);
serviceRecord->scrollConsume[index].clearThreshold = (uint32_t)floor((FIXED_TO_DOUBLE(resolution) / kIOHIDScrollConsumeResolution) * 2);
serviceRecord->scrollConsume[index].countThreshold = serviceRecord->scrollConsume[index].clearThreshold * kIOHIDScrollConsumeCountMultiplier;
}
}
void IOHIDPointerEventTranslatorRegisterService (IOHIDPointerEventTranslatorRef translator, CFTypeRef service)
{
if (service == NULL || translator == NULL) {
return;
}
uint64_t serviceID = __IOHIDEventTranslatorGetServiceIDForObject (service);
HIDLogDebug ("register service %llu", serviceID);
if (CFDictionaryContainsKey (translator->serviceRecord, (const void*)serviceID)) {
return;
}
SERVICE_RECORD record = {
.buttons = 0,
.isMultiTouchService = false,
.isContinuousScroll = false,
.buttonCount = 0,
.clickRemappingDisable = false,
.service = service
};
record.isMultiTouchService = __IOHIDEventTranslatorGetBooleanProperty(service, CFSTR("MTEventSource"), false);
if (__IOHIDEventTranslatorGetIntegerProperty (service, CFSTR(kIOHIDScrollResolutionXKey), 0) > (18 << 16) ||
__IOHIDEventTranslatorGetIntegerProperty (service, CFSTR(kIOHIDScrollResolutionYKey), 0) > (18 << 16) ||
__IOHIDEventTranslatorGetIntegerProperty (service, CFSTR(kIOHIDScrollResolutionZKey), 0) > (18 << 16) ||
__IOHIDEventTranslatorGetIntegerProperty (service, CFSTR(kIOHIDScrollResolutionKey), 0) > (18 << 16) ) {
record.isContinuousScroll = true;
}
record.buttonCount = (uint32_t)__IOHIDEventTranslatorGetIntegerProperty (service, CFSTR(kIOHIDPointerButtonCountKey), 1);
record.clickRemappingDisable = __IOHIDEventTranslatorGetBooleanProperty (service, CFSTR(kIOHIDDisallowRemappingOfPrimaryClickKey), false);
__IOHIDPointerEventTranslatorInitScrollConsumeRecords (&record);
CFMutableDataRef serviceRecord = CFDataCreateMutable(CFGetAllocator(translator), sizeof (record));
if (serviceRecord) {
CFDataSetLength(serviceRecord, sizeof (record));
UInt8 * serviceRecordPtr = (UInt8*)CFDataGetBytePtr(serviceRecord);
if (serviceRecordPtr) {
memcpy(serviceRecordPtr, &record, sizeof(record));
CFDictionarySetValue(translator->serviceRecord, (const void *) serviceID, serviceRecord);
}
CFRelease(serviceRecord);
}
}
void IOHIDPointerEventTranslatorUnRegisterService (IOHIDPointerEventTranslatorRef translator, CFTypeRef service)
{
if (service == NULL || translator == NULL) {
return;
}
uint64_t serviceID = __IOHIDEventTranslatorGetServiceIDForObject (service);
CFDictionaryRemoveValue (translator->serviceRecord, (const void *)serviceID);
}
void IOHIDPointerEventTranslatorSetProperty (IOHIDPointerEventTranslatorRef translator, CFStringRef key, CFTypeRef property) {
if (CFEqual(key, CFSTR(kIOHIDClickTimeKey)) && property && CFGetTypeID(property) == CFNumberGetTypeID()) {
CFNumberGetValue(property, kCFNumberSInt64Type, &translator->clickCountTimeTreshold);
} else if (CFEqual(key, CFSTR(kIOHIDScrollZoomModifierMaskKey)) && property && CFGetTypeID(property) == CFNumberGetTypeID()) {
CFNumberGetValue(property, kCFNumberSInt32Type, &translator->zoomModifierMask);
translator->zoomModifierMask &= kZoomModifierMask;
} else if (CFEqual(key, CFSTR(kIOHIDPointerButtonMode)) && property && CFGetTypeID(property) == CFNumberGetTypeID()) {
CFNumberGetValue(property, kCFNumberSInt32Type, &translator->buttonMode);
}
}
CFArrayRef IOHIDPointerEventTranslatorCreateEventCollection (IOHIDPointerEventTranslatorRef translator, IOHIDEventRef event, CFTypeRef sender, uint32_t flags, uint32_t options __unused)
{
if (!event) {
return NULL;
}
CFMutableArrayRef eventCollection = CFArrayCreateMutable(kCFAllocatorDefault, 2, &kCFTypeArrayCallBacks);
if (eventCollection == NULL) {
return NULL;
}
IOHIDEventRef translatedEvent;
EVENT_TRANSLATOR_CONTEXT context;
context.serviceid = IOHIDEventGetSenderID (event);
context.timestamp = IOHIDEventGetTimeStamp (event);
context.flags = flags;
context.globalButtons = translator->globalButtons;
context.eventCollection = eventCollection;
context.event = event;
context.serviceRecord = __IOHIDEventTranslatorGetServiceRecordForServiceID (translator, context.serviceid);
if (context.serviceRecord == NULL) {
IOHIDPointerEventTranslatorRegisterService(translator, sender);
context.serviceRecord = __IOHIDEventTranslatorGetServiceRecordForServiceID (translator, context.serviceid);
if (context.serviceRecord == NULL) {
HIDLogError("unable to get/create service record for pointer event translation");
return NULL;
}
}
IOHIDEventRef legacyMouseEvent = __IOHIDPointerEventTranslatorGetNxMouseEvents (event) ? event : NULL;
if (legacyMouseEvent) {
__IOHIDPointerEventTranslatorProcessLegacyEvent (translator, &context, legacyMouseEvent);
}
IOHIDEventRef pointerEvent = IOHIDEventGetEvent (event, kIOHIDEventTypePointer);
if (pointerEvent != NULL && (IOHIDEventGetEventFlags(pointerEvent) & kIOHIDAccelerated) == 0) {
CFIndex i, count;
CFArrayRef children = IOHIDEventGetChildren(pointerEvent);
for (i=0, count = (children) ? CFArrayGetCount(children) : 0; i < count; i++) {
IOHIDEventRef child = IOHIDEventGetEvent((IOHIDEventRef)CFArrayGetValueAtIndex(children, i), kIOHIDEventTypePointer);
if (child && IOHIDEventGetEventFlags(child) & kIOHIDAccelerated) {
pointerEvent = child;
break;
}
}
}
IOHIDEventRef scrollEvent = IOHIDEventGetEvent (event, kIOHIDEventTypeScroll);
IOHIDEventRef accelScrollEvent = scrollEvent;
if (scrollEvent != NULL && (IOHIDEventGetEventFlags(scrollEvent) & kIOHIDAccelerated) == 0) {
CFIndex i, count;
CFArrayRef children = IOHIDEventGetChildren(scrollEvent);
for (i=0, count = (children) ? CFArrayGetCount(children) : 0; i < count; i++) {
IOHIDEventRef child = IOHIDEventGetEvent((IOHIDEventRef)CFArrayGetValueAtIndex(children, i), kIOHIDEventTypeScroll);
if (child && IOHIDEventGetEventFlags(child) & kIOHIDAccelerated) {
accelScrollEvent = child;
break;
}
}
}
IOHIDEventRef buttonEvent = IOHIDEventGetEvent (event, kIOHIDEventTypeButton);
if (buttonEvent || pointerEvent) {
__IOHIDPointerEventTranslatorProcessClickState (translator, &context, pointerEvent, buttonEvent);
}
if (scrollEvent) {
__IOHIDPointerEventTranslatorProcessScrollCount (translator, &context, accelScrollEvent);
translatedEvent = __IOHIDPointerEventTranslatorCreateScrollEvent (translator, &context, scrollEvent, accelScrollEvent);
if (translatedEvent) {
CFArrayAppendValue(eventCollection, translatedEvent);
CFRelease(translatedEvent);
}
}
if (pointerEvent) {
__IOHIDPointerEventTranslatorProcessButtonState (translator, &context, pointerEvent);
if (context.globalButtons != translator->globalButtons) {
__IOHIDPointerEventTranslatorCreateSysdefineEvent (translator, &context);
__IOHIDPointerEventTranslatorCreateMouseUpDownEvent (translator, &context, pointerEvent);
}
translatedEvent = __IOHIDPointerEventTranslatorCreateMouseMoveEvent (translator, &context, pointerEvent);
if (translatedEvent) {
CFArrayAppendValue(eventCollection, translatedEvent);
CFRelease(translatedEvent);
}
if (IOHIDEventIsAbsolute(pointerEvent)) {
context.serviceRecord->lastAbsoluteX = IOHIDEventGetFloatValue (pointerEvent, kIOHIDEventFieldPointerX);
context.serviceRecord->lastAbsoluteY = IOHIDEventGetFloatValue (pointerEvent, kIOHIDEventFieldPointerY);
}
}
translator->flags = context.flags;
return eventCollection;
}
#define __IOHIDPointerEventTranslatorCreateHidEventForNXEvent(nxEvent, hidEvent, usage) \
IOHIDEventCreateVendorDefinedEvent ( \
CFGetAllocator(hidEvent), \
nxEvent.payload.time, \
kHIDPage_AppleVendor, \
usage, \
0, \
(uint8_t*)&nxEvent, \
sizeof (nxEvent), \
0 \
)
void __IOHIDPointerEventTranslatorInitNxEvent (EVENT_TRANSLATOR_CONTEXT *context, NXEventExt *nxEvent, uint8_t type) {
memset(nxEvent, 0, sizeof(*nxEvent));
nxEvent->payload.service_id = context->serviceid;
nxEvent->payload.time = context->timestamp;
nxEvent->payload.type = type;
nxEvent->payload.flags = context->flags;
nxEvent->extension.flags = NX_EVENT_EXTENSION_LOCATION_INVALID;
}
IOHIDEventRef __IOHIDPointerEventTranslatorCreateMouseMoveEvent (IOHIDPointerEventTranslatorRef translator, EVENT_TRANSLATOR_CONTEXT *context, IOHIDEventRef pointerEvent) {
NXEventExt nxEvent;
uint8_t type;
uint32_t button = __IOHIDPointerEventTranslatorRemapButtons (translator, context, translator->globalButtons);
if (button & 0x1) {
type = NX_LMOUSEDRAGGED;
} else if (button & 0x2) {
type = NX_RMOUSEDRAGGED;
} else {
type = NX_MOUSEMOVED;
}
__IOHIDPointerEventTranslatorInitNxEvent (context, &nxEvent, type);
float x = (float)IOHIDEventGetFloatValue (pointerEvent, kIOHIDEventFieldPointerX);
float y = (float)IOHIDEventGetFloatValue (pointerEvent, kIOHIDEventFieldPointerY);
if ((x == 0.0 && y == 0.0) ||
(IOHIDEventIsAbsolute(pointerEvent) && x == context->serviceRecord->lastAbsoluteX && y == context->serviceRecord->lastAbsoluteY)) {
return NULL;
}
if (IOHIDEventIsAbsolute(pointerEvent)) {
*((float*)&nxEvent.payload.location.x) = x;
*((float*)&nxEvent.payload.location.y) = y;
nxEvent.extension.flags = NX_EVENT_EXTENSION_LOCATION_TYPE_FLOAT | NX_EVENT_EXTENSION_LOCATION_DEVICE_SCALED;
} else {
*((float*)&nxEvent.payload.data.mouseMove.dx) = x;
*((float*)&nxEvent.payload.data.mouseMove.dy) = y;
nxEvent.extension.flags |= NX_EVENT_EXTENSION_MOUSE_DELTA_TYPE_FLOAT;
}
if (context->serviceRecord->isMultiTouchService) {
nxEvent.payload.data.mouseMove.subType = NX_SUBTYPE_MOUSE_TOUCH;
}
return __IOHIDPointerEventTranslatorCreateHidEventForNXEvent(nxEvent, pointerEvent, kHIDUsage_AppleVendor_NXEvent_Translated);
}
void __IOHIDPointerEventTranslatorProcessButtonState (IOHIDPointerEventTranslatorRef translator, EVENT_TRANSLATOR_CONTEXT *context __unused, IOHIDEventRef pointerEvent) {
uint32_t buttons = (uint32_t)IOHIDEventGetIntegerValue (pointerEvent, kIOHIDEventFieldPointerButtonMask);
if (context->serviceRecord->buttons != buttons) {
context->serviceRecord->buttons = buttons;
translator->globalButtons = IOHIDPointerEventTranslatorGetGlobalButtonState (translator);
}
}
uint32_t __IOHIDPointerEventTranslatorRemapButtons (IOHIDPointerEventTranslatorRef translator, EVENT_TRANSLATOR_CONTEXT *context, uint32_t buttons) {
uint32_t result = buttons;
if (context->serviceRecord->clickRemappingDisable) {
return result;
}
if (translator->buttonMode == NX_OneButton) {
result = ((buttons & 0x3) ? 0x1 : 0) | (buttons & (~0x3));
} else if (context->serviceRecord->buttonCount > 1 && translator->buttonMode == NX_LeftButton) {
result = ((buttons & 0x1) << 1) | ((buttons & 0x2) >> 1) | (buttons & (~0x3));
}
return result;
}
void __IOHIDPointerEventTranslatorProcessClickState (IOHIDPointerEventTranslatorRef translator, EVENT_TRANSLATOR_CONTEXT *context, IOHIDEventRef pointerEvent, IOHIDEventRef buttonEvent) {
if (context->flags != translator->flags) {
translator->clickCount = 0;
}
if (pointerEvent) {
IOHIDFloat dx = IOHIDEventGetFloatValue (pointerEvent, kIOHIDEventFieldPointerX);
IOHIDFloat dy = IOHIDEventGetFloatValue (pointerEvent, kIOHIDEventFieldPointerY);
if (IOHIDEventIsAbsolute(pointerEvent)) {
dx = (dx - context->serviceRecord->lastAbsoluteX) * kAbsoluteToPixelTranslation;
dy = (dy - context->serviceRecord->lastAbsoluteY) * kAbsoluteToPixelTranslation;
}
if (translator->clickCount >= 1) {
translator->clickCountDeltaX += dx;
translator->clickCountDeltaY += dy;
if ((fabs(translator->clickCountDeltaX) > (IOHIDFloat)translator->clickCountPixelTreshold / 2) ||
(fabs(translator->clickCountDeltaY) > (IOHIDFloat)translator->clickCountPixelTreshold / 2)) {
translator->clickCount = 0;
}
} else {
translator->clickCountDeltaX = 0;
translator->clickCountDeltaY = 0;
}
if (translator->scrollCount >= 1) {
translator->scrollCountDeltaX += dx;
translator->scrollCountDeltaY += dy;
if ((fabs(translator->scrollCountDeltaX) > (IOHIDFloat)translator->clickCountPixelTreshold / 2) ||
(fabs(translator->scrollCountDeltaY) > (IOHIDFloat)translator->clickCountPixelTreshold / 2)) {
translator->scrollCount = 0;
}
} else {
translator->scrollCountDeltaX = 0;
translator->scrollCountDeltaY = 0;
}
}
if (buttonEvent && IOHIDEventGetIntegerValue (buttonEvent, kIOHIDEventFieldButtonState)) {
uint64_t eventTime = ABS_TO_NS(IOHIDEventGetTimeStamp(buttonEvent), translator->timebaseInfo) ;
if ((uint64_t)llabs((int64_t)eventTime - (int64_t)translator->lastClickTime) < translator->clickCountTimeTreshold) {
++translator->clickCount;
} else {
translator->clickCount = 1;
}
translator->lastClickTime = eventTime;
}
}
void __IOHIDPointerEventTranslatorCreateSysdefineEvent (IOHIDPointerEventTranslatorRef translator, EVENT_TRANSLATOR_CONTEXT *context) {
uint32_t buttons;
NXEventExt nxEvent;
IOHIDEventRef translated;
buttons = translator->globalButtons ^ context->globalButtons;
__IOHIDPointerEventTranslatorInitNxEvent (context, &nxEvent, NX_SYSDEFINED);
nxEvent.payload.data.compound.subType = NX_SUBTYPE_AUX_MOUSE_BUTTONS;
nxEvent.payload.data.compound.misc.L[0] = __IOHIDPointerEventTranslatorRemapButtons (translator, context, buttons);
nxEvent.payload.data.compound.misc.L[1] = __IOHIDPointerEventTranslatorRemapButtons (translator, context, translator->globalButtons);
translated = __IOHIDPointerEventTranslatorCreateHidEventForNXEvent(nxEvent, context->event, kHIDUsage_AppleVendor_NXEvent_Translated);
if (translated) {
CFArrayAppendValue(context->eventCollection, translated);
CFRelease(translated);
}
}
void __IOHIDPointerEventTranslatorCreateMouseUpDownEvent (IOHIDPointerEventTranslatorRef translator, EVENT_TRANSLATOR_CONTEXT *context, IOHIDEventRef pointerEvent) {
uint32_t changedButtons;
uint32_t buttons;
NXEventExt nxEvent;
IOHIDEventRef translated;
changedButtons = __IOHIDPointerEventTranslatorRemapButtons (translator, context, translator->globalButtons ^ context->globalButtons);
if (changedButtons == 0) {
return;
}
__IOHIDPointerEventTranslatorInitNxEvent (context, &nxEvent, 0);
buttons = __IOHIDPointerEventTranslatorRemapButtons (translator, context, translator->globalButtons);
nxEvent.payload.data.mouse.click = translator->clickCount;
if (context->serviceRecord->isMultiTouchService) {
nxEvent.payload.data.mouse.subType = NX_SUBTYPE_MOUSE_TOUCH;
}
if (IOHIDEventIsAbsolute(pointerEvent)) {
*((float*)&nxEvent.payload.location.x) = (float)IOHIDEventGetFloatValue (pointerEvent, kIOHIDEventFieldPointerX);
*((float*)&nxEvent.payload.location.y) = (float)IOHIDEventGetFloatValue (pointerEvent, kIOHIDEventFieldPointerY);
nxEvent.extension.flags = NX_EVENT_EXTENSION_LOCATION_TYPE_FLOAT | NX_EVENT_EXTENSION_LOCATION_DEVICE_SCALED;
}
if (changedButtons & 1) {
if (buttons & 1) {
nxEvent.payload.type = NX_LMOUSEDOWN;
nxEvent.payload.data.mouse.pressure = 255;
translator->lastLeftEventNum = __IOHIDPointerEventTranslatorGetUniqueEventNumber (translator);
nxEvent.payload.data.mouse.eventNum = translator->lastLeftEventNum;
} else {
nxEvent.payload.type = NX_LMOUSEUP;
nxEvent.payload.data.mouse.eventNum = translator->lastLeftEventNum;
translator->lastLeftEventNum = NULLEVENTNUM;
}
translated = __IOHIDPointerEventTranslatorCreateHidEventForNXEvent(nxEvent, context->event, kHIDUsage_AppleVendor_NXEvent_Translated);
if (translated) {
CFArrayAppendValue(context->eventCollection, translated);
CFRelease(translated);
}
}
if (changedButtons & 2) {
if (buttons & 2) {
nxEvent.payload.type = NX_RMOUSEDOWN;
nxEvent.payload.data.mouse.pressure = 255;
translator->lastRightEventNum = __IOHIDPointerEventTranslatorGetUniqueEventNumber (translator);
nxEvent.payload.data.mouse.eventNum = translator->lastRightEventNum;
} else {
nxEvent.payload.type = NX_RMOUSEUP;
nxEvent.payload.data.mouse.eventNum = translator->lastRightEventNum;
translator->lastRightEventNum = NULLEVENTNUM;
}
translated = __IOHIDPointerEventTranslatorCreateHidEventForNXEvent(nxEvent, context->event, kHIDUsage_AppleVendor_NXEvent_Translated);
if (translated) {
CFArrayAppendValue(context->eventCollection, translated);
CFRelease(translated);
}
}
}
double __IOHIDPointerEventTranslatorGetScrollDelta (SERVICE_RECORD *record, int axisIndex, double value, double accelValue) {
double result = accelValue;
if (record->scrollConsume[axisIndex].countThreshold) {
boolean_t direction = (value >= 0);
if (record->scrollConsume[axisIndex].direction != direction) {
record->scrollConsume[axisIndex].accumulator = 0.0;
record->scrollConsume[axisIndex].count = 0;
}
record->scrollConsume[axisIndex].direction = direction;
record->scrollConsume[axisIndex].accumulator += accelValue;
record->scrollConsume[axisIndex].count += fabs (value);
if (value &&
(fabs (value) > (record->scrollConsume[axisIndex].clearThreshold) ||
record->scrollConsume[axisIndex].count >= record->scrollConsume[axisIndex].countThreshold)) {
double accum = record->scrollConsume[axisIndex].accumulator;
result = copysign (fabs(floor(accum * 10) / 10), accum);
record->scrollConsume[axisIndex].count = 0;
record->scrollConsume[axisIndex].accumulator = 0.0;
} else {
result = 0.0;
}
}
result = (result && fabs(result) < 0.1) ? copysign(0.1, result) : result;
return result;
}
IOHIDEventRef __IOHIDPointerEventTranslatorCreateScrollEvent (IOHIDPointerEventTranslatorRef translator, EVENT_TRANSLATOR_CONTEXT *context, IOHIDEventRef scrollEvent, IOHIDEventRef accellScrollEvent) {
NXEventExt nxEvent;
SInt32 eventType = NX_SCROLLWHEELMOVED;
if (translator->zoomModifierMask) {
bool isZoom = ((context->flags & kZoomModifierMask) == translator->zoomModifierMask);
bool isMomentum = (0 != (TRANSLATE_SCROLL_MOMENTUM(scrollEvent) & kScrollTypeMomentumAny));
if ((isMomentum && translator->zoomLastScrollWasZoom) || (isZoom && !isMomentum)) {
translator->zoomLastScrollWasZoom = true;
eventType = NX_ZOOM;
} else {
translator->zoomLastScrollWasZoom = false;
}
} else {
translator->zoomLastScrollWasZoom = false;
}
__IOHIDPointerEventTranslatorInitNxEvent (context, &nxEvent, eventType);
double scrollAccell [3];
double scrollNonAccell [3];
double consumeScroll [3];
static int fields[] = {kIOHIDEventFieldScrollY, kIOHIDEventFieldScrollX, kIOHIDEventFieldScrollZ};
for (int index = 0; index < 3; index++) {
scrollAccell[index] = IOHIDEventGetFloatValue (accellScrollEvent, fields[index]);
scrollNonAccell[index] = IOHIDEventGetFloatValue (scrollEvent, fields[index]);
consumeScroll [index] = __IOHIDPointerEventTranslatorGetScrollDelta (context->serviceRecord, index, scrollNonAccell[index], scrollAccell[index]);
}
if (consumeScroll[0]) {
nxEvent.payload.data.scrollWheel.deltaAxis1 = (SInt16) (fabs(consumeScroll[0]) < 1 ? copysign (1, consumeScroll[0]) : copysign(fabs(consumeScroll[0]), consumeScroll[0]));
nxEvent.payload.data.scrollWheel.fixedDeltaAxis1 = (SInt32)copysign(ceil(fabs(consumeScroll[0] * 65536)), consumeScroll[0]);
}
if (consumeScroll[1]) {
nxEvent.payload.data.scrollWheel.deltaAxis2 = (SInt16) (fabs(consumeScroll[1]) < 1 ? copysign (1, consumeScroll[1]) : copysign(fabs(consumeScroll[1]), consumeScroll[1]));
nxEvent.payload.data.scrollWheel.fixedDeltaAxis2 = (SInt32)copysign(ceil(fabs(consumeScroll[1] * 65536)), consumeScroll[1]);
}
if (consumeScroll[2]) {
nxEvent.payload.data.scrollWheel.deltaAxis3 = (SInt16) (fabs(consumeScroll[2]) < 1 ? copysign (1, consumeScroll[2]) : copysign(fabs(consumeScroll[2]), consumeScroll[2]));
nxEvent.payload.data.scrollWheel.fixedDeltaAxis3 = (SInt32)copysign(ceil(fabs(consumeScroll[2] * 65536)), consumeScroll[2]);
}
nxEvent.payload.data.scrollWheel.pointDeltaAxis1 = copysign(ceil(fabs(scrollAccell[0]) * 10), scrollAccell[0]);
nxEvent.payload.data.scrollWheel.pointDeltaAxis2 = copysign(ceil(fabs(scrollAccell[1]) * 10), scrollAccell[1]);
nxEvent.payload.data.scrollWheel.pointDeltaAxis3 = copysign(ceil(fabs(scrollAccell[2]) * 10), scrollAccell[2]);
nxEvent.payload.data.scrollWheel.reserved1 = TRANSLATE_SCROLL_MOMENTUM(scrollEvent);
if (context->serviceRecord->isMultiTouchService) {
nxEvent.payload.data.scrollWheel.reserved1 |= kScrollTypeTouch;
}
if (context->serviceRecord->isContinuousScroll) {
nxEvent.payload.data.scrollWheel.reserved1 |= kScrollTypeContinuous;
}
nxEvent.payload.data.scrollWheel.reserved8[1] = translator->scrollCount;
nxEvent.payload.data.scrollWheel.reserved8[2] = (SInt32)context->serviceid;
return __IOHIDPointerEventTranslatorCreateHidEventForNXEvent(nxEvent, scrollEvent, kHIDUsage_AppleVendor_NXEvent_Translated);
}
void __IOHIDPointerEventTranslatorProcessScrollCount (IOHIDPointerEventTranslatorRef translator, EVENT_TRANSLATOR_CONTEXT *context __unused, IOHIDEventRef scrollEvent) {
uint32_t phaseAndMomentum = TRANSLATE_SCROLL_MOMENTUM(scrollEvent);
if (phaseAndMomentum == 0) {
return;
}
boolean_t checkSustain = false;
uint32_t scrollDirection;
double axis [3] = {
10 * IOHIDEventGetFloatValue (scrollEvent, kIOHIDEventFieldScrollX),
10 * IOHIDEventGetFloatValue (scrollEvent, kIOHIDEventFieldScrollY),
10 * IOHIDEventGetFloatValue (scrollEvent, kIOHIDEventFieldScrollZ)};
double axisPow2 [3] = {axis[0] * axis[0],axis[1] * axis[1], axis[2] * axis[2]};
double scrollMagnitudeSquared = axisPow2[0] + axisPow2[1] + axisPow2[2];
int m = 0;
(void)((axisPow2[m] < axisPow2[1]) && (m = 1));
(void)((axisPow2[m] < axisPow2[2]) && (m = 2));
scrollDirection = SIGN (axis[m]) * m;
if (scrollDirection && translator->scrollDicrection != scrollDirection) {
translator->scrollCount = 0;
translator->scrollDicrection = scrollDirection;
}
uint64_t ts = IOHIDEventGetTimeStamp(scrollEvent);
switch (phaseAndMomentum) {
case kScrollTypeOptionPhaseBegan: {
if (translator->scrollCount > 0) {
if ((translator->lastScrollTime + translator->scrollCountMaxTimeDeltaBetween) > ts) {
if (!translator->scrollIncrementThisPhase) {
translator->scrollCount++;
translator->scrollIncrementThisPhase = true;
}
translator->lastScrollSustainTime = ts;
}
else {
translator->scrollCount = 0;
}
}
break;
}
case kScrollTypeOptionPhaseChanged: {
if (translator->scrollCount == 0) {
if (scrollMagnitudeSquared >= translator->scrollCountMinDeltaToStartPow2) {
translator->scrollCount = 1;
translator->lastScrollSustainTime = ts;
}
}
else {
if (translator->scrollCount > 2) {
translator->scrollCount += sqrt(scrollMagnitudeSquared) / translator->scrollCountAccelerationFactor;
if (translator->scrollCount > translator->scrollCountMax) {
translator->scrollCount = translator->scrollCountMax;
}
}
checkSustain = true;
}
break;
}
case kScrollTypeOptionPhaseEnded: {
if (translator->scrollCount > 0) {
translator->lastScrollTime = ts;
translator->scrollIncrementThisPhase = false;
}
break;
}
case kScrollTypeOptionPhaseCanceled: {
translator->scrollIncrementThisPhase = false;
translator->scrollCount = 0;
break;
}
case kScrollTypeOptionPhaseMayBegin: {
if (translator->scrollCount > 0) {
if (((translator->lastScrollTime + translator->scrollCountMaxTimeDeltaBetween) > ts) &&
!translator->scrollIncrementThisPhase) {
translator->scrollCount++;
translator->scrollIncrementThisPhase = true;
translator->lastScrollSustainTime = ts;
}
else {
translator->scrollCount = 0;
translator->scrollIncrementThisPhase = false;
}
}
break;
}
case kScrollTypeMomentumStart: {
break;
}
case kScrollTypeMomentumContinue: {
checkSustain = true;
break;
}
case kScrollTypeMomentumEnd: {
if (translator->scrollCount > 0) {
translator->lastScrollTime = ts;
translator->scrollIncrementThisPhase = false;
}
break;
}
default:
HIDLogError ("SCROLLCOUNT: Unknown phase 0x%x", phaseAndMomentum);
}
if (checkSustain) {
if (scrollMagnitudeSquared > translator->scrollCountMinDeltaToSustainPow2) {
translator->lastScrollSustainTime = ts;
}
else if (translator->lastScrollSustainTime + translator->scrollCountMaxTimeDeltaToSustain < ts) {
translator->scrollCount = 0;
}
}
}
IOHIDPointerEventTranslatorRef __IOHIDPointerEventTranslatorCreatePrivate(CFAllocatorRef allocator, CFAllocatorContext * context __unused)
{
IOHIDPointerEventTranslatorRef translator = NULL;
void * offset = NULL;
uint32_t size;
size = sizeof(__IOHIDPointerEventTranslator) - sizeof(CFRuntimeBase);
translator = (IOHIDPointerEventTranslatorRef)_CFRuntimeCreateInstance(allocator, IOHIDPointerEventTranslatorGetTypeID(), size, NULL);
if (!translator)
return NULL;
offset = translator;
bzero(offset + sizeof(CFRuntimeBase), size);
return translator;
}
static void __IOHIDPointerEventTranslatorFree( CFTypeRef object )
{
IOHIDPointerEventTranslatorRef translator = (IOHIDPointerEventTranslatorRef) object;
if (!translator) {
return;
}
CFRelease(translator->serviceRecord);
}
static CFStringRef __IOHIDPointerEventTranslatorCopyDebugDescription(CFTypeRef cf)
{
return CFStringCreateWithFormat(CFGetAllocator(cf), NULL, CFSTR("IOHIDPointerEventTranslatorRef"));
}
static void __ButtonsApplierFunction(const void *key __unused, const void *value, void *context)
{
uint32_t *globalButtons = (uint32_t*)context;
SERVICE_RECORD *serviceRecord = (SERVICE_RECORD*)CFDataGetBytePtr ((CFDataRef)value);
*globalButtons |= serviceRecord->buttons;
}
uint32_t IOHIDPointerEventTranslatorGetGlobalButtonState (IOHIDPointerEventTranslatorRef translator) {
uint32_t globalButtons = 0;
CFDictionaryApplyFunction (translator->serviceRecord, __ButtonsApplierFunction, &globalButtons);
return globalButtons;
}
uint32_t __IOHIDPointerEventTranslatorGetUniqueEventNumber (IOHIDPointerEventTranslatorRef translator) {
while (++translator->eventNumber == 0);
return translator->eventNumber;
}
static uint64_t __IOHIDEventTranslatorGetServiceIDForObject (CFTypeRef service) {
uint64_t result = 0;
CFNumberRef registryId = NULL;
if (CFGetTypeID(service) == IOHIDServiceGetTypeID ()) {
registryId = IOHIDServiceGetRegistryID((IOHIDServiceRef) service);
} else if (CFGetTypeID(service) == IOHIDServiceClientGetTypeID ()) {
registryId = IOHIDServiceClientGetRegistryID((IOHIDServiceClientRef) service);
} else {
HIDLogError ("Unknown service object type");
}
if (registryId) {
CFNumberGetValue(registryId, kCFNumberSInt64Type, &result);
}
return result;
}
CFTypeRef __IOHIDEventTranslatorCopyServiceProperty (CFTypeRef service, CFStringRef key) {
CFTypeRef result = NULL;
if (CFGetTypeID(service) == IOHIDServiceGetTypeID ()) {
result = IOHIDServiceCopyProperty((IOHIDServiceRef) service, key);
} else if (CFGetTypeID(service) == IOHIDServiceClientGetTypeID ()) {
result = IOHIDServiceClientCopyProperty((IOHIDServiceClientRef) service, key);
} else {
HIDLogError ("Unknown service object type");
}
return result;
}
boolean_t __IOHIDEventTranslatorGetBooleanProperty (CFTypeRef service, CFStringRef key, boolean_t defaultValue) {
boolean_t result = defaultValue;
CFTypeRef value = __IOHIDEventTranslatorCopyServiceProperty (service, key);
if (value) {
if (CFGetTypeID(value) == CFBooleanGetTypeID()) {
result = CFBooleanGetValue(value);
}
CFRelease(value);
}
return result;
}
uint64_t __IOHIDEventTranslatorGetIntegerProperty (CFTypeRef service, CFStringRef key, uint64_t defaultValue) {
uint64_t result = defaultValue;
CFTypeRef value = __IOHIDEventTranslatorCopyServiceProperty (service, key);
if (value) {
if (CFGetTypeID(value) == CFNumberGetTypeID()) {
CFNumberGetValue(value, kCFNumberSInt64Type, &result);
}
CFRelease(value);
}
return result;
}
SERVICE_RECORD * __IOHIDEventTranslatorGetServiceRecordForServiceID (IOHIDPointerEventTranslatorRef translator, uint64_t serviceID) {
CFDataRef record = CFDictionaryGetValue(translator->serviceRecord, (const void*) serviceID);
if (record == NULL) {
return NULL;
}
return (SERVICE_RECORD*)CFDataGetBytePtr (record);
}
NXEventExt * __IOHIDPointerEventTranslatorGetNxMouseEvents (IOHIDEventRef event) {
if (IOHIDEventGetType(event) != kIOHIDEventTypeVendorDefined ||
IOHIDEventGetIntegerValue(event, kIOHIDEventFieldVendorDefinedUsage) != kHIDUsage_AppleVendor_NXEvent) {
return NULL;
}
NXEventExt *nxEvent = NULL;
CFIndex eventLength = 0;
IOHIDEventGetVendorDefinedData (event, (uint8_t**)&nxEvent, &eventLength);
if (nxEvent) {
if ((1 << nxEvent->payload.type) & kLegacyMouseEventsMask) {
return nxEvent;
}
}
return NULL;
}
void __IOHIDPointerEventTranslatorProcessLegacyEvent (IOHIDPointerEventTranslatorRef translator,EVENT_TRANSLATOR_CONTEXT *context __unused, IOHIDEventRef legacyMouseEvent) {
if (legacyMouseEvent) {
NXEventExt * nxEvent = __IOHIDPointerEventTranslatorGetNxMouseEvents (legacyMouseEvent);
uint32_t eventMask = (1 << nxEvent->payload.type);
if (nxEvent) {
if (eventMask & (NX_LMOUSEDOWNMASK | NX_RMOUSEDOWNMASK)) {
uint64_t eventTime = ABS_TO_NS(IOHIDEventGetTimeStamp(legacyMouseEvent), translator->timebaseInfo) ;
if ((uint64_t)llabs((int64_t)eventTime - (int64_t)translator->lastClickTime) < translator->clickCountTimeTreshold) {
++translator->clickCount;
} else {
translator->clickCount = 1;
}
translator->lastClickTime = eventTime;
nxEvent->payload.data.mouse.click = translator->clickCount;
}
if (eventMask & (NX_LMOUSEUPMASK | NX_RMOUSEUPMASK)) {
nxEvent->payload.data.mouse.click = translator->clickCount;
}
switch (nxEvent->payload.type) {
case NX_RMOUSEDOWN:
translator->lastRightEventNum = __IOHIDPointerEventTranslatorGetUniqueEventNumber (translator);
nxEvent->payload.data.mouse.eventNum = translator->lastRightEventNum;
break;
case NX_RMOUSEUP:
nxEvent->payload.data.mouse.eventNum = translator->lastRightEventNum;
translator->lastRightEventNum = NULLEVENTNUM;
break;
case NX_LMOUSEDOWN:
translator->lastLeftEventNum = __IOHIDPointerEventTranslatorGetUniqueEventNumber (translator);
nxEvent->payload.data.mouse.eventNum = translator->lastLeftEventNum;
break;
case NX_LMOUSEUP:
nxEvent->payload.data.mouse.eventNum = translator->lastLeftEventNum;
translator->lastLeftEventNum = NULLEVENTNUM;
break;
}
if (eventMask & (NX_LMOUSEDRAGGEDMASK | NX_RMOUSEDRAGGEDMASK | NX_MOUSEMOVEDMASK)) {
if (translator->clickCount >= 1) {
translator->clickCountDeltaX += nxEvent->payload.data.mouseMove.dx;
translator->clickCountDeltaY += nxEvent->payload.data.mouseMove.dy;
if ((fabs(translator->clickCountDeltaX) > (float)translator->clickCountPixelTreshold / 2) ||
(fabs(translator->clickCountDeltaY) > (float)translator->clickCountPixelTreshold / 2)) {
translator->clickCount = 0;
}
} else {
translator->clickCountDeltaX = 0;
translator->clickCountDeltaY = 0;
}
}
}
}
}