87 lines
2.9 KiB
Markdown
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.
|