Skip to content

Multiple Fixes & New Mouse Filtering Feature#21

Open
some1ataplace wants to merge 80 commits into
finkrer:masterfrom
some1ataplace:Multiple-Fixes
Open

Multiple Fixes & New Mouse Filtering Feature#21
some1ataplace wants to merge 80 commits into
finkrer:masterfrom
some1ataplace:Multiple-Fixes

Conversation

@some1ataplace
Copy link
Copy Markdown
Contributor

@some1ataplace some1ataplace commented May 9, 2026

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 massive expansion of features—most notably, Mouse double-click and Scroll-wheel 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!)

Massive Feature Expansion (New)

  • Mouse Double-Click Support: I separated the logic into keyboard_main and mouse_main. The mouse logic natively bypasses X/Y cursor movement and scrolling (EV_REL / EV_ABS) so the cursor remains flawlessly smooth, applying the chatter filter only to physical button clicks.
  • Scroll Wheel Glitch Filters: Added -sr (Reverse) and -sd (Double-Action) thresholds to explicitly block faulty hardware encoders that jump in the wrong direction or fire twice for a single physical notch.
  • Cursor Teleport Filter: Added -jl (Jump Limit) to drop massive, impossible cursor jumps caused by dirty laser sensors (e.g., jumping >300px in a single frame).
  • Per-Key / Per-Button Custom Thresholds: You can now define custom limits in the config files (e.g., set a heavy Spacebar to 50ms while leaving your gaming WASD keys at a crisp 15ms).
  • Kernel-Level Remapping / Macros: Built-in ability to remap any key or button natively before it hits the virtual device (e.g., Swap CapsLock to Ctrl, or Mouse Side-Button to Middle-Click).
  • Auto-Reconnect (Hotplug Support): Added an -r flag that enables a native polling loop. This allows wireless/Bluetooth mice to safely reconnect on the fly for non-systemd users!

Core Bug Fixes

  • 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 use 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, 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 / Open PRs): 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 to target only the keys/buttons that chatter using the CLI (--keys KEY_A) or the new config files. If empty, it defaults to filtering everything.
    • Native "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 instructions to the README reminding modern Linux users how to install the dependency using a venv or --break-system-packages.

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).

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

Pre-Flight Check

Before running any manual tests, you must stop any background services that might be holding the exclusive lock on your hardware, otherwise you will get [Errno 16] Device or resource busy:

