Available devices:
/dev/input/event0: Power Button
/dev/input/event1: AT Translated Set 2 keyboard
/dev/input/event2: ImExPS/2 Generic Explorer Mouse
/dev/input/event3: Surface Dial System Multi Axis
/dev/input/event4: Surface Dial System Control
Select the device event number [0-4]: 3
Input driver version is 1.0.1
Input device ID: bus 0x5 vendor 0x45e product 0x91b version 0x108
Input device name: "Surface Dial System Multi Axis"
Supported events:
Event type 0 (EV_SYN)
Event type 1 (EV_KEY)
Event code 256 (BTN_0)
Event type 2 (EV_REL)
Event code 7 (REL_DIAL)
Event type 4 (EV_MSC)
Event code 4 (MSC_SCAN)
Properties:
Event: time 1735727359.044172, type 2 (EV_REL), code 7 (REL_DIAL), value -1
Event: time 1735727359.044172, -------------- SYN_REPORT ------------
Event: time 1735727359.207239, type 2 (EV_REL), code 7 (REL_DIAL), value -1
Event: time 1735727359.207239, -------------- SYN_REPORT ------------
Event: time 1735727359.244200, type 2 (EV_REL), code 7 (REL_DIAL), value -1
Event: time 1735727359.244200, -------------- SYN_REPORT ------------
Event: time 1735727359.269217, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90001
Event: time 1735727359.269217, type 1 (EV_KEY), code 256 (BTN_0), value 1
Event: time 1735727359.269217, -------------- SYN_REPORT ------------
Event: time 1735727359.481240, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90001
Event: time 1735727359.481240, type 1 (EV_KEY), code 256 (BTN_0), value 0
Event: time 1735727359.481240, -------------- SYN_REPORT ------------
Event: time 1735727359.492606, type 2 (EV_REL), code 7 (REL_DIAL), value 1
Haptic feedback
Reference: https://github.com/daniel5151/surface-dial-linux/blob/43dd973092871d8ef0c452b0797b519f5a9ddfac/src/dial_device/haptics.rs
In case repo is down:
use std::sync::mpsc;
use hidapi::{HidApi, HidDevice};
use crate::error::{Error, Result};
/// Proxy object - forwards requests to the DialHapticsWorker task
pub struct DialHaptics {
msg: mpsc::Sender<DialHapticsWorkerMsg>,
}
impl DialHaptics {
pub(super) fn new(msg: mpsc::Sender<DialHapticsWorkerMsg>) -> Result<DialHaptics> {
Ok(DialHaptics { msg })
}
/// `steps` should be a value between 0 and 3600, which corresponds to the
/// number of subdivisions the dial should use.
pub fn set_mode(&self, haptics: bool, steps: u16) -> Result<()> {
let _ = (self.msg).send(DialHapticsWorkerMsg::SetMode { haptics, steps });
Ok(())
}
pub fn buzz(&self, repeat: u8) -> Result<()> {
let _ = (self.msg).send(DialHapticsWorkerMsg::Manual { repeat });
Ok(())
}
}
#[derive(Debug)]
pub(super) enum DialHapticsWorkerMsg {
DialConnected,
DialDisconnected,
SetMode { haptics: bool, steps: u16 },
Manual { repeat: u8 },
}
pub(super) struct DialHapticsWorker {
msg: mpsc::Receiver<DialHapticsWorkerMsg>,
}
impl DialHapticsWorker {
pub(super) fn new(msg: mpsc::Receiver<DialHapticsWorkerMsg>) -> Result<DialHapticsWorker> {
Ok(DialHapticsWorker { msg })
}
pub(super) fn run(&mut self) -> Result<()> {
loop {
eprintln!("haptics worker is waiting...");
loop {
match self.msg.recv().unwrap() {
DialHapticsWorkerMsg::DialConnected => break,
other => eprintln!("haptics worker dropped an event: {:?}", other),
}
}
eprintln!("haptics worker is ready");
let api = HidApi::new().map_err(Error::HidError)?;
let hid_device = api.open(0x045e, 0x091b).map_err(Error::HidError)?;
let wrapper = DialHidWrapper { hid_device };
loop {
match self.msg.recv().unwrap() {
DialHapticsWorkerMsg::DialConnected => {
eprintln!("Unexpected haptics worker ready event.");
// should be fine though?
}
DialHapticsWorkerMsg::DialDisconnected => break,
DialHapticsWorkerMsg::SetMode { haptics, steps } => {
wrapper.set_mode(haptics, steps)?
}
DialHapticsWorkerMsg::Manual { repeat } => wrapper.buzz(repeat)?,
}
}
}
}
}
struct DialHidWrapper {
hid_device: HidDevice,
}
impl DialHidWrapper {
/// `steps` should be a value between 0 and 3600, which corresponds to the
/// number of subdivisions the dial should use. If left unspecified, this
/// defaults to 36 (an arbitrary choice that "feels good" most of the time)
fn set_mode(&self, haptics: bool, steps: u16) -> Result<()> {
assert!(steps <= 3600);
let steps_lo = steps & 0xff;
let steps_hi = (steps >> 8) & 0xff;
let mut buf = [0; 8];
buf[0] = 1;
buf[1] = steps_lo as u8; // steps
buf[2] = steps_hi as u8; // steps
buf[3] = 0x00; // Repeat Count
buf[4] = if haptics { 0x03 } else { 0x02 }; // auto trigger
buf[5] = 0x00; // Waveform Cutoff Time
buf[6] = 0x00; // retrigger period
buf[7] = 0x00; // retrigger period
self.hid_device
.send_feature_report(&buf[..8])
.map_err(Error::HidError)?;
Ok(())
}
fn buzz(&self, repeat: u8) -> Result<()> {
let mut buf = [0; 5];
buf[0] = 0x01; // Report ID
buf[1] = repeat; // RepeatCount
buf[2] = 0x03; // ManualTrigger
buf[3] = 0x00; // RetriggerPeriod (lo)
buf[4] = 0x00; // RetriggerPeriod (hi)
self.hid_device.write(&buf).map_err(Error::HidError)?;
Ok(())
}
}
斟酌 鵬兄
Thu Jan 02 2025 07:06:21 GMT+0000 (Coordinated Universal Time)
Last modified: Thu Jan 02 2025 07:08:35 GMT+0000 (Coordinated Universal Time)