--- /dev/null
+use libc::{termios, tcgetattr, tcsetattr};
+use std::sync::mpsc;
+use std::io::Read;
+use std::thread;
+
+#[derive(Clone,Copy,Debug,PartialEq)]
+pub enum Command {
+ Debug,
+ Mute,
+ VolumeUp,
+ VolumeDown,
+ Pause,
+ Back(u8),
+ Forward(u8),
+ Repeat,
+ Next,
+ Quit,
+}
+
+pub struct CmdLineState {
+ orig_state: termios
+}
+impl CmdLineState {
+ pub fn new() -> Self {
+ let mut orig_state: termios = unsafe { std::mem::uninitialized() };
+ unsafe { tcgetattr(0, &mut orig_state); }
+ let mut new_state = orig_state;
+ new_state.c_lflag &= !(libc::ECHO | libc::ICANON);
+ unsafe { tcsetattr(0, 0, &new_state); }
+ Self { orig_state }
+ }
+ pub fn restore(&self) {
+ unsafe { tcsetattr(0, 0, &self.orig_state); }
+ }
+}
+
+pub fn start_reader() -> (thread::JoinHandle<()>, mpsc::Receiver<Command>) {
+ let (sender, cmd_receiver) = mpsc::sync_channel(100);
+ (thread::spawn(move || {
+ let stdin = std::io::stdin();
+ let mut file = stdin.lock();
+ let mut ch = [0u8; 8];
+ loop {
+/*
+\e char -> alt-char (including alt-[)
+\e [ char -> A - up B - down C - right D - left F - end H - home (or \e[OF/OH)
+\e [ O P-S -> F1-F4
+\e [ num ~ -> 5 - PgUp, 6 - PgDn, 15, 17-24 - F5,F6-F12
+*/
+ match file.read(&mut ch) {
+ Ok(1) => {
+ match ch[0] {
+ b'\n' => { sender.send(Command::Next).unwrap(); },
+ b' ' => { sender.send(Command::Pause).unwrap(); },
+ b'q' | b'Q' | 0o33 => {
+ sender.send(Command::Quit).unwrap();
+ break;
+ },
+ b'+' => { sender.send(Command::VolumeUp).unwrap(); },
+ b'-' => { sender.send(Command::VolumeDown).unwrap(); },
+ b'd' | b'D' => { sender.send(Command::Debug).unwrap(); },
+ b'm' | b'M' => { sender.send(Command::Mute).unwrap(); },
+ _ => {},
+ };
+ },
+ Ok(3) => {
+ if ch[0] == 0o33 {
+ if ch[1] == b'[' {
+ match ch[2] {
+ b'D' => { sender.send(Command::Back(1)).unwrap(); },
+ b'B' => { sender.send(Command::Back(2)).unwrap(); },
+ b'C' => { sender.send(Command::Forward(1)).unwrap(); },
+ b'A' => { sender.send(Command::Forward(2)).unwrap(); },
+ b'F' => { sender.send(Command::Repeat).unwrap(); },
+ b'H' => { sender.send(Command::Next).unwrap(); },
+ _ => {},
+ };
+ } else if ch[1] == b'O' {
+ match ch[2] {
+ b'F' => { sender.send(Command::Repeat).unwrap(); },
+ b'H' => { sender.send(Command::Next).unwrap(); },
+ _ => {},
+ };
+ }
+ }
+ },
+ Ok(4) => {
+ if ch[0] == 0o33 && ch[1] == b'[' && ch[3] == b'~' {
+ match ch[2] {
+ b'5' => { sender.send(Command::Forward(3)).unwrap(); },
+ b'6' => { sender.send(Command::Back(3)).unwrap(); },
+ _ => {},
+ };
+ }
+ },
+ Ok(_) => {},
+ Err(_) => break,
+ }
+ }
+ }), cmd_receiver)
+}
\ No newline at end of file