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

87 lines
2.9 KiB
Markdown

# 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.