1use std::io::{self, Write};
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
22pub struct Modifiers {
23 pub ctrl: bool,
25 pub alt: bool,
27 pub shift: bool,
29}
30
31impl Modifiers {
32 pub const NONE: Self = Self {
34 ctrl: false,
35 alt: false,
36 shift: false,
37 };
38
39 pub const CTRL: Self = Self {
41 ctrl: true,
42 alt: false,
43 shift: false,
44 };
45
46 pub const ALT: Self = Self {
48 ctrl: false,
49 alt: true,
50 shift: false,
51 };
52
53 pub const SHIFT: Self = Self {
55 ctrl: false,
56 alt: false,
57 shift: true,
58 };
59
60 #[must_use]
62 pub const fn any(self) -> bool {
63 self.ctrl || self.alt || self.shift
64 }
65
66 #[must_use]
69 pub fn csi_param(self) -> u8 {
70 let mut param = 1u8;
71 if self.shift {
72 param += 1;
73 }
74 if self.alt {
75 param += 2;
76 }
77 if self.ctrl {
78 param += 4;
79 }
80 param
81 }
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
86pub enum Key {
87 Char(char),
89 F(u8),
91 Backspace,
93 Enter,
95 Tab,
97 Escape,
99 Up,
101 Down,
103 Left,
105 Right,
107 Home,
109 End,
111 PageUp,
113 PageDown,
115 Insert,
117 Delete,
119}
120
121#[derive(Debug, Clone, Copy, PartialEq, Eq)]
123pub struct KeyEvent {
124 pub key: Key,
126 pub modifiers: Modifiers,
128}
129
130impl KeyEvent {
131 #[must_use]
133 pub const fn new(key: Key, modifiers: Modifiers) -> Self {
134 Self { key, modifiers }
135 }
136
137 #[must_use]
139 pub const fn plain(key: Key) -> Self {
140 Self {
141 key,
142 modifiers: Modifiers::NONE,
143 }
144 }
145}
146
147impl From<char> for KeyEvent {
148 fn from(c: char) -> Self {
149 Self::plain(Key::Char(c))
150 }
151}
152
153#[must_use]
171pub fn key_to_sequence(event: KeyEvent) -> Vec<u8> {
172 let KeyEvent { key, modifiers } = event;
173
174 match key {
175 Key::Char(c) => char_sequence(c, modifiers),
176 Key::F(n) => function_key_sequence(n, modifiers),
177 Key::Backspace => backspace_sequence(modifiers),
178 Key::Enter => enter_sequence(modifiers),
179 Key::Tab => tab_sequence(modifiers),
180 Key::Escape => escape_sequence(modifiers),
181 Key::Up => cursor_key_sequence(b'A', modifiers),
182 Key::Down => cursor_key_sequence(b'B', modifiers),
183 Key::Right => cursor_key_sequence(b'C', modifiers),
184 Key::Left => cursor_key_sequence(b'D', modifiers),
185 Key::Home => home_end_sequence(b'H', modifiers),
186 Key::End => home_end_sequence(b'F', modifiers),
187 Key::PageUp => page_key_sequence(5, modifiers),
188 Key::PageDown => page_key_sequence(6, modifiers),
189 Key::Insert => insert_delete_sequence(2, modifiers),
190 Key::Delete => insert_delete_sequence(3, modifiers),
191 }
192}
193
194fn char_sequence(c: char, modifiers: Modifiers) -> Vec<u8> {
196 if modifiers.ctrl
198 && !modifiers.alt
199 && let Some(ctrl_byte) = ctrl_char(c)
200 {
201 return vec![ctrl_byte];
202 }
203
204 if modifiers.alt && !modifiers.ctrl {
206 let mut seq = vec![0x1b]; let ch = if modifiers.shift {
208 c.to_ascii_uppercase()
209 } else {
210 c
211 };
212 let mut buf = [0u8; 4];
213 seq.extend_from_slice(ch.encode_utf8(&mut buf).as_bytes());
214 return seq;
215 }
216
217 if modifiers.ctrl
219 && modifiers.alt
220 && let Some(ctrl_byte) = ctrl_char(c)
221 {
222 return vec![0x1b, ctrl_byte]; }
224
225 let ch = if modifiers.shift {
227 c.to_ascii_uppercase()
228 } else {
229 c
230 };
231 let mut buf = [0u8; 4];
232 ch.encode_utf8(&mut buf).as_bytes().to_vec()
233}
234
235fn ctrl_char(c: char) -> Option<u8> {
237 match c.to_ascii_lowercase() {
238 'a'..='z' => Some(c.to_ascii_lowercase() as u8 - b'a' + 1),
239 '[' | '3' => Some(0x1b), '\\' | '4' => Some(0x1c), ']' | '5' => Some(0x1d), '^' | '6' => Some(0x1e), '_' | '7' => Some(0x1f), '?' | '8' => Some(0x7f), '@' | '2' | ' ' => Some(0x00), _ => None,
247 }
248}
249
250fn function_key_sequence(n: u8, modifiers: Modifiers) -> Vec<u8> {
252 let (code, use_tilde) = match n {
255 1 => (b'P', false),
256 2 => (b'Q', false),
257 3 => (b'R', false),
258 4 => (b'S', false),
259 5 => (15, true),
260 6 => (17, true),
261 7 => (18, true),
262 8 => (19, true),
263 9 => (20, true),
264 10 => (21, true),
265 11 => (23, true),
266 12 => (24, true),
267 _ => return Vec::new(),
268 };
269
270 if use_tilde {
271 if modifiers.any() {
272 format!("\x1b[{};{}~", code, modifiers.csi_param()).into_bytes()
274 } else {
275 format!("\x1b[{}~", code).into_bytes()
277 }
278 } else if modifiers.any() {
279 format!("\x1b[1;{}{}", modifiers.csi_param(), code as char).into_bytes()
281 } else {
282 vec![0x1b, b'O', code]
284 }
285}
286
287fn backspace_sequence(modifiers: Modifiers) -> Vec<u8> {
289 if modifiers.ctrl {
290 vec![0x08] } else if modifiers.alt {
292 vec![0x1b, 0x7f] } else {
294 vec![0x7f] }
296}
297
298fn enter_sequence(modifiers: Modifiers) -> Vec<u8> {
300 if modifiers.alt {
301 vec![0x1b, 0x0d] } else {
303 vec![0x0d] }
305}
306
307fn tab_sequence(modifiers: Modifiers) -> Vec<u8> {
309 if modifiers.shift {
310 b"\x1b[Z".to_vec() } else if modifiers.alt {
312 vec![0x1b, 0x09] } else {
314 vec![0x09] }
316}
317
318fn escape_sequence(modifiers: Modifiers) -> Vec<u8> {
320 if modifiers.alt {
321 vec![0x1b, 0x1b] } else {
323 vec![0x1b] }
325}
326
327fn cursor_key_sequence(code: u8, modifiers: Modifiers) -> Vec<u8> {
329 if modifiers.any() {
330 format!("\x1b[1;{}{}", modifiers.csi_param(), code as char).into_bytes()
332 } else {
333 vec![0x1b, b'[', code]
335 }
336}
337
338fn home_end_sequence(code: u8, modifiers: Modifiers) -> Vec<u8> {
340 if modifiers.any() {
341 format!("\x1b[1;{}{}", modifiers.csi_param(), code as char).into_bytes()
343 } else {
344 vec![0x1b, b'[', code]
346 }
347}
348
349fn page_key_sequence(code: u8, modifiers: Modifiers) -> Vec<u8> {
351 if modifiers.any() {
352 format!("\x1b[{};{}~", code, modifiers.csi_param()).into_bytes()
354 } else {
355 format!("\x1b[{}~", code).into_bytes()
357 }
358}
359
360fn insert_delete_sequence(code: u8, modifiers: Modifiers) -> Vec<u8> {
362 if modifiers.any() {
363 format!("\x1b[{};{}~", code, modifiers.csi_param()).into_bytes()
365 } else {
366 format!("\x1b[{}~", code).into_bytes()
368 }
369}
370
371#[derive(Debug, Clone)]
376pub struct BracketedPaste {
377 enabled: bool,
378}
379
380impl Default for BracketedPaste {
381 fn default() -> Self {
382 Self::new()
383 }
384}
385
386impl BracketedPaste {
387 pub const START: &'static [u8] = b"\x1b[200~";
389 pub const END: &'static [u8] = b"\x1b[201~";
391
392 #[must_use]
394 pub const fn new() -> Self {
395 Self { enabled: false }
396 }
397
398 #[must_use]
400 pub const fn is_enabled(&self) -> bool {
401 self.enabled
402 }
403
404 pub fn enable(&mut self) {
406 self.enabled = true;
407 }
408
409 pub fn disable(&mut self) {
411 self.enabled = false;
412 }
413
414 pub fn set_enabled(&mut self, enabled: bool) {
416 self.enabled = enabled;
417 }
418
419 #[must_use]
427 pub fn wrap(&self, text: &[u8]) -> Vec<u8> {
428 if self.enabled {
429 if Self::contains_delimiter(text) {
430 return text.to_vec();
431 }
432 let mut result = Vec::with_capacity(Self::START.len() + text.len() + Self::END.len());
433 result.extend_from_slice(Self::START);
434 result.extend_from_slice(text);
435 result.extend_from_slice(Self::END);
436 result
437 } else {
438 text.to_vec()
439 }
440 }
441
442 #[must_use]
443 fn contains_delimiter(text: &[u8]) -> bool {
444 text.windows(Self::START.len())
445 .any(|window| window == Self::START)
446 || text
447 .windows(Self::END.len())
448 .any(|window| window == Self::END)
449 }
450}
451
452pub struct InputForwarder<W: Write> {
454 writer: W,
455 bracketed_paste: BracketedPaste,
456}
457
458impl<W: Write> InputForwarder<W> {
459 pub fn new(writer: W) -> Self {
461 Self {
462 writer,
463 bracketed_paste: BracketedPaste::new(),
464 }
465 }
466
467 #[must_use]
469 pub const fn bracketed_paste(&self) -> &BracketedPaste {
470 &self.bracketed_paste
471 }
472
473 pub fn bracketed_paste_mut(&mut self) -> &mut BracketedPaste {
475 &mut self.bracketed_paste
476 }
477
478 pub fn set_bracketed_paste(&mut self, enabled: bool) {
480 self.bracketed_paste.set_enabled(enabled);
481 }
482
483 pub fn forward_key(&mut self, event: KeyEvent) -> io::Result<()> {
485 let seq = key_to_sequence(event);
486 if !seq.is_empty() {
487 self.writer.write_all(&seq)?;
488 self.writer.flush()?;
489 }
490 Ok(())
491 }
492
493 pub fn forward_keys(&mut self, events: &[KeyEvent]) -> io::Result<()> {
495 for event in events {
496 let seq = key_to_sequence(*event);
497 if !seq.is_empty() {
498 self.writer.write_all(&seq)?;
499 }
500 }
501 self.writer.flush()
502 }
503
504 pub fn forward_raw(&mut self, data: &[u8]) -> io::Result<()> {
506 self.writer.write_all(data)?;
507 self.writer.flush()
508 }
509
510 pub fn forward_paste(&mut self, text: &str) -> io::Result<()> {
512 let data = self.bracketed_paste.wrap(text.as_bytes());
513 self.writer.write_all(&data)?;
514 self.writer.flush()
515 }
516
517 pub fn writer_mut(&mut self) -> &mut W {
519 &mut self.writer
520 }
521
522 pub fn into_writer(self) -> W {
524 self.writer
525 }
526}
527
528#[cfg(test)]
529mod tests {
530 use super::*;
531
532 #[test]
533 fn test_plain_char() {
534 let event = KeyEvent::plain(Key::Char('a'));
535 assert_eq!(key_to_sequence(event), b"a");
536 }
537
538 #[test]
539 fn test_shift_char() {
540 let event = KeyEvent::new(Key::Char('a'), Modifiers::SHIFT);
541 assert_eq!(key_to_sequence(event), b"A");
542 }
543
544 #[test]
545 fn test_ctrl_char() {
546 let event = KeyEvent::new(Key::Char('c'), Modifiers::CTRL);
547 assert_eq!(key_to_sequence(event), vec![0x03]); }
549
550 #[test]
551 fn test_ctrl_a() {
552 let event = KeyEvent::new(Key::Char('a'), Modifiers::CTRL);
553 assert_eq!(key_to_sequence(event), vec![0x01]); }
555
556 #[test]
557 fn test_ctrl_z() {
558 let event = KeyEvent::new(Key::Char('z'), Modifiers::CTRL);
559 assert_eq!(key_to_sequence(event), vec![0x1a]); }
561
562 #[test]
563 fn test_alt_char() {
564 let event = KeyEvent::new(Key::Char('x'), Modifiers::ALT);
565 assert_eq!(key_to_sequence(event), vec![0x1b, b'x']);
566 }
567
568 #[test]
569 fn test_ctrl_alt_char() {
570 let event = KeyEvent::new(
571 Key::Char('c'),
572 Modifiers {
573 ctrl: true,
574 alt: true,
575 shift: false,
576 },
577 );
578 assert_eq!(key_to_sequence(event), vec![0x1b, 0x03]);
579 }
580
581 #[test]
582 fn test_arrow_keys() {
583 assert_eq!(key_to_sequence(KeyEvent::plain(Key::Up)), b"\x1b[A");
584 assert_eq!(key_to_sequence(KeyEvent::plain(Key::Down)), b"\x1b[B");
585 assert_eq!(key_to_sequence(KeyEvent::plain(Key::Right)), b"\x1b[C");
586 assert_eq!(key_to_sequence(KeyEvent::plain(Key::Left)), b"\x1b[D");
587 }
588
589 #[test]
590 fn test_arrow_with_modifiers() {
591 let event = KeyEvent::new(Key::Up, Modifiers::CTRL);
592 assert_eq!(key_to_sequence(event), b"\x1b[1;5A");
593
594 let event = KeyEvent::new(Key::Down, Modifiers::SHIFT);
595 assert_eq!(key_to_sequence(event), b"\x1b[1;2B");
596
597 let event = KeyEvent::new(Key::Left, Modifiers::ALT);
598 assert_eq!(key_to_sequence(event), b"\x1b[1;3D");
599 }
600
601 #[test]
602 fn test_function_keys_f1_f4() {
603 assert_eq!(key_to_sequence(KeyEvent::plain(Key::F(1))), b"\x1bOP");
604 assert_eq!(key_to_sequence(KeyEvent::plain(Key::F(2))), b"\x1bOQ");
605 assert_eq!(key_to_sequence(KeyEvent::plain(Key::F(3))), b"\x1bOR");
606 assert_eq!(key_to_sequence(KeyEvent::plain(Key::F(4))), b"\x1bOS");
607 }
608
609 #[test]
610 fn test_function_keys_f5_f12() {
611 assert_eq!(key_to_sequence(KeyEvent::plain(Key::F(5))), b"\x1b[15~");
612 assert_eq!(key_to_sequence(KeyEvent::plain(Key::F(6))), b"\x1b[17~");
613 assert_eq!(key_to_sequence(KeyEvent::plain(Key::F(10))), b"\x1b[21~");
614 assert_eq!(key_to_sequence(KeyEvent::plain(Key::F(12))), b"\x1b[24~");
615 }
616
617 #[test]
618 fn test_function_keys_with_modifiers() {
619 let event = KeyEvent::new(Key::F(1), Modifiers::SHIFT);
620 assert_eq!(key_to_sequence(event), b"\x1b[1;2P");
621
622 let event = KeyEvent::new(Key::F(5), Modifiers::CTRL);
623 assert_eq!(key_to_sequence(event), b"\x1b[15;5~");
624 }
625
626 #[test]
627 fn test_backspace() {
628 assert_eq!(key_to_sequence(KeyEvent::plain(Key::Backspace)), vec![0x7f]);
629 }
630
631 #[test]
632 fn test_enter() {
633 assert_eq!(key_to_sequence(KeyEvent::plain(Key::Enter)), vec![0x0d]);
634 }
635
636 #[test]
637 fn test_tab() {
638 assert_eq!(key_to_sequence(KeyEvent::plain(Key::Tab)), vec![0x09]);
639 }
640
641 #[test]
642 fn test_shift_tab() {
643 let event = KeyEvent::new(Key::Tab, Modifiers::SHIFT);
644 assert_eq!(key_to_sequence(event), b"\x1b[Z");
645 }
646
647 #[test]
648 fn test_escape() {
649 assert_eq!(key_to_sequence(KeyEvent::plain(Key::Escape)), vec![0x1b]);
650 }
651
652 #[test]
653 fn test_home_end() {
654 assert_eq!(key_to_sequence(KeyEvent::plain(Key::Home)), b"\x1b[H");
655 assert_eq!(key_to_sequence(KeyEvent::plain(Key::End)), b"\x1b[F");
656 }
657
658 #[test]
659 fn test_page_keys() {
660 assert_eq!(key_to_sequence(KeyEvent::plain(Key::PageUp)), b"\x1b[5~");
661 assert_eq!(key_to_sequence(KeyEvent::plain(Key::PageDown)), b"\x1b[6~");
662 }
663
664 #[test]
665 fn test_insert_delete() {
666 assert_eq!(key_to_sequence(KeyEvent::plain(Key::Insert)), b"\x1b[2~");
667 assert_eq!(key_to_sequence(KeyEvent::plain(Key::Delete)), b"\x1b[3~");
668 }
669
670 #[test]
671 fn test_modifiers_csi_param() {
672 assert_eq!(Modifiers::NONE.csi_param(), 1);
673 assert_eq!(Modifiers::SHIFT.csi_param(), 2);
674 assert_eq!(Modifiers::ALT.csi_param(), 3);
675 assert_eq!(Modifiers::CTRL.csi_param(), 5);
676
677 let ctrl_shift = Modifiers {
678 ctrl: true,
679 alt: false,
680 shift: true,
681 };
682 assert_eq!(ctrl_shift.csi_param(), 6);
683
684 let all = Modifiers {
685 ctrl: true,
686 alt: true,
687 shift: true,
688 };
689 assert_eq!(all.csi_param(), 8);
690 }
691
692 #[test]
693 fn test_bracketed_paste_disabled() {
694 let bp = BracketedPaste::new();
695 assert!(!bp.is_enabled());
696 assert_eq!(bp.wrap(b"hello"), b"hello");
697 }
698
699 #[test]
700 fn test_bracketed_paste_enabled() {
701 let mut bp = BracketedPaste::new();
702 bp.enable();
703 assert!(bp.is_enabled());
704
705 let wrapped = bp.wrap(b"hello");
706 assert!(wrapped.starts_with(BracketedPaste::START));
707 assert!(wrapped.ends_with(BracketedPaste::END));
708 assert!(wrapped[BracketedPaste::START.len()..].starts_with(b"hello"));
709 }
710
711 #[test]
712 fn test_bracketed_paste_falls_back_to_raw_when_payload_contains_end_delimiter() {
713 let mut bp = BracketedPaste::new();
714 bp.enable();
715
716 let payload = b"prefix\x1b[201~suffix";
717 let wrapped = bp.wrap(payload);
718 assert_eq!(wrapped, payload);
719 }
720
721 #[test]
722 fn test_bracketed_paste_falls_back_to_raw_when_payload_contains_start_delimiter() {
723 let mut bp = BracketedPaste::new();
724 bp.enable();
725
726 let payload = b"prefix\x1b[200~suffix";
727 let wrapped = bp.wrap(payload);
728 assert_eq!(wrapped, payload);
729 }
730
731 #[test]
732 fn test_input_forwarder() {
733 let mut buffer = Vec::new();
734
735 {
736 let mut forwarder = InputForwarder::new(&mut buffer);
737 forwarder
738 .forward_key(KeyEvent::plain(Key::Char('a')))
739 .unwrap();
740 forwarder.forward_key(KeyEvent::plain(Key::Enter)).unwrap();
741 }
742
743 assert_eq!(buffer, vec![b'a', 0x0d]);
744 }
745
746 #[test]
747 fn test_input_forwarder_paste() {
748 let mut buffer = Vec::new();
749
750 {
751 let mut forwarder = InputForwarder::new(&mut buffer);
752 forwarder.forward_paste("text").unwrap();
753 }
754
755 assert_eq!(buffer, b"text");
756 }
757
758 #[test]
759 fn test_input_forwarder_bracketed_paste() {
760 let mut buffer = Vec::new();
761
762 {
763 let mut forwarder = InputForwarder::new(&mut buffer);
764 forwarder.set_bracketed_paste(true);
765 forwarder.forward_paste("text").unwrap();
766 }
767
768 let expected = [BracketedPaste::START, b"text", BracketedPaste::END].concat();
769 assert_eq!(buffer, expected);
770 }
771
772 #[test]
773 fn test_input_forwarder_bracketed_paste_uses_raw_fallback_for_delimiter_payload() {
774 let mut buffer = Vec::new();
775 let payload = "alpha\u{1b}[201~omega";
776
777 {
778 let mut forwarder = InputForwarder::new(&mut buffer);
779 forwarder.set_bracketed_paste(true);
780 forwarder.forward_paste(payload).unwrap();
781 }
782
783 assert_eq!(buffer, payload.as_bytes());
784 }
785
786 #[test]
787 fn test_utf8_char() {
788 let event = KeyEvent::plain(Key::Char('日'));
789 let seq = key_to_sequence(event);
790 assert_eq!(std::str::from_utf8(&seq).unwrap(), "日");
791 }
792
793 #[test]
794 fn test_emoji_char() {
795 let event = KeyEvent::plain(Key::Char('🎉'));
796 let seq = key_to_sequence(event);
797 assert_eq!(std::str::from_utf8(&seq).unwrap(), "🎉");
798 }
799
800 #[test]
801 fn test_ctrl_special_chars() {
802 let event = KeyEvent::new(Key::Char('['), Modifiers::CTRL);
804 assert_eq!(key_to_sequence(event), vec![0x1b]);
805
806 let event = KeyEvent::new(Key::Char('@'), Modifiers::CTRL);
808 assert_eq!(key_to_sequence(event), vec![0x00]);
809
810 let event = KeyEvent::new(Key::Char('?'), Modifiers::CTRL);
812 assert_eq!(key_to_sequence(event), vec![0x7f]);
813 }
814}