Post

Replies

Boosts

Views

Activity

HIDVirtualDevice digitizer pen: position, proximity and tip switch reach NSEvent, but tablet pressure is always 0 — is pen pressure supported at all?
I'm building a virtual pen digitizer with HIDVirtualDevice (CoreHID, macOS 26.2, com.apple.developer.hid.virtual.device entitlement granted, Developer ID signed with the provisioning profile embedding the entitlement). The device is created and activated fine and shows up as expected: hidutil list: 0xface 0xbeef UsagePage 13 Usage 2 Transport Virtual "Hej Stylus Virtual Pen" AppleUserHIDEventService / AppleUserHIDEventDriver Report descriptor (Digitizer/Pen application collection, Stylus physical collection, 7-byte input report): 05 0D Usage Page (Digitizer) 09 02 Usage (Pen) A1 01 Collection (Application) 09 20 Usage (Stylus) A1 00 Collection (Physical) 09 42 Usage (Tip Switch) 09 32 Usage (In Range) 15 00 25 01 75 01 95 02 81 02 ; 2 bits 95 06 81 03 ; 6 bits padding (Const) 05 01 09 30 09 31 ; Generic Desktop X, Y 16 00 00 26 FF 7F 75 10 95 02 81 02 ; 0..32767, 16 bit each 05 0D 09 30 ; Digitizer / Tip Pressure 16 00 00 26 FF 1F 75 10 95 01 81 02 ; 0..8191, 16 bit C0 C0 I feed it a synthetic stream at 60 Hz (X sweep, Y fixed, tip switch down, in range, pressure ramping 0→8191) via dispatchInputReport(data:timestamp:) and observe the results with a global NSEvent monitor (.tabletProximity, .tabletPoint, .leftMouseDown/Up/Dragged, .mouseMoved) plus the raw CGEvent fields. What works tabletProximity: isEnteringProximity=1, pointingDeviceType=.pen, vendorID=0xFACE, tabletID=0xBEEF, systemTabletID assigned. All movement arrives as tabletPoint / mouseMoved with subtype == .tabletPoint; positions are exact. Tip switch maps to leftMouseDown / leftMouseUp correctly (verified by toggling the tip bit with pressure held at max). capabilityMask on the proximity event is 0x407 = NX_TABLET_CAPABILITY_DEVICEIDMASK | ABSXMASK | ABSYMASK | PRESSUREMASK — so the system declares pressure capability for this device. What doesn't NSEvent.pressure, kCGTabletEventPointPressure and kCGMouseEventPressure are always 0.000, on every event type, including with a constant maximum pressure value (8191). NSEvent.buttonMask is 1 (pen tip) and kCGTabletEventPointButtons is 1, so the report is being parsed — the pressure field just never makes it into the tablet event data. Things I've established / tried The pressure value is parsed and does influence touch/click: with tip switch held down and pressure held at 0, no mouse down is ever generated. With pressure ramping, the click happens at exactly 75 % of the logical range. Reading the open-source IOHIDEventDriver::parseDigitizerTransducerElement explains this: Tip Pressure is read with kIOHIDValueScaleTypeCalibrated, but only X/Y/Z elements get a calibration, and an uncalibrated element scales to −1…+1 — so raw 0…8191 becomes −1…+1 and the touch threshold (+0.5) sits at 75 %. Changing Logical Minimum to −8191 (so raw 0…8191 maps to 0…1) moves the click to exactly 50 % — confirming the model. Pressure in the event data is still 0. Adding Physical Minimum/Maximum and a Unit to the pressure element: no change. hidutil monitor no longer exists on macOS 26, so I can't inspect the IOHIDEvent digitizer fields directly. This looks like the same behaviour reported for kext-based digitizers since macOS 10.12 (developer.apple.com/forums thread "IOHIPointing dispatchAbsolutePointerEvent not works" and its sibling: "the pressure information is there from the transducer, the OS doesn't respond to it on 10.12+"). The tablet-pressure dispatch in the open-source IOHIDEventService::dispatchDigitizerEventWithOrientation is commented out, and the userspace IOHIDEventTranslation isn't open source, so I can't tell where the value is dropped. Questions Is pen pressure from a HIDVirtualDevice (or any generic HID digitizer handled by AppleUserHIDEventDriver) expected to reach NSEvent.pressure / kCGTabletEventPointPressure at all on current macOS? Or is that path reserved for vendor drivers posting tablet events themselves? If it is supported: which descriptor properties does the digitizer→tablet translation require for pressure — specific usages (Transducer Index, Barrel Switch, Tilt, Twist), Report ID, Physical range/Unit on the pressure element, a Feature report, or a particular device property (e.g. something in HIDVirtualDevice.Properties / kIOHIDDigitizer* keys)? Is there a documented way to set element calibration for a virtual device so Tip Pressure scales 0…1 instead of −1…+1 without abusing Logical Minimum? Is there a supported diagnostic on macOS 26 to see the IOHIDEvent digitizer fields (pressure, touch, event mask) that the event system builds from my reports, now that hidutil monitor is gone? Happy to file a Feedback with the full project and a sysdiagnose if that helps.
2
0
41
13h
Low-level event-posting help needed.
Hi there, I am working on a little application which processes cursor and graphics tablet data and adds some extra control to the output. So far it makes use of... if let eventTap = CGEvent.tapCreate(tap: .cgSessionEventTap, //.cghidEventTap place: .headInsertEventTap, options: .defaultTap, eventsOfInterest: eventMask, callback: handleTapEvent, userInfo: userInfo) ... to modify existing events. The issue that in some cases arises (it's a globally working app) - that some other applications pull and process pointer-data aside the event stream and therefor create conflicting values. Would creating and posting events to a 'virtual pointing device' on a lower system level (kext) help? Let's discuss. BR, E
1
0
683
22h
HIDVirtualDevice digitizer pen: position, proximity and tip switch reach NSEvent, but tablet pressure is always 0 — is pen pressure supported at all?
I'm building a virtual pen digitizer with HIDVirtualDevice (CoreHID, macOS 26.2, com.apple.developer.hid.virtual.device entitlement granted, Developer ID signed with the provisioning profile embedding the entitlement). The device is created and activated fine and shows up as expected: hidutil list: 0xface 0xbeef UsagePage 13 Usage 2 Transport Virtual "Hej Stylus Virtual Pen" AppleUserHIDEventService / AppleUserHIDEventDriver Report descriptor (Digitizer/Pen application collection, Stylus physical collection, 7-byte input report): 05 0D Usage Page (Digitizer) 09 02 Usage (Pen) A1 01 Collection (Application) 09 20 Usage (Stylus) A1 00 Collection (Physical) 09 42 Usage (Tip Switch) 09 32 Usage (In Range) 15 00 25 01 75 01 95 02 81 02 ; 2 bits 95 06 81 03 ; 6 bits padding (Const) 05 01 09 30 09 31 ; Generic Desktop X, Y 16 00 00 26 FF 7F 75 10 95 02 81 02 ; 0..32767, 16 bit each 05 0D 09 30 ; Digitizer / Tip Pressure 16 00 00 26 FF 1F 75 10 95 01 81 02 ; 0..8191, 16 bit C0 C0 I feed it a synthetic stream at 60 Hz (X sweep, Y fixed, tip switch down, in range, pressure ramping 0→8191) via dispatchInputReport(data:timestamp:) and observe the results with a global NSEvent monitor (.tabletProximity, .tabletPoint, .leftMouseDown/Up/Dragged, .mouseMoved) plus the raw CGEvent fields. What works tabletProximity: isEnteringProximity=1, pointingDeviceType=.pen, vendorID=0xFACE, tabletID=0xBEEF, systemTabletID assigned. All movement arrives as tabletPoint / mouseMoved with subtype == .tabletPoint; positions are exact. Tip switch maps to leftMouseDown / leftMouseUp correctly (verified by toggling the tip bit with pressure held at max). capabilityMask on the proximity event is 0x407 = NX_TABLET_CAPABILITY_DEVICEIDMASK | ABSXMASK | ABSYMASK | PRESSUREMASK — so the system declares pressure capability for this device. What doesn't NSEvent.pressure, kCGTabletEventPointPressure and kCGMouseEventPressure are always 0.000, on every event type, including with a constant maximum pressure value (8191). NSEvent.buttonMask is 1 (pen tip) and kCGTabletEventPointButtons is 1, so the report is being parsed — the pressure field just never makes it into the tablet event data. Things I've established / tried The pressure value is parsed and does influence touch/click: with tip switch held down and pressure held at 0, no mouse down is ever generated. With pressure ramping, the click happens at exactly 75 % of the logical range. Reading the open-source IOHIDEventDriver::parseDigitizerTransducerElement explains this: Tip Pressure is read with kIOHIDValueScaleTypeCalibrated, but only X/Y/Z elements get a calibration, and an uncalibrated element scales to −1…+1 — so raw 0…8191 becomes −1…+1 and the touch threshold (+0.5) sits at 75 %. Changing Logical Minimum to −8191 (so raw 0…8191 maps to 0…1) moves the click to exactly 50 % — confirming the model. Pressure in the event data is still 0. Adding Physical Minimum/Maximum and a Unit to the pressure element: no change. hidutil monitor no longer exists on macOS 26, so I can't inspect the IOHIDEvent digitizer fields directly. This looks like the same behaviour reported for kext-based digitizers since macOS 10.12 (developer.apple.com/forums thread "IOHIPointing dispatchAbsolutePointerEvent not works" and its sibling: "the pressure information is there from the transducer, the OS doesn't respond to it on 10.12+"). The tablet-pressure dispatch in the open-source IOHIDEventService::dispatchDigitizerEventWithOrientation is commented out, and the userspace IOHIDEventTranslation isn't open source, so I can't tell where the value is dropped. Questions Is pen pressure from a HIDVirtualDevice (or any generic HID digitizer handled by AppleUserHIDEventDriver) expected to reach NSEvent.pressure / kCGTabletEventPointPressure at all on current macOS? Or is that path reserved for vendor drivers posting tablet events themselves? If it is supported: which descriptor properties does the digitizer→tablet translation require for pressure — specific usages (Transducer Index, Barrel Switch, Tilt, Twist), Report ID, Physical range/Unit on the pressure element, a Feature report, or a particular device property (e.g. something in HIDVirtualDevice.Properties / kIOHIDDigitizer* keys)? Is there a documented way to set element calibration for a virtual device so Tip Pressure scales 0…1 instead of −1…+1 without abusing Logical Minimum? Is there a supported diagnostic on macOS 26 to see the IOHIDEvent digitizer fields (pressure, touch, event mask) that the event system builds from my reports, now that hidutil monitor is gone? Happy to file a Feedback with the full project and a sysdiagnose if that helps.
Replies
2
Boosts
0
Views
41
Activity
13h
Low-level event-posting help needed.
Hi there, I am working on a little application which processes cursor and graphics tablet data and adds some extra control to the output. So far it makes use of... if let eventTap = CGEvent.tapCreate(tap: .cgSessionEventTap, //.cghidEventTap place: .headInsertEventTap, options: .defaultTap, eventsOfInterest: eventMask, callback: handleTapEvent, userInfo: userInfo) ... to modify existing events. The issue that in some cases arises (it's a globally working app) - that some other applications pull and process pointer-data aside the event stream and therefor create conflicting values. Would creating and posting events to a 'virtual pointing device' on a lower system level (kext) help? Let's discuss. BR, E
Replies
1
Boosts
0
Views
683
Activity
22h