fix(browser_profiler): improve keyboard input handling

- fix handling of special keys in Windows msvcrt implementation
- Guard against UnicodeDecodeError from multi-byte key sequences
- Filter out non-printable characters and control sequences
- Add error handling to prevent coroutine crashes
- Add unit test to verify keyboard input handling

Key changes:
- Safe UTF-8 decoding with try/except for special keys
- Skip non-printable and multi-byte character sequences
- Add broad exception handling in keyboard listener

Test runs on Windows only due to msvcrt dependency.
This commit is contained in:
prokopis3
2025-06-12 14:33:12 +03:00
parent 4bcb7171a3
commit ef722766f0
3 changed files with 112 additions and 25 deletions

View File

@@ -207,21 +207,35 @@ class BrowserProfiler:
import msvcrt
while True:
if msvcrt.kbhit():
key = msvcrt.getch().decode("utf-8")
if key.lower() == "q":
self.logger.info(
"Closing browser and saving profile...",
tag="PROFILE",
base_color=LogColor.GREEN
)
user_done_event.set()
try:
if msvcrt.kbhit():
raw = msvcrt.getch()
try:
key = raw.decode("utf-8")
except UnicodeDecodeError:
# Arrow/function keys come back as multi-byte sequences
continue
# Skip control/multi-byte keys that decoded but aren't printable
if len(key) != 1 or not key.isprintable():
continue
if key.lower() == "q":
self.logger.info(
"Closing browser and saving profile...",
tag="PROFILE",
base_color=LogColor.GREEN
)
user_done_event.set()
return
if await check_browser_process():
return
if await check_browser_process():
return
await asyncio.sleep(0.1)
await asyncio.sleep(0.1)
except Exception as e:
self.logger.error(f"Error in keyboard listener: {e}", tag="PROFILE")
continue
else: # Unix-like
import termios
@@ -713,17 +727,31 @@ class BrowserProfiler:
import msvcrt
while True:
if msvcrt.kbhit():
key = msvcrt.getch().decode("utf-8")
if key.lower() == "q":
self.logger.info("Closing browser...", tag="CDP")
user_done_event.set()
try:
if msvcrt.kbhit():
raw = msvcrt.getch()
try:
key = raw.decode("utf-8")
except UnicodeDecodeError:
# Arrow/function keys come back as multi-byte sequences
continue
# Skip control/multi-byte keys that decoded but aren't printable
if len(key) != 1 or not key.isprintable():
continue
if key.lower() == "q":
self.logger.info("Closing browser...", tag="CDP")
user_done_event.set()
return
if await check_browser_process():
return
if await check_browser_process():
return
await asyncio.sleep(0.1)
await asyncio.sleep(0.1)
except Exception as e:
self.logger.error(f"Error in keyboard listener: {e}", tag="CDP")
continue
else:
import termios
import tty