mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-12 15:10:59 -07:00
106 lines
2.8 KiB
TypeScript
106 lines
2.8 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2025 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
let detectionComplete = false;
|
|
let protocolSupported = false;
|
|
let protocolEnabled = false;
|
|
|
|
/**
|
|
* Detects Kitty keyboard protocol support.
|
|
* Definitive document about this protocol lives at https://sw.kovidgoyal.net/kitty/keyboard-protocol/
|
|
* This function should be called once at app startup.
|
|
*/
|
|
export async function detectAndEnableKittyProtocol(): Promise<boolean> {
|
|
if (detectionComplete) {
|
|
return protocolSupported;
|
|
}
|
|
|
|
return new Promise((resolve) => {
|
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
detectionComplete = true;
|
|
resolve(false);
|
|
return;
|
|
}
|
|
|
|
const originalRawMode = process.stdin.isRaw;
|
|
if (!originalRawMode) {
|
|
process.stdin.setRawMode(true);
|
|
}
|
|
|
|
let responseBuffer = '';
|
|
let progressiveEnhancementReceived = false;
|
|
let checkFinished = false;
|
|
|
|
const handleData = (data: Buffer) => {
|
|
responseBuffer += data.toString();
|
|
|
|
// Check for progressive enhancement response (CSI ? <flags> u)
|
|
if (responseBuffer.includes('\x1b[?') && responseBuffer.includes('u')) {
|
|
progressiveEnhancementReceived = true;
|
|
}
|
|
|
|
// Check for device attributes response (CSI ? <attrs> c)
|
|
if (responseBuffer.includes('\x1b[?') && responseBuffer.includes('c')) {
|
|
if (!checkFinished) {
|
|
checkFinished = true;
|
|
process.stdin.removeListener('data', handleData);
|
|
|
|
if (!originalRawMode) {
|
|
process.stdin.setRawMode(false);
|
|
}
|
|
|
|
if (progressiveEnhancementReceived) {
|
|
// Enable the protocol
|
|
process.stdout.write('\x1b[>1u');
|
|
protocolSupported = true;
|
|
protocolEnabled = true;
|
|
|
|
// Set up cleanup on exit
|
|
process.on('exit', disableProtocol);
|
|
process.on('SIGTERM', disableProtocol);
|
|
}
|
|
|
|
detectionComplete = true;
|
|
resolve(protocolSupported);
|
|
}
|
|
}
|
|
};
|
|
|
|
process.stdin.on('data', handleData);
|
|
|
|
// Send queries
|
|
process.stdout.write('\x1b[?u'); // Query progressive enhancement
|
|
process.stdout.write('\x1b[c'); // Query device attributes
|
|
|
|
// Timeout after 50ms
|
|
setTimeout(() => {
|
|
if (!checkFinished) {
|
|
process.stdin.removeListener('data', handleData);
|
|
if (!originalRawMode) {
|
|
process.stdin.setRawMode(false);
|
|
}
|
|
detectionComplete = true;
|
|
resolve(false);
|
|
}
|
|
}, 50);
|
|
});
|
|
}
|
|
|
|
function disableProtocol() {
|
|
if (protocolEnabled) {
|
|
process.stdout.write('\x1b[<u');
|
|
protocolEnabled = false;
|
|
}
|
|
}
|
|
|
|
export function isKittyProtocolEnabled(): boolean {
|
|
return protocolEnabled;
|
|
}
|
|
|
|
export function isKittyProtocolSupported(): boolean {
|
|
return protocolSupported;
|
|
}
|