e555561a2d
- 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)
115 lines
3.0 KiB
TypeScript
115 lines
3.0 KiB
TypeScript
import React from "react";
|
|
import { getSequenceWithModifier, type SpecialKey, type ModifierKey } from "../hooks/use-special-keys";
|
|
|
|
interface SpecialKeysPanelProps {
|
|
onSend: (data: string) => void;
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
onKeepFocus?: () => void;
|
|
activeModifier: ModifierKey | null;
|
|
onModifierChange: (modifier: ModifierKey | null) => void;
|
|
}
|
|
|
|
const EXPANDED_KEYS: { key: SpecialKey; label: string }[] = [
|
|
{ key: "home", label: "Home" },
|
|
{ key: "end", label: "End" },
|
|
{ key: "pageup", label: "PgUp" },
|
|
{ key: "pagedown", label: "PgDn" },
|
|
{ key: "ctrlc", label: "Ctrl+C" },
|
|
{ key: "ctrld", label: "Ctrl+D" },
|
|
{ key: "ctrlz", label: "Ctrl+Z" },
|
|
];
|
|
|
|
const F_KEYS: { key: SpecialKey; label: string }[] = [
|
|
{ key: "f1", label: "F1" },
|
|
{ key: "f2", label: "F2" },
|
|
{ key: "f3", label: "F3" },
|
|
{ key: "f4", label: "F4" },
|
|
{ key: "f5", label: "F5" },
|
|
{ key: "f6", label: "F6" },
|
|
{ key: "f7", label: "F7" },
|
|
{ key: "f8", label: "F8" },
|
|
{ key: "f9", label: "F9" },
|
|
{ key: "f10", label: "F10" },
|
|
{ key: "f11", label: "F11" },
|
|
{ key: "f12", label: "F12" },
|
|
];
|
|
|
|
export const SpecialKeysPanel: React.FC<SpecialKeysPanelProps> = ({
|
|
onSend,
|
|
isOpen,
|
|
onClose,
|
|
onKeepFocus,
|
|
activeModifier,
|
|
onModifierChange,
|
|
}) => {
|
|
if (!isOpen) return null;
|
|
|
|
const handlePointerDown = (e: React.PointerEvent, key: SpecialKey) => {
|
|
e.preventDefault();
|
|
|
|
const result = getSequenceWithModifier(key, activeModifier);
|
|
if (result) {
|
|
onSend(result.sequence);
|
|
if (result.clearModifier) {
|
|
onModifierChange(null);
|
|
}
|
|
}
|
|
|
|
onClose();
|
|
// Always refocus terminal after sending
|
|
requestAnimationFrame(() => {
|
|
onKeepFocus?.();
|
|
});
|
|
};
|
|
|
|
const handleOverlayPointerDown = (e: React.PointerEvent) => {
|
|
e.preventDefault();
|
|
onModifierChange(null);
|
|
onClose();
|
|
requestAnimationFrame(() => {
|
|
onKeepFocus?.();
|
|
});
|
|
};
|
|
|
|
return (
|
|
<div
|
|
className="special-keys-panel-overlay"
|
|
onPointerDown={handleOverlayPointerDown}
|
|
>
|
|
<div
|
|
className="special-keys-panel"
|
|
onPointerDown={(e) => e.stopPropagation()}
|
|
>
|
|
<div className="special-keys-panel-section">
|
|
{EXPANDED_KEYS.map(({ key, label }) => (
|
|
<button
|
|
key={key}
|
|
className="special-key-button"
|
|
onPointerDown={(e) => handlePointerDown(e, key)}
|
|
type="button"
|
|
tabIndex={-1}
|
|
>
|
|
{label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
<div className="special-keys-panel-divider" />
|
|
<div className="special-keys-panel-section">
|
|
{F_KEYS.map(({ key, label }) => (
|
|
<button
|
|
key={key}
|
|
className="special-key-button"
|
|
onPointerDown={(e) => handlePointerDown(e, key)}
|
|
type="button"
|
|
tabIndex={-1}
|
|
>
|
|
{label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|