git.christianimmanuel.de / Linux & System / Linux-disable-Middle-Mouse-Click

Linux-disable-Middle-Mouse-Click git · main

git clone https://git.christianimmanuel.de/linux-system/Linux-disable-Middle-Mouse-Click.gitwget https://git.christianimmanuel.de/linux-system/Linux-disable-Middle-Mouse-Click/archive/Linux-disable-Middle-Mouse-Click.tar.gz
1fff041Fix unable to righclick+ouseChristian Immanuel · 1 day ago
-.gitignore22 B
-middle_button_disable.c24.3 KB
-README.md6.8 KB
-sysv_script_for_lfs.sh2.2 KB

README.md

Linux-disable-Middle-Mouse-Click

Disable TrackPoint middle-click while keeping press-and-scroll working. ThinkPad/Lenovo TrackPoint devices use the middle button + TrackPoint to implement click-and-scroll. If you also use middle-click to open links/tabs, it’s easy to accidentally middle-click while scrolling. This small C program intercepts raw evdev events, removes the plain middle-click, but still emits the correct events when you actually scroll with the middle button held.

100% vibecode: this repo/program was generated/iterated with ChatGPT. It’s intentionally small and hackable.


Features

OptionWhat it does
-d /dev/input/eventX (repeatable)Filter a specific device.
--autoAuto-detect TrackPoint devices via udev (matches ID_INPUT_POINTINGSTICK=1 and also requires the device to expose BTN_MIDDLE).
--match REGEXOptional extra filter for --auto: case-insensitive POSIX regex matched against udev ID_MODEL (useful if auto finds too many devices).
-h / --helpShow a usage summary.

If you give both -d and --auto, the program will filter the union of the explicit devices and the auto‑detected ones.


Getting the right device names

The kernel creates a node for every input device under /dev/input/, named event0, event1, … You need the exact node that belongs to the TrackPoint you want to filter.

1. Using udevadm

# replace event13 with the number you suspect
udevadm info -a -n /dev/input/event13 | grep -i "trackpoint"

If the output contains a line like ATTRS{idInputPointingStick}=="1" you have the right one.

2. Using libinput

$ libinput debug-events
-event13  DEVICE_ADDED  TPPS/2 Elan TrackPoint   seat0 default group10 …
-event15  DEVICE_ADDED  Lenovo TrackPoint Keyboard II Mouse …

The part after -event is the eventX you need (e.g. event13).

3. By‑id /path shortcuts

The /dev/input/by-id/ and /dev/input/by-path/ symlinks are stable across boots, e.g.:

ls -l /dev/input/by-id/*TrackPoint*mouse
lrwxrwxrwx 1 root root 13 Sep  1 12:34 usb-Lenovo_TrackPoint_Keyboard_II-if01-event-mouse -> ../event15

You can feed those symlinks straight to the program (-d /dev/input/by-id/...).

Building

You need the libudev development headers (package libudev-dev on Debian/Ubuntu, systemd-devel on Fedora, etc.).

gcc -Wall -O2 -D_GNU_SOURCE -o middle_button_disable middle_button_disable.c -ludev

The binary must be run as root (or with the CAP_SYS_ADMIN capability) because it needs to:

  • open /dev/uinput and create a virtual device,
  • grab the real /dev/input/eventX devices so the kernel stops sending them to X/Wayland.

Running

1. Manual start (for testing)

sudo ./middle_button_disable --auto
# or
sudo ./middle_button_disable -d /dev/input/event13 -d /dev/input/event15

Press Ctrl‑C to stop – the program cleans up the uinput nodes and releases the grabs.

2. Systemd service (run at boot)

Create /etc/systemd/system/middle_button_disable.service:

[Unit]
Description=Disable TrackPoint middle click (keep scrolling)
After=systemd-udevd.service
Wants=systemd-udevd.service

[Service]
Type=simple
ExecStart=/usr/local/sbin/middle_button_disable --auto
# change the path if you installed it elsewhere
Restart=on-failure
CapabilityBoundingSet=CAP_SYS_ADMIN
AmbientCapabilities=CAP_SYS_ADMIN
User=root

[Install]
WantedBy=multi-user.target

Enable and start it:

sudo systemctl daemon-reload
sudo systemctl enable --now middle_button_disable.service

Check the log:

journalctl -u middle_button_disable -f

3. SysV init (sysvinit / sysv-rc / Devuan, etc.)

Create /etc/init.d/middle_button_disable:

#!/bin/sh
### BEGIN INIT INFO
# Provides:          middle_button_disable
# Required-Start:    $local_fs $remote_fs udev
# Required-Stop:     $local_fs $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Disable TrackPoint middle click (keep scrolling)
### END INIT INFO

DAEMON=/usr/local/sbin/middle_button_disable
NAME=middle_button_disable
PIDFILE=/run/$NAME.pid

# Choose ONE:
ARGS="--auto"
# ARGS="-d /dev/input/event13 -d /dev/input/event15"

case "$1" in
  start)
    echo "Starting $NAME..."
    start-stop-daemon --start --quiet --background \
      --make-pidfile --pidfile "$PIDFILE" \
      --exec "$DAEMON" -- $ARGS
    ;;
  stop)
    echo "Stopping $NAME..."
    start-stop-daemon --stop --quiet --pidfile "$PIDFILE" --retry 5
    rm -f "$PIDFILE"
    ;;
  restart)
    "$0" stop
    sleep 1
    "$0" start
    ;;
  status)
    if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; then
      echo "$NAME is running (pid $(cat "$PIDFILE"))."
      exit 0
    else
      echo "$NAME is not running."
      exit 3
    fi
    ;;
  *)
    echo "Usage: $0 {start|stop|restart|status}"
    exit 2
    ;;
esac

exit 0

Enable it (Debian/Devuan style):

sudo chmod +x /etc/init.d/middle_button_disable
sudo update-rc.d middle_button_disable defaults
sudo service middle_button_disable start

On some distros you may use chkconfig instead of update-rc.d.

4. OpenRC

Create /etc/init.d/middle_button_disable:

#!/sbin/openrc-run

name="middle_button_disable"
description="Disable TrackPoint middle click (keep scrolling)"

command="/usr/local/sbin/middle_button_disable"

# Choose ONE:
command_args="--auto"
# command_args="-d /dev/input/event13 -d /dev/input/event15"

command_background="yes"
pidfile="/run/${RC_SVCNAME}.pid"

depend() {
  need localmount
  after udev
}

Enable and start:

sudo chmod +x /etc/init.d/middle_button_disable
sudo rc-update add middle_button_disable default
sudo rc-service middle_button_disable start


How it works (short explanation)

  • The program grabs the physical input device (EVIOCGRAB).
  • This tells the kernel “don’t deliver the events downstream”.

  • It creates a virtual device with uinput that mimics the original
  • capabilities (buttons, relative axes).

  • For the built‑in TrackPoint (internal), the logic is:
  • When BTN_MIDDLE goes down, don’t forward it immediately.
  • If a wheel (REL_WHEEL, REL_HWHEEL, …) shows up while the button is held,
  • emit a synthetic BTN_MIDDLE press – this is what the desktop thinks of as “click‑and‑scroll”.

  • When the button is released, forward the BTN_MIDDLE release only if we
  • previously sent the synthetic press.

  • For external keyboards (external), any BTN_MIDDLE events are simply dropped.
  • All other events (movement, left/right click, etc.) are forwarded unchanged.

That is exactly the behaviour you had in the original code, now with a clean command‑line interface and automatic detection.


License

Public domain / “free as vibecode”. Do whatever you want with it.