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.
Topic:
App & System Services
SubTopic:
Drivers
2
0
41