From 16ea80207d8dabc79ea2caa5666786af3c3648b4 Mon Sep 17 00:00:00 2001 From: Sean Collins <173011278+SMC17@users.noreply.github.com> Date: Tue, 19 May 2026 16:30:46 -0400 Subject: [PATCH] docs: add non-root ydotoold setup section to README Documents the systemd-user + input-group + udev-rule pattern that multiple open issues (#42, #73, #207, #210) have asked for. The README currently states 'this usually requires root permissions', which leads users to assemble the non-root setup from external blog posts and frequently get it wrong. The pattern shipped here is the minimal working configuration: - input group membership for /dev/uinput access - udev rule with KERNEL=="uinput" + GROUP="input" + MODE="0660" - modprobe + static_node uinput so the rule applies on load - systemd --user enable ydotoold.service (built by default) - YDOTOOL_SOCKET pointing at $XDG_RUNTIME_DIR/.ydotool_socket Tested on Arch Linux 6.x + Hyprland (Wayland). Pure docs change; no code touched. --- README.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/README.md b/README.md index a7b295f..b9b85b3 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,55 @@ Repeat the keyboard presses from stdin: #### Runtime `ydotoold` (daemon) program requires access to `/dev/uinput`. **This usually requires root permissions.** +#### Running ydotoold without root (recommended setup) + +`ydotoold` does not have to run as root. A minimal non-root setup uses +the `input` group, a udev rule to relax `/dev/uinput` permissions, and +the bundled systemd user service (built when `-DSYSTEMD_USER_SERVICE=ON`, +which is the default). + +1. Add your user to the `input` group: + + ```sh + sudo usermod -aG input "$USER" + ``` + +2. Create `/etc/udev/rules.d/60-uinput.rules`: + + ``` + KERNEL=="uinput", GROUP="input", MODE="0660", OPTIONS+="static_node=uinput" + ``` + +3. Reload udev rules and ensure the `uinput` module is loaded (the + `static_node` option only applies on next module load): + + ```sh + sudo udevadm control --reload-rules + sudo modprobe -r uinput && sudo modprobe uinput + ``` + + Log out and back in (or `newgrp input`) so the group change takes + effect for your session. + +4. Enable and start the user service: + + ```sh + systemctl --user enable --now ydotoold.service + ``` + +5. Export the socket path so `ydotool` knows where to find the daemon: + + ```sh + export YDOTOOL_SOCKET="$XDG_RUNTIME_DIR/.ydotool_socket" + ``` + + The user service writes the socket under `$XDG_RUNTIME_DIR`, not + `/tmp`. Add the export to your shell rc so it persists. + +This non-root setup is the recurring pattern in #42, #73, #207, and +#210; documenting it inline avoids re-deriving it from external +blog posts. + #### Available key names See `/usr/include/linux/input-event-codes.h`