Multiple Fixes & New Mouse Filtering Feature#21
Open
some1ataplace wants to merge 56 commits intofinkrer:masterfrom
Open
Multiple Fixes & New Mouse Filtering Feature#21some1ataplace wants to merge 56 commits intofinkrer:masterfrom
some1ataplace wants to merge 56 commits intofinkrer:masterfrom
Conversation
Reference for blacklist or command line arguments
Core logic. Updated with the double-letter fix and specific key filtering.
Entry point. Updated with CPU fix, config routing, and CLI parsing.
This is the mouse version of the filter. It instantly forwards movement data so your cursor remains flawlessly smooth, and only applies the chatter filter to button clicks (like BTN_LEFT, BTN_RIGHT, etc.).
Mouse devices end in -event-mouse. This file searches specifically for mice.
This is the entry point for the mouse fix. You run this instead of python3 -m src. Read from the new mouse_config.py, exactly how we did for the keyboard.
This file holds the configuration for the mouse and lists all the possible button values you can pass to it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
There are multiple changes applied in this PR. Would appreciate some testing from others in case anything was missed.
Description of Changes
This PR is a major overhaul that resolves several long-standing open issues, drastically improves system stability, and introduces a new feature: Mouse double-click filtering.
(Note for the maintainer: Because this now handles both keyboards and mice, you might want to consider renaming the repository to HardwareChatteringFix-Linux or something similar to improve SEO for people searching for Linux mouse double-click fixes!)
Mouse Double-Click Support (New Feature)
Mechanical mice (especially gaming mice) are infamous for double-clicking. I separated the logic into keyboard_main.py and mouse_main.py. The mouse logic natively bypasses X/Y cursor movement and scroll-wheel activity (EV_REL / EV_ABS) so the cursor remains flawlessly smooth, applying the chatter filter only to physical button clicks (BTN_LEFT, etc.).
CPU Exhaustion Fix (Issue python3 process runs on full CPU capacity when keyboard disconnected #1)
When a physical device is disconnected/undocked, the script originally went into a crash loop that consumed 100% of a CPU thread. The modules now check os.path.exists(). If the device vanishes, it performs a clean sys.exit(0). Systemd's Restart=always parameter then safely polls every 5 seconds until the device is reconnected, consuming ~0% CPU.
Double Letter Cancellation Fix (Issue Cancelling double letters, even when they are separated #9)
Fast typists noted that typing words like "even" turned into "evn". The script was filtering the second 'e' because it appeared too quickly after the first 'e', ignoring the 'v' in between. By introducing _last_key_code in keyboard_filtering.py, the threshold is safely bypassed if the previous key pressed was a different character. (This logic is also applied to alternating mouse clicks).
Specific Key Targeting / Modifier Integrity (Issues Cancels held down key. #7 / Update filtering.py with blacklist #19 )
Originally, the script applied chatter filtering to every single key. This often broke modifier keys (Ctrl/Shift/Alt) when held down or pressed quickly.
We avoided a messy "hardcoded blacklist" and instead implemented the ability for the user to target only the keys/buttons that chatter.
You can now target keys either via the CLI (e.g., --keys KEY_A,KEY_SPACE / --buttons BTN_LEFT) or via the new src/keyboard_config.py and src/mouse_config.py files.
If both are left empty, it defaults to filtering all keys natively.
Additionally, "hold" events (event.value > 1) are explicitly forwarded without filtering, ensuring held shortcuts behave identically to a physical keyboard.
PEP 668 Warning (Issue PEP 668 prevents system pip install #6)
Added a note to the .sh and README files reminding users on modern Linux distros that they may need to append --break-system-packages or use a venv to install libevdev using pip3.
Testing Guide for Reviewers
Since it can be difficult to physically force a healthy keyboard or mouse to "chatter" on command, the best way to test this script is to artificially raise the threshold to a massive number (like 1000 ms / 1 second). This makes it painfully obvious whether the filter is applying, ignoring, or allowing specific keys.
Phase 1: Preparation & Setup
Ensure your project folder matches the new structure:
KeyboardChatteringFix-Linux/
├── requirements.txt
├── keyboard_chattering.sh
├── keyboard_chattering.service
├── mouse_chattering.sh
├── mouse_chattering.service
└── src/
├── init.py
├── keyboard_config.py
├── keyboard_filtering.py
├── keyboard_main.py
├── keyboard_retrieval.py
├── mouse_config.py
├── mouse_filtering.py
├── mouse_main.py
└── mouse_retrieval.py
Phase 2: Testing Keyboard Core Fixes (Typing Tests)
Run this command in the terminal (sets threshold to 1 second, -v 2 turns on DEBUG logging):
sudo python3 -m src.keyboard_main -t 1000 -v 2Test 1 (Basic Filter): Press the a key twice rapidly. Only one a should type on your screen. You should see FILTERED 30 down in the terminal.
Test 2 (Issue #9 Fix): Type a, then b, then a as fast as you can. You should see aba typed on your screen. The b successfully resets the filter for a.
Test 3 (Issue #7 Fix): Press and hold Shift, then press a. It should successfully produce a capital A. Held events are no longer incorrectly filtered. (Press Ctrl+C to stop).
Phase 4: Testing Mouse Core Fixes
Run this command for the mouse module:
sudo python3 -m src.mouse_main -t 1000 -v 2Test 4 (Basic Click Filter): Double-click your left mouse button as fast as you can. It should only register as a single click.
Test 5 (Movement Integrity): Move your mouse around and scroll your scroll wheel. The cursor should be perfectly smooth and unaffected by the 1000ms delay. (Press Ctrl+C to stop).
Phase 5: Testing Specific Hardware Targeting
Let's tell the script to ONLY fix the a key, and leave the b key completely alone.
sudo python3 -m src.keyboard_main -t 1000 -v 2 --keys KEY_ATest 6 (CLI Targeting): Press a twice rapidly. Then press b twice rapidly. a will only type once (filtered). But b will type twice (bb) because it is safely bypassing the filter! (Note: This works identically for mice using --buttons BTN_LEFT).
Test 7 (Config Targeting): Open src/keyboard_config.py and change the empty set to: FILTERED_KEYS = {"KEY_C"}. Run
sudo python3 -m src.keyboard_main -t 1000 -v 2(without CLI flags). Pressing c twice fast yields one c. Pressing a twice fast yields two as. The script successfully read the config file.Phase 6: Testing Hardware Disconnect / CPU Loop (Issue #1)
Run either script normally:
sudo python3 -m src.keyboard_main -v 1Test 8 (Unplug): Physically unplug your external USB keyboard. The terminal should immediately print: CRITICAL - Keyboard device not connected. Exiting to prevent CPU loop. The script will close cleanly instead of maxing out your CPU.