Commit | Line | Data |
---|---|---|
b043bd0a KS |
1 | use libc::{termios, tcgetattr, tcsetattr}; |
2 | use std::sync::mpsc; | |
3 | use std::io::Read; | |
4 | use std::thread; | |
5 | ||
6 | #[derive(Clone,Copy,Debug,PartialEq)] | |
7 | pub enum Command { | |
8 | Debug, | |
9 | Mute, | |
10 | VolumeUp, | |
11 | VolumeDown, | |
12 | Pause, | |
13 | Back(u8), | |
14 | Forward(u8), | |
15 | Repeat, | |
16 | Next, | |
17 | Quit, | |
18 | } | |
19 | ||
20 | pub struct CmdLineState { | |
21 | orig_state: termios | |
22 | } | |
23 | impl CmdLineState { | |
24 | pub fn new() -> Self { | |
25 | let mut orig_state: termios = unsafe { std::mem::uninitialized() }; | |
26 | unsafe { tcgetattr(0, &mut orig_state); } | |
27 | let mut new_state = orig_state; | |
28 | new_state.c_lflag &= !(libc::ECHO | libc::ICANON); | |
29 | unsafe { tcsetattr(0, 0, &new_state); } | |
30 | Self { orig_state } | |
31 | } | |
32 | pub fn restore(&self) { | |
33 | unsafe { tcsetattr(0, 0, &self.orig_state); } | |
34 | } | |
35 | } | |
36 | ||
37 | pub fn start_reader() -> (thread::JoinHandle<()>, mpsc::Receiver<Command>) { | |
38 | let (sender, cmd_receiver) = mpsc::sync_channel(100); | |
39 | (thread::spawn(move || { | |
40 | let stdin = std::io::stdin(); | |
41 | let mut file = stdin.lock(); | |
42 | let mut ch = [0u8; 8]; | |
43 | loop { | |
44 | /* | |
45 | \e char -> alt-char (including alt-[) | |
46 | \e [ char -> A - up B - down C - right D - left F - end H - home (or \e[OF/OH) | |
47 | \e [ O P-S -> F1-F4 | |
48 | \e [ num ~ -> 5 - PgUp, 6 - PgDn, 15, 17-24 - F5,F6-F12 | |
49 | */ | |
50 | match file.read(&mut ch) { | |
51 | Ok(1) => { | |
52 | match ch[0] { | |
53 | b'\n' => { sender.send(Command::Next).unwrap(); }, | |
54 | b' ' => { sender.send(Command::Pause).unwrap(); }, | |
55 | b'q' | b'Q' | 0o33 => { | |
56 | sender.send(Command::Quit).unwrap(); | |
57 | break; | |
58 | }, | |
59 | b'+' => { sender.send(Command::VolumeUp).unwrap(); }, | |
60 | b'-' => { sender.send(Command::VolumeDown).unwrap(); }, | |
61 | b'd' | b'D' => { sender.send(Command::Debug).unwrap(); }, | |
62 | b'm' | b'M' => { sender.send(Command::Mute).unwrap(); }, | |
63 | _ => {}, | |
64 | }; | |
65 | }, | |
66 | Ok(3) => { | |
67 | if ch[0] == 0o33 { | |
68 | if ch[1] == b'[' { | |
69 | match ch[2] { | |
70 | b'D' => { sender.send(Command::Back(1)).unwrap(); }, | |
71 | b'B' => { sender.send(Command::Back(2)).unwrap(); }, | |
72 | b'C' => { sender.send(Command::Forward(1)).unwrap(); }, | |
73 | b'A' => { sender.send(Command::Forward(2)).unwrap(); }, | |
74 | b'F' => { sender.send(Command::Repeat).unwrap(); }, | |
75 | b'H' => { sender.send(Command::Next).unwrap(); }, | |
76 | _ => {}, | |
77 | }; | |
78 | } else if ch[1] == b'O' { | |
79 | match ch[2] { | |
80 | b'F' => { sender.send(Command::Repeat).unwrap(); }, | |
81 | b'H' => { sender.send(Command::Next).unwrap(); }, | |
82 | _ => {}, | |
83 | }; | |
84 | } | |
85 | } | |
86 | }, | |
87 | Ok(4) => { | |
88 | if ch[0] == 0o33 && ch[1] == b'[' && ch[3] == b'~' { | |
89 | match ch[2] { | |
90 | b'5' => { sender.send(Command::Forward(3)).unwrap(); }, | |
91 | b'6' => { sender.send(Command::Back(3)).unwrap(); }, | |
92 | _ => {}, | |
93 | }; | |
94 | } | |
95 | }, | |
96 | Ok(_) => {}, | |
97 | Err(_) => break, | |
98 | } | |
99 | } | |
100 | }), cmd_receiver) | |
101 | } |