fix(web-ssh): draw the cursor on the alternate screen, and keep focus

Two reports, one of them plainly a bug of mine.

The cursor was never drawn inside vi. The renderer skipped it whenever the
alternate screen was active, on the theory that a full-screen program draws its
own -- but that screen is exactly where a cursor matters most: vi, less and htop
all run there, and an editor without one tells you nothing about where you are
typing. It is drawn whenever the program has not hidden it.

The other report was that Escape left the terminal deaf until the window was
clicked. That does not reproduce here -- a bare Chrome types straight through
after Escape, in vi and at a prompt -- but the symptom is unmistakably focus
leaving the panel's own element, and clicking only helps because the click hands
it back. Since this window is nothing but the terminal, it now takes the
keystroke itself when focus has drifted, and restores focus on the way. Whether
the browser really moves focus on Escape on macOS is still unconfirmed; this
makes the question moot for the user either way.
This commit is contained in:
bluebluesoda committed 2026-09-17 13:36:57 +00:00
1 parent 08cc747b32
commit 9ad52438c6
1 file changed
+14 -1
+14 -1
View File
@@ -140,6 +140,16 @@
if (v) { self.input.value = ""; self._send(v); }
});
this.mount.addEventListener("keydown", function (e) { self._onKey(e); });
// A browser can move focus off the page's own element (Escape is one way),
// and then every keystroke goes nowhere until the user clicks back in. This
// window sits on a page that IS the terminal, so take the key instead of
// making the user find the focus again.
window.addEventListener("keydown", function (e) {
if (self.disposed || self.exited) return;
if (self.mount.contains(document.activeElement)) return; // already ours
self.input.focus();
self._onKey(e);
});
this.mount.addEventListener("paste", function (e) { self._onPaste(e); });
this.mount.addEventListener("wheel", function (e) { self._onWheel(e); }, { passive: false });
// A click must leave focus on the hidden input, never on the mount itself:
@@ -513,7 +523,10 @@
if (this.vy > maxVy) this.vy = maxVy;
var start = total - this.rows - this.vy;
var focused = this.mount.contains(document.activeElement);
var cursorRow = (this.vy === 0 && !this.modes.alt) ? this.cy : -1;
// The alternate screen is where the cursor matters most: vi, less and htop
// all run there, and an editor with no cursor tells you nothing about where
// you are typing.
var cursorRow = this.vy === 0 ? this.cy : -1;
for (var y = 0; y < this.rows; y++) {
var idx = start + y;