mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-15 02:49:33 +01:00
Merge #799: cancel the Ctrl+V keydown once the paste trap has the clipboard (Firefox double paste)
This commit is contained in:
commit
1d7288dc4f
7 files changed
+126
-26
No files matched your search
@@ -196,11 +196,13 @@ Object.assign(CodemanApp.prototype, {
|
||||
// own. Images upload to THAT session. Plain text goes to that pane's session
|
||||
// as a Codeman-built bracketed-paste frame: the terminal is only refocused
|
||||
// and receives input(framed). onData delivers the frame; it is not written
|
||||
// into the xterm buffer.
|
||||
// into the xterm buffer. `target.keyEvent` is the Ctrl+V keydown itself,
|
||||
// which the trap cancels when execCommand('paste') has already delivered.
|
||||
_handleImagePaste(target = {}) {
|
||||
const self = this;
|
||||
const terminal = target.terminal || this.terminal;
|
||||
const sessionId = target.sessionId || this.activeSessionId;
|
||||
const keyEvent = target.keyEvent;
|
||||
|
||||
// Create a hidden contenteditable div to receive the paste
|
||||
const trap = document.createElement('div');
|
||||
@@ -267,6 +269,20 @@ Object.assign(CodemanApp.prototype, {
|
||||
// Trigger the browser's native paste via execCommand
|
||||
// (this fires the paste event on our focused trap element)
|
||||
document.execCommand('paste');
|
||||
|
||||
// Firefox dispatches the execCommand paste synchronously, inside the call
|
||||
// above, and then delivers the key's own paste as a SEPARATE task about
|
||||
// 10 ms later. That second event races the setTimeout above that removes
|
||||
// the trap and refocuses the terminal. When the timer wins, the second
|
||||
// paste lands on xterm's textarea, xterm's own paste handler sends the
|
||||
// clipboard again, and the one-shot flag never sees it. That race is why
|
||||
// Ctrl+V still pasted twice only sometimes. Once execCommand has delivered
|
||||
// a paste, cancel the keydown so the browser never issues its own.
|
||||
// Chromium and WebKit refuse the command and dispatch nothing here, so
|
||||
// they keep the default action, which delivers their only paste event.
|
||||
if (pasteConsumed && keyEvent && typeof keyEvent.preventDefault === 'function') {
|
||||
keyEvent.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
/** What a pick or a paste may upload: 'image', 'video' for the camera roll's
|
||||
|
||||
@@ -349,7 +349,7 @@
|
||||
// input(framed), which onData delivers. Mirrors terminal-ui.js's own
|
||||
// Ctrl+V gate; without it xterm's default only ever pasted text.
|
||||
if ((ev.ctrlKey || ev.metaKey) && ev.key === 'v' && ev.type === 'keydown') {
|
||||
global.app?._handleImagePaste?.({ terminal: this.terminal, sessionId: this.sessionId });
|
||||
global.app?._handleImagePaste?.({ terminal: this.terminal, sessionId: this.sessionId, keyEvent: ev });
|
||||
return false;
|
||||
}
|
||||
// Ctrl+Z (SIGTSTP/job-control suspend), as terminal-ui.js swallows it:
|
||||
|
||||
@@ -924,7 +924,9 @@ Object.assign(CodemanApp.prototype, {
|
||||
// Route through our paste trap which handles both images and text.
|
||||
if ((ev.ctrlKey || ev.metaKey) && ev.key === 'v' && ev.type === 'keydown') {
|
||||
if (this.activeSessionId && this._handleImagePaste) {
|
||||
this._handleImagePaste();
|
||||
// The trap cancels this keydown itself when execCommand('paste')
|
||||
// already delivered the clipboard (Firefox), so pass the event in.
|
||||
this._handleImagePaste({ keyEvent: ev });
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user