fix: lift modifier state to MobileTerminalWrapper for virtual keyboard integration
- Remove useSpecialKeys hook state, export pure utility functions instead - MobileTerminalWrapper now owns activeModifier state - SpecialKeysStrip and SpecialKeysPanel receive modifier via props - TerminalComponent applies modifier to virtual keyboard input via activeModifier prop - Modifier now works with both special keys AND virtual keyboard input - Modifier clears after any key press (special or virtual keyboard)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState, useCallback } from "react";
|
||||
|
||||
|
||||
export type SpecialKey =
|
||||
| "escape"
|
||||
@@ -103,47 +103,38 @@ const MODIFIER_PREFIXES: Record<string, { ctrl: string; alt: string; ctrlAlt: st
|
||||
"9": { ctrl: "9", alt: "\x1B9", ctrlAlt: "\x1B9" },
|
||||
};
|
||||
|
||||
interface UseSpecialKeysOptions {
|
||||
onSend: (data: string) => void;
|
||||
export function getSequenceWithModifier(
|
||||
key: SpecialKey,
|
||||
activeModifier: ModifierKey | null
|
||||
): { sequence: string; clearModifier: boolean } | null {
|
||||
// Handle modifier keys (one-shot)
|
||||
if (key === "ctrl" || key === "alt") {
|
||||
return null; // Modifiers don't send anything themselves
|
||||
}
|
||||
|
||||
const sequence = KEY_SEQUENCES[key];
|
||||
if (!sequence) return null;
|
||||
|
||||
// Check if we have an active modifier and the key is a single character
|
||||
if (activeModifier && sequence.length === 1) {
|
||||
const char = sequence;
|
||||
const mapping = MODIFIER_PREFIXES[char.toLowerCase()];
|
||||
if (mapping) {
|
||||
return { sequence: mapping[activeModifier], clearModifier: true };
|
||||
}
|
||||
}
|
||||
|
||||
return { sequence, clearModifier: !!activeModifier };
|
||||
}
|
||||
|
||||
export function useSpecialKeys({ onSend }: UseSpecialKeysOptions) {
|
||||
const [activeModifier, setActiveModifier] = useState<ModifierKey | null>(null);
|
||||
|
||||
const sendKey = useCallback(
|
||||
(key: SpecialKey) => {
|
||||
// Handle modifier keys (one-shot)
|
||||
if (key === "ctrl" || key === "alt") {
|
||||
// Toggle modifier
|
||||
setActiveModifier((current) => (current === key ? null : key));
|
||||
return;
|
||||
}
|
||||
|
||||
const sequence = KEY_SEQUENCES[key];
|
||||
if (!sequence) return;
|
||||
|
||||
// Check if we have an active modifier and the key is a single character
|
||||
if (activeModifier && sequence.length === 1) {
|
||||
const char = sequence;
|
||||
const mapping = MODIFIER_PREFIXES[char.toLowerCase()];
|
||||
if (mapping) {
|
||||
onSend(mapping[activeModifier]);
|
||||
setActiveModifier(null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
onSend(sequence);
|
||||
setActiveModifier(null);
|
||||
},
|
||||
[onSend, activeModifier]
|
||||
);
|
||||
|
||||
const clearModifier = useCallback(() => {
|
||||
setActiveModifier(null);
|
||||
}, []);
|
||||
|
||||
return { sendKey, activeModifier, clearModifier };
|
||||
export function applyModifierToChar(
|
||||
char: string,
|
||||
modifier: ModifierKey
|
||||
): string | null {
|
||||
if (char.length !== 1) return null;
|
||||
const mapping = MODIFIER_PREFIXES[char.toLowerCase()];
|
||||
if (!mapping) return null;
|
||||
return mapping[modifier];
|
||||
}
|
||||
|
||||
export { KEY_SEQUENCES };
|
||||
|
||||
Reference in New Issue
Block a user