From 8c4422d0d0f836209dd506b2918a3e4996ab6721 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Sat, 14 Mar 2026 20:36:17 +0300 Subject: [PATCH] feat: support extended keyboard enhancements This adds support for the Kitty keyboard protocol's extended enhancements, allowing applications to request that the terminal report additional information about key events, such as whether they're part of a repeat sequence, alternate key values, and associated text. Supersedes: https://github.com/charmbracelet/bubbletea/pull/1622 Fixes: https://github.com/charmbracelet/bubbletea/issues/1621 Fixes: https://github.com/charmbracelet/bubbletea/issues/1623 --- cursed_renderer.go | 27 +++++++++++++++++++-------- keyboard.go | 18 ++++++++++++++++++ tea.go | 19 +++++++++++++++++++ 3 files changed, 56 insertions(+), 8 deletions(-) diff --git a/cursed_renderer.go b/cursed_renderer.go index c954873033..f22d94a351 100644 --- a/cursed_renderer.go +++ b/cursed_renderer.go @@ -131,10 +131,7 @@ func (s *cursedRenderer) start() { // Both can coexist; terminals ignore what they don't support. _, _ = s.scr.WriteString(ansi.SetModifyOtherKeys2) - kittyFlags := ansi.KittyDisambiguateEscapeCodes - if s.lastView.KeyboardEnhancements.ReportEventTypes { - kittyFlags |= ansi.KittyReportEventTypes - } + kittyFlags := keyboardEnhancementsFlags(s.lastView.KeyboardEnhancements) _, _ = s.scr.WriteString(ansi.KittyKeyboard(kittyFlags, 1)) } @@ -379,10 +376,7 @@ func (s *cursedRenderer) flush(closing bool) error { // Enable modifyOtherKeys and Kitty keyboard protocol. _, _ = s.scr.WriteString(ansi.SetModifyOtherKeys2) - kittyFlags := ansi.KittyDisambiguateEscapeCodes // always enable basic key disambiguation - if view.KeyboardEnhancements.ReportEventTypes { - kittyFlags |= ansi.KittyReportEventTypes - } + kittyFlags := keyboardEnhancementsFlags(view.KeyboardEnhancements) _, _ = s.scr.WriteString(ansi.KittyKeyboard(kittyFlags, 1)) if !closing { // Request keyboard enhancements when they change @@ -828,3 +822,20 @@ func viewEquals(a, b *View) bool { return true } + +func keyboardEnhancementsFlags(ke KeyboardEnhancements) int { + flags := 1 // always enable basic key disambiguation + if ke.ReportEventTypes { + flags |= ansi.KittyReportEventTypes + } + if ke.ReportAlternateKeys { + flags |= ansi.KittyReportAlternateKeys + } + if ke.ReportAllKeysAsEscapeCodes { + flags |= ansi.KittyReportAllKeysAsEscapeCodes + } + if ke.ReportAssociatedText { + flags |= ansi.KittyReportAssociatedKeys + } + return flags +} diff --git a/keyboard.go b/keyboard.go index dfc433496f..33747a4563 100644 --- a/keyboard.go +++ b/keyboard.go @@ -39,3 +39,21 @@ func (k KeyboardEnhancementsMsg) SupportsKeyDisambiguation() bool { func (k KeyboardEnhancementsMsg) SupportsEventTypes() bool { return k.Flags&ansi.KittyReportEventTypes != 0 } + +// SupportsAlternateKeys returns whether the terminal supports reporting +// alternate key codes. +func (k KeyboardEnhancementsMsg) SupportsAlternateKeys() bool { + return k.Flags&ansi.KittyReportAlternateKeys != 0 +} + +// SupportsAllKeysAsEscapeCodes returns whether the terminal supports reporting +// all keys as escape codes. +func (k KeyboardEnhancementsMsg) SupportsAllKeysAsEscapeCodes() bool { + return k.Flags&ansi.KittyReportAllKeysAsEscapeCodes != 0 +} + +// SupportsAssociatedText returns whether the terminal supports reporting +// associated text with key events. +func (k KeyboardEnhancementsMsg) SupportsAssociatedText() bool { + return k.Flags&ansi.KittyReportAssociatedKeys != 0 +} diff --git a/tea.go b/tea.go index e1dfc97d9f..cd98092a53 100644 --- a/tea.go +++ b/tea.go @@ -245,6 +245,25 @@ type KeyboardEnhancements struct { // [KeyPressMsg] with the [Key.IsRepeat] field set indicating that this is // a it's part of a key repeat sequence. ReportEventTypes bool + + // ReportAlternateKeys requests the terminal to report alternate key values + // in addition to the main ones. + // Note that only key events represented as escape codes will affected by + // this enhancement. + ReportAlternateKeys bool + + // ReportAllKeysAsEscapeCodes requests the terminal to report all key + // events, including plain text keys, as escape codes. + // When this is enabled, text won't be sent as plain text but instead as + // escape codes that encode the key value and modifiers. + ReportAllKeysAsEscapeCodes bool + + // ReportAssociatedText requests the terminal to report the text associated + // with key events. + // Note that this is an enhancement to + // [KeyboardEnhancements.ReportAllKeysAsEscapeCodes] and only has an effect + // if that is enabled. + ReportAssociatedText bool } // SetContent is a helper method to set the content of a [View] with a styled