Last active
December 8, 2025 14:59
-
-
Save xcud/a3587af9788837b4c89aafd96c28225a to your computer and use it in GitHub Desktop.
A bash script to disable your laptop keyboard when your cat sits on it. Auto-detects common laptop keyboards (including dual-controller setups like Lenovo Ideapad). Just `chmod +x cat_mode.sh` and bind to an F key. Override detection via ~/.config/cat_mode.conf if needed.
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
| #!/bin/bash | |
| # Cat Mode Toggle Script | |
| # Detects current state and toggles between enabled/disabled keyboard | |
| MASTER_ID=3 | |
| TIMER_PID_FILE="/tmp/keyboard_timer_pid" | |
| CONFIG_FILE="$HOME/.config/cat_mode.conf" | |
| # Auto-detect laptop keyboard(s) - some laptops have multiple controllers | |
| detect_keyboards() { | |
| # If user has a config file, use that (one name per line) | |
| if [ -f "$CONFIG_FILE" ]; then | |
| cat "$CONFIG_FILE" | |
| return | |
| fi | |
| # Common laptop keyboard patterns - check all that match | |
| local found="" | |
| for pattern in "AT Translated Set 2 keyboard" "Internal Keyboard" "Built-in Keyboard" "ITE Tech. Inc. ITE Device(8258) Keyboard"; do | |
| if xinput list --name-only | grep -qF "$pattern"; then | |
| echo "$pattern" | |
| found="yes" | |
| fi | |
| done | |
| if [ -z "$found" ]; then | |
| echo "" | |
| fi | |
| } | |
| # Get keyboard ID from name (exclude pointer devices) | |
| get_keyboard_id() { | |
| local name="$1" | |
| xinput list | grep -F "$name" | grep -v "slave pointer" | grep -oP 'id=\K[0-9]+' | |
| } | |
| # Read detected keyboards into array | |
| mapfile -t KEYBOARD_NAMES < <(detect_keyboards) | |
| if [ ${#KEYBOARD_NAMES[@]} -eq 0 ] || [ -z "${KEYBOARD_NAMES[0]}" ]; then | |
| echo "Error: Could not auto-detect laptop keyboard." | |
| echo "" | |
| echo "Available keyboards:" | |
| xinput list --name-only | grep -i keyboard | while read -r kb; do | |
| echo " - $kb" | |
| done | |
| echo "" | |
| echo "To fix, save keyboard name(s) to: $CONFIG_FILE (one per line)" | |
| echo "Example: echo 'Your Keyboard Name' > $CONFIG_FILE" | |
| notify-send "Cat Mode Error" "Could not detect keyboard. Run script in terminal for help." -i dialog-error | |
| exit 1 | |
| fi | |
| # Build array of keyboard IDs | |
| KEYBOARD_IDS=() | |
| for name in "${KEYBOARD_NAMES[@]}"; do | |
| id=$(get_keyboard_id "$name") | |
| if [ -n "$id" ]; then | |
| KEYBOARD_IDS+=("$id") | |
| echo "Detected: $name (id=$id)" | |
| fi | |
| done | |
| if [ ${#KEYBOARD_IDS[@]} -eq 0 ]; then | |
| notify-send "Cat Mode Error" "Could not find keyboard IDs" -i dialog-error | |
| echo "Error: Could not find any keyboard IDs" | |
| exit 1 | |
| fi | |
| # Function to check if keyboards are currently floating (disabled) | |
| is_keyboard_disabled() { | |
| # Check if first keyboard is floating (they should all be in sync) | |
| xinput list | grep -q "id=${KEYBOARD_IDS[0]}.*floating slave" | |
| return $? | |
| } | |
| # Function to disable keyboard (activate cat mode) | |
| disable_keyboard() { | |
| # Disable all detected keyboards | |
| for id in "${KEYBOARD_IDS[@]}"; do | |
| xinput float "$id" | |
| done | |
| # Show notification | |
| notify-send "Cat Mode Activated" "Keyboard disabled for 30 minutes (${#KEYBOARD_IDS[@]} devices)" -i input-keyboard | |
| echo "Keyboard disabled. It will automatically re-enable in 30 minutes." | |
| echo "To manually toggle back, press F8 again or run this script." | |
| # Schedule automatic re-enable in 30 minutes (1800 seconds) | |
| # Save IDs to temp file for the timer subprocess | |
| printf '%s\n' "${KEYBOARD_IDS[@]}" > /tmp/keyboard_ids_to_restore | |
| (sleep 1800 && while read -r id; do xinput reattach "$id" $MASTER_ID; done < /tmp/keyboard_ids_to_restore && notify-send "Cat Mode Deactivated" "Keyboard automatically re-enabled" -i input-keyboard && rm -f $TIMER_PID_FILE /tmp/keyboard_ids_to_restore) & | |
| # Store the background job PID | |
| echo $! > $TIMER_PID_FILE | |
| echo "Timer PID: $! (saved to $TIMER_PID_FILE)" | |
| } | |
| # Function to enable keyboard (deactivate cat mode) | |
| enable_keyboard() { | |
| # Re-enable all keyboards | |
| for id in "${KEYBOARD_IDS[@]}"; do | |
| xinput reattach "$id" $MASTER_ID | |
| done | |
| # Kill the timer if it's still running | |
| if [ -f $TIMER_PID_FILE ]; then | |
| PID=$(cat $TIMER_PID_FILE) | |
| if kill -0 $PID 2>/dev/null; then | |
| kill $PID | |
| notify-send "Cat Mode Deactivated" "Timer cancelled, keyboard re-enabled" -i input-keyboard | |
| else | |
| notify-send "Cat Mode Deactivated" "Keyboard manually re-enabled" -i input-keyboard | |
| fi | |
| rm -f $TIMER_PID_FILE /tmp/keyboard_ids_to_restore | |
| else | |
| notify-send "Cat Mode Deactivated" "Keyboard manually re-enabled" -i input-keyboard | |
| fi | |
| echo "Keyboard manually re-enabled" | |
| } | |
| # Main logic: detect current state and toggle | |
| if is_keyboard_disabled; then | |
| echo "Cat mode is currently ACTIVE. Disabling cat mode..." | |
| enable_keyboard | |
| else | |
| echo "Cat mode is currently INACTIVE. Activating cat mode..." | |
| disable_keyboard | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment