/
dgrigorev
/
veda
Обзор
Документация
Войти
/
dgrigorev
/
veda
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/input/key_processor.rs
121 строка
5 KB
Дмитрий Григорьев
Improve terminal theming and rendering
02 июн 2026, 01:59
02 июн 2026, 01:59
b1766a7
Код
Авторство
О чём код?
// ============================================================================ // input/key_processor.rs — преобразование клавиатуры в escape-последовательности. // --------------------------------------------------------------------------- // Назначение модуля: // * перевести логические клавиши winit (winit::keyboard::Key) в байты, // которые ожидает оболочка в PTY (VT100/xterm-совместимые коды); // * обработать модификаторы (Ctrl, Alt) для управляющих символов; // * сформировать ESC-последовательности для стрелок, функциональных и // навигационных клавиш. // // Это «сердце» ввода: именно отсюда в shell уходят нажатия. Текстовые // символы (буквы, цифры) берутся из event.text, спец-клавиши — из NamedKey. // ============================================================================ use winit::keyboard::{Key, ModifiersState, NamedKey}; /// Закодировать нажатие клавиши в байты для PTY. /// Возвращает None, если клавиша не порождает ввода (например, чистый Shift). /// /// * `key` — логическая клавиша из winit; /// * `text` — текст, который winit сопоставил клавише (с учётом раскладки); /// * `mods` — состояние модификаторов на момент нажатия. pub fn encode_key(key: &Key, text: Option<&str>, mods: ModifiersState) -> Option<Vec<u8>> { let ctrl = mods.control_key(); let alt = mods.alt_key(); match key { // --- Именованные (спец) клавиши --- Key::Named(named) => encode_named(*named, mods), // --- Символьные клавиши --- Key::Character(s) => { // Ctrl+<буква> -> управляющий символ (Ctrl+A = 0x01 и т.д.). if ctrl { if let Some(b) = ctrl_byte(s) { return Some(vec![b]); } } // Alt+<символ> -> ESC + символ (метакод xterm). let base = text.unwrap_or(s); if alt { let mut out = vec![0x1b]; out.extend_from_slice(base.as_bytes()); return Some(out); } // Обычный ввод: отдаём байты текста как есть (UTF-8). if base.is_empty() { None } else { Some(base.as_bytes().to_vec()) } } _ => None, } } /// Коды для именованных клавиш (Enter, стрелки, F-клавиши и т.п.). fn encode_named(named: NamedKey, mods: ModifiersState) -> Option<Vec<u8>> { let b = |s: &str| Some(s.as_bytes().to_vec()); match named { NamedKey::Enter => b("\r"), // CR — стандарт для shell NamedKey::Backspace => Some(vec![0x7f]), // DEL (так ждёт большинство shell) NamedKey::Tab => { if mods.shift_key() { b("\x1b[Z") // Shift+Tab -> обратная табуляция } else { b("\t") } } NamedKey::Escape => Some(vec![0x1b]), NamedKey::Space => b(" "), // Стрелки (нормальный режим курсора, CSI). NamedKey::ArrowUp => b("\x1b[A"), NamedKey::ArrowDown => b("\x1b[B"), NamedKey::ArrowRight => b("\x1b[C"), NamedKey::ArrowLeft => b("\x1b[D"), // Навигация. NamedKey::Home => b("\x1b[H"), NamedKey::End => b("\x1b[F"), NamedKey::PageUp => b("\x1b[5~"), NamedKey::PageDown => b("\x1b[6~"), NamedKey::Insert => b("\x1b[2~"), NamedKey::Delete => b("\x1b[3~"), // Функциональные клавиши F1..F12. NamedKey::F1 => b("\x1bOP"), NamedKey::F2 => b("\x1bOQ"), NamedKey::F3 => b("\x1bOR"), NamedKey::F4 => b("\x1bOS"), NamedKey::F5 => b("\x1b[15~"), NamedKey::F6 => b("\x1b[17~"), NamedKey::F7 => b("\x1b[18~"), NamedKey::F8 => b("\x1b[19~"), NamedKey::F9 => b("\x1b[20~"), NamedKey::F10 => b("\x1b[21~"), NamedKey::F11 => b("\x1b[23~"), NamedKey::F12 => b("\x1b[24~"), // Чистые модификаторы и прочее ввода не порождают. _ => None, } } /// Перевести символ при зажатом Ctrl в управляющий байт. /// Ctrl+A..Ctrl+Z = 0x01..0x1a; плюс несколько специальных сочетаний. fn ctrl_byte(s: &str) -> Option<u8> { let c = s.chars().next()?.to_ascii_lowercase(); match c { 'a'..='z' => Some((c as u8 - b'a') + 1), // Ctrl+A = 1 '[' => Some(0x1b), // Ctrl+[ = ESC '\\' => Some(0x1c), ']' => Some(0x1d), '^' => Some(0x1e), '_' => Some(0x1f), ' ' => Some(0x00), // Ctrl+Space = NUL _ => None, } }