Dead pointer. Live buttons. Works on Wayland + X11. No BIOS toggle, no xinput gymnastics, no dotfile religion.
Problem · Install · How it works · Config · Hardware · Troubleshooting · Design
On modern Linux ThinkPads — Yoga 370, T470, X270, X1 Carbon Gen 5 and most of the 2017-onward Elantech-digitizer lineup — the three TrackPoint buttons below the spacebar share an input device with the red dot (pointing stick) itself. Disable the pointer (BIOS toggle, inhibited=1, xinput disable) and you lose the buttons too. On Wayland, the classic Coordinate Transformation Matrix escape hatch is gone.
Every forum answer, every Stack Overflow thread, every dotfile gist ignores this. Here's the receipt:
| Approach | Works? | Problem |
|---|---|---|
echo 1 > /sys/class/input/inputN/inhibited |
✗ | Disables the whole device, buttons included |
| BIOS "TrackPoint = Disabled" | ✗ | Same — EC turns off the device entirely |
xinput set-prop "Device Enabled" 0 |
✗ | X11 only, also kills the device |
libinput AttrTrackpointMultiplier / udev POINTINGSTICK_SENSITIVITY |
✗ | Ignored on many Elantech devices |
xinput set-prop "Coordinate Transformation Matrix" 0 0 0 0 0 0 0 0 1 |
✓ | X11 only — useless under Wayland |
| ZO-REDdot | ✓ | Works on Wayland + X11, keeps buttons |
The only fix that actually works is to grab the device at the kernel boundary and drop the X/Y motion while re-emitting the button events through a fresh uinput pointer. 30 lines of Python. That's it.
git clone https://github.com/Jok0ne/zo-reddot.git
cd zo-reddot
./install.shThe installer:
- installs
python3-evdev(supportsdnf/apt-get/pacman), - copies
zo-reddot.pyto/usr/local/bin/and the unit to/etc/systemd/system/, - enables and starts
zo-reddot.service.
Root is required — exclusive grab on an input device and writing to /dev/uinput are privileged operations.
systemctl status zo-reddot
journalctl -u zo-reddot -fExpected log line:
zo-reddot: grabbed + uinput up — buttons only, motion dropped
Nudge the red dot: nothing. Click any of the three buttons under the spacebar: normal left / middle / right click.
┌────────────────────────┐
│ TrackPoint device │ /dev/input/event4
│ (Elantech ISA PS/2) │ emits: BTN_LEFT/RIGHT/MIDDLE + EV_REL(X,Y)
└────────────┬───────────┘
│ device.grab() — exclusive read
▼
┌────────────────────────┐
│ zo-reddot │ forward: BTN_LEFT/RIGHT/MIDDLE
│ event filter │ drop: EV_REL X/Y, scroll emulation
└────────────┬───────────┘
│ UInput.write_event() + syn()
▼
┌────────────────────────┐
│ "TrackPoint Buttons │ new /dev/input/eventN
│ Only" (uinput device) │ advertises only BTN_LEFT/RIGHT/MIDDLE
└────────────┬───────────┘
│
▼
┌────────────────────────┐
│ libinput + │ buttons integrate normally,
│ Wayland / X11 │ no pointer motion
└────────────────────────┘
libinput and the desktop environment see the new uinput device as a normal button-only pointer and integrate it automatically. The pointing-stick itself has no visible consumer anymore, so nudging it does nothing.
Service survives reboots. Uninstall releases the device cleanly and restores the original behaviour.
The service matches the input device by exact name. Default:
TRACKPOINT_NAME=ETPS/2 Elantech TrackPointIf your device has a different name — find it with cat /proc/bus/input/devices or sudo libinput list-devices — set TRACKPOINT_NAME in /etc/systemd/system/zo-reddot.service:
Environment=TRACKPOINT_NAME=TPPS/2 Elan TrackPointThen:
sudo systemctl daemon-reload
sudo systemctl restart zo-reddot./install.sh uninstallStops and disables the service, removes the script and unit file. Original TrackPoint behaviour (pointer + buttons) is back immediately.
| Device | Digitizer | Tested on | Status |
|---|---|---|---|
| ThinkPad Yoga 370 | Elantech 056a:50b0 |
Fedora 42, Plasma 6 Wayland | ✓ |
| T470 / T470s / T470p | Elantech | — | likely |
| X270 / L470 | Elantech | — | likely |
| X1 Carbon Gen 5 / X1 Yoga Gen 2 | Elantech | — | likely |
If you run it successfully on other hardware, a PR adding to this list is welcome.
- Touchpad — separate input device.
- External USB / Bluetooth mice.
- Keyboard.
- Plasma / GNOME pointer-speed settings on every other pointer.
The service is active but the TrackPoint still moves the cursor
libinput may have cached the original device. Log out and back in, or force a full config reload:
qdbus-qt6 org.kde.KWin /KWin reconfigureIf it still moves, verify the daemon grabbed the right device:
journalctl -u zo-reddot -n 20You should see grabbing /dev/input/eventN (<device name>). If no input device named '…' found appears instead, your TrackPoint has a different name — set TRACKPOINT_NAME as described in Configuration.
I have a different TrackPoint brand (Synaptics, IBM, ALPS)
Find the exact device name:
cat /proc/bus/input/devices | grep -iE "trackpoint|pointing"Then set TRACKPOINT_NAME in the unit file. Common values:
TPPS/2 Elan TrackPointTPPS/2 IBM TrackPointSynaptics TM2334-004AlpsPS/2 ALPS DualPoint Stick
GNOME / Cinnamon / XFCE / Sway support
ZO-REDdot operates at the kernel/uinput layer, below every desktop environment and display server. Anything that speaks libinput or evdev sees the buttons-only device and treats it as a normal button pointer. No desktop-specific configuration needed.
The service enters restart loop
The daemon exits with code 1 if it can't find the matching device. In a restart loop, this usually means the TRACKPOINT_NAME is wrong or the device was renamed after a kernel update. Disable auto-restart temporarily to debug:
sudo systemctl stop zo-reddot
sudo /usr/bin/python3 /usr/local/bin/zo-reddot.pyRead the stderr output, correct the env var, and restart.
Both work. ZO-REDdot exists because:
- Zero compilation. One Python file, done.
- Readable source — ~30 lines you can audit before running as root.
- Single dependency (
python3-evdev) that every distro packages. - One process, one syscall loop — no cascading dependency services.
If you need maximum efficiency, a compiled C equivalent saves ~15 MB of Python RSS. For a background daemon on a modern laptop, that tradeoff is usually fine.
EVIOCGRAB (exclusive device grab) and writing to /dev/uinput both require CAP_SYS_ADMIN or explicit input-group access plus uaccess. We could drop to a dedicated user with those capabilities, but root + SupplementaryGroups=input is clearer and the attack surface is ~30 lines of code.
X11's Coordinate Transformation Matrix zeros out motion at the server level and leaves buttons alone — elegant, but bound to X11. Wayland has no equivalent primitive exposed to userspace. Kernel-level grab + uinput re-emit works on both, with the same latency as any other input device.
GPL-3.0-or-later — see LICENSE.
Copyright © 2026 Zerone. If you redistribute this — modified or not — recipients must keep the same freedoms you received: attribution preserved, source available, changes released under the same terms.
SPDX-License-Identifier: GPL-3.0-or-later
