Skip to main content

terminput/
encoder.rs

1use std::fmt::Debug;
2use std::format;
3use std::io::{self, Cursor, Seek, Write};
4use std::string::{String, ToString};
5
6use bitflags::bitflags;
7
8use crate::{
9    Event, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers, MediaKeyCode,
10    ModifierDirection, ModifierKeyCode, MouseButton, MouseEvent, MouseEventKind, ScrollDirection,
11};
12
13bitflags! {
14    /// Controls which keyboard enhancement flags will be considered during encoding.
15    /// These flags are described in Kitty's documentation on [progressive enhancement](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement).
16    #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
17    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(transparent))]
18    pub struct KittyFlags: u8 {
19        /// Represent escape and modified keys using CSI-u sequences.
20        const DISAMBIGUATE_ESCAPE_CODES = 1<<1;
21        /// Report release and repeat events.
22        const REPORT_EVENT_TYPES = 1<<2;
23        /// Send [alternate keycodes](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#key-codes)
24        /// in addition to the base keycode. The encoder currently only supports this for
25        /// alphabetic keys since applying this to other types of keys requires knowledge of the
26        /// keyboard layout used to type the key.
27        const REPORT_ALTERNATE_KEYS = 1<<3;
28        /// Represent all keyboard events as CSI-u sequences.
29        const REPORT_ALL_KEYS_AS_ESCAPE_CODES = 1<<4;
30
31    }
32}
33
34/// Encoding protocol used to control the output of [`Event::encode`]
35#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
37pub enum Encoding {
38    /// Encode using the legacy Xterm protocol.
39    Xterm,
40    /// Encode using the Kitty protocol.
41    Kitty(KittyFlags),
42}
43
44fn unsupported_error<T>(event: T) -> io::Result<usize>
45where
46    T: Debug,
47{
48    Err(io::Error::new(
49        io::ErrorKind::Unsupported,
50        format!("Unsupported event: {event:?}"),
51    ))
52}
53
54impl Event {
55    /// Encode the event into the given buffer using the supplied [`Encoding`] mode.
56    /// Returns the number of bytes written, following the semantics of [`std::io::Write::write`].
57    ///
58    /// The supplied buffer needs enough space to hold the encoded sequence. If you're unsure of
59    /// how large the result will be, 16 bytes is more than sufficient.
60    ///
61    /// # Example
62    ///
63    /// ```
64    /// use terminput::{Encoding, Event, KeyCode, KeyEvent};
65    ///
66    /// let event = Event::Key(KeyEvent::new(KeyCode::Char('a')));
67    /// let mut buf = [0; 16];
68    /// let written = event.encode(&mut buf, Encoding::Xterm);
69    /// if let Ok(written) = written {
70    ///     println!("Encoded: {:?}", &buf[..written]);
71    /// }
72    /// ````
73    pub fn encode(&self, buf: &mut [u8], encoding: Encoding) -> io::Result<usize> {
74        match encoding {
75            Encoding::Xterm => self.to_escape_sequence(buf),
76            Encoding::Kitty(flags) => self.to_kitty_escape_sequence(buf, flags),
77        }
78    }
79
80    fn to_escape_sequence(&self, buf: &mut [u8]) -> io::Result<usize> {
81        let mut buf = Cursor::new(buf);
82        match self {
83            Self::FocusGained => {
84                buf.write_all(b"\x1B[I")?;
85                Ok(buf.position() as usize)
86            }
87            Self::FocusLost => {
88                buf.write_all(b"\x1B[O")?;
89                Ok(buf.position() as usize)
90            }
91            Self::Key(key_event) => encode_key_event(key_event, &mut buf),
92            Self::Mouse(mouse_event) => encode_mouse_event(mouse_event, &mut buf),
93            Self::Paste(text) => {
94                buf.write_all(b"\x1B[200~")?;
95                buf.write_all(text.as_bytes())?;
96                buf.write_all(b"\x1B[201~")?;
97                Ok(buf.position() as usize)
98            }
99            Self::Resize { .. } => unsupported_error("Resize"),
100        }
101    }
102
103    fn to_kitty_escape_sequence(&self, buf: &mut [u8], flags: KittyFlags) -> io::Result<usize> {
104        match self {
105            Self::Key(key_event) => self.encode_kitty_key_event(buf, key_event, flags),
106            _ => self.to_escape_sequence(buf),
107        }
108    }
109
110    fn encode_kitty_key_event(
111        &self,
112        buf: &mut [u8],
113        key_event: &KeyEvent,
114        flags: KittyFlags,
115    ) -> io::Result<usize> {
116        if !flags.intersects(
117            KittyFlags::DISAMBIGUATE_ESCAPE_CODES | KittyFlags::REPORT_ALL_KEYS_AS_ESCAPE_CODES,
118        ) {
119            return self.to_escape_sequence(buf);
120        }
121
122        // If this flag is disabled, normal text keys with no special modifiers should use
123        // simple encoding
124        if !flags.intersects(KittyFlags::REPORT_ALL_KEYS_AS_ESCAPE_CODES)
125            && key_event.kind == KeyEventKind::Press
126            && !key_event.modifiers.intersects(
127                KeyModifiers::CTRL
128                    | KeyModifiers::ALT
129                    | KeyModifiers::SUPER
130                    | KeyModifiers::HYPER
131                    | KeyModifiers::META,
132            )
133            && matches!(key_event.code, KeyCode::Char(_))
134        {
135            return self.to_escape_sequence(buf);
136        }
137
138        let key_event = key_event.normalize_case();
139        let mut buf = Cursor::new(buf);
140        buf.write_all(b"\x1B[")?;
141        let mut trailing_char = b'u';
142        let is_keypad = key_event.state.intersects(KeyEventState::KEYPAD);
143
144        // legacy encoding keys
145        if !is_keypad
146            && matches!(
147                key_event.code,
148                KeyCode::Home
149                    | KeyCode::End
150                    | KeyCode::Delete
151                    | KeyCode::Insert
152                    | KeyCode::Left
153                    | KeyCode::Right
154                    | KeyCode::Up
155                    | KeyCode::Down
156                    | KeyCode::F(1..=12)
157            )
158        {
159            if key_event.kind == KeyEventKind::Press && !matches!(key_event.code, KeyCode::F(1..=4))
160            {
161                buf.set_position(0);
162                let pos = self.to_escape_sequence(buf.get_mut())?;
163                return Ok(pos);
164            }
165            write_keycode_suffix(key_event.code, key_event.modifiers, false, &mut buf)?;
166            let pos = buf.position();
167            // Instead of the usual 'u' suffix, we need to use the last character from
168            // the legacy encoding
169            trailing_char = buf.get_ref()[pos as usize - 1];
170            // Encodings with only 2 characters require adding this placeholder
171            let mut add_placeholder = pos == 3;
172
173            if matches!(key_event.code, KeyCode::F(1..=4)) {
174                // F(1-4) require overwriting the second-last character from the legacy
175                // encoding
176                buf.set_position(pos - 2);
177                if !key_event.modifiers.is_empty() || key_event.kind != KeyEventKind::Press {
178                    // We need the placeholder if the F(1-4) key requires any kind of
179                    // modifiers
180                    add_placeholder = true;
181                }
182            } else {
183                buf.set_position(pos - 1);
184            }
185
186            if add_placeholder {
187                buf.write_all(b"1")?;
188            }
189        } else {
190            write_kitty_encoding(key_event, flags, &mut buf)?;
191        }
192        write_kitty_modifiers(key_event, flags, trailing_char, &mut buf)?;
193        Ok(buf.position() as usize)
194    }
195}
196
197fn encode_key_event(key_event: &KeyEvent, buf: &mut Cursor<&mut [u8]>) -> io::Result<usize> {
198    let key_event = key_event.normalize_case();
199    if key_event.kind != KeyEventKind::Press {
200        return unsupported_error(key_event.kind);
201    }
202
203    let is_shift = key_event.modifiers.intersects(KeyModifiers::SHIFT);
204    let is_ctrl = key_event.modifiers.intersects(KeyModifiers::CTRL);
205    let is_alt = key_event.modifiers.intersects(KeyModifiers::ALT);
206
207    if is_alt {
208        match key_event.code {
209            KeyCode::Char(_)
210            | KeyCode::Esc
211            | KeyCode::Backspace
212            | KeyCode::Enter
213            | KeyCode::Tab => {
214                buf.write_all(b"\x1B")?;
215            }
216            _ => {}
217        }
218    }
219    match key_event.code {
220        KeyCode::F(1..=4) => {
221            buf.write_all(b"\x1B")?;
222            write_keycode_suffix(key_event.code, key_event.modifiers, true, buf)?;
223        }
224        KeyCode::Left
225        | KeyCode::Right
226        | KeyCode::Up
227        | KeyCode::Down
228        | KeyCode::Home
229        | KeyCode::End
230        | KeyCode::PageUp
231        | KeyCode::PageDown
232        | KeyCode::Delete
233        | KeyCode::Insert
234        | KeyCode::F(_) => {
235            buf.write_all(b"\x1B[")?;
236            write_keycode_suffix(key_event.code, key_event.modifiers, true, buf)?;
237        }
238        KeyCode::Tab if is_shift => {
239            buf.write_all(b"\x1B[")?;
240            write_keycode_suffix(key_event.code, key_event.modifiers, true, buf)?;
241        }
242        KeyCode::Char(' ') if is_ctrl => {
243            buf.write_all(b"\x00")?;
244        }
245        KeyCode::Char(c @ '4'..='7') if is_ctrl => {
246            buf.write_all(&[c as u8 - b'4' + b'\x1C'])?;
247        }
248        key_code => {
249            let handled = write_keycode_suffix(key_event.code, key_event.modifiers, true, buf)?;
250            if !handled {
251                return unsupported_error(key_code);
252            }
253        }
254    }
255
256    if !key_event.modifiers.is_empty() {
257        write_modifier_prefix(key_event.code, buf)?;
258    }
259
260    if is_ctrl {
261        match key_event.code {
262            KeyCode::Char(' ' | '4'..='7') if is_ctrl => {}
263            KeyCode::Char(c) => {
264                let pos = buf.position() as usize;
265                let base = (c as u8) + 0x1;
266                if base < b'a' {
267                    return unsupported_error(key_event);
268                }
269                buf.get_mut()[pos - 1] = base - b'a';
270            }
271            KeyCode::Backspace => {
272                let pos = buf.position() as usize;
273                buf.get_mut()[pos - 1] = b'\x08';
274            }
275            _ => {}
276        }
277    }
278    match key_event.code {
279        KeyCode::Left
280        | KeyCode::Right
281        | KeyCode::Up
282        | KeyCode::Down
283        | KeyCode::Home
284        | KeyCode::End
285        | KeyCode::PageUp
286        | KeyCode::PageDown
287        | KeyCode::Delete
288        | KeyCode::Insert
289        | KeyCode::F(1..=4) => {
290            buf.get_mut()[4] += key_event.modifiers.bits();
291        }
292        KeyCode::F(_) => {
293            buf.get_mut()[5] += key_event.modifiers.bits();
294        }
295        _ => {}
296    }
297    Ok(buf.position() as usize)
298}
299
300fn encode_mouse_event(mouse_event: &MouseEvent, buf: &mut Cursor<&mut [u8]>) -> io::Result<usize> {
301    let mut base = match mouse_event.kind {
302        MouseEventKind::Moved => 35,
303        MouseEventKind::Down(MouseButton::Left | MouseButton::Unknown)
304        | MouseEventKind::Up(MouseButton::Left | MouseButton::Unknown) => 0,
305        MouseEventKind::Down(MouseButton::Middle) | MouseEventKind::Up(MouseButton::Middle) => 1,
306        MouseEventKind::Down(MouseButton::Right) | MouseEventKind::Up(MouseButton::Right) => 2,
307        MouseEventKind::Drag(MouseButton::Left | MouseButton::Unknown) => 32,
308        MouseEventKind::Drag(MouseButton::Middle) => 33,
309        MouseEventKind::Drag(MouseButton::Right) => 34,
310        MouseEventKind::Scroll(ScrollDirection::Down) => 65,
311        MouseEventKind::Scroll(ScrollDirection::Up) => 64,
312        MouseEventKind::Scroll(ScrollDirection::Left) => 66,
313        MouseEventKind::Scroll(ScrollDirection::Right) => 67,
314    };
315    if mouse_event.modifiers.intersects(KeyModifiers::SHIFT) {
316        base += 4;
317    }
318    if mouse_event.modifiers.intersects(KeyModifiers::ALT) {
319        base += 8;
320    }
321    if mouse_event.modifiers.intersects(KeyModifiers::CTRL) {
322        base += 16;
323    }
324    buf.write_all(b"\x1B[<")?;
325    buf.write_all(base.to_string().as_bytes())?;
326    buf.write_all(b";")?;
327    buf.write_all((mouse_event.column + 1).to_string().as_bytes())?;
328    buf.write_all(b";")?;
329    buf.write_all((mouse_event.row + 1).to_string().as_bytes())?;
330
331    if matches!(mouse_event.kind, MouseEventKind::Up(_)) {
332        buf.write_all(b"m")?;
333    } else {
334        buf.write_all(b"M")?;
335    }
336
337    Ok(buf.position() as usize)
338}
339
340fn write_kitty_modifiers(
341    key_event: KeyEvent,
342    flags: KittyFlags,
343    trailing_char: u8,
344    buf: &mut Cursor<&mut [u8]>,
345) -> io::Result<()> {
346    let report_event_types = flags.intersects(KittyFlags::REPORT_EVENT_TYPES);
347    let extra_modifiers = key_event
348        .state
349        .intersection(KeyEventState::CAPS_LOCK | KeyEventState::NUM_LOCK);
350
351    if !key_event.modifiers.is_empty()
352        || !extra_modifiers.is_empty()
353        || (key_event.kind != KeyEventKind::Press && report_event_types)
354    {
355        buf.write_all(b";")?;
356        let modifier_sum = key_event.modifiers.bits() + (extra_modifiers.bits() << 5) + 1;
357        buf.write_all(&modifier_sum.to_string().into_bytes())?;
358    }
359    if report_event_types {
360        match key_event.kind {
361            KeyEventKind::Repeat => {
362                buf.write_all(b":2")?;
363            }
364            KeyEventKind::Release => {
365                buf.write_all(b":3")?;
366            }
367            KeyEventKind::Press => {}
368        };
369    }
370    buf.write_all(&[trailing_char])?;
371    Ok(())
372}
373
374fn write_kitty_encoding(
375    key_event: KeyEvent,
376    flags: KittyFlags,
377    buf: &mut Cursor<&mut [u8]>,
378) -> io::Result<()> {
379    let is_keypad = key_event.state.intersects(KeyEventState::KEYPAD);
380    match key_event.code {
381        KeyCode::CapsLock => {
382            buf.write_all(b"57358")?;
383        }
384        KeyCode::ScrollLock => {
385            buf.write_all(b"57359")?;
386        }
387        KeyCode::NumLock => {
388            buf.write_all(b"57360")?;
389        }
390        KeyCode::PrintScreen => {
391            buf.write_all(b"57361")?;
392        }
393        KeyCode::Pause => {
394            buf.write_all(b"57362")?;
395        }
396        KeyCode::Menu => {
397            buf.write_all(b"57363")?;
398        }
399        KeyCode::F(val @ 13..=35) => {
400            buf.write_all(&(57376 + (val as u16 - 13)).to_string().into_bytes())?;
401        }
402        KeyCode::F(36..) => return unsupported_error(key_event).map(|_| ()),
403        KeyCode::Media(MediaKeyCode::Play) => {
404            buf.write_all(b"57428")?;
405        }
406        KeyCode::Media(MediaKeyCode::Pause) => {
407            buf.write_all(b"57429")?;
408        }
409        KeyCode::Media(MediaKeyCode::PlayPause) => {
410            buf.write_all(b"57430")?;
411        }
412        KeyCode::Media(MediaKeyCode::Reverse) => {
413            buf.write_all(b"57431")?;
414        }
415        KeyCode::Media(MediaKeyCode::Stop) => {
416            buf.write_all(b"57432")?;
417        }
418        KeyCode::Media(MediaKeyCode::FastForward) => {
419            buf.write_all(b"57433")?;
420        }
421        KeyCode::Media(MediaKeyCode::Rewind) => {
422            buf.write_all(b"57434")?;
423        }
424        KeyCode::Media(MediaKeyCode::TrackNext) => {
425            buf.write_all(b"57435")?;
426        }
427        KeyCode::Media(MediaKeyCode::TrackPrevious) => {
428            buf.write_all(b"57436")?;
429        }
430        KeyCode::Media(MediaKeyCode::Record) => {
431            buf.write_all(b"57437")?;
432        }
433        KeyCode::Media(MediaKeyCode::LowerVolume) => {
434            buf.write_all(b"57438")?;
435        }
436        KeyCode::Media(MediaKeyCode::RaiseVolume) => {
437            buf.write_all(b"57439")?;
438        }
439        KeyCode::Media(MediaKeyCode::MuteVolume) => {
440            buf.write_all(b"57440")?;
441        }
442        KeyCode::Modifier(ModifierKeyCode::Shift, ModifierDirection::Left) => {
443            buf.write_all(b"57441")?;
444        }
445        KeyCode::Modifier(ModifierKeyCode::Control, ModifierDirection::Left) => {
446            buf.write_all(b"57442")?;
447        }
448        KeyCode::Modifier(ModifierKeyCode::Alt, ModifierDirection::Left) => {
449            buf.write_all(b"57443")?;
450        }
451        KeyCode::Modifier(ModifierKeyCode::Super, ModifierDirection::Left) => {
452            buf.write_all(b"57444")?;
453        }
454        KeyCode::Modifier(ModifierKeyCode::Hyper, ModifierDirection::Left) => {
455            buf.write_all(b"57445")?;
456        }
457        KeyCode::Modifier(ModifierKeyCode::Meta, ModifierDirection::Left) => {
458            buf.write_all(b"57446")?;
459        }
460        KeyCode::Modifier(ModifierKeyCode::Shift, ModifierDirection::Right) => {
461            buf.write_all(b"57447")?;
462        }
463        KeyCode::Modifier(ModifierKeyCode::Control, ModifierDirection::Right) => {
464            buf.write_all(b"57448")?;
465        }
466        KeyCode::Modifier(ModifierKeyCode::Alt, ModifierDirection::Right) => {
467            buf.write_all(b"57449")?;
468        }
469        KeyCode::Modifier(ModifierKeyCode::Super, ModifierDirection::Right) => {
470            buf.write_all(b"57450")?;
471        }
472        KeyCode::Modifier(ModifierKeyCode::Hyper, ModifierDirection::Right) => {
473            buf.write_all(b"57451")?;
474        }
475        KeyCode::Modifier(ModifierKeyCode::Meta, ModifierDirection::Right) => {
476            buf.write_all(b"57452")?;
477        }
478        KeyCode::Modifier(ModifierKeyCode::IsoLevel3Shift, ModifierDirection::Unknown) => {
479            buf.write_all(b"57453")?;
480        }
481        KeyCode::Modifier(ModifierKeyCode::IsoLevel5Shift, ModifierDirection::Unknown) => {
482            buf.write_all(b"57454")?;
483        }
484        KeyCode::Char(val @ '0'..='9') if is_keypad => {
485            buf.write_all(&(57399 + (val as u16 - 48)).to_string().into_bytes())?;
486        }
487        KeyCode::Char('.') if is_keypad => {
488            buf.write_all(b"57409")?;
489        }
490        KeyCode::Char('/') if is_keypad => {
491            buf.write_all(b"57410")?;
492        }
493        KeyCode::Char('*') if is_keypad => {
494            buf.write_all(b"57411")?;
495        }
496        KeyCode::Char('-') if is_keypad => {
497            buf.write_all(b"57412")?;
498        }
499        KeyCode::Char('+') if is_keypad => {
500            buf.write_all(b"57413")?;
501        }
502        KeyCode::Enter if is_keypad => {
503            buf.write_all(b"57414")?;
504        }
505        KeyCode::Char('=') if is_keypad => {
506            buf.write_all(b"57415")?;
507        }
508        KeyCode::Char(',') if is_keypad => {
509            buf.write_all(b"57416")?;
510        }
511        KeyCode::Left if is_keypad => {
512            buf.write_all(b"57417")?;
513        }
514        KeyCode::Right if is_keypad => {
515            buf.write_all(b"57418")?;
516        }
517        KeyCode::Up if is_keypad => {
518            buf.write_all(b"57419")?;
519        }
520        KeyCode::Down if is_keypad => {
521            buf.write_all(b"57420")?;
522        }
523        KeyCode::PageUp if is_keypad => {
524            buf.write_all(b"57421")?;
525        }
526        KeyCode::PageDown if is_keypad => {
527            buf.write_all(b"57422")?;
528        }
529        KeyCode::Home if is_keypad => {
530            buf.write_all(b"57423")?;
531        }
532        KeyCode::End if is_keypad => {
533            buf.write_all(b"57424")?;
534        }
535        KeyCode::Insert if is_keypad => {
536            buf.write_all(b"57425")?;
537        }
538        KeyCode::Delete if is_keypad => {
539            buf.write_all(b"57426")?;
540        }
541        KeyCode::KeypadBegin if is_keypad => {
542            buf.write_all(b"57427")?;
543        }
544        KeyCode::Char(c) => {
545            // We should always use the lower-cased key for the first value
546            let c = c.to_ascii_lowercase();
547            convert_suffix_code(KeyCode::Char(c), key_event.modifiers, buf)?;
548            if flags.intersects(KittyFlags::REPORT_ALTERNATE_KEYS)
549                && key_event.modifiers.intersects(KeyModifiers::SHIFT)
550            {
551                // Ideally we could do this for other chars besides just ascii,
552                // but that requires knowing the keyboard layout
553                let upper = c.to_ascii_uppercase();
554                if upper != c {
555                    buf.write_all(b":")?;
556                    buf.write_all(&(upper as u8).to_string().into_bytes())?;
557                }
558            }
559        }
560        KeyCode::Esc | KeyCode::Enter | KeyCode::Tab | KeyCode::Backspace => {
561            convert_suffix_code(key_event.code, key_event.modifiers, buf)?;
562        }
563        key_code => {
564            write_keycode_suffix(key_code, key_event.modifiers, false, buf)?;
565        }
566    }
567    Ok(())
568}
569
570fn write_keycode_suffix(
571    key_code: KeyCode,
572    modifiers: KeyModifiers,
573    special_back_tab: bool,
574    buf: &mut Cursor<&mut [u8]>,
575) -> io::Result<bool> {
576    match key_code {
577        KeyCode::Backspace => buf.write_all(b"\x7F"),
578        KeyCode::Enter => buf.write_all(b"\r"),
579        KeyCode::Left => buf.write_all(b"D"),
580        KeyCode::Right => buf.write_all(b"C"),
581        KeyCode::Up => buf.write_all(b"A"),
582        KeyCode::Down => buf.write_all(b"B"),
583        KeyCode::Home => buf.write_all(b"H"),
584        KeyCode::End => buf.write_all(b"F"),
585        KeyCode::PageUp => buf.write_all(b"5~"),
586        KeyCode::PageDown => buf.write_all(b"6~"),
587        KeyCode::Tab if modifiers.intersects(KeyModifiers::SHIFT) && special_back_tab => {
588            buf.write_all(b"Z")
589        }
590        KeyCode::Tab => buf.write_all(b"\t"),
591        KeyCode::Delete => buf.write_all(b"3~"),
592        KeyCode::Insert => buf.write_all(b"2~"),
593        KeyCode::F(1) => buf.write_all(b"OP"),
594        KeyCode::F(2) => buf.write_all(b"OQ"),
595        KeyCode::F(3) => buf.write_all(b"OR"),
596        KeyCode::F(4) => buf.write_all(b"OS"),
597        KeyCode::F(5) => buf.write_all(b"15~"),
598        KeyCode::F(6) => buf.write_all(b"17~"),
599        KeyCode::F(7) => buf.write_all(b"18~"),
600        KeyCode::F(8) => buf.write_all(b"19~"),
601        KeyCode::F(9) => buf.write_all(b"20~"),
602        KeyCode::F(10) => buf.write_all(b"21~"),
603        KeyCode::F(11) => buf.write_all(b"23~"),
604        KeyCode::F(12) => buf.write_all(b"24~"),
605        KeyCode::Char(c) => {
606            let pos = buf.position() as usize;
607            let len = c.encode_utf8(&mut buf.get_mut()[pos..]).len();
608            buf.seek_relative(len as i64)
609        }
610        KeyCode::Esc => buf.write_all(b"\x1B"),
611        _ => return Ok(false),
612    }?;
613    Ok(true)
614}
615
616fn write_modifier_prefix(key_code: KeyCode, buf: &mut Cursor<&mut [u8]>) -> io::Result<()> {
617    let pos = buf.position() as usize;
618    let last = buf.get_mut()[pos - 1];
619    match key_code {
620        KeyCode::Left
621        | KeyCode::Right
622        | KeyCode::Up
623        | KeyCode::Down
624        | KeyCode::Home
625        | KeyCode::End => {
626            buf.seek_relative(-1)?;
627            buf.write_all(b"1;1")?;
628            buf.write_all(&[last])?;
629        }
630        KeyCode::F(1..=4) => {
631            buf.seek_relative(-2)?;
632            buf.write_all(b"[1;1")?;
633            buf.write_all(&[last])?;
634        }
635        KeyCode::PageUp | KeyCode::PageDown | KeyCode::Delete | KeyCode::Insert | KeyCode::F(_) => {
636            buf.seek_relative(-1)?;
637            buf.write_all(b";1")?;
638            buf.write_all(&[last])?;
639        }
640        _ => {}
641    }
642    Ok(())
643}
644
645fn convert_suffix_code(
646    key_code: KeyCode,
647    modifiers: KeyModifiers,
648    buf: &mut Cursor<&mut [u8]>,
649) -> io::Result<()> {
650    let old_pos = buf.position() as usize;
651    write_keycode_suffix(key_code, modifiers, false, buf)?;
652    let new_pos = buf.position() as usize;
653    let suffix_bytes = buf.get_ref()[old_pos..new_pos]
654        .iter()
655        .map(|b| b.to_string())
656        .collect::<String>()
657        .into_bytes();
658    buf.seek_relative(old_pos as i64 - new_pos as i64)?;
659    buf.write_all(&suffix_bytes)?;
660    Ok(())
661}