1
0
Files
surface-dial-linux/README.md
Daniel Prilik f7a261cb8a use libudev to handle device disconnect/reconnect
This change has substantially bumped up the daemon's overall robustness,
as the code now ensures that the controller will only start once the
/dev/input/eventXX file is set up, which was causing all sorts of issues
in the past.

Additionally, this change enables the daemon to run as a proper
background task that _doesn't_ constantly die / need to be restarted,
which removes the need for any janky udev "on add" rules, and instead, a
simple systemd user service will suffice.
2020-11-06 00:22:56 -05:00

6.1 KiB

surface-dial-linux

A Linux userspace controller for the Microsoft Surface Dial. Requires Linux Kernel 4.19 or higher.

DISCLAIMER: This software is still under active development!

Things will change. Things will break. Things are probably buggy.

Bug reports are appreciated!

Overview

surface-dial-daemon is a background daemon which receives raw events from the surface dial, and translates them to various actions.

The daemon uses FreeDesktop notifications to provide visual feedback when switching between actions.

It would be cool to create some sort of GUI overlay (similar to the Windows one), though that's out of scope at the moment.

Implementation

Core functionality is provided by the following libraries.

  • libudev to monitor when the dial connects/disconnects.
  • libevdev to read events from the surface dial through /dev/input/eventXX, and to fake input through /dev/uinput.
  • hidapi to configure dial sensitivity + haptics.
  • notify-rust to send desktop notifications over D-Bus.

While the device-handling code itself is somewhat messy at the moment, it should be really easy to add new operating modes. Just add a new mode implementation under src/controller/controls (making sure to update src/controller/controls/mod.rs), and add it to the list of available modes in main.rs!

Functionality

Feel free to contribute new features!

Dependencies

Building surface-dial-daemon requires the following:

  • Linux Kernel 4.19 or higher
  • A fairly recent version of the Rust compiler
  • libudev
  • libevdev
  • hidapi

You can install Rust through rustup.

Unless you're a cool hackerman, the easiest way to get libudev, libevdev, and hidapi is via your distro's package manager.

# e.g: on ubuntu
sudo apt install libevdev-dev libhidapi-dev libudev-dev

Building

surface-dial-daemon uses the standard cargo build flow.

cargo build -p surface-dial-daemon --release

The resulting binary is output to target/release/surface-dial-daemon

Running

The daemon is able to handle the dial disconnecting/reconnecting, so as long as it's running in the background, things should Just Work™️.

Note that the daemon must run as a user process (not as root), as it needs access to the user's D-Bus to send notifications.

Having to run as a user process complicates things a bit, as the daemon must be able to access several restricted-by-default devices under /dev/. Notably, the /dev/uinput device will need to have it's permissions changed for things to work correctly. The proper way to do this is using the included udev rule, though if you just want to get something up and running, sudo chmod 666 /dev/uinput should work fine (though it will revert back once you reboot!).

See the Installation instructions below for how to set up the permissions / udev rules.

During development, the easiest way to run surface-dial-linux is using cargo:

cargo run -p surface-dial-daemon

Alternatively, you can run the daemon directly using the executable at target/release/surface-dial-daemon.

Installation

I encourage you to tweak the following setup procedure for your particular linux configuration.

The following steps have been tested working on Ubuntu 20.04/20.10.

# Install the `surface-dial-daemon` (i.e: build it, and place it under ~/.cargo/bin/surface-dial-daemon)
# You could also just copy the executable from /target/release/surface-dial-daemon to wherever you like.
cargo install --path .

# IMPORTANT: modify the .service file to reflect where you placed the `service-dial-daemon` executable.
# if you used `cargo install`, this should be as simple as replacing `danielprilik` with your own user id
vi ./install/surface-dial.service

# create new group for uinput
# (the 99-uinput.rules file changes the group of /dev/uinput to this new group)
sudo groupdadd -f uinput

# add self to the new uinput group and the existing /dev/input group
sudo gpasswd -a $(whoami) uinput
sudo gpasswd -a $(whoami) $(stat -c "%G" /dev/input/event0)

# install the systemd user service
mkdir -p ~/.config/systemd/user/
cp ./install/surface-dial.service ~/.config/systemd/user/surface-dial.service

# install the udev rule
sudo cp ./install/99-uinput.rules /etc/udev/rules.d/99-uinput.rules

# reload systemd + udev
systemctl --user daemon-reload
sudo udevadm control --reload

# enable and start the user service
systemctl --user enable surface-dial.service
systemctl --user start surface-dial.service

To see if the service is running correctly, run systemctl --user status surface-dial.service.

You may need to reboot to have the various groups / udev rules propagate.

If things aren't working, feel free to file a bug report!

Call for Contributors: It would be awesome to have a proper rpm/deb package as well.