Files
2026-06-26 15:35:13 +02:00

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:

  • DriverState in src/main.rs
  • VirtualInput in src/virtual_input.rs
  • Haptics in src/haptics.rs
  • SensitivityNotifier in src/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 Touchpad for multitouch scrolling.
  • Surface Dial Renewed Wheel for 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

  1. DialReader finds Surface Dial System Multi Axis.
  2. Raw evdev events are sent to the main loop.
  3. main.rs decodes intent:
    • button held + rotate: sensitivity adjustment
    • rotate alone: scrolling
    • connect/disconnect: haptics and gesture cleanup
  4. VirtualInput emits either multitouch or wheel events.
  5. Haptics buzzes on selector entry and sensitivity level changes.
  6. SensitivityNotifier displays Surface 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.