Fix iPad modifier handling for mobile keybar

This commit is contained in:
GitHub Copilot
2026-02-01 01:36:35 +00:00
parent e99ac51495
commit 7849e53edd
2 changed files with 43 additions and 60 deletions
File diff suppressed because one or more lines are too long
+35 -52
View File
@@ -676,32 +676,41 @@ class WebTerminal {
this.element.appendChild(textarea); this.element.appendChild(textarea);
this.mobileInput = textarea; this.mobileInput = textarea;
const applyMobileModifiers = (text: string): string => {
let toSend = text;
if ((this.shiftActive || this.pendingShift) && toSend.length === 1) {
toSend = toSend.toUpperCase();
}
if ((this.ctrlActive || this.pendingCtrl) && toSend.length === 1) {
const code = toSend.toUpperCase().charCodeAt(0);
if (code >= 65 && code <= 90) {
toSend = String.fromCharCode(code - 64);
}
}
return toSend;
};
const handleMobileInput = (text: string, e?: Event) => {
if (e) {
e.preventDefault();
e.stopPropagation();
}
if (!text) {
return;
}
this.send(["stdin", applyMobileModifiers(text)]);
textarea.value = "";
this.deactivateModifiers();
this.pendingCtrl = false;
this.pendingShift = false;
};
// Handle special keys via beforeinput to intercept before browser modifies textarea // Handle special keys via beforeinput to intercept before browser modifies textarea
textarea.addEventListener("beforeinput", (e) => { textarea.addEventListener("beforeinput", (e) => {
if ( if (e.inputType === "insertText" && e.data) {
e.inputType === "insertText" handleMobileInput(e.data, e);
&& e.data return;
&& (this.ctrlActive || this.shiftActive || this.pendingCtrl || this.pendingShift) }
) {
let toSend = e.data;
if ((this.shiftActive || this.pendingShift) && toSend.length === 1) {
toSend = toSend.toUpperCase();
}
if ((this.ctrlActive || this.pendingCtrl) && toSend.length === 1) {
const code = toSend.toUpperCase().charCodeAt(0);
if (code >= 65 && code <= 90) {
toSend = String.fromCharCode(code - 64);
}
}
e.preventDefault();
e.stopPropagation();
this.send(["stdin", toSend]);
textarea.value = "";
this.deactivateModifiers();
this.pendingCtrl = false;
this.pendingShift = false;
return;
}
let seq: string | null = null; let seq: string | null = null;
switch (e.inputType) { switch (e.inputType) {
@@ -716,39 +725,13 @@ class WebTerminal {
break; break;
} }
if (seq) { if (seq) {
e.preventDefault(); handleMobileInput(seq, e);
e.stopPropagation();
this.send(["stdin", seq]);
// Clear modifiers after sending special keys from soft keyboard
this.deactivateModifiers();
} }
}); });
// Handle input from mobile keyboard (regular text only, special keys handled above) // Handle input from mobile keyboard (regular text only, special keys handled above)
textarea.addEventListener("input", () => { textarea.addEventListener("input", () => {
const value = textarea.value; handleMobileInput(textarea.value);
if (value) {
let toSend = value;
// Apply Shift modifier (uppercase letters)
if (this.shiftActive || this.pendingShift) {
toSend = value.toUpperCase();
}
// Apply Ctrl modifier if active (convert letters to control codes)
if (this.ctrlActive || this.pendingCtrl) {
const firstChar = toSend[0] ?? "";
const code = firstChar.toUpperCase().charCodeAt(0);
if (code >= 65 && code <= 90) {
toSend = String.fromCharCode(code - 64); // Ctrl+A = 0x01, Ctrl+D = 0x04, etc.
} else {
toSend = firstChar;
}
}
this.send(["stdin", toSend]);
textarea.value = "";
this.deactivateModifiers();
this.pendingCtrl = false;
this.pendingShift = false;
}
}); });
// Handle special navigation keys via keydown (not covered by beforeinput) // Handle special navigation keys via keydown (not covered by beforeinput)