From 09a227466a4898d384f9513e0566a71a46238c91 Mon Sep 17 00:00:00 2001 From: davidmonterocrespo24 Date: Sun, 17 May 2026 16:37:56 +0200 Subject: [PATCH] fix(pi3): auto-focus terminal + log serial input bytes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PiTerminal didn't call term.focus() on mount, so xterm.js stayed passive — onData only fires when the DOM element has focus. Users saw the boot prompt but their keystrokes went to whatever element held focus when they clicked Run (canvas, code editor), never reaching the bridge. Calling focus() right after fit() makes the prompt receive input the moment it's visible. The qemu_manager change adds INFO-level logging when serial_input WebSocket messages reach send_serial_bytes — useful diagnostic for future Pi3 input problems (proves whether bytes reached the backend before we look at TTY / kernel / PL011 wiring). --- backend/app/services/qemu_manager.py | 18 ++++++++++++------ .../src/components/raspberry-pi/PiTerminal.tsx | 5 +++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/backend/app/services/qemu_manager.py b/backend/app/services/qemu_manager.py index d0dddfae..9b9f7e00 100644 --- a/backend/app/services/qemu_manager.py +++ b/backend/app/services/qemu_manager.py @@ -118,12 +118,18 @@ class QemuManager: async def send_serial_bytes(self, client_id: str, data: bytes) -> None: inst = self._instances.get(client_id) - if inst and inst._serial_writer: - inst._serial_writer.write(data) - try: - await inst._serial_writer.drain() - except Exception as e: - logger.warning('send_serial_bytes drain: %s', e) + if not inst: + logger.warning('send_serial_bytes: no instance for client_id=%s', client_id) + return + if not inst._serial_writer: + logger.warning('send_serial_bytes: %s has no serial writer (qemu not connected yet?)', client_id) + return + logger.info('send_serial_bytes: %s sending %d bytes: %r', client_id, len(data), bytes(data[:32])) + inst._serial_writer.write(data) + try: + await inst._serial_writer.drain() + except Exception as e: + logger.warning('send_serial_bytes drain: %s', e) # ── Boot sequence ───────────────────────────────────────────────────────── diff --git a/frontend/src/components/raspberry-pi/PiTerminal.tsx b/frontend/src/components/raspberry-pi/PiTerminal.tsx index eb7968c0..08f8e400 100644 --- a/frontend/src/components/raspberry-pi/PiTerminal.tsx +++ b/frontend/src/components/raspberry-pi/PiTerminal.tsx @@ -48,6 +48,11 @@ export const PiTerminal: React.FC = ({ boardId }) => { } catch (_) { /* ignore if dimensions not ready */ } + // Without an explicit focus call xterm.js stays passive — onData + // only fires when the DOM element has focus, so users staring at + // a working prompt see no echo because their keystrokes go to + // whatever element had focus at mount time (canvas, code editor). + try { term.focus(); } catch (_) { /* container may not be visible */ } }); termRef.current = term;