2.9 KiB
Architecture
surface-dial-renewed is a userspace Linux driver. It reads the Microsoft
Surface Dial through evdev, emits virtual input devices through uinput, uses HID
for haptic feedback, and uses KDE's OSD service for sensitivity feedback.
Runtime Threads
The process has one main event loop and one input worker thread.
The input worker is created by DialReader::spawn in src/dial.rs. It finds
the Surface Dial System Multi Axis event node through udev, blocks on evdev
events, and sends simplified raw events through a channel.
The main thread owns all output state:
DriverStateinsrc/main.rsVirtualInputinsrc/virtual_input.rsHapticsinsrc/haptics.rsSensitivityNotifierinsrc/notify.rs
Keeping output ownership on one thread avoids locking around uinput devices and keeps gesture lifecycle decisions local to the main loop.
Module Responsibilities
src/main.rs
The state machine. It decides whether a Dial rotation means scroll or sensitivity adjustment. It starts and ends multitouch gestures, updates sensitivity, and calls haptics/OSD hooks.
src/dial.rs
Device discovery and event decoding. It converts evdev events into
DialEventKind values: connect, disconnect, button press/release, long press,
rotation, and ignored noise.
src/virtual_input.rs
Creates two uinput devices:
Surface Dial Renewed Touchpadfor multitouch scrolling.Surface Dial Renewed Wheelfor regular wheel mode.
The touchpad device is intentionally not advertised as a buttonpad and does not
expose BTN_LEFT, reducing the chance that very short gestures become tap or
right-click behavior.
src/sensitivity.rs
Defines the 1-32 sensitivity scale and maps each level to scroll scaling.
src/haptics.rs
Opens the Dial's HID device and sends manual haptic buzz reports. Haptics are best-effort; failure disables haptics but does not stop scrolling.
src/notify.rs
Shows the sensitivity value. KDE uses qdbus6 with
org.kde.osdService.showText. If that fails, the code falls back to
FreeDesktop notifications.
src/error.rs
Small shared error enum for the concept driver.
Data Flow
DialReaderfindsSurface Dial System Multi Axis.- Raw evdev events are sent to the main loop.
main.rsdecodes intent:- button held + rotate: sensitivity adjustment
- rotate alone: scrolling
- connect/disconnect: haptics and gesture cleanup
VirtualInputemits either multitouch or wheel events.Hapticsbuzzes on selector entry and sensitivity level changes.SensitivityNotifierdisplaysSurface Dial sensitivity N/32.
Reconnect Model
The input worker scans for an existing Dial at startup. If the device is removed or an input read fails, it sends a disconnect event, sleeps briefly, and retries discovery/monitoring. The main loop ends any active multitouch gesture and drops the HID haptics handle on disconnect. On reconnect it reopens haptics.