sudo systemctl stop keyboard_chattering.service
sudo systemctl stop mouse_chattering.service
# OR, if using the fallback method:
sudo pkill -f keyboard_main
sudo pkill -f mouse_main

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 2
  • Test 1 (Basic Filter): Press the A key twice rapidly. Only one a should type on your screen. You should see FILTERED in the terminal.
  • Test 2 (Issue Cancelling double letters, even when they are separated #9 Fix - Fast Alternating): 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 Cancels held down key. #7 Fix - Held Modifiers): Press and hold Shift, then press a. It should successfully produce a capital A. Held events bypass the filter natively. (Press Ctrl+C to stop).

Phase 3: Testing Mouse Core Fixes

Run this command for the mouse module:

sudo python3 -m src.mouse_main -t 1000 -v 2
  • Test 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 rapidly. The cursor should be perfectly smooth and unaffected by the 1000ms delay. (Press Ctrl+C to stop).

Phase 4: Testing Advanced Thresholds & Targeting

Let's test CLI targeting and the Per-Key/Per-Button config thresholds.

Keyboard Targeting:

sudo python3 -m src.keyboard_main -t 1000 -v 2 --keys KEY_A
  • Test 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!

Per-Key Thresholds (Keyboard Config):

  1. Open src/keyboard_config.py and set KEY_THRESHOLDS = {"KEY_A": 1000}.
  2. Run: sudo python3 -m src.keyboard_main -t 0 -v 2 (Default is 0ms, so everything bypasses EXCEPT 'A').
  • Test 7 (Per-Key Threshold): Type S rapidly, it spams instantly. Type A rapidly, it is restricted to once per second.

Per-Button Thresholds (Mouse Config):

  1. Open src/mouse_config.py and set BUTTON_THRESHOLDS = {"BTN_RIGHT": 1000}.
  2. Run: sudo python3 -m src.mouse_main -t 0 -v 2
  • Test 8 (Per-Button Threshold): Click the Left mouse button rapidly, it spams instantly. Click the Right mouse button rapidly, it is restricted to once per second.

Phase 5: Testing Remapping

Keyboard Remapping:

  1. Open src/keyboard_config.py and set KEY_MAP = {"KEY_A": "KEY_B"}.
  2. Run: sudo python3 -m src.keyboard_main -v 2
  • Test 9 (Key Remap): Every time you physically press A, your computer will type b. Check the terminal for REMAPPED to KEY_B.

Mouse Remapping:

  1. Open src/mouse_config.py and set BUTTON_MAP = {"BTN_SIDE": "BTN_MIDDLE"}.
  2. Run: sudo python3 -m src.mouse_main -v 2
  • Test 10 (Button Remap): Open a web browser and click your Side Thumb button. Instead of going "Back", the cursor should turn into the auto-scroll icon (Middle Click behavior).

(Note: Remember to clear your config maps after testing!)


Phase 6: Testing Scroll Wheel Advanced Features

Scroll Reverse Glitch:

sudo python3 -m src.mouse_main -sr 5000 -v 2
  • Test 11 (Scroll Reverse Filter): Scroll down, then immediately scroll up. You will be physically blocked from scrolling up for 5 seconds! Terminal will print BLOCKED REVERSE SCROLL.

Scroll Double-Action:

sudo python3 -m src.mouse_main -sd 100 -v 2
  • Test 12 (Scroll Double-Action): Flick your scroll wheel as fast as you can in one direction. The script will throttle the ticks, and you will see BLOCKED DOUBLE-SCROLL in the terminal. (CAUTION: Do not use -sd on infinite/free-spin scroll wheels!)

Scroll Axis Allowlist:

  1. Open src/mouse_config.py and set FILTERED_SCROLL_AXES = {"REL_WHEEL", "REL_WHEEL_HI_RES"} (Targeting vertical only).
  2. Run: sudo python3 -m src.mouse_main -sr 5000 -v 2
  • Test 13 (Axis Allowlist): Scroll down, then immediately scroll up (Vertical). It will be blocked. Scroll left, then immediately scroll right (Horizontal). It will be perfectly smooth and ignore the filter.

Phase 7: Testing Sensor Anomalies

It is impossible to force a hardware glitch on command, but we can set the limits so low that normal movements trigger the block, proving the code works.

sudo python3 -m src.mouse_main -jl 10 -v 2
  • Test 14 (Cursor Teleport / Jump): Move the mouse across the screen at a moderate-to-fast pace. Because fast movement easily exceeds 10 pixels per frame, the script will aggressively block your cursor. Terminal will spam BLOCKED TELEPORT. Your cursor will stutter. (In actual use, you'd set this to something like -jl 500 to only block true hardware glitches).

Phase 8: Testing Hardware Disconnect & Reconnection

Clean Exit (Systemd Mode):
Run either script normally (without the -r flag):

sudo python3 -m src.keyboard_main -v 1
  • Test 15 (Clean Exit): Physically unplug your USB keyboard. The terminal should immediately print Keyboard disconnected... Exiting cleanly. The script closes safely instead of crashing or maxing out your CPU.

Auto-Reconnect (Hotplug Mode):
Run the script WITH the -r flag:

sudo python3 -m src.mouse_main -r -v 2
  • Test 16 (Auto-Reconnect): Unplug your USB mouse. Terminal prints Waiting for mouse... every 2 seconds. Plug it back in. Within 2 seconds, the terminal prints Successfully connected... and the mouse works again instantly without needing to restart the script.

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.
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.

1 participant