add nihav-sndplay
[nihav-player.git] / sndplay / src / command.rs
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 }