From 73cafe075bdfea996b30f5b6b678fc86ea02f4e1 Mon Sep 17 00:00:00 2001 From: UnnaturalTwilight <107954129+UnnaturalTwilight@users.noreply.github.com> Date: Thu, 11 Jun 2026 13:49:55 -0400 Subject: [PATCH 1/4] fix: Kitty CSI u key inputs this is needed to parse ctrl+shift+ and other unprintable modifier combos I have only tested this with en-us querty and it may have weird behavor with non latin layouts due to casting the codepoint to u8 --- crates/edit/src/input.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/crates/edit/src/input.rs b/crates/edit/src/input.rs index 09144fb7b64..26fdfeb0bd9 100644 --- a/crates/edit/src/input.rs +++ b/crates/edit/src/input.rs @@ -454,6 +454,13 @@ impl<'input> Iterator for Stream<'_, '_, 'input> { let height = (csi.params[1] as CoordType).clamp(1, 32767); return Some(Input::Resize(Size { width, height })); } + 'u' if csi.param_count > 1 => { + // Kitty keyboard events + let char = csi.params[0] as u8; + return Some(Input::Keyboard( + InputKey::from_ascii(char as char)? | Self::parse_modifiers(csi), + )); + } _ => {} } } From 35feec86236da3a54b76b3fee278b721d8683501 Mon Sep 17 00:00:00 2001 From: UnnaturalTwilight <107954129+UnnaturalTwilight@users.noreply.github.com> Date: Thu, 7 May 2026 12:18:53 -0400 Subject: [PATCH 2/4] ctrl+shift+c copy --- crates/edit/src/tui.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/edit/src/tui.rs b/crates/edit/src/tui.rs index 9826c91cfc7..dde9f2a8008 100644 --- a/crates/edit/src/tui.rs +++ b/crates/edit/src/tui.rs @@ -2759,6 +2759,7 @@ impl<'a> Context<'a, '_> { }, vk::C => match modifiers { kbmod::CTRL => tb.copy(self.clipboard_mut()), + kbmod::CTRL_SHIFT => tb.copy(self.clipboard_mut()), _ => return false, }, vk::V => match modifiers { From 6d7b19f2e99d0a251cff18e586f9abb0d4cb846b Mon Sep 17 00:00:00 2001 From: UnnaturalTwilight <107954129+UnnaturalTwilight@users.noreply.github.com> Date: Tue, 21 Jul 2026 23:03:53 -0400 Subject: [PATCH 3/4] Full kitty keyboard implementation for the first level of progressive enhancements. --- crates/edit/src/bin/edit/main.rs | 5 ++- crates/edit/src/input.rs | 66 ++++++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/crates/edit/src/bin/edit/main.rs b/crates/edit/src/bin/edit/main.rs index 27ae7fab6c0..0121a60ae4e 100644 --- a/crates/edit/src/bin/edit/main.rs +++ b/crates/edit/src/bin/edit/main.rs @@ -580,7 +580,7 @@ impl Drop for RestoreModes { // Same as in the beginning but in the reverse order. // It also includes DECSCUSR 0 to reset the cursor style and DECTCEM to show the cursor. // We specifically don't reset mode 1036, because most applications expect it to be set nowadays. - sys::write_stdout("\x1b[0 q\x1b[?25h\x1b]0;\x07\x1b[?1002;1006;2004l\x1b[?1049l"); + sys::write_stdout("\x1b[1u", // OSC 4 color table requests for indices 0 through 15 (base colors). "\x1b]4;0;?;1;?;2;?;3;?;4;?;5;?;6;?;7;?\x07", "\x1b]4;8;?;9;?;10;?;11;?;12;?;13;?;14;?;15;?\x07", diff --git a/crates/edit/src/input.rs b/crates/edit/src/input.rs index 26fdfeb0bd9..4817a3957f4 100644 --- a/crates/edit/src/input.rs +++ b/crates/edit/src/input.rs @@ -454,11 +454,71 @@ impl<'input> Iterator for Stream<'_, '_, 'input> { let height = (csi.params[1] as CoordType).clamp(1, 32767); return Some(Input::Resize(Size { width, height })); } - 'u' if csi.param_count > 1 => { + 'u' => { // Kitty keyboard events - let char = csi.params[0] as u8; + let key = match csi.params[0] { + 97 ..= 122 => Some(InputKey::new(csi.params[0] as u32 & !0x20)), // Shift a-z to A-Z + 127 => Some(vk::BACK), + + // F13-F24 + 57376 => Some(vk::F13), + 57377 => Some(vk::F14), + 57378 => Some(vk::F15), + 57379 => Some(vk::F16), + 57380 => Some(vk::F17), + 57381 => Some(vk::F18), + 57382 => Some(vk::F19), + 57383 => Some(vk::F20), + 57384 => Some(vk::F21), + 57385 => Some(vk::F22), + 57386 => Some(vk::F23), + 57387 => Some(vk::F24), + 57388 ..= 57398 => None, // Ignore F25-F35 + + // Number pad keys + 57399 => Some(vk::NUMPAD0), + 57400 => Some(vk::NUMPAD1), + 57401 => Some(vk::NUMPAD2), + 57402 => Some(vk::NUMPAD3), + 57403 => Some(vk::NUMPAD4), + 57404 => Some(vk::NUMPAD5), + 57405 => Some(vk::NUMPAD6), + 57406 => Some(vk::NUMPAD7), + 57407 => Some(vk::NUMPAD8), + 57408 => Some(vk::NUMPAD9), + 57409 => Some(vk::DECIMAL), + 57410 => Some(vk::DIVIDE), + 57411 => Some(vk::MULTIPLY), + 57412 => Some(vk::SUBTRACT), + 57413 => Some(vk::ADD), + 57414 => Some(vk::RETURN), + 57415 => Some(InputKey::new('=' as u32)), + 57416 => Some(vk::SEPARATOR), + 57417 => Some(vk::LEFT), + 57418 => Some(vk::RIGHT), + 57419 => Some(vk::UP), + 57420 => Some(vk::DOWN), + 57421 => Some(vk::PRIOR), + 57422 => Some(vk::NEXT), + 57423 => Some(vk::HOME), + 57424 => Some(vk::END), + 57425 => Some(vk::INSERT), + 57426 => Some(vk::DELETE), + + // Keys to Ignore + 57358 => None, // Caps Lock + 57359 => None, // Scroll Lock + 57360 => None, // Num Lock + 57361 => None, // Print Screen + 57362 => None, // Pause + 57363 => None, // Menu + 57428 ..= 57440 => None, // Media and Volume + 57441 ..= 57454 => None, // Left/Right Modifiers + + _ => Some(InputKey::new(csi.params[0] as u32)), + }?; return Some(Input::Keyboard( - InputKey::from_ascii(char as char)? | Self::parse_modifiers(csi), + key | Self::parse_modifiers(csi), )); } _ => {} From 6bc76524fba952df8bf614c1801e8be9bda13528 Mon Sep 17 00:00:00 2001 From: UnnaturalTwilight <107954129+UnnaturalTwilight@users.noreply.github.com> Date: Wed, 5 Aug 2026 15:00:19 -0400 Subject: [PATCH 4/4] Parse the menu key and super mod menu is bound to focus the menubar super as a mod is unused for now but is needed for cmd bindings on macos in the future --- crates/edit/src/bin/edit/draw_menubar.rs | 2 +- crates/edit/src/input.rs | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/crates/edit/src/bin/edit/draw_menubar.rs b/crates/edit/src/bin/edit/draw_menubar.rs index 401614786a1..79dbef51053 100644 --- a/crates/edit/src/bin/edit/draw_menubar.rs +++ b/crates/edit/src/bin/edit/draw_menubar.rs @@ -20,7 +20,7 @@ pub fn draw_menubar(ctx: &mut Context, state: &mut State) { if ctx.menubar_menu_begin(loc(LocId::File), 'F') { draw_menu_file(ctx, state); } - if !contains_focus && ctx.consume_shortcut(vk::F10) { + if !contains_focus && (ctx.consume_shortcut(vk::F10) || ctx.consume_shortcut(vk::APPS)) { ctx.steal_focus(); } if state.documents.active().is_some() { diff --git a/crates/edit/src/input.rs b/crates/edit/src/input.rs index 4817a3957f4..e5e284948c1 100644 --- a/crates/edit/src/input.rs +++ b/crates/edit/src/input.rs @@ -161,6 +161,7 @@ pub mod vk { pub const Y: InputKey = InputKey::new('Y' as u32); pub const Z: InputKey = InputKey::new('Z' as u32); + pub const APPS: InputKey = InputKey::new(0x5D); pub const NUMPAD0: InputKey = InputKey::new(0x60); pub const NUMPAD1: InputKey = InputKey::new(0x61); pub const NUMPAD2: InputKey = InputKey::new(0x62); @@ -212,11 +213,19 @@ pub mod kbmod { pub const CTRL: InputKeyMod = InputKeyMod::new(0x01000000); pub const ALT: InputKeyMod = InputKeyMod::new(0x02000000); pub const SHIFT: InputKeyMod = InputKeyMod::new(0x04000000); + pub const SUPER: InputKeyMod = InputKeyMod::new(0x08000000); pub const CTRL_ALT: InputKeyMod = InputKeyMod::new(0x03000000); pub const CTRL_SHIFT: InputKeyMod = InputKeyMod::new(0x05000000); pub const ALT_SHIFT: InputKeyMod = InputKeyMod::new(0x06000000); pub const CTRL_ALT_SHIFT: InputKeyMod = InputKeyMod::new(0x07000000); + pub const SUPER_CTRL: InputKeyMod = InputKeyMod::new(0x09000000); + pub const SUPER_ALT: InputKeyMod = InputKeyMod::new(0x0A000000); + pub const SUPER_CTRL_ALT: InputKeyMod = InputKeyMod::new(0x0B000000); + pub const SUPER_SHIFT: InputKeyMod = InputKeyMod::new(0x0C000000); + pub const SUPER_CTRL_SHIFT: InputKeyMod = InputKeyMod::new(0x0D000000); + pub const SUPER_ALT_SHIFT: InputKeyMod = InputKeyMod::new(0x0E000000); + pub const SUPER_CTRL_ALT_SHIFT: InputKeyMod = InputKeyMod::new(0x0F000000); } /// Mouse input state. Up/Down, Left/Right, etc. @@ -473,7 +482,6 @@ impl<'input> Iterator for Stream<'_, '_, 'input> { 57385 => Some(vk::F22), 57386 => Some(vk::F23), 57387 => Some(vk::F24), - 57388 ..= 57398 => None, // Ignore F25-F35 // Number pad keys 57399 => Some(vk::NUMPAD0), @@ -504,6 +512,7 @@ impl<'input> Iterator for Stream<'_, '_, 'input> { 57424 => Some(vk::END), 57425 => Some(vk::INSERT), 57426 => Some(vk::DELETE), + 57363 => Some(vk::APPS), // Menu // Keys to Ignore 57358 => None, // Caps Lock @@ -511,7 +520,7 @@ impl<'input> Iterator for Stream<'_, '_, 'input> { 57360 => None, // Num Lock 57361 => None, // Print Screen 57362 => None, // Pause - 57363 => None, // Menu + 57388 ..= 57398 => None, // F25-F35 57428 ..= 57440 => None, // Media and Volume 57441 ..= 57454 => None, // Left/Right Modifiers @@ -610,6 +619,9 @@ impl<'input> Stream<'_, '_, 'input> { if (p1 & 0x04) != 0 { modifiers |= kbmod::CTRL; } + if (p1 & 0x08) != 0 { + modifiers |= kbmod::SUPER; + } modifiers }