From 9b6eee968eeaf84442d8252b4c54c3fbf3558310 Mon Sep 17 00:00:00 2001 From: Carolyn Sun <117613176+carolyn-sun@users.noreply.github.com> Date: Sat, 15 Nov 2025 10:10:44 +0800 Subject: [PATCH] fix: improve input handling for mouse wheel events (#49) --- lib/common.sh | 28 +++++++++++++++++++++++----- lib/menu_paginated.sh | 18 +++++++++++++----- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/lib/common.sh b/lib/common.sh index 077606d..853bfd6 100755 --- a/lib/common.sh +++ b/lib/common.sh @@ -330,8 +330,21 @@ read_key() { else echo "QUIT" # ESC [ timeout fi + elif [[ "$rest" == "O" ]]; then + # Application keypad mode sequences (mouse wheel often generates these) + if IFS= read -r -s -n 1 -t 1 rest2 2> /dev/null; then + case "$rest2" in + "A") echo "UP" ;; # ESC O A + "B") echo "DOWN" ;; # ESC O B + "C") echo "RIGHT" ;; # ESC O C + "D") echo "LEFT" ;; # ESC O D + *) echo "OTHER" ;; # Ignore other ESC O sequences + esac + else + echo "OTHER" # ESC O timeout + fi else - echo "QUIT" # ESC + something else + echo "OTHER" # ESC + something else (not [ or O) fi else # ESC pressed alone - treat as quit @@ -351,12 +364,17 @@ read_key() { # Drain pending input (useful for scrolling prevention) drain_pending_input() { local drained=0 - # Single pass with reasonable timeout - # Touchpad scrolling can generate bursts of arrow keys + # Multiple passes with very short timeout to catch mouse wheel bursts + # Mouse wheel scrolling can generate rapid sequences like B^[OB^[OB^[O... + while IFS= read -r -s -n 1 -t 0.01 _ 2> /dev/null; do + ((drained++)) + # Higher safety limit for mouse wheel sequences + [[ $drained -gt 1000 ]] && break + done + # Second pass with even shorter timeout to catch any remaining input while IFS= read -r -s -n 1 -t 0.001 _ 2> /dev/null; do ((drained++)) - # Safety limit to prevent infinite loop - [[ $drained -gt 500 ]] && break + [[ $drained -gt 1500 ]] && break done } diff --git a/lib/menu_paginated.sh b/lib/menu_paginated.sh index a8d9445..4330aed 100755 --- a/lib/menu_paginated.sh +++ b/lib/menu_paginated.sh @@ -27,12 +27,18 @@ _pm_parse_csv_to_array() { done } -# Non-blocking input drain (bash 3.2) +# Non-blocking input drain (bash 3.2) - improved for mouse wheel drain_pending_input() { - local _k - # -t 0 is non-blocking; -n 1 consumes one byte at a time - while IFS= read -r -s -n 1 -t 0 _k; do - IFS= read -r -s -n 1 _k || break + local _k drained=0 + # Multiple passes to handle mouse wheel burst sequences + while IFS= read -r -s -n 1 -t 0.01 _k 2> /dev/null; do + ((drained++)) + [[ $drained -gt 1000 ]] && break + done + # Second pass with shorter timeout + while IFS= read -r -s -n 1 -t 0.001 _k 2> /dev/null; do + ((drained++)) + [[ $drained -gt 1500 ]] && break done } @@ -488,6 +494,8 @@ paginated_multi_select() { # Main interaction loop while true; do draw_menu + # Drain any pending input to prevent mouse wheel scroll issues + drain_pending_input local key key=$(read_key)