From ef5be896438dc5c7668da8d86f6d3cd2e84a23ad Mon Sep 17 00:00:00 2001
From: bluebluesoda <300733005+bluebluesoda@users.noreply.github.com>
Date: Sat, 26 Sep 2026 15:46:48 +0000
Subject: [PATCH] feat(webssh): replace the arrow keys with a Paste button
- drop the four on-screen arrow buttons: a physical keyboard already sends
them, and the app-cursor mode that made them awkward is handled by keySequence
- add a Paste button that reads the clipboard and hands the text to the shell
the same way a browser paste does, bracketed paste included
- report a refusal (no secure context or permission) instead of looking dead,
and fall back to Ctrl+V
---
docs/web-ssh.md | 5 ++++-
src/internal/panel/assets/term.js | 15 ++++++++++++--
src/internal/panel/templates/webssh.html | 26 ++++++++++++++++++------
3 files changed, 37 insertions(+), 9 deletions(-)
diff --git a/docs/web-ssh.md b/docs/web-ssh.md
index 192e0b0..be6eb7a 100644
--- a/docs/web-ssh.md
+++ b/docs/web-ssh.md
@@ -52,7 +52,10 @@ Insert/Delete, Tab, Escape and the function keys all send what a terminal sends,
and the arrows follow the mode a full-screen program asks for.
A small bar above the terminal carries the few keys a browser keeps for itself
-(Ctrl+C, Ctrl+Z, Ctrl+D, Escape, Tab), so they are never out of reach.
+(Ctrl+C, Ctrl+Z, Ctrl+D, Escape, Tab), so they are never out of reach, plus a
+**Paste** button. It reads the clipboard through the browser's clipboard API,
+so it needs a secure context and permission; if either is missing the bar says
+so, and Ctrl+V still works.
Selecting text is left to the browser, so it works like text anywhere: drag
across the terminal to select, double-click a word, and the selection survives
diff --git a/src/internal/panel/assets/term.js b/src/internal/panel/assets/term.js
index 3040e9e..65668de 100644
--- a/src/internal/panel/assets/term.js
+++ b/src/internal/panel/assets/term.js
@@ -664,12 +664,20 @@
e.preventDefault();
};
+ // paste hands text to the shell the way a browser paste would, including the
+ // bracketed-paste wrapper when the running program asked for it. The toolbar's
+ // Paste button goes through here so it behaves exactly like Ctrl+V.
+ Term.prototype.paste = function (text) {
+ if (!text) return;
+ if (this.modes.bracketed) this._send("\x1b[200~" + text + "\x1b[201~");
+ else this._send(text);
+ };
+
Term.prototype._onPaste = function (e) {
var text = (e.clipboardData || window.clipboardData).getData("text");
if (!text) return;
e.preventDefault();
- if (this.modes.bracketed) this._send("\x1b[200~" + text + "\x1b[201~");
- else this._send(text);
+ this.paste(text);
};
// keySequence is what a named key sends. The arrows depend on the mode the
@@ -961,6 +969,9 @@
if (seq !== null) { input(seq); term.focus(); }
},
raw: function (text) { input(text); if (term) term.focus(); },
+ // paste is the toolbar's Paste button: clipboard text is delivered the
+ // same way a browser paste is, so bracketed paste still applies.
+ paste: function (text) { if (term) { term.paste(text); term.focus(); } },
// reconnect is the manual path offered once the retries are exhausted.
reconnect: function () {
finished = false;
diff --git a/src/internal/panel/templates/webssh.html b/src/internal/panel/templates/webssh.html
index 8409bd9..4e6457b 100644
--- a/src/internal/panel/templates/webssh.html
+++ b/src/internal/panel/templates/webssh.html
@@ -71,14 +71,11 @@ main>div{height:100%}
-
-
-
-
-
+
+