@@ -5,6 +5,79 @@ pub const PIX_VID: u16 = 0x093A;
55pub const P274_REPORT_ID : u8 = 0x43 ;
66pub const P239_REPORT_ID : u8 = 0x42 ;
77
8+ // Standard HID Precision Touchpad (PTP) interface — every PTP-compliant touchpad
9+ // reports on this usage. Only haptic touchpads expose the feature reports below.
10+ const TOUCHPAD_USAGE_PAGE : u16 = 0x000D ; // Digitizers
11+ const TOUCHPAD_USAGE : u16 = 0x0005 ; // Touch Pad
12+
13+ // Haptic feedback intensity (HID Haptic page 0x0E, Usage 0x23 Intensity).
14+ // Descriptor says logical range 0..100, but the Boreas haptic firmware
15+ // only implements five steps: 0%, 25%, 50%, 75%, 100%.
16+ const HAPTIC_INTENSITY_REPORT_ID : u8 = 0x09 ;
17+ pub const HAPTIC_INTENSITY_LEVELS : [ u8 ; 5 ] = [ 0 , 25 , 50 , 75 , 100 ] ;
18+
19+ // Button press threshold / click force (HID Digitizer page 0x0D, Usage 0xB0).
20+ // 2-bit field, firmware accepts 1=Low, 2=Medium, 3=High.
21+ const CLICK_FORCE_REPORT_ID : u8 = 0x08 ;
22+
23+ /// Open the PTP HID interface of the touchpad. Note: every modern touchpad
24+ /// exposes this interface; only haptic touchpads respond to the feature
25+ /// reports used by `set_haptic_intensity` / `set_click_force`.
26+ fn open_haptic_touchpad ( ) -> Option < HidDevice > {
27+ let api = HidApi :: new ( ) . ok ( ) ?;
28+ for dev_info in api. device_list ( ) {
29+ if dev_info. usage_page ( ) != TOUCHPAD_USAGE_PAGE || dev_info. usage ( ) != TOUCHPAD_USAGE {
30+ continue ;
31+ }
32+ debug ! (
33+ " Touchpad candidate {:04X}:{:04X} (Usage Page {:04X}, Usage {:04X})" ,
34+ dev_info. vendor_id( ) ,
35+ dev_info. product_id( ) ,
36+ dev_info. usage_page( ) ,
37+ dev_info. usage( )
38+ ) ;
39+ if let Ok ( device) = dev_info. open_device ( & api) {
40+ return Some ( device) ;
41+ }
42+ }
43+ None
44+ }
45+
46+ // The firmware accepts SET_FEATURE for these reports but doesn't reply
47+ // to GET_FEATURE, so both controls are write-only.
48+
49+ pub fn set_haptic_intensity ( value : u8 ) -> Result < ( ) , HidError > {
50+ if !HAPTIC_INTENSITY_LEVELS . contains ( & value) {
51+ error ! (
52+ "Haptic intensity must be one of: {:?}" ,
53+ HAPTIC_INTENSITY_LEVELS
54+ ) ;
55+ return Ok ( ( ) ) ;
56+ }
57+ let Some ( device) = open_haptic_touchpad ( ) else {
58+ error ! ( "Could not find a haptic touchpad" ) ;
59+ return Ok ( ( ) ) ;
60+ } ;
61+ let buf = [ HAPTIC_INTENSITY_REPORT_ID , value] ;
62+ debug ! ( " send_feature_report (haptic intensity) {:X?}" , buf) ;
63+ device. send_feature_report ( & buf)
64+ }
65+
66+ pub fn set_click_force ( level : u8 ) -> Result < ( ) , HidError > {
67+ if !( 1 ..=3 ) . contains ( & level) {
68+ error ! ( "Click force level must be 1 (Low), 2 (Medium), or 3 (High)" ) ;
69+ return Ok ( ( ) ) ;
70+ }
71+ let Some ( device) = open_haptic_touchpad ( ) else {
72+ error ! ( "Could not find a haptic touchpad" ) ;
73+ return Ok ( ( ) ) ;
74+ } ;
75+ // Field is 2 bits at the bottom of the report payload
76+ let buf = [ CLICK_FORCE_REPORT_ID , level & 0x03 ] ;
77+ debug ! ( " send_feature_report (click force) {:X?}" , buf) ;
78+ device. send_feature_report ( & buf)
79+ }
80+
881fn read_byte ( device : & HidDevice , report_id : u8 , addr : u8 ) -> Result < u8 , HidError > {
982 device. send_feature_report ( & [ report_id, addr, 0x10 , 0 ] ) ?;
1083
0 commit comments