diff --git a/packages/cli/src/ui/contexts/KeypressContext.tsx b/packages/cli/src/ui/contexts/KeypressContext.tsx index 97db27563..9a42c8e86 100644 --- a/packages/cli/src/ui/contexts/KeypressContext.tsx +++ b/packages/cli/src/ui/contexts/KeypressContext.tsx @@ -173,11 +173,37 @@ export function KeypressProvider({ let isPaste = false; let pasteBuffer = Buffer.alloc(0); let kittySequenceBuffer = ''; + let kittySequenceTimeout: NodeJS.Timeout | null = null; + const KITTY_SEQUENCE_TIMEOUT_MS = 200; + const kittySequenceBufferRef = { current: '' }; let backslashTimeout: NodeJS.Timeout | null = null; let waitingForEnterAfterBackslash = false; let rawDataBuffer = Buffer.alloc(0); let rawFlushTimeout: NodeJS.Timeout | null = null; + const clearKittyTimeout = () => { + if (kittySequenceTimeout) { + clearTimeout(kittySequenceTimeout); + kittySequenceTimeout = null; + } + }; + + const startKittyTimeout = () => { + clearKittyTimeout(); + kittySequenceTimeout = setTimeout(() => { + if (kittySequenceBufferRef.current) { + if (debugKeystrokeLogging) { + debugLogger.debug( + '[DEBUG] Kitty buffer timeout, clearing:', + kittySequenceBufferRef.current, + ); + } + kittySequenceBufferRef.current = ''; + kittySequenceBuffer = ''; + } + }, KITTY_SEQUENCE_TIMEOUT_MS); + }; + const createPrintableKey = (char: string): Key => { const printableName = char === ' ' @@ -685,6 +711,8 @@ export function KeypressProvider({ !key.sequence.startsWith(FOCUS_OUT)) ) { kittySequenceBuffer += key.sequence; + kittySequenceBufferRef.current = kittySequenceBuffer; + startKittyTimeout(); if (debugKeystrokeLogging) { debugLogger.debug( @@ -720,6 +748,10 @@ export function KeypressProvider({ } // Consume the parsed prefix and broadcast it. kittySequenceBuffer = kittySequenceBuffer.slice(parsed.length); + kittySequenceBufferRef.current = kittySequenceBuffer; + if (!kittySequenceBuffer) { + clearKittyTimeout(); + } broadcast(parsed.key); bufferedInputHandled = true; continue; @@ -737,6 +769,10 @@ export function KeypressProvider({ kittySequenceBuffer = kittySequenceBuffer.slice( completeUnsupportedCsiLength, ); + kittySequenceBufferRef.current = kittySequenceBuffer; + if (!kittySequenceBuffer) { + clearKittyTimeout(); + } bufferedInputHandled = true; continue; } @@ -752,6 +788,10 @@ export function KeypressProvider({ kittySequenceBuffer = kittySequenceBuffer.slice( plainTextPrefix.length, ); + kittySequenceBufferRef.current = kittySequenceBuffer; + if (!kittySequenceBuffer) { + clearKittyTimeout(); + } broadcast(plainTextPrefix.key); bufferedInputHandled = true; continue; @@ -767,6 +807,10 @@ export function KeypressProvider({ ); } kittySequenceBuffer = kittySequenceBuffer.slice(nextStart); + kittySequenceBufferRef.current = kittySequenceBuffer; + if (!kittySequenceBuffer) { + clearKittyTimeout(); + } bufferedInputHandled = true; continue; } @@ -796,6 +840,8 @@ export function KeypressProvider({ logKittySequenceOverflow(config, event); } kittySequenceBuffer = ''; + kittySequenceBufferRef.current = ''; + clearKittyTimeout(); } else { return; } @@ -956,6 +1002,8 @@ export function KeypressProvider({ backslashTimeout = null; } + clearKittyTimeout(); + if (rawFlushTimeout) { clearTimeout(rawFlushTimeout); rawFlushTimeout = null;