1package tea
2
3import (
4 "github.com/charmbracelet/x/ansi"
5)
6
7// KeyboardEnhancements is a type that represents a set of keyboard
8// enhancements.
9type KeyboardEnhancements struct {
10 // Kitty progressive keyboard enhancements protocol. This can be used to
11 // enable different keyboard features.
12 //
13 // - 0: disable all features
14 // - 1: [ansi.KittyDisambiguateEscapeCodes] Disambiguate escape codes such as
15 // ctrl+i and tab, ctrl+[ and escape, ctrl+space and ctrl+@, etc.
16 // - 2: [ansi.KittyReportEventTypes] Report event types such as key presses,
17 // releases, and repeat events.
18 // - 4: [ansi.KittyReportAlternateKeys] Report keypresses as though they were
19 // on a PC-101 ANSI US keyboard layout regardless of what they layout
20 // actually is. Also include information about whether or not is enabled,
21 // - 8: [ansi.KittyReportAllKeysAsEscapeCodes] Report all key events as escape
22 // codes. This includes simple printable keys like "a" and other Unicode
23 // characters.
24 // - 16: [ansi.KittyReportAssociatedKeys] Report associated text with key
25 // events. This encodes multi-rune key events as escape codes instead of
26 // individual runes.
27 //
28 kittyFlags int
29
30 // Xterm modifyOtherKeys feature.
31 //
32 // - Mode 0 disables modifyOtherKeys.
33 // - Mode 1 reports ambiguous keys as escape codes. This is similar to
34 // [ansi.KittyDisambiguateEscapeCodes] but uses XTerm escape codes.
35 // - Mode 2 reports all key as escape codes including printable keys like "a" and "shift+b".
36 modifyOtherKeys int
37
38 // keyReleases indicates whether we have key release events enabled. This is mainly
39 // used in Windows to ignore key releases when they are not requested.
40 keyReleases bool
41}
42
43// KeyboardEnhancementOption is a type that represents a keyboard enhancement.
44type KeyboardEnhancementOption func(k *KeyboardEnhancements)
45
46// withKeyReleases enables support for reporting release key events. This is
47// useful for terminals that support the Kitty keyboard protocol "Report event
48// types" progressive enhancement feature.
49//
50// Note that not all terminals support this feature.
51func withKeyReleases(k *KeyboardEnhancements) {
52 k.kittyFlags |= ansi.KittyReportEventTypes
53 k.keyReleases = true
54}
55
56// withUniformKeyLayout enables support for reporting key events as though they
57// were on a PC-101 layout. This is useful for uniform key event reporting
58// across different keyboard layouts. This is equivalent to the Kitty keyboard
59// protocol "Report alternate keys" and "Report all keys as escape codes"
60// progressive enhancement features.
61//
62// Note that not all terminals support this feature.
63func withUniformKeyLayout(k *KeyboardEnhancements) {
64 k.kittyFlags |= ansi.KittyReportAlternateKeys | ansi.KittyReportAllKeysAsEscapeCodes
65}
66
67// withKeyDisambiguation enables support for disambiguating keyboard escape
68// codes. This is useful for terminals that support the Kitty keyboard protocol
69// "Disambiguate escape codes" progressive enhancement feature or the XTerm
70// modifyOtherKeys mode 1 feature to report ambiguous keys as escape codes.
71func withKeyDisambiguation(k *KeyboardEnhancements) {
72 k.kittyFlags |= ansi.KittyDisambiguateEscapeCodes
73 if k.modifyOtherKeys < 1 {
74 k.modifyOtherKeys = 1
75 }
76}
77
78type enableKeyboardEnhancementsMsg []KeyboardEnhancementOption
79
80// RequestKeyDisambiguation is a command that enables support for reporting
81// disambiguous keys as escape codes. This is enabled by default in Bubble Tea
82// and there's no need to call this function unless you disabled keyboard
83// enhancements through [DisableKeyboardEnhancements].
84//
85// If the terminal supports the requested enhancements, it will send a
86// [KeyboardEnhancementsMsg] message with the supported enhancements.
87//
88// Note that not all terminals support this feature. If the terminal does not
89// support this feature, the program will not receive disambiguated key
90// events.
91func RequestKeyDisambiguation() Msg {
92 return enableKeyboardEnhancementsMsg{withKeyDisambiguation}
93}
94
95// RequestKeyReleases is a command that enables support for reporting key
96// release events.
97//
98// If the terminal supports the requested enhancements, it will send a
99// [KeyboardEnhancementsMsg] message with the supported enhancements.
100//
101// Note that not all terminals support all enhancements.
102func RequestKeyReleases() Msg {
103 return enableKeyboardEnhancementsMsg{withKeyReleases}
104}
105
106// RequestUniformKeyLayout is a command that enables support for reporting key
107// events as though they were on a PC-101 layout.
108//
109// If the terminal supports the requested enhancements, it will send a
110// [KeyboardEnhancementsMsg] message with the supported enhancements.
111//
112// Note that not all terminals support all enhancements.
113func RequestUniformKeyLayout() Msg {
114 return enableKeyboardEnhancementsMsg{withUniformKeyLayout}
115}
116
117type disableKeyboardEnhancementsMsg struct{}
118
119// DisableKeyboardEnhancements is a command that disables keyboard enhancements
120// in the terminal.
121func DisableKeyboardEnhancements() Msg {
122 return disableKeyboardEnhancementsMsg{}
123}
124
125// KeyboardEnhancementsMsg is a message that gets sent when the terminal
126// supports keyboard enhancements.
127type KeyboardEnhancementsMsg KeyboardEnhancements
128
129// SupportsKeyDisambiguation returns whether the terminal supports reporting
130// disambiguous keys as escape codes.
131func (k KeyboardEnhancementsMsg) SupportsKeyDisambiguation() bool {
132 if isWindows() {
133 // We use Windows Console API which supports reporting disambiguous keys.
134 return true
135 }
136 return k.kittyFlags&ansi.KittyDisambiguateEscapeCodes != 0 || k.modifyOtherKeys >= 1
137}
138
139// SupportsKeyReleases returns whether the terminal supports key release
140// events.
141func (k KeyboardEnhancementsMsg) SupportsKeyReleases() bool {
142 if isWindows() {
143 // We use Windows Console API which supports key release events.
144 return k.keyReleases
145 }
146 return k.kittyFlags&ansi.KittyReportEventTypes != 0
147}
148
149// SupportsUniformKeyLayout returns whether the terminal supports reporting key
150// events as though they were on a PC-101 layout.
151func (k KeyboardEnhancementsMsg) SupportsUniformKeyLayout() bool {
152 if isWindows() {
153 // We use Windows Console API which supports reporting key events as
154 // though they were on a PC-101 layout.
155 return true
156 }
157 return k.SupportsKeyDisambiguation() &&
158 k.kittyFlags&ansi.KittyReportAlternateKeys != 0 &&
159 k.kittyFlags&ansi.KittyReportAllKeysAsEscapeCodes != 0
160}