Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
3b3d99c
Create config.py
some1ataplace May 9, 2026
bff5377
Update filtering.py
some1ataplace May 9, 2026
423882a
Update __main__.py
some1ataplace May 9, 2026
f7ebe34
Update keyboard_retrieval.py
some1ataplace May 9, 2026
ebcdb71
Update chattering_fix.sh
some1ataplace May 9, 2026
109888d
Merge branch 'master' into Multiple-Fixes
some1ataplace May 9, 2026
e11d56a
Create mouse_filtering.py
some1ataplace May 9, 2026
6b501dc
Create mouse_retrieval.py
some1ataplace May 9, 2026
6d9dba2
Create mouse_main.py
some1ataplace May 9, 2026
2b41225
Create mouse_config.py
some1ataplace May 9, 2026
4843e07
Create mouse_fix.sh
some1ataplace May 9, 2026
4b34237
Delete src/mouse_fix.sh
some1ataplace May 9, 2026
b4b360b
Create mouse_chattering.sh
some1ataplace May 9, 2026
567f5fa
Create mouse_fix.service
some1ataplace May 9, 2026
bb6e45c
Rename chattering_fix.sh to keyboard_chattering.sh
some1ataplace May 9, 2026
558a871
Rename chattering_fix.service to keyboard_chattering.service
some1ataplace May 9, 2026
0811deb
Rename mouse_fix.service to mouse_chattering.service
some1ataplace May 9, 2026
c01a759
Rename config.py to keyboard_config.py
some1ataplace May 9, 2026
c845b70
Rename filtering.py to keyboard_filtering.py
some1ataplace May 9, 2026
65f321a
Update keyboard_filtering.py
some1ataplace May 9, 2026
179ca9c
Update keyboard_retrieval.py
some1ataplace May 9, 2026
f165665
Update and rename __main__.py to keyboard_main.py
some1ataplace May 9, 2026
f38bc08
Update mouse_filtering.py
some1ataplace May 9, 2026
6aeb242
Update mouse_retrieval.py
some1ataplace May 9, 2026
33c7e80
Update mouse_main.py
some1ataplace May 9, 2026
d413d3f
Update keyboard_chattering.sh
some1ataplace May 9, 2026
3d66341
Update mouse_chattering.sh
some1ataplace May 9, 2026
6071ce5
Update mouse_chattering.sh
some1ataplace May 9, 2026
32903fa
Update mouse_chattering.service
some1ataplace May 9, 2026
b107a6b
Update keyboard_chattering.service
some1ataplace May 9, 2026
193105b
Update README.md
some1ataplace May 9, 2026
d72fb35
Update README.md
some1ataplace May 9, 2026
4f11429
Update keyboard_chattering.sh
some1ataplace May 9, 2026
746c1e8
Update mouse_chattering.sh
some1ataplace May 9, 2026
566701d
Update keyboard_filtering.py
some1ataplace May 9, 2026
1bdf5c8
Update keyboard_main.py
some1ataplace May 9, 2026
02f5184
Update mouse_filtering.py
some1ataplace May 9, 2026
a930fb1
Update mouse_main.py
some1ataplace May 9, 2026
bc84357
Update keyboard_retrieval.py
some1ataplace May 9, 2026
9c39f93
Update mouse_retrieval.py
some1ataplace May 9, 2026
8850586
Update keyboard_retrieval.py
some1ataplace May 9, 2026
8c85f60
Update mouse_retrieval.py
some1ataplace May 9, 2026
eb3d9df
Update README.md
some1ataplace May 9, 2026
e6d8313
Update README.md
some1ataplace May 9, 2026
23ab86e
Update README.md
some1ataplace May 9, 2026
05a37b5
Update keyboard_retrieval.py
some1ataplace May 9, 2026
f983e5f
Update mouse_retrieval.py
some1ataplace May 9, 2026
e6a0707
Update mouse_retrieval.py
some1ataplace May 9, 2026
ec37dd6
Update keyboard_retrieval.py
some1ataplace May 9, 2026
90a59b2
Update keyboard_filtering.py
some1ataplace May 9, 2026
ca50a28
Update mouse_filtering.py
some1ataplace May 9, 2026
e2a6dc3
Update keyboard_filtering.py
some1ataplace May 9, 2026
b0907c4
Update mouse_filtering.py
some1ataplace May 9, 2026
7352b51
Update README.md
some1ataplace May 9, 2026
c194a64
Update README.md
some1ataplace May 9, 2026
90a358c
Update README.md
some1ataplace May 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 125 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,101 +1,170 @@
# __Keyboard Chattering Fix for Linux__
# __Keyboard Chattering & Mouse Double-Click Fix for Linux__

