1use std::fmt;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct KeyMsg {
27 pub key_type: KeyType,
29 pub runes: Vec<char>,
31 pub alt: bool,
33 pub paste: bool,
35}
36
37impl KeyMsg {
38 pub fn from_type(key_type: KeyType) -> Self {
40 Self {
41 key_type,
42 runes: Vec::new(),
43 alt: false,
44 paste: false,
45 }
46 }
47
48 pub fn from_char(c: char) -> Self {
50 Self {
51 key_type: KeyType::Runes,
52 runes: vec![c],
53 alt: false,
54 paste: false,
55 }
56 }
57
58 pub fn from_runes(runes: Vec<char>) -> Self {
60 Self {
61 key_type: KeyType::Runes,
62 runes,
63 alt: false,
64 paste: false,
65 }
66 }
67
68 pub fn with_alt(mut self) -> Self {
70 self.alt = true;
71 self
72 }
73
74 pub fn with_paste(mut self) -> Self {
76 self.paste = true;
77 self
78 }
79}
80
81impl fmt::Display for KeyMsg {
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 if self.alt {
84 write!(f, "alt+")?;
85 }
86 if self.key_type == KeyType::Runes {
87 if self.paste {
88 write!(f, "[")?;
89 }
90 for c in &self.runes {
91 write!(f, "{}", c)?;
92 }
93 if self.paste {
94 write!(f, "]")?;
95 }
96 } else {
97 write!(f, "{}", self.key_type)?;
98 }
99 Ok(())
100 }
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
107#[repr(i16)]
108pub enum KeyType {
109 Null = 0,
112 CtrlA = 1,
114 CtrlB = 2,
116 CtrlC = 3,
118 CtrlD = 4,
120 CtrlE = 5,
122 CtrlF = 6,
124 CtrlG = 7,
126 CtrlH = 8,
128 Tab = 9,
130 CtrlJ = 10,
132 CtrlK = 11,
134 CtrlL = 12,
136 Enter = 13,
138 CtrlN = 14,
140 CtrlO = 15,
142 CtrlP = 16,
144 CtrlQ = 17,
146 CtrlR = 18,
148 CtrlS = 19,
150 CtrlT = 20,
152 CtrlU = 21,
154 CtrlV = 22,
156 CtrlW = 23,
158 CtrlX = 24,
160 CtrlY = 25,
162 CtrlZ = 26,
164 Esc = 27,
166 CtrlBackslash = 28,
168 CtrlCloseBracket = 29,
170 CtrlCaret = 30,
172 CtrlUnderscore = 31,
174 Backspace = 127,
176
177 Runes = -1,
180 Up = -2,
182 Down = -3,
184 Right = -4,
186 Left = -5,
188 ShiftTab = -6,
190 Home = -7,
192 End = -8,
194 PgUp = -9,
196 PgDown = -10,
198 CtrlPgUp = -11,
200 CtrlPgDown = -12,
202 Delete = -13,
204 Insert = -14,
206 Space = -15,
208 CtrlUp = -16,
210 CtrlDown = -17,
212 CtrlRight = -18,
214 CtrlLeft = -19,
216 CtrlHome = -20,
218 CtrlEnd = -21,
220 ShiftUp = -22,
222 ShiftDown = -23,
224 ShiftRight = -24,
226 ShiftLeft = -25,
228 ShiftHome = -26,
230 ShiftEnd = -27,
232 CtrlShiftUp = -28,
234 CtrlShiftDown = -29,
236 CtrlShiftLeft = -30,
238 CtrlShiftRight = -31,
240 CtrlShiftHome = -32,
242 CtrlShiftEnd = -33,
244 F1 = -34,
246 F2 = -35,
248 F3 = -36,
250 F4 = -37,
252 F5 = -38,
254 F6 = -39,
256 F7 = -40,
258 F8 = -41,
260 F9 = -42,
262 F10 = -43,
264 F11 = -44,
266 F12 = -45,
268 F13 = -46,
270 F14 = -47,
272 F15 = -48,
274 F16 = -49,
276 F17 = -50,
278 F18 = -51,
280 F19 = -52,
282 F20 = -53,
284 ShiftEnter = -54,
286 CtrlEnter = -55,
288 CtrlShiftEnter = -56,
290}
291
292impl fmt::Display for KeyType {
293 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
294 let name = match self {
295 KeyType::Null => "ctrl+@",
296 KeyType::CtrlA => "ctrl+a",
297 KeyType::CtrlB => "ctrl+b",
298 KeyType::CtrlC => "ctrl+c",
299 KeyType::CtrlD => "ctrl+d",
300 KeyType::CtrlE => "ctrl+e",
301 KeyType::CtrlF => "ctrl+f",
302 KeyType::CtrlG => "ctrl+g",
303 KeyType::CtrlH => "ctrl+h",
304 KeyType::Tab => "tab",
305 KeyType::CtrlJ => "ctrl+j",
306 KeyType::CtrlK => "ctrl+k",
307 KeyType::CtrlL => "ctrl+l",
308 KeyType::Enter => "enter",
309 KeyType::CtrlN => "ctrl+n",
310 KeyType::CtrlO => "ctrl+o",
311 KeyType::CtrlP => "ctrl+p",
312 KeyType::CtrlQ => "ctrl+q",
313 KeyType::CtrlR => "ctrl+r",
314 KeyType::CtrlS => "ctrl+s",
315 KeyType::CtrlT => "ctrl+t",
316 KeyType::CtrlU => "ctrl+u",
317 KeyType::CtrlV => "ctrl+v",
318 KeyType::CtrlW => "ctrl+w",
319 KeyType::CtrlX => "ctrl+x",
320 KeyType::CtrlY => "ctrl+y",
321 KeyType::CtrlZ => "ctrl+z",
322 KeyType::Esc => "esc",
323 KeyType::CtrlBackslash => "ctrl+\\",
324 KeyType::CtrlCloseBracket => "ctrl+]",
325 KeyType::CtrlCaret => "ctrl+^",
326 KeyType::CtrlUnderscore => "ctrl+_",
327 KeyType::Backspace => "backspace",
328 KeyType::Runes => "runes",
329 KeyType::Up => "up",
330 KeyType::Down => "down",
331 KeyType::Right => "right",
332 KeyType::Left => "left",
333 KeyType::ShiftTab => "shift+tab",
334 KeyType::Home => "home",
335 KeyType::End => "end",
336 KeyType::PgUp => "pgup",
337 KeyType::PgDown => "pgdown",
338 KeyType::CtrlPgUp => "ctrl+pgup",
339 KeyType::CtrlPgDown => "ctrl+pgdown",
340 KeyType::Delete => "delete",
341 KeyType::Insert => "insert",
342 KeyType::Space => " ",
343 KeyType::CtrlUp => "ctrl+up",
344 KeyType::CtrlDown => "ctrl+down",
345 KeyType::CtrlRight => "ctrl+right",
346 KeyType::CtrlLeft => "ctrl+left",
347 KeyType::CtrlHome => "ctrl+home",
348 KeyType::CtrlEnd => "ctrl+end",
349 KeyType::ShiftUp => "shift+up",
350 KeyType::ShiftDown => "shift+down",
351 KeyType::ShiftRight => "shift+right",
352 KeyType::ShiftLeft => "shift+left",
353 KeyType::ShiftHome => "shift+home",
354 KeyType::ShiftEnd => "shift+end",
355 KeyType::CtrlShiftUp => "ctrl+shift+up",
356 KeyType::CtrlShiftDown => "ctrl+shift+down",
357 KeyType::CtrlShiftLeft => "ctrl+shift+left",
358 KeyType::CtrlShiftRight => "ctrl+shift+right",
359 KeyType::CtrlShiftHome => "ctrl+shift+home",
360 KeyType::CtrlShiftEnd => "ctrl+shift+end",
361 KeyType::F1 => "f1",
362 KeyType::F2 => "f2",
363 KeyType::F3 => "f3",
364 KeyType::F4 => "f4",
365 KeyType::F5 => "f5",
366 KeyType::F6 => "f6",
367 KeyType::F7 => "f7",
368 KeyType::F8 => "f8",
369 KeyType::F9 => "f9",
370 KeyType::F10 => "f10",
371 KeyType::F11 => "f11",
372 KeyType::F12 => "f12",
373 KeyType::F13 => "f13",
374 KeyType::F14 => "f14",
375 KeyType::F15 => "f15",
376 KeyType::F16 => "f16",
377 KeyType::F17 => "f17",
378 KeyType::F18 => "f18",
379 KeyType::F19 => "f19",
380 KeyType::F20 => "f20",
381 KeyType::ShiftEnter => "shift+enter",
382 KeyType::CtrlEnter => "ctrl+enter",
383 KeyType::CtrlShiftEnter => "ctrl+shift+enter",
384 };
385 write!(f, "{}", name)
386 }
387}
388
389impl KeyType {
390 pub fn is_ctrl(&self) -> bool {
392 let val = *self as i16;
393 (0..=31).contains(&val) || val == 127
394 }
395
396 pub fn is_function_key(&self) -> bool {
398 matches!(
399 self,
400 KeyType::F1
401 | KeyType::F2
402 | KeyType::F3
403 | KeyType::F4
404 | KeyType::F5
405 | KeyType::F6
406 | KeyType::F7
407 | KeyType::F8
408 | KeyType::F9
409 | KeyType::F10
410 | KeyType::F11
411 | KeyType::F12
412 | KeyType::F13
413 | KeyType::F14
414 | KeyType::F15
415 | KeyType::F16
416 | KeyType::F17
417 | KeyType::F18
418 | KeyType::F19
419 | KeyType::F20
420 )
421 }
422
423 pub fn is_cursor(&self) -> bool {
425 matches!(
426 self,
427 KeyType::Up
428 | KeyType::Down
429 | KeyType::Left
430 | KeyType::Right
431 | KeyType::Home
432 | KeyType::End
433 | KeyType::PgUp
434 | KeyType::PgDown
435 | KeyType::CtrlUp
436 | KeyType::CtrlDown
437 | KeyType::CtrlLeft
438 | KeyType::CtrlRight
439 | KeyType::CtrlHome
440 | KeyType::CtrlEnd
441 | KeyType::ShiftUp
442 | KeyType::ShiftDown
443 | KeyType::ShiftLeft
444 | KeyType::ShiftRight
445 | KeyType::ShiftHome
446 | KeyType::ShiftEnd
447 | KeyType::CtrlShiftUp
448 | KeyType::CtrlShiftDown
449 | KeyType::CtrlShiftLeft
450 | KeyType::CtrlShiftRight
451 | KeyType::CtrlShiftHome
452 | KeyType::CtrlShiftEnd
453 | KeyType::CtrlPgUp
454 | KeyType::CtrlPgDown
455 )
456 }
457}
458
459pub fn from_crossterm_key(
461 code: crossterm::event::KeyCode,
462 modifiers: crossterm::event::KeyModifiers,
463) -> KeyMsg {
464 use crossterm::event::{KeyCode, KeyModifiers};
465
466 let ctrl = modifiers.contains(KeyModifiers::CONTROL);
467 let shift = modifiers.contains(KeyModifiers::SHIFT);
468 let alt = modifiers.contains(KeyModifiers::ALT);
469
470 let (key_type, runes) = match code {
471 KeyCode::Char(c) if ctrl => {
472 let kt = match c.to_ascii_lowercase() {
473 '@' => KeyType::Null,
474 'a' => KeyType::CtrlA,
475 'b' => KeyType::CtrlB,
476 'c' => KeyType::CtrlC,
477 'd' => KeyType::CtrlD,
478 'e' => KeyType::CtrlE,
479 'f' => KeyType::CtrlF,
480 'g' => KeyType::CtrlG,
481 'h' => KeyType::CtrlH,
482 'i' => KeyType::Tab,
483 'j' => KeyType::CtrlJ,
484 'k' => KeyType::CtrlK,
485 'l' => KeyType::CtrlL,
486 'm' => KeyType::Enter,
487 'n' => KeyType::CtrlN,
488 'o' => KeyType::CtrlO,
489 'p' => KeyType::CtrlP,
490 'q' => KeyType::CtrlQ,
491 'r' => KeyType::CtrlR,
492 's' => KeyType::CtrlS,
493 't' => KeyType::CtrlT,
494 'u' => KeyType::CtrlU,
495 'v' => KeyType::CtrlV,
496 'w' => KeyType::CtrlW,
497 'x' => KeyType::CtrlX,
498 'y' => KeyType::CtrlY,
499 'z' => KeyType::CtrlZ,
500 '\\' => KeyType::CtrlBackslash,
501 ']' => KeyType::CtrlCloseBracket,
502 '^' => KeyType::CtrlCaret,
503 '_' => KeyType::CtrlUnderscore,
504 _ => {
505 return KeyMsg {
506 key_type: KeyType::Runes,
507 runes: vec![c],
508 alt,
509 paste: false,
510 };
511 }
512 };
513 (kt, Vec::new())
514 }
515 KeyCode::Char(' ') => (KeyType::Space, Vec::new()),
516 KeyCode::Char(c) => (KeyType::Runes, vec![c]),
517 KeyCode::Enter if ctrl && shift => (KeyType::CtrlShiftEnter, Vec::new()),
518 KeyCode::Enter if ctrl => (KeyType::CtrlEnter, Vec::new()),
519 KeyCode::Enter if shift => (KeyType::ShiftEnter, Vec::new()),
520 KeyCode::Enter => (KeyType::Enter, Vec::new()),
521 KeyCode::Backspace => (KeyType::Backspace, Vec::new()),
522 KeyCode::Tab if shift => (KeyType::ShiftTab, Vec::new()),
523 KeyCode::Tab => (KeyType::Tab, Vec::new()),
524 KeyCode::Esc => (KeyType::Esc, Vec::new()),
525 KeyCode::Delete => (KeyType::Delete, Vec::new()),
526 KeyCode::Insert => (KeyType::Insert, Vec::new()),
527 KeyCode::Up if ctrl && shift => (KeyType::CtrlShiftUp, Vec::new()),
528 KeyCode::Up if ctrl => (KeyType::CtrlUp, Vec::new()),
529 KeyCode::Up if shift => (KeyType::ShiftUp, Vec::new()),
530 KeyCode::Up => (KeyType::Up, Vec::new()),
531 KeyCode::Down if ctrl && shift => (KeyType::CtrlShiftDown, Vec::new()),
532 KeyCode::Down if ctrl => (KeyType::CtrlDown, Vec::new()),
533 KeyCode::Down if shift => (KeyType::ShiftDown, Vec::new()),
534 KeyCode::Down => (KeyType::Down, Vec::new()),
535 KeyCode::Left if ctrl && shift => (KeyType::CtrlShiftLeft, Vec::new()),
536 KeyCode::Left if ctrl => (KeyType::CtrlLeft, Vec::new()),
537 KeyCode::Left if shift => (KeyType::ShiftLeft, Vec::new()),
538 KeyCode::Left => (KeyType::Left, Vec::new()),
539 KeyCode::Right if ctrl && shift => (KeyType::CtrlShiftRight, Vec::new()),
540 KeyCode::Right if ctrl => (KeyType::CtrlRight, Vec::new()),
541 KeyCode::Right if shift => (KeyType::ShiftRight, Vec::new()),
542 KeyCode::Right => (KeyType::Right, Vec::new()),
543 KeyCode::Home if ctrl && shift => (KeyType::CtrlShiftHome, Vec::new()),
544 KeyCode::Home if ctrl => (KeyType::CtrlHome, Vec::new()),
545 KeyCode::Home if shift => (KeyType::ShiftHome, Vec::new()),
546 KeyCode::Home => (KeyType::Home, Vec::new()),
547 KeyCode::End if ctrl && shift => (KeyType::CtrlShiftEnd, Vec::new()),
548 KeyCode::End if ctrl => (KeyType::CtrlEnd, Vec::new()),
549 KeyCode::End if shift => (KeyType::ShiftEnd, Vec::new()),
550 KeyCode::End => (KeyType::End, Vec::new()),
551 KeyCode::PageUp if ctrl => (KeyType::CtrlPgUp, Vec::new()),
552 KeyCode::PageUp => (KeyType::PgUp, Vec::new()),
553 KeyCode::PageDown if ctrl => (KeyType::CtrlPgDown, Vec::new()),
554 KeyCode::PageDown => (KeyType::PgDown, Vec::new()),
555 KeyCode::F(1) => (KeyType::F1, Vec::new()),
556 KeyCode::F(2) => (KeyType::F2, Vec::new()),
557 KeyCode::F(3) => (KeyType::F3, Vec::new()),
558 KeyCode::F(4) => (KeyType::F4, Vec::new()),
559 KeyCode::F(5) => (KeyType::F5, Vec::new()),
560 KeyCode::F(6) => (KeyType::F6, Vec::new()),
561 KeyCode::F(7) => (KeyType::F7, Vec::new()),
562 KeyCode::F(8) => (KeyType::F8, Vec::new()),
563 KeyCode::F(9) => (KeyType::F9, Vec::new()),
564 KeyCode::F(10) => (KeyType::F10, Vec::new()),
565 KeyCode::F(11) => (KeyType::F11, Vec::new()),
566 KeyCode::F(12) => (KeyType::F12, Vec::new()),
567 KeyCode::F(13) => (KeyType::F13, Vec::new()),
568 KeyCode::F(14) => (KeyType::F14, Vec::new()),
569 KeyCode::F(15) => (KeyType::F15, Vec::new()),
570 KeyCode::F(16) => (KeyType::F16, Vec::new()),
571 KeyCode::F(17) => (KeyType::F17, Vec::new()),
572 KeyCode::F(18) => (KeyType::F18, Vec::new()),
573 KeyCode::F(19) => (KeyType::F19, Vec::new()),
574 KeyCode::F(20) => (KeyType::F20, Vec::new()),
575 _ => (KeyType::Runes, Vec::new()),
576 };
577
578 KeyMsg {
579 key_type,
580 runes,
581 alt,
582 paste: false,
583 }
584}
585
586pub fn parse_sequence(input: &[u8]) -> Option<KeyMsg> {
611 let seq = std::str::from_utf8(input).ok()?;
613
614 SEQUENCES.get(seq).cloned()
616}
617
618pub fn parse_sequence_prefix(input: &[u8]) -> Option<(KeyMsg, usize)> {
643 let s = std::str::from_utf8(input).ok()?;
644
645 let mut best_match: Option<(KeyMsg, usize)> = None;
648
649 for (seq, key) in SEQUENCES.iter() {
650 if s.starts_with(seq) {
651 let len = seq.len();
652 match best_match {
653 None => best_match = Some((key.clone(), len)),
654 Some((_, best_len)) => {
655 if len > best_len {
656 best_match = Some((key.clone(), len));
657 }
658 }
659 }
660 }
661 }
662
663 best_match
664}
665
666pub fn is_sequence_prefix(input: &[u8]) -> bool {
676 let s = match std::str::from_utf8(input) {
677 Ok(s) => s,
678 Err(_) => return false,
679 };
680
681 SEQUENCES.keys().any(|seq| seq.starts_with(s))
682}
683
684use std::collections::HashMap;
685use std::sync::LazyLock;
686
687static SEQUENCES: LazyLock<HashMap<&'static str, KeyMsg>> = LazyLock::new(|| {
690 let mut m = HashMap::new();
691
692 m.insert("\x1b[A", KeyMsg::from_type(KeyType::Up));
694 m.insert("\x1b[B", KeyMsg::from_type(KeyType::Down));
695 m.insert("\x1b[C", KeyMsg::from_type(KeyType::Right));
696 m.insert("\x1b[D", KeyMsg::from_type(KeyType::Left));
697
698 m.insert("\x1b[1;2A", KeyMsg::from_type(KeyType::ShiftUp));
700 m.insert("\x1b[1;2B", KeyMsg::from_type(KeyType::ShiftDown));
701 m.insert("\x1b[1;2C", KeyMsg::from_type(KeyType::ShiftRight));
702 m.insert("\x1b[1;2D", KeyMsg::from_type(KeyType::ShiftLeft));
703 m.insert("\x1b[OA", KeyMsg::from_type(KeyType::ShiftUp));
705 m.insert("\x1b[OB", KeyMsg::from_type(KeyType::ShiftDown));
706 m.insert("\x1b[OC", KeyMsg::from_type(KeyType::ShiftRight));
707 m.insert("\x1b[OD", KeyMsg::from_type(KeyType::ShiftLeft));
708 m.insert("\x1b[a", KeyMsg::from_type(KeyType::ShiftUp));
710 m.insert("\x1b[b", KeyMsg::from_type(KeyType::ShiftDown));
711 m.insert("\x1b[c", KeyMsg::from_type(KeyType::ShiftRight));
712 m.insert("\x1b[d", KeyMsg::from_type(KeyType::ShiftLeft));
713
714 m.insert("\x1b[1;3A", KeyMsg::from_type(KeyType::Up).with_alt());
716 m.insert("\x1b[1;3B", KeyMsg::from_type(KeyType::Down).with_alt());
717 m.insert("\x1b[1;3C", KeyMsg::from_type(KeyType::Right).with_alt());
718 m.insert("\x1b[1;3D", KeyMsg::from_type(KeyType::Left).with_alt());
719
720 m.insert("\x1b[1;4A", KeyMsg::from_type(KeyType::ShiftUp).with_alt());
722 m.insert(
723 "\x1b[1;4B",
724 KeyMsg::from_type(KeyType::ShiftDown).with_alt(),
725 );
726 m.insert(
727 "\x1b[1;4C",
728 KeyMsg::from_type(KeyType::ShiftRight).with_alt(),
729 );
730 m.insert(
731 "\x1b[1;4D",
732 KeyMsg::from_type(KeyType::ShiftLeft).with_alt(),
733 );
734
735 m.insert("\x1b[1;5A", KeyMsg::from_type(KeyType::CtrlUp));
737 m.insert("\x1b[1;5B", KeyMsg::from_type(KeyType::CtrlDown));
738 m.insert("\x1b[1;5C", KeyMsg::from_type(KeyType::CtrlRight));
739 m.insert("\x1b[1;5D", KeyMsg::from_type(KeyType::CtrlLeft));
740 m.insert("\x1b[Oa", KeyMsg::from_type(KeyType::CtrlUp).with_alt());
742 m.insert("\x1b[Ob", KeyMsg::from_type(KeyType::CtrlDown).with_alt());
743 m.insert("\x1b[Oc", KeyMsg::from_type(KeyType::CtrlRight).with_alt());
744 m.insert("\x1b[Od", KeyMsg::from_type(KeyType::CtrlLeft).with_alt());
745
746 m.insert("\x1b[1;6A", KeyMsg::from_type(KeyType::CtrlShiftUp));
748 m.insert("\x1b[1;6B", KeyMsg::from_type(KeyType::CtrlShiftDown));
749 m.insert("\x1b[1;6C", KeyMsg::from_type(KeyType::CtrlShiftRight));
750 m.insert("\x1b[1;6D", KeyMsg::from_type(KeyType::CtrlShiftLeft));
751
752 m.insert("\x1b[1;7A", KeyMsg::from_type(KeyType::CtrlUp).with_alt());
754 m.insert("\x1b[1;7B", KeyMsg::from_type(KeyType::CtrlDown).with_alt());
755 m.insert(
756 "\x1b[1;7C",
757 KeyMsg::from_type(KeyType::CtrlRight).with_alt(),
758 );
759 m.insert("\x1b[1;7D", KeyMsg::from_type(KeyType::CtrlLeft).with_alt());
760
761 m.insert(
763 "\x1b[1;8A",
764 KeyMsg::from_type(KeyType::CtrlShiftUp).with_alt(),
765 );
766 m.insert(
767 "\x1b[1;8B",
768 KeyMsg::from_type(KeyType::CtrlShiftDown).with_alt(),
769 );
770 m.insert(
771 "\x1b[1;8C",
772 KeyMsg::from_type(KeyType::CtrlShiftRight).with_alt(),
773 );
774 m.insert(
775 "\x1b[1;8D",
776 KeyMsg::from_type(KeyType::CtrlShiftLeft).with_alt(),
777 );
778
779 m.insert("\x1b[Z", KeyMsg::from_type(KeyType::ShiftTab));
781
782 m.insert("\x1b[2~", KeyMsg::from_type(KeyType::Insert));
784 m.insert("\x1b[3;2~", KeyMsg::from_type(KeyType::Insert).with_alt());
785
786 m.insert("\x1b[3~", KeyMsg::from_type(KeyType::Delete));
788 m.insert("\x1b[3;3~", KeyMsg::from_type(KeyType::Delete).with_alt());
789
790 m.insert("\x1b[5~", KeyMsg::from_type(KeyType::PgUp));
792 m.insert("\x1b[5;3~", KeyMsg::from_type(KeyType::PgUp).with_alt());
793 m.insert("\x1b[5;5~", KeyMsg::from_type(KeyType::CtrlPgUp));
794 m.insert("\x1b[5^", KeyMsg::from_type(KeyType::CtrlPgUp)); m.insert("\x1b[5;7~", KeyMsg::from_type(KeyType::CtrlPgUp).with_alt());
796
797 m.insert("\x1b[6~", KeyMsg::from_type(KeyType::PgDown));
799 m.insert("\x1b[6;3~", KeyMsg::from_type(KeyType::PgDown).with_alt());
800 m.insert("\x1b[6;5~", KeyMsg::from_type(KeyType::CtrlPgDown));
801 m.insert("\x1b[6^", KeyMsg::from_type(KeyType::CtrlPgDown)); m.insert(
803 "\x1b[6;7~",
804 KeyMsg::from_type(KeyType::CtrlPgDown).with_alt(),
805 );
806
807 m.insert("\x1b[1~", KeyMsg::from_type(KeyType::Home));
809 m.insert("\x1b[H", KeyMsg::from_type(KeyType::Home)); m.insert("\x1b[1;3H", KeyMsg::from_type(KeyType::Home).with_alt());
811 m.insert("\x1b[1;5H", KeyMsg::from_type(KeyType::CtrlHome));
812 m.insert("\x1b[1;7H", KeyMsg::from_type(KeyType::CtrlHome).with_alt());
813 m.insert("\x1b[1;2H", KeyMsg::from_type(KeyType::ShiftHome));
814 m.insert(
815 "\x1b[1;4H",
816 KeyMsg::from_type(KeyType::ShiftHome).with_alt(),
817 );
818 m.insert("\x1b[1;6H", KeyMsg::from_type(KeyType::CtrlShiftHome));
819 m.insert(
820 "\x1b[1;8H",
821 KeyMsg::from_type(KeyType::CtrlShiftHome).with_alt(),
822 );
823 m.insert("\x1b[7~", KeyMsg::from_type(KeyType::Home)); m.insert("\x1b[7^", KeyMsg::from_type(KeyType::CtrlHome)); m.insert("\x1b[7$", KeyMsg::from_type(KeyType::ShiftHome)); m.insert("\x1b[7@", KeyMsg::from_type(KeyType::CtrlShiftHome)); m.insert("\x1b[4~", KeyMsg::from_type(KeyType::End));
830 m.insert("\x1b[F", KeyMsg::from_type(KeyType::End)); m.insert("\x1b[1;3F", KeyMsg::from_type(KeyType::End).with_alt());
832 m.insert("\x1b[1;5F", KeyMsg::from_type(KeyType::CtrlEnd));
833 m.insert("\x1b[1;7F", KeyMsg::from_type(KeyType::CtrlEnd).with_alt());
834 m.insert("\x1b[1;2F", KeyMsg::from_type(KeyType::ShiftEnd));
835 m.insert("\x1b[1;4F", KeyMsg::from_type(KeyType::ShiftEnd).with_alt());
836 m.insert("\x1b[1;6F", KeyMsg::from_type(KeyType::CtrlShiftEnd));
837 m.insert(
838 "\x1b[1;8F",
839 KeyMsg::from_type(KeyType::CtrlShiftEnd).with_alt(),
840 );
841 m.insert("\x1b[8~", KeyMsg::from_type(KeyType::End)); m.insert("\x1b[8^", KeyMsg::from_type(KeyType::CtrlEnd)); m.insert("\x1b[8$", KeyMsg::from_type(KeyType::ShiftEnd)); m.insert("\x1b[8@", KeyMsg::from_type(KeyType::CtrlShiftEnd)); m.insert("\x1b[[A", KeyMsg::from_type(KeyType::F1));
848 m.insert("\x1b[[B", KeyMsg::from_type(KeyType::F2));
849 m.insert("\x1b[[C", KeyMsg::from_type(KeyType::F3));
850 m.insert("\x1b[[D", KeyMsg::from_type(KeyType::F4));
851 m.insert("\x1b[[E", KeyMsg::from_type(KeyType::F5));
852
853 m.insert("\x1bOP", KeyMsg::from_type(KeyType::F1));
855 m.insert("\x1bOQ", KeyMsg::from_type(KeyType::F2));
856 m.insert("\x1bOR", KeyMsg::from_type(KeyType::F3));
857 m.insert("\x1bOS", KeyMsg::from_type(KeyType::F4));
858
859 m.insert("\x1b[1;3P", KeyMsg::from_type(KeyType::F1).with_alt());
861 m.insert("\x1b[1;3Q", KeyMsg::from_type(KeyType::F2).with_alt());
862 m.insert("\x1b[1;3R", KeyMsg::from_type(KeyType::F3).with_alt());
863 m.insert("\x1b[1;3S", KeyMsg::from_type(KeyType::F4).with_alt());
864
865 m.insert("\x1b[11~", KeyMsg::from_type(KeyType::F1));
867 m.insert("\x1b[12~", KeyMsg::from_type(KeyType::F2));
868 m.insert("\x1b[13~", KeyMsg::from_type(KeyType::F3));
869 m.insert("\x1b[14~", KeyMsg::from_type(KeyType::F4));
870
871 m.insert("\x1b[15~", KeyMsg::from_type(KeyType::F5));
873 m.insert("\x1b[15;3~", KeyMsg::from_type(KeyType::F5).with_alt());
874 m.insert("\x1b[17~", KeyMsg::from_type(KeyType::F6));
875 m.insert("\x1b[17;3~", KeyMsg::from_type(KeyType::F6).with_alt());
876 m.insert("\x1b[18~", KeyMsg::from_type(KeyType::F7));
877 m.insert("\x1b[18;3~", KeyMsg::from_type(KeyType::F7).with_alt());
878 m.insert("\x1b[19~", KeyMsg::from_type(KeyType::F8));
879 m.insert("\x1b[19;3~", KeyMsg::from_type(KeyType::F8).with_alt());
880 m.insert("\x1b[20~", KeyMsg::from_type(KeyType::F9));
881 m.insert("\x1b[20;3~", KeyMsg::from_type(KeyType::F9).with_alt());
882 m.insert("\x1b[21~", KeyMsg::from_type(KeyType::F10));
883 m.insert("\x1b[21;3~", KeyMsg::from_type(KeyType::F10).with_alt());
884 m.insert("\x1b[23~", KeyMsg::from_type(KeyType::F11));
885 m.insert("\x1b[23;3~", KeyMsg::from_type(KeyType::F11).with_alt());
886 m.insert("\x1b[24~", KeyMsg::from_type(KeyType::F12));
887 m.insert("\x1b[24;3~", KeyMsg::from_type(KeyType::F12).with_alt());
888
889 m.insert("\x1b[1;2P", KeyMsg::from_type(KeyType::F13));
891 m.insert("\x1b[1;2Q", KeyMsg::from_type(KeyType::F14));
892 m.insert("\x1b[25~", KeyMsg::from_type(KeyType::F13));
893 m.insert("\x1b[26~", KeyMsg::from_type(KeyType::F14));
894 m.insert("\x1b[25;3~", KeyMsg::from_type(KeyType::F13).with_alt());
895 m.insert("\x1b[26;3~", KeyMsg::from_type(KeyType::F14).with_alt());
896 m.insert("\x1b[1;2R", KeyMsg::from_type(KeyType::F15));
897 m.insert("\x1b[1;2S", KeyMsg::from_type(KeyType::F16));
898 m.insert("\x1b[28~", KeyMsg::from_type(KeyType::F15));
899 m.insert("\x1b[29~", KeyMsg::from_type(KeyType::F16));
900 m.insert("\x1b[28;3~", KeyMsg::from_type(KeyType::F15).with_alt());
901 m.insert("\x1b[29;3~", KeyMsg::from_type(KeyType::F16).with_alt());
902
903 m.insert("\x1b[15;2~", KeyMsg::from_type(KeyType::F17));
905 m.insert("\x1b[17;2~", KeyMsg::from_type(KeyType::F18));
906 m.insert("\x1b[18;2~", KeyMsg::from_type(KeyType::F19));
907 m.insert("\x1b[19;2~", KeyMsg::from_type(KeyType::F20));
908 m.insert("\x1b[31~", KeyMsg::from_type(KeyType::F17));
909 m.insert("\x1b[32~", KeyMsg::from_type(KeyType::F18));
910 m.insert("\x1b[33~", KeyMsg::from_type(KeyType::F19));
911 m.insert("\x1b[34~", KeyMsg::from_type(KeyType::F20));
912
913 m.insert("\x1bOA", KeyMsg::from_type(KeyType::Up));
915 m.insert("\x1bOB", KeyMsg::from_type(KeyType::Down));
916 m.insert("\x1bOC", KeyMsg::from_type(KeyType::Right));
917 m.insert("\x1bOD", KeyMsg::from_type(KeyType::Left));
918
919 m
920});
921
922#[cfg(test)]
923mod tests {
924 use super::*;
925 use proptest::prelude::*;
926
927 fn sequence_strategy() -> impl Strategy<Value = &'static str> {
928 let sequences: Vec<&'static str> = SEQUENCES.keys().copied().collect();
929 prop::sample::select(sequences)
930 }
931
932 #[test]
933 fn test_parse_sequence_arrows() {
934 assert_eq!(
935 parse_sequence(b"\x1b[A"),
936 Some(KeyMsg::from_type(KeyType::Up))
937 );
938 assert_eq!(
939 parse_sequence(b"\x1b[B"),
940 Some(KeyMsg::from_type(KeyType::Down))
941 );
942 assert_eq!(
943 parse_sequence(b"\x1b[C"),
944 Some(KeyMsg::from_type(KeyType::Right))
945 );
946 assert_eq!(
947 parse_sequence(b"\x1b[D"),
948 Some(KeyMsg::from_type(KeyType::Left))
949 );
950 }
951
952 #[test]
953 fn test_parse_sequence_alt_arrows() {
954 assert_eq!(
955 parse_sequence(b"\x1b[1;3A"),
956 Some(KeyMsg::from_type(KeyType::Up).with_alt())
957 );
958 assert_eq!(
959 parse_sequence(b"\x1b[1;3B"),
960 Some(KeyMsg::from_type(KeyType::Down).with_alt())
961 );
962 }
963
964 #[test]
965 fn test_parse_sequence_ctrl_arrows() {
966 assert_eq!(
967 parse_sequence(b"\x1b[1;5A"),
968 Some(KeyMsg::from_type(KeyType::CtrlUp))
969 );
970 assert_eq!(
971 parse_sequence(b"\x1b[1;5B"),
972 Some(KeyMsg::from_type(KeyType::CtrlDown))
973 );
974 assert_eq!(
975 parse_sequence(b"\x1b[1;5C"),
976 Some(KeyMsg::from_type(KeyType::CtrlRight))
977 );
978 assert_eq!(
979 parse_sequence(b"\x1b[1;5D"),
980 Some(KeyMsg::from_type(KeyType::CtrlLeft))
981 );
982 }
983
984 #[test]
985 fn test_parse_sequence_ctrl_alt_arrows() {
986 assert_eq!(
988 parse_sequence(b"\x1b[1;7A"),
989 Some(KeyMsg::from_type(KeyType::CtrlUp).with_alt())
990 );
991 assert_eq!(
992 parse_sequence(b"\x1b[1;7B"),
993 Some(KeyMsg::from_type(KeyType::CtrlDown).with_alt())
994 );
995 assert_eq!(
996 parse_sequence(b"\x1b[1;7C"),
997 Some(KeyMsg::from_type(KeyType::CtrlRight).with_alt())
998 );
999 assert_eq!(
1000 parse_sequence(b"\x1b[1;7D"),
1001 Some(KeyMsg::from_type(KeyType::CtrlLeft).with_alt())
1002 );
1003
1004 let key = parse_sequence(b"\x1b[1;7A").unwrap();
1006 assert!(key.alt);
1007 assert_eq!(key.key_type, KeyType::CtrlUp);
1008 }
1009
1010 #[test]
1011 fn test_parse_sequence_ctrl_shift_alt_arrows() {
1012 assert_eq!(
1014 parse_sequence(b"\x1b[1;8A"),
1015 Some(KeyMsg::from_type(KeyType::CtrlShiftUp).with_alt())
1016 );
1017 assert_eq!(
1018 parse_sequence(b"\x1b[1;8B"),
1019 Some(KeyMsg::from_type(KeyType::CtrlShiftDown).with_alt())
1020 );
1021 assert_eq!(
1022 parse_sequence(b"\x1b[1;8C"),
1023 Some(KeyMsg::from_type(KeyType::CtrlShiftRight).with_alt())
1024 );
1025 assert_eq!(
1026 parse_sequence(b"\x1b[1;8D"),
1027 Some(KeyMsg::from_type(KeyType::CtrlShiftLeft).with_alt())
1028 );
1029 }
1030
1031 #[test]
1032 fn test_parse_sequence_function_keys() {
1033 assert_eq!(
1034 parse_sequence(b"\x1bOP"),
1035 Some(KeyMsg::from_type(KeyType::F1))
1036 );
1037 assert_eq!(
1038 parse_sequence(b"\x1b[15~"),
1039 Some(KeyMsg::from_type(KeyType::F5))
1040 );
1041 assert_eq!(
1042 parse_sequence(b"\x1b[24~"),
1043 Some(KeyMsg::from_type(KeyType::F12))
1044 );
1045 }
1046
1047 #[test]
1048 fn test_parse_sequence_special_keys() {
1049 assert_eq!(
1050 parse_sequence(b"\x1b[Z"),
1051 Some(KeyMsg::from_type(KeyType::ShiftTab))
1052 );
1053 assert_eq!(
1054 parse_sequence(b"\x1b[2~"),
1055 Some(KeyMsg::from_type(KeyType::Insert))
1056 );
1057 assert_eq!(
1058 parse_sequence(b"\x1b[3~"),
1059 Some(KeyMsg::from_type(KeyType::Delete))
1060 );
1061 assert_eq!(
1062 parse_sequence(b"\x1b[5~"),
1063 Some(KeyMsg::from_type(KeyType::PgUp))
1064 );
1065 assert_eq!(
1066 parse_sequence(b"\x1b[6~"),
1067 Some(KeyMsg::from_type(KeyType::PgDown))
1068 );
1069 }
1070
1071 #[test]
1072 fn test_parse_sequence_home_end() {
1073 assert_eq!(
1074 parse_sequence(b"\x1b[H"),
1075 Some(KeyMsg::from_type(KeyType::Home))
1076 );
1077 assert_eq!(
1078 parse_sequence(b"\x1b[1~"),
1079 Some(KeyMsg::from_type(KeyType::Home))
1080 );
1081 assert_eq!(
1082 parse_sequence(b"\x1b[F"),
1083 Some(KeyMsg::from_type(KeyType::End))
1084 );
1085 assert_eq!(
1086 parse_sequence(b"\x1b[4~"),
1087 Some(KeyMsg::from_type(KeyType::End))
1088 );
1089 }
1090
1091 #[test]
1092 fn test_parse_sequence_unknown() {
1093 assert_eq!(parse_sequence(b"unknown"), None);
1094 assert_eq!(parse_sequence(b"\x1b[999~"), None);
1095 }
1096
1097 #[test]
1098 fn test_key_msg_display() {
1099 let key = KeyMsg::from_type(KeyType::Enter);
1100 assert_eq!(key.to_string(), "enter");
1101
1102 let key = KeyMsg::from_char('a');
1103 assert_eq!(key.to_string(), "a");
1104
1105 let key = KeyMsg::from_char('a').with_alt();
1106 assert_eq!(key.to_string(), "alt+a");
1107
1108 let key = KeyMsg::from_runes(vec!['h', 'e', 'l', 'l', 'o']).with_paste();
1109 assert_eq!(key.to_string(), "[hello]");
1110 }
1111
1112 #[test]
1113 fn test_key_type_display() {
1114 assert_eq!(KeyType::Enter.to_string(), "enter");
1115 assert_eq!(KeyType::CtrlC.to_string(), "ctrl+c");
1116 assert_eq!(KeyType::F1.to_string(), "f1");
1117 }
1118
1119 #[test]
1120 fn test_key_type_is_ctrl() {
1121 assert!(KeyType::CtrlC.is_ctrl());
1122 assert!(KeyType::Enter.is_ctrl());
1123 assert!(!KeyType::Up.is_ctrl());
1124 }
1125
1126 #[test]
1127 fn test_key_type_is_function_key() {
1128 assert!(KeyType::F1.is_function_key());
1129 assert!(KeyType::F12.is_function_key());
1130 assert!(!KeyType::Enter.is_function_key());
1131 }
1132
1133 #[test]
1134 fn test_key_type_is_cursor() {
1135 assert!(KeyType::Up.is_cursor());
1136 assert!(KeyType::CtrlLeft.is_cursor());
1137 assert!(!KeyType::Enter.is_cursor());
1138 }
1139
1140 proptest! {
1141 #[test]
1142 fn prop_parse_sequence_matches_table(seq in sequence_strategy()) {
1143 let expected = SEQUENCES.get(seq).cloned();
1144 prop_assert_eq!(parse_sequence(seq.as_bytes()), expected);
1145 }
1146 }
1147}