Skip to content

docs: ✏️ Add udev rules section for Linux HID permissions - #6

Open
sammyapoex wants to merge 1 commit into
maatthc:masterfrom
sammyapoex:docs/udev-rules
Open

docs: ✏️ Add udev rules section for Linux HID permissions#6
sammyapoex wants to merge 1 commit into
maatthc:masterfrom
sammyapoex:docs/udev-rules

Conversation

@sammyapoex

Copy link
Copy Markdown

Problem

The Troubleshooting section currently says only:

On Linux, you may need to configure udev rules to access HID devices without root

There is no rule, no example, and no way for a reader to work one out. On a stock setup this is the first thing that blocks the app: /dev/hidraw* is root:root 0600 on most distributions, so hid.Device(path=...) raises a permission error and the app exits via print_instructions() — which points at config.ini rather than at the real cause.

What this adds

A ### Permission denied on Linux (udev rules) section under Troubleshooting covering:

  • Finding your device's nodegrep -H -E 'HID_NAME|HID_ID' /sys/class/hidraw/*/device/uevent

  • The rule itself, matching on KERNELS so a single line covers both the USB raw-HID path (libs/keyboard_hid.py) and the ZMK Bluetooth path (libs/keyboard_ble_hid.py):

    KERNEL=="hidraw*", SUBSYSTEM=="hidraw", KERNELS=="????:1D50:615E.*", MODE="0660", GROUP="plugdev"
    
  • A dry-run check with udevadm test so readers can confirm the match before reconnecting anything

  • Notes on the three things that are easy to get wrong (below)

The existing bullet now links to the new section instead of trailing off.

Why KERNELS rather than ATTRS{idVendor}

Most keyboard udev rules found in the wild match ATTRS{idVendor}. That cannot work for the ZMK Bluetooth path. A BLE keyboard's hidraw node is created by uhid, so its parent chain is hid → misc/uhid → virtual with no USB device anywhere in it and no idVendor attribute to match:

DEVPATH=/devices/virtual/misc/uhid/0005:1D50:615E.0008/hidraw/hidraw6
HID_NAME=Kibard

The KERNELS name is <bus>:<VID>:<PID>.<n>, present on both buses (0003 USB, 0005 Bluetooth), so the ???? wildcard handles either connection with one rule.

Verification

Checked against live devices with udevadm test -D <dir> (a dry run — computes GROUP/MODE without re-permissioning), rather than from recall:

Check Result
Rule matches a BLE keyboard (ZMK, bus 0005) GROUP="plugdev" → gid 958, MODE → 0660
Same rule shape matches a USB keyboard (bus 0003) ✅ verified against a separate USB board
Lowercase hex (1d50:615e) ❌ no match — udev matching is case sensitive, hence the uppercase instruction

On the input group

The section states explicitly that input is not involved, because it is the common wrong guess. It governs /dev/input/event*, which this app never reads — it goes through HIDAPI to hidraw. Joining input does not help, and it grants read access to every keystroke on the machine, so it is worth steering people away from.

Caveats noted in the text

  • The VID/PID in the example is the ZMK/nice_nano default from config.ini; readers are told to substitute their own from the discovery command.
  • The hid package binds to whichever HIDAPI it finds. This is hidraw on most distributions, but a libusb-backend distro would need SUBSYSTEM=="usb" rules instead — called out in the notes.
  • TAG+="uaccess" is mentioned as the seat-local alternative to a group, with the caveat that the file must then sort before 73-seat-late.rules.

Docs only — no code changes.

🤖 Generated with Claude Code

The Troubleshooting section only said udev rules "may" be needed, with no
rule and no way to work one out. Add a section with the actual steps.

Both the USB raw-HID and ZMK Bluetooth paths open /dev/hidraw*, which most
distributions leave as root:root 0600. A single rule matching KERNELS on
"????:VID:PID.*" covers either bus. Note that ATTRS{idVendor} cannot work
for Bluetooth (the node is a uhid child with no USB attributes), that hex
matching is case sensitive, and that the input group is unrelated - it
governs /dev/input/event*, which this app never reads.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@sammyapoex sammyapoex closed this Aug 28, 2026
@maatthc

maatthc commented Sep 2, 2026

Copy link
Copy Markdown
Owner

I glad you contributed.. thanks..

@maatthc maatthc reopened this Sep 2, 2026
@sammyapoex

Copy link
Copy Markdown
Author

I accidentally opened this pr. I thought I had a clone of the repo. But I'm glad you appreciate it. I will submit another one soon (a fix for some freezing/hanging issues that I've had)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants