diff --git a/VoodooI2CHID.xcodeproj/project.pbxproj b/VoodooI2CHID.xcodeproj/project.pbxproj index 9d4109c..3521fc4 100644 --- a/VoodooI2CHID.xcodeproj/project.pbxproj +++ b/VoodooI2CHID.xcodeproj/project.pbxproj @@ -34,6 +34,8 @@ ACE41BFE22FE5BCF00F75673 /* VoodooI2CHIDSYNA3602Device.hpp in Headers */ = {isa = PBXBuildFile; fileRef = ACE41BFC22FE5BCF00F75673 /* VoodooI2CHIDSYNA3602Device.hpp */; }; ACF66526201A762F00D211EA /* VoodooI2CSensorHubEnabler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ACF66524201A762F00D211EA /* VoodooI2CSensorHubEnabler.cpp */; }; ACF66527201A762F00D211EA /* VoodooI2CSensorHubEnabler.hpp in Headers */ = {isa = PBXBuildFile; fileRef = ACF66525201A762F00D211EA /* VoodooI2CSensorHubEnabler.hpp */; }; + EE3DD2D72C0AC1A100C2873F /* VoodooI2CHIDTrackpointWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EE3DD2D52C0AC1A100C2873F /* VoodooI2CHIDTrackpointWrapper.cpp */; }; + EE3DD2D82C0AC1A100C2873F /* VoodooI2CHIDTrackpointWrapper.hpp in Headers */ = {isa = PBXBuildFile; fileRef = EE3DD2D62C0AC1A100C2873F /* VoodooI2CHIDTrackpointWrapper.hpp */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -67,6 +69,8 @@ ACE41BFC22FE5BCF00F75673 /* VoodooI2CHIDSYNA3602Device.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = VoodooI2CHIDSYNA3602Device.hpp; sourceTree = ""; }; ACF66524201A762F00D211EA /* VoodooI2CSensorHubEnabler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VoodooI2CSensorHubEnabler.cpp; path = Sensors/VoodooI2CSensorHubEnabler.cpp; sourceTree = ""; }; ACF66525201A762F00D211EA /* VoodooI2CSensorHubEnabler.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = VoodooI2CSensorHubEnabler.hpp; path = Sensors/VoodooI2CSensorHubEnabler.hpp; sourceTree = ""; }; + EE3DD2D52C0AC1A100C2873F /* VoodooI2CHIDTrackpointWrapper.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = VoodooI2CHIDTrackpointWrapper.cpp; sourceTree = ""; }; + EE3DD2D62C0AC1A100C2873F /* VoodooI2CHIDTrackpointWrapper.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = VoodooI2CHIDTrackpointWrapper.hpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -124,6 +128,8 @@ AC0B0C541FFB08600039AC33 /* VoodooI2CHIDTransducerWrapper.hpp */, AC0ADA322017C2DC004DB693 /* VoodooI2CStylusHIDEventDriver.cpp */, AC0ADA332017C2DC004DB693 /* VoodooI2CStylusHIDEventDriver.hpp */, + EE3DD2D52C0AC1A100C2873F /* VoodooI2CHIDTrackpointWrapper.cpp */, + EE3DD2D62C0AC1A100C2873F /* VoodooI2CHIDTrackpointWrapper.hpp */, ); path = VoodooI2CHID; sourceTree = ""; @@ -166,6 +172,7 @@ files = ( ACCFCF241F69C1DC003E4131 /* VoodooI2CMultitouchHIDEventDriver.hpp in Headers */, ACE41BFA22FE565000F75673 /* VoodooI2CHIDDeviceOverride.hpp in Headers */, + EE3DD2D82C0AC1A100C2873F /* VoodooI2CHIDTrackpointWrapper.hpp in Headers */, ACF66527201A762F00D211EA /* VoodooI2CSensorHubEnabler.hpp in Headers */, AC05569A1F7333FB00ABFD91 /* VoodooI2CPrecisionTouchpadHIDEventDriver.hpp in Headers */, AC6388CD201B8E9F005E1341 /* VoodooI2CDeviceOrientationSensor.hpp in Headers */, @@ -254,6 +261,7 @@ AC0E628B201A629A00A31157 /* VoodooI2CSensorHubEventDriver.cpp in Sources */, 4E9F1E831F8AFECD00E91849 /* VoodooI2CTouchscreenHIDEventDriver.cpp in Sources */, AC01EE9C201E2B7D005A2988 /* VoodooI2CAccelerometerSensor.cpp in Sources */, + EE3DD2D72C0AC1A100C2873F /* VoodooI2CHIDTrackpointWrapper.cpp in Sources */, ACCFCF231F69C1DC003E4131 /* VoodooI2CMultitouchHIDEventDriver.cpp in Sources */, ACF66526201A762F00D211EA /* VoodooI2CSensorHubEnabler.cpp in Sources */, ACE41BFD22FE5BCF00F75673 /* VoodooI2CHIDSYNA3602Device.cpp in Sources */, diff --git a/VoodooI2CHID/VoodooI2CHIDTrackpointWrapper.cpp b/VoodooI2CHID/VoodooI2CHIDTrackpointWrapper.cpp new file mode 100644 index 0000000..81e2e3b --- /dev/null +++ b/VoodooI2CHID/VoodooI2CHIDTrackpointWrapper.cpp @@ -0,0 +1,40 @@ +// +// VoodooI2CHIDTrackpointWrapper.cpp +// VoodooI2CHID +// +// Created by Avery Black on 5/31/24. +// Copyright © 2024 Alexandre Daoud. All rights reserved. +// + +#include "VoodooI2CHIDTrackpointWrapper.hpp" + +#define super OSObject +OSDefineMetaClassAndStructors(VoodooI2CHIDTrackpointWrapper, OSObject); + +VoodooI2CHIDTrackpointWrapper* VoodooI2CHIDTrackpointWrapper::wrapper() { + auto *tp = OSTypeAlloc(VoodooI2CHIDTrackpointWrapper); + if (tp == nullptr) { + return nullptr; + } + + if (!tp->init()) { + OSSafeReleaseNULL(tp); + return nullptr; + } + + return tp; +} + +bool VoodooI2CHIDTrackpointWrapper::init() { + if (!super::init()) { + return false; + } + + buttons = OSArray::withCapacity(1); + return buttons != nullptr; +} + +void VoodooI2CHIDTrackpointWrapper::free() { + OSSafeReleaseNULL(buttons); + super::free(); +} diff --git a/VoodooI2CHID/VoodooI2CHIDTrackpointWrapper.hpp b/VoodooI2CHID/VoodooI2CHIDTrackpointWrapper.hpp new file mode 100644 index 0000000..f21b89e --- /dev/null +++ b/VoodooI2CHID/VoodooI2CHIDTrackpointWrapper.hpp @@ -0,0 +1,28 @@ +// +// VoodooI2CHIDTrackpointWrapper.hpp +// VoodooI2CHID +// +// Created by Avery Black on 5/31/24. +// Copyright © 2024 Alexandre Daoud. All rights reserved. +// + +#ifndef VoodooI2CHIDTrackpointWrapper_hpp +#define VoodooI2CHIDTrackpointWrapper_hpp + +#include + +class VoodooI2CHIDTrackpointWrapper : public OSObject { + OSDeclareDefaultStructors(VoodooI2CHIDTrackpointWrapper); +public: + static VoodooI2CHIDTrackpointWrapper* wrapper(); + + bool init() override; + void free() override; + + UInt8 report_id = 0; + IOHIDElement* dx = nullptr; + IOHIDElement* dy = nullptr; + OSArray* buttons = nullptr; +}; + +#endif /* VoodooI2CHIDTrackpointWrapper_hpp */ diff --git a/VoodooI2CHID/VoodooI2CMultitouchHIDEventDriver.cpp b/VoodooI2CHID/VoodooI2CMultitouchHIDEventDriver.cpp index 9ffacfa..7ff2c71 100644 --- a/VoodooI2CHID/VoodooI2CMultitouchHIDEventDriver.cpp +++ b/VoodooI2CHID/VoodooI2CMultitouchHIDEventDriver.cpp @@ -94,6 +94,31 @@ void VoodooI2CMultitouchHIDEventDriver::handleInterruptReport(AbsoluteTime times uint64_t now_ns; absolutetime_to_nanoseconds(now_abs, &now_ns); + for (int index = 0; index < trackpointReports->getCount(); index++) { + VoodooI2CHIDTrackpointWrapper* tp = OSDynamicCast(VoodooI2CHIDTrackpointWrapper, trackpointReports->getObject(index)); + + if (tp == nullptr || tp->report_id != report_id) { + continue; + } + + UInt8 button_bitmap = 0; + for (int btn_idx = 0; btn_idx < tp->buttons->getCount(); btn_idx++) { + IOHIDElement* elem = OSDynamicCast(IOHIDElement, tp->buttons->getObject(btn_idx)); + if (elem->getValue()) { + button_bitmap |= BIT(elem->getUsage() - 1); + } + } + + VoodooI2CTrackpointEvent event; + UInt32 dx = tp->dx->getValue(); + UInt32 dy = tp->dy->getValue(); + event.dx = *reinterpret_cast(&dx); + event.dy = *reinterpret_cast(&dy); + event.buttons = button_bitmap; + multitouch_interface->handleTrackpointReport(event, timestamp); + return; + } + if (report_type == kIOHIDReportTypeInput && readyForReports()) clock_get_uptime(&last_multi_touch_event); @@ -207,6 +232,7 @@ void VoodooI2CMultitouchHIDEventDriver::handleDigitizerReport(AbsoluteTime times void VoodooI2CMultitouchHIDEventDriver::handleDigitizerTransducerReport(VoodooI2CDigitiserTransducer* transducer, AbsoluteTime timestamp, UInt32 report_id) { bool handled = false; bool has_confidence = false; + bool has_valid = false; UInt32 element_index = 0; UInt32 element_count = 0; @@ -297,6 +323,12 @@ void VoodooI2CMultitouchHIDEventDriver::handleDigitizerTransducerReport(VoodooI2 transducer->in_range = value != 0; handled |= element_is_current; break; + case kHIDUsage_Dig_Confidence: + case kHIDUsage_Dig_Quality: + transducer->confidence.update(element->getValue(), timestamp); + handled |= element_is_current; + has_confidence = true; + break; case kHIDUsage_Dig_TipPressure: case kHIDUsage_Dig_SecondaryTipSwitch: { @@ -334,13 +366,11 @@ void VoodooI2CMultitouchHIDEventDriver::handleDigitizerTransducerReport(VoodooI2 handled |= element_is_current; break; case kHIDUsage_Dig_DataValid: - case kHIDUsage_Dig_TouchValid: - case kHIDUsage_Dig_Quality: if (value) transducer->is_valid = true; else transducer->is_valid = false; - has_confidence = true; + has_valid = true; handled |= element_is_current; break; case kHIDUsage_Dig_BarrelPressure: @@ -382,6 +412,9 @@ void VoodooI2CMultitouchHIDEventDriver::handleDigitizerTransducerReport(VoodooI2 } if (!has_confidence) + transducer->confidence.update(1, timestamp); + + if (!has_valid) transducer->is_valid = true; if (!handled) @@ -440,6 +473,10 @@ bool VoodooI2CMultitouchHIDEventDriver::handleStart(IOService* provider) { if (!digitiser.transducers) return false; + + trackpointReports = OSArray::withCapacity(1); + if (!trackpointReports) + return false; if (parseElements(kHIDUsage_Dig_Any) != kIOReturnSuccess) { IOLog("%s::%s Could not parse multitouch elements\n", getName(), name); @@ -475,7 +512,7 @@ void VoodooI2CMultitouchHIDEventDriver::handleStop(IOService* provider) { OSSafeReleaseNULL(work_loop); - + OSSafeReleaseNULL(trackpointReports); OSSafeReleaseNULL(digitiser.transducers); OSSafeReleaseNULL(digitiser.wrappers); OSSafeReleaseNULL(digitiser.styluses); @@ -607,6 +644,43 @@ IOReturn VoodooI2CMultitouchHIDEventDriver::parseDigitizerElement(IOHIDElement* return kIOReturnSuccess; } + +IOReturn VoodooI2CMultitouchHIDEventDriver::parseTrackpointElement(IOHIDElement* element) { + auto* tp = VoodooI2CHIDTrackpointWrapper::wrapper(); + if (tp == nullptr) { + return kIOReturnNoMemory; + } + + const auto* collections = element->getChildElements(); + IOHIDElement* collection = OSDynamicCast(IOHIDElement, collections->getObject(0)); + if (collection == nullptr || + !collection->conformsTo(kHIDPage_GenericDesktop, kHIDUsage_GD_Pointer)) { + OSSafeReleaseNULL(tp); + return kIOReturnSuccess; + } + + OSArray* elements = collection->getChildElements(); + for (int index = 0; index < elements->getCount(); index++) { + IOHIDElement* element = OSDynamicCast(IOHIDElement, elements->getObject(index)); + if (element == nullptr) { + continue; + } + + if (element->conformsTo(kHIDPage_GenericDesktop, kHIDUsage_GD_X)) { + tp->dx = element; + tp->report_id = element->getReportID(); + } else if (element->conformsTo(kHIDPage_GenericDesktop, kHIDUsage_GD_Y)) { + tp->dy = element; + } else if (element->conformsTo(kHIDPage_Button)) { + tp->buttons->setObject(element); + } + } + + trackpointReports->setObject(tp); + OSSafeReleaseNULL(tp); + + return kIOReturnError; +} IOReturn VoodooI2CMultitouchHIDEventDriver::parseElements(UInt32 usage) { int index, count; @@ -626,6 +700,11 @@ IOReturn VoodooI2CMultitouchHIDEventDriver::parseElements(UInt32 usage) { if (element->getUsage() == 0) continue; + /* Trackpoint devices */ + if (element->conformsTo(kHIDPage_GenericDesktop, kHIDUsage_GD_Mouse)) { + parseTrackpointElement(element); + } + /* * Parse digitzer elements depending on which Event Driver is attaching. * Precision/TouchScreen are specifically looking for kHIDUsage_Dig_TouchPad/TouchScreen respectively. @@ -776,6 +855,7 @@ void VoodooI2CMultitouchHIDEventDriver::setDigitizerProperties() { setOSDictionaryNumber(properties, "Transducer Count", digitiser.transducers->getCount()); setProperty("Digitizer", properties); + setProperty("Trackpoints", trackpointReports->getCount(), 32); OSSafeReleaseNULL(properties); } diff --git a/VoodooI2CHID/VoodooI2CMultitouchHIDEventDriver.hpp b/VoodooI2CHID/VoodooI2CMultitouchHIDEventDriver.hpp index 951a478..afee361 100644 --- a/VoodooI2CHID/VoodooI2CMultitouchHIDEventDriver.hpp +++ b/VoodooI2CHID/VoodooI2CMultitouchHIDEventDriver.hpp @@ -31,6 +31,7 @@ #include "VoodooI2CHIDDevice.hpp" #include "VoodooI2CHIDTransducerWrapper.hpp" +#include "VoodooI2CHIDTrackpointWrapper.hpp" #include "../../../Multitouch Support/VoodooI2CDigitiserStylus.hpp" #include "../../../Multitouch Support/VoodooI2CMultitouchInterface.hpp" @@ -63,6 +64,7 @@ class EXPORT VoodooI2CMultitouchHIDEventDriver : public IOHIDEventService { OSDeclareDefaultStructors(VoodooI2CMultitouchHIDEventDriver); public: + struct { OSArray* fingers = NULL; OSArray* styluses = NULL; @@ -179,7 +181,16 @@ class EXPORT VoodooI2CMultitouchHIDEventDriver : public IOHIDEventService { */ IOReturn parseDigitizerTransducerElement(IOHIDElement* element, IOHIDElement* parent); - + + /* Parses a mouse usage page element + * @element The element to parse + * + * This function is reponsible for adding a new mouse report. + * + * @return *kIOReturnSuccess* on successful parse, *kIOReturnDeviceError*, *kIOReturnError* or *kIOReturnNoDevice* if the mouse element is not supported + */ + + IOReturn parseTrackpointElement(IOHIDElement* element); /* Postprocessing of digitizer elements * @@ -260,6 +271,7 @@ class EXPORT VoodooI2CMultitouchHIDEventDriver : public IOHIDEventService { IOHIDDevice* hid_device; VoodooI2CMultitouchInterface* multitouch_interface; bool should_have_interface = true; + OSArray* trackpointReports = nullptr; virtual void forwardReport(VoodooI2CMultitouchEvent event, AbsoluteTime timestamp); diff --git a/VoodooI2CHID/VoodooI2CTouchscreenHIDEventDriver.cpp b/VoodooI2CHID/VoodooI2CTouchscreenHIDEventDriver.cpp index fb0174b..8c35adf 100755 --- a/VoodooI2CHID/VoodooI2CTouchscreenHIDEventDriver.cpp +++ b/VoodooI2CHID/VoodooI2CTouchscreenHIDEventDriver.cpp @@ -313,7 +313,7 @@ bool VoodooI2CTouchscreenHIDEventDriver::handleStart(IOService* provider) { if (active_framebuffer) { active_framebuffer->retain(); } - + return true; }