如何为含循环的BASH脚本添加鼠标启停切换并修复合并问题?
合并BASH鼠标切换开关与动作循环脚本的解决方案
合并脚本后无法正确跳出内部循环的核心原因是:单线程顺序执行时,鼠标监听循环和动作循环会互相阻塞——当脚本在执行动作内部循环时,无法同时监听鼠标按键事件,导致toggle文件的状态变化不能被及时检测到,反之亦然。
下面是修复后的合并脚本,通过后台子进程处理鼠标监听,让主进程专注于动作循环,两者互不阻塞,同时保证toggle状态的实时响应:
#!/bin/bash # 防止多实例运行 PIDS=$(pidof -o $$ -x "$0") if [ -n "$PIDS" ]; then exit 0 fi # 定义toggle文件路径 TOGGLE="$HOME/.toggle" # 初始化toggle文件(默认开启状态) [ ! -e "$TOGGLE" ] && touch "$TOGGLE" # 检测鼠标设备 if xinput --list | grep -q "My Mouse Label 1"; then pointerLabel="My Mouse Label 1" else pointerLabel="My Mouse Label 2" fi pointerDevice=$(xinput --list --id-only "$pointerLabel") # 检测键盘设备 keyboardLabel="My Keyboard" keyboardDevice=$(xinput --list --id-only "$keyboardLabel") # -------------------------- # 后台子进程:监听鼠标按键,切换toggle状态 # -------------------------- ( while true; do state_mouse=$(xinput --query-state "$pointerDevice") if [[ "$state_mouse" == *"button[8]=down"* ]]; then if [ -f "$TOGGLE" ]; then rm -f "$TOGGLE" echo "Toggle Off" else touch "$TOGGLE" echo "Toggle On" fi sleep 0.5 # 防止按键重复触发 fi # 短暂休眠,降低CPU占用 sleep 0.05 done ) & # 记录后台进程PID,用于脚本退出时清理 mouse_pid=$! # -------------------------- # 主进程:动作循环 # -------------------------- action() { while [ -f "$TOGGLE" ]; do state=$(xinput --query-state "$keyboardDevice" | grep 'down') if [ -n "$state" ]; then case "$state" in *"key[10]=down"*) xdotool key --clearmodifiers 1 ;; *"key[11]=down"*) xdotool key --clearmodifiers 2 ;; *"key[12]=down"*) xdotool key --clearmodifiers 3 ;; esac break # 处理一次按键后退出子循环,回到主循环重新检测toggle状态 fi sleep 1 done } # 主循环 while true; do action done # 脚本退出时清理后台进程(如果脚本被正常终止) trap "kill $mouse_pid" EXIT
关键改动说明:
- 后台子进程处理鼠标监听:把鼠标按键检测逻辑放到后台异步运行,主进程和子进程并行执行,避免互相阻塞。
- 降低CPU占用:在鼠标监听循环中添加短暂休眠,避免无限空循环消耗过多系统资源。
- 实时响应toggle状态:动作内部循环每次都会检查toggle文件的存在性,一旦开关被关闭,会立即跳出循环。
- 进程清理:通过
trap命令捕获脚本退出信号,自动终止后台的鼠标监听进程,避免残留僵尸进程。
内容的提问来源于stack exchange,提问作者proxyx
相关产品推荐
相关产品推荐