[![GitHub](https://img.shields.io/github/license/w2sv/KeyboardChatteringFix-Linux?)](LICENSE)

__A tool for filtering mechanical keyboard chattering on Linux__
__A tool for filtering mechanical keyboard chattering and mouse double-clicking on Linux__

## The problem

Switches on mechanical keyboards occasionally start to "chatter",
meaning when you press a key with a faulty switch it erroneously detects
two or even more key presses.
Switches on mechanical keyboards occasionally start to "chatter" or "bounce", meaning when you press a key with a faulty switch it erroneously detects two or even more key presses. Similarly, mechanical switches on mice (especially gaming mice) frequently develop "double-click" issues where a single physical click registers as multiple rapid clicks.

## The existing solutions

Apart from buying a new keyboard, there have been ways to deal
with this problem using software methods. The idea is to filter key presses
that occur faster than a certain threshold. "Keyboard Chattering Fix v 0.0.1"
is a tool I had been using on Windows for a long time, and these days you also have
[Keyboard Chatter Blocker](https://github.com/mcmonkeyprojects/KeyboardChatterBlocker),
which is a nice open source tool with some additional functionality. It's actually what
I use myself when I use Windows.

Unfortunately, all existing tools only work on Windows.
On Linux, the answer everyone seems to give is to use the Bounce Keys feature of X,
but it's not really useful in this way. For one, it resets the delay even on filtered
key presses, meaning that if you press the key fast enough,
*none* of the presses with pass through, ever. And if the key chatters,
this is bound to happen eventually and interfere with fast repeated key presses.
Apart from buying new hardware, there have been ways to deal with this problem using software methods. The idea is to filter inputs that occur faster than a certain threshold. "Keyboard Chattering Fix v 0.0.1" is a tool I had been using on Windows for a long time, and these days you also have [Keyboard Chatter Blocker](https://github.com/mcmonkeyprojects/KeyboardChatterBlocker).

Unfortunately, all existing tools only work on Windows. On Linux, the answer everyone seems to give is to use the Bounce Keys feature of X, but it's not really useful in this way. For one, it resets the delay even on filtered key presses, meaning that if you press the key fast enough, *none* of the presses will pass through, ever.

## This project's solution

This tool attempts to solve any such problems that may arise by having full low-level access
and control over all keyboard events.
Using `libevdev`'s Python bindings, it grabs your keyboard's event device and processes its events,
then outputs the result back to the system using `/dev/uinput`, effectively emulating a keyboard -
one that doesn't chatter, unlike your real one!
This tool attempts to solve these hardware problems by having full low-level access and control over all input events. Using `libevdev`'s Python bindings, it grabs your device and processes its events, then outputs the result back to the system using `/dev/uinput`. This effectively emulates a flawless keyboard and mouse that doesn't chatter or double-click, unlike your real ones!

This also means it works across the whole system, without depending on X11 or Wayland.

*Note for Mice:* To ensure your mouse cursor remains flawlessly smooth, this tool uses completely separate logic for mice. It natively bypasses X/Y cursor movement and scrolling, applying the chatter filter *only* to physical button clicks (Left click, Right click, Side buttons, etc.).

As for the filtering rule, what seems to work well is the time between the last "key up" event and the current "key down" event. When the switch chatters, that time is very low - around 10 ms. By filtering such anomalies, we remove chatter without impeding actual fast typing or clicking.

### Understanding Linux Input Devices (Which one do I pick?)

Modern gaming peripherals (like Corsair, Razer, or Logitech) are "composite USB devices". This means a single physical mouse might tell Linux it is actually 4 different devices! When you run the scripts manually, you will see a list of endpoints ending in different suffixes.

This also means it works across the system, without depending on X.
Here is a guide on which one to choose:

As for the filtering rule, what seems to work well is the time between the last key up event
and the current key down event. When the key chatters, that time seems to be very low - around 10 ms.
By filtering such anomalies, we can hopefully remove chatter without impeding actual fast key presses.
- **`-event-kbd`**: The primary endpoint for standard keystrokes. For keyboards, select this to fix chattering on standard keys (A-Z, 0-9).
- **`-event-mouse`**: The primary endpoint for standard mouse clicks (Left, Right, Middle) and X/Y movement. Select this to fix standard mouse double-clicking.
- **`-ifXX-event-kbd` (Virtual Mouse Keyboards)**: Advanced gaming mice often register a "virtual keyboard" to handle macro side-buttons. If your mouse's side buttons are double-clicking, you may need to point the mouse script at this endpoint instead of the standard mouse endpoint!
- **`-event-ifXX` (Interfaces)**: These handle multimedia controls (Volume wheels, Play/Pause) or vendor-specific data (RGB lighting). You rarely need to select these unless your volume wheel is bouncing.

**Troubleshooting Manual Testing:**
If you run the script manually in the terminal and receive a `[Errno 16] Device or resource busy` error, it means you have a background Systemd service currently running! The script requires an exclusive lock on the hardware. Simply run `sudo systemctl stop keyboard_chattering` or `sudo systemctl stop mouse_chattering` to release the lock before testing manually.

*Note: Legacy raw nodes (like those ending simply in `-mouse` or `-kbd` without the word `event`) are legacy X11 nodes and cannot be read by `libevdev`.*

## Installation

Download the repository as a zip and extract the file. The dependencies are listed in the requirements.txt. And you can install it with the command below.
Download the repository and extract the files. The dependencies are listed in `requirements.txt`. You can install them with the command below.

*(Note: According to PEP 668, newer Linux distributions may require the `--break-system-packages` flag, or the use of a python `venv`)*.

```shell
sudo pip install -r requirements.txt --break-system-packages
```

### Python Virtual Environment
Using the built-in `venv` module is the safest and cleanest way to run this tool.
```shell
sudo pip3 install -r requirements.txt
# 1. Create a virtual environment named 'venv' inside the project folder
python -m venv venv

# 2. Activate the virtual environment
source venv/bin/activate

# 3. Install the dependencies inside the isolated environment
pip install -r requirements.txt
```

## Usage

`cd` inside the location of the KeyboardChatteringFix-Linux-master extracted folder and enter the command below to run.
`cd` inside the location of the extracted folder. Because keyboards and mice are handled differently by the OS, they are executed as separate modules. Enter the commands below to run them manually:

**To run the Keyboard fix:**
```shell
sudo python -m src.keyboard_main
```

**To run the Mouse fix:**
```shell
sudo python3 -m src
sudo python -m src.mouse_main
```

### Customization Options

- -k KEYBOARD, --keyboard KEYBOARD
- Name of your chattering keyboard device as listed in /dev/input/by-id. If left unset, will be attempted to be retrieved
automatically. The device is captured `by-id`, and therefore in a persistent way.
- `-k KEYBOARD`, `--keyboard KEYBOARD`
- Name of your chattering keyboard device as listed in `/dev/input/by-id`. If left unset, it will attempt to retrieve it automatically.
- `-m MOUSE`, `--mouse MOUSE`
- Name of your double-clicking mouse device. Works identically to the keyboard argument above.
- `-t THRESHOLD`, `--threshold THRESHOLD`
- Filter time threshold in milliseconds. Default=30ms. Note: This denotes the time between a key/button being *released* and pressed again. For reference, if you click really fast, this delay is around 50 ms.
- `--keys KEYS` (For Keyboard)
- Comma-separated list of specific keys to filter (e.g., `KEY_A,KEY_SPACE`). If provided, *only* these keys will be filtered, leaving the rest of your keyboard untouched. You can also permanently define these in `src/keyboard_config.py`.
- `--buttons BUTTONS` (For Mouse)
- Comma-separated list of specific buttons to filter (e.g., `BTN_LEFT,BTN_RIGHT`). You can also permanently define these in `src/mouse_config.py`.
- `-v {0,1,2}`, `--verbosity {0,1,2}`

- -t THRESHOLD, --threshold THRESHOLD
- Filter time threshold in milliseconds. Default=30ms. Note: This does not denote the time between key presses, but
between a key being
released and pressed again, so the number should probably be lower than you might think. For reference, if you
press the key really fast this delay is around 50 ms.
## Automation

- -v {0,1,2}, --verbosity {0,1,2}
Starting the scripts manually every time is not ideal. You should set them up as background Systemd services. Because the keyboard and mouse scripts are separate, they can run concurrently in the background without interfering with one another.

## Automation
### Step 1: Configure the shell scripts
Modify `keyboard_chattering.sh` and/or `mouse_chattering.sh` to `cd` into the absolute path of your downloaded folder, and input your device IDs and desired thresholds.

**Example `keyboard_chattering.sh`:**
```shell
cd /home/foouser/Downloads/HardwareChatteringFix-Linux/ && sudo python3 -m src.keyboard_main -k usb-SINO_WEALTH_USB_KEYBOARD-event-kbd -t 40 --keys KEY_E,KEY_SPACE
```

Starting the script manually every time doesn't sound like the greatest idea, so
you should probably consider something that does it for you. Modify the `chattering_fix.sh` to `cd` into the absolute path of the downloaded folder and input the keyboard id and the desired threshold. For example:
**Example `mouse_chattering.sh`:**
```shell
cd /home/foouser/Downloads/KeyboardChatteringFix-Linux-master/ && sudo python3 -m src -k usb-SINO_WEALTH_USB_KEYBOARD-event-kbd -t 50
cd /home/foouser/Downloads/HardwareChatteringFix-Linux/ && sudo python3 -m src.mouse_main -m usb-Logitech_Gaming_Mouse-event-mouse -t 50 --buttons BTN_LEFT,BTN_RIGHT
```
Also, make sure to change the file permission of `chattering_fix.sh` so that it is executable.

Make sure to change the file permissions so they are executable:
```shell
chmod +x keyboard_chattering.sh mouse_chattering.sh
```

### Step 2: Configure the service files
Edit `keyboard_chattering.service` and `mouse_chattering.service`. The `ExecStart` should be the absolute path of the respective `.sh` file.

**Example keyboard_chattering.service:**
```shell
ExecStart=/home/foouser/Downloads/HardwareChatteringFix-Linux/keyboard_chattering.sh
```

**Example mouse_chattering.service:**
```shell
ExecStart=/home/foouser/Downloads/HardwareChatteringFix-Linux/mouse_chattering.sh
```

### Step 3: Enable the Services (Separately or Combined)

Copy the `.service` files to your systemd folder:
```shell
chmod +x chattering_fix.sh
sudo cp keyboard_chattering.service /etc/systemd/system/
sudo cp mouse_chattering.service /etc/systemd/system/
```
The `chattering_fix.service` file should also be edited. The `ExecStart` should be the absolute path of the `chattering_fix.sh`. For example:

**To enable ONLY the keyboard fix:**
```shell
ExecStart=/home/foouser/Downloads/KeyboardChatteringFix-Linux-master/chattering_fix.sh
sudo systemctl enable --now keyboard_chattering
```
Then, copy the `chattering_fix.service` to `/etc/systemd/system/` and enable it with the command below.

**To enable ONLY the mouse fix:**
```shell
systemctl enable --now chattering_fix
sudo systemctl enable --now mouse_chattering
```
You can check if the systemd unit file is properly working using

**To run BOTH concurrently:**
Simply run both enable commands! They operate completely independently of one another.
```shell
systemctl status chattering_fix.service
sudo systemctl enable --now keyboard_chattering
sudo systemctl enable --now mouse_chattering
```
You can also use

### Step 4: Checking Status and Logs

You can check if the scripts are running properly by checking their independent statuses:

**For the Keyboard:**
```shell
journalctl -xeu chattering_fix.service
systemctl status keyboard_chattering.service
journalctl -xeu keyboard_chattering.service
```
just to make sure that there are no errors.

**For the Mouse:**
```shell
systemctl status mouse_chattering.service
journalctl -xeu mouse_chattering.service
```

*(Note: If your device disconnects, is unplugged, or goes to sleep, the Python script will gracefully exit. Systemd will then safely attempt to restart it every 5 seconds in the background until the device is reconnected, ensuring 0% CPU waste!)*
12 changes: 0 additions & 12 deletions chattering_fix.service

This file was deleted.

3 changes: 0 additions & 3 deletions chattering_fix.sh

This file was deleted.

12 changes: 12 additions & 0 deletions keyboard_chattering.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[Unit]
Description=Keyboard Chattering Fix service

[Service]
# Change ExecStart to the absolute path of the file, executing keyboard_chattering.sh
ExecStart=<absolute/path/to/file/keyboard_chattering.sh>

Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
6 changes: 6 additions & 0 deletions keyboard_chattering.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash
# Change the line below to the absolute path of the folder.
# You can append `--keys KEY_A,KEY_SPACE` at the very end to ONLY filter those specific keys.
# (If using modern Linux/Python, you may need to run: sudo pip3 install -r requirements.txt --break-system-packages)

cd </absolute/path/to/folder> && sudo python3 -m src.keyboard_main -k <KEYBOARD id> -t 30
12 changes: 12 additions & 0 deletions mouse_chattering.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[Unit]
Description=Mouse Chattering service

[Service]
# Change ExecStart to the absolute path of the file, executing mouse_chattering.sh
ExecStart=<absolute/path/to/file/mouse_chattering.sh>

Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
6 changes: 6 additions & 0 deletions mouse_chattering.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash
# Change the line below to the absolute path of the folder.
# You can append `--buttons BTN_LEFT,BTN_SIDE` at the very end to ONLY filter those specific buttons.
# (If using modern Linux/Python, you may need to run: sudo pip3 install -r requirements.txt --break-system-packages)

cd </absolute/path/to/folder> && sudo python3 -m src.mouse_main -m <MOUSE id> -t 30
50 changes: 0 additions & 50 deletions src/__main__.py

This file was deleted.

60 changes: 0 additions & 60 deletions src/filtering.py

This file was deleted.

Loading