fix: handle terminal keyboard input on Android tablet (#1133)
* fix: handle terminal keyboard input on Android with desktop UA - Detect Android via navigator.userAgentData.platform when UA is spoofed by Chrome's "Desktop site" mode, so the <input> overlay (useTextInput) is used instead of <textarea>. - Handle Ctrl+letter and Alt+letter combos in the hidden input overlay's keydown handler, so terminal control sequences (^C, ^D, ^S, M-x, etc.) work through the touch input path. - Skip global keyboard shortcuts (sidebar toggle, etc.) when focus is inside the terminal viewport, preventing shortcut steal. * fix: preserve terminal keyboard shortcuts --------- Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
committed by
GitHub
co-authored by
Bohdan Triapitsyn
parent
d5b3590901
commit
b65edc3436
@@ -128,7 +128,10 @@ const TerminalViewport = React.forwardRef<TerminalController, TerminalViewportPr
|
|||||||
inputHandlerRef.current = onInput;
|
inputHandlerRef.current = onInput;
|
||||||
resizeHandlerRef.current = onResize;
|
resizeHandlerRef.current = onResize;
|
||||||
|
|
||||||
const isAndroid = typeof navigator !== 'undefined' && /Android/i.test(navigator.userAgent);
|
const isAndroid = typeof navigator !== 'undefined' && (
|
||||||
|
/Android/i.test(navigator.userAgent) ||
|
||||||
|
(navigator as { userAgentData?: { platform: string } }).userAgentData?.platform === 'Android'
|
||||||
|
);
|
||||||
// Touch devices need a dedicated editable surface so special keys like
|
// Touch devices need a dedicated editable surface so special keys like
|
||||||
// Backspace and arrows are captured reliably without relying on Ghostty's
|
// Backspace and arrows are captured reliably without relying on Ghostty's
|
||||||
// internal mobile text handling.
|
// internal mobile text handling.
|
||||||
@@ -1409,6 +1412,25 @@ const TerminalViewport = React.forwardRef<TerminalController, TerminalViewportPr
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.ctrlKey && !event.metaKey && !event.altKey && event.key.length === 1) {
|
||||||
|
const upper = event.key.toUpperCase();
|
||||||
|
if (upper >= 'A' && upper <= 'Z') {
|
||||||
|
event.preventDefault();
|
||||||
|
(event.nativeEvent as KeyboardEvent | undefined)?.stopImmediatePropagation();
|
||||||
|
inputHandlerRef.current(String.fromCharCode(upper.charCodeAt(0) - 64));
|
||||||
|
clearEditableValue(event.currentTarget as HTMLElement);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.altKey && !event.ctrlKey && !event.metaKey && event.key.length === 1) {
|
||||||
|
event.preventDefault();
|
||||||
|
(event.nativeEvent as KeyboardEvent | undefined)?.stopImmediatePropagation();
|
||||||
|
inputHandlerRef.current('\x1b' + event.key);
|
||||||
|
clearEditableValue(event.currentTarget as HTMLElement);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const specialKeySequences: Record<string, string> = {
|
const specialKeySequences: Record<string, string> = {
|
||||||
ArrowUp: '\u001b[A',
|
ArrowUp: '\u001b[A',
|
||||||
ArrowDown: '\u001b[B',
|
ArrowDown: '\u001b[B',
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ export const useKeyboardShortcuts = () => {
|
|||||||
target.getAttribute('data-terminal-hidden-input') === 'true'
|
target.getAttribute('data-terminal-hidden-input') === 'true'
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleTerminalShortcutCapture = (e: KeyboardEvent) => {
|
const handleTerminalShortcutCapture = (e: KeyboardEvent) => {
|
||||||
if (!isTerminalEventTarget(e.target)) {
|
if (!isTerminalEventTarget(e.target)) {
|
||||||
return;
|
return;
|
||||||
@@ -94,6 +93,10 @@ export const useKeyboardShortcuts = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleKeyDown = (e: KeyboardEvent) => {
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
|
if (isTerminalEventTarget(e.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (eventMatchesShortcut(e, combo('open_command_palette'))) {
|
if (eventMatchesShortcut(e, combo('open_command_palette'))) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
toggleCommandPalette();
|
toggleCommandPalette();
|
||||||
|
|||||||
Reference in New Issue
Block a user