update for rustc 1.46
[nihav-player.git] / sndplay / src / command.rs
CommitLineData
b043bd0a
KS
1use libc::{termios, tcgetattr, tcsetattr};
2use std::sync::mpsc;
0a727e05 3use std::io::{Read, BufRead};
b043bd0a 4use std::thread;
0a727e05 5use nihav_core::frame::NATimePoint;
b043bd0a
KS
6
7#[derive(Clone,Copy,Debug,PartialEq)]
8pub enum Command {
9 Debug,
10 Mute,
11 VolumeUp,
12 VolumeDown,
13 Pause,
14 Back(u8),
15 Forward(u8),
0a727e05 16 Seek(u64),
b043bd0a
KS
17 Repeat,
18 Next,
0a727e05
KS
19 PauseDisplay,
20 ResumeDisplay,
b043bd0a
KS
21 Quit,
22}
23
24pub struct CmdLineState {
25 orig_state: termios
26}
27impl CmdLineState {
28 pub fn new() -> Self {
3f9b450c 29 let mut orig_state: termios = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
b043bd0a
KS
30 unsafe { tcgetattr(0, &mut orig_state); }
31 let mut new_state = orig_state;
32 new_state.c_lflag &= !(libc::ECHO | libc::ICANON);
33 unsafe { tcsetattr(0, 0, &new_state); }
34 Self { orig_state }
35 }
0a727e05 36 pub fn new_normal() -> Self {
3f9b450c 37 let mut orig_state: termios = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
0a727e05
KS
38 unsafe { tcgetattr(0, &mut orig_state); }
39 let mut new_state = orig_state;
40 new_state.c_lflag |= libc::ECHO | libc::ICANON;
41 unsafe { tcsetattr(0, 0, &new_state); }
42 Self { orig_state }
43 }
b043bd0a
KS
44 pub fn restore(&self) {
45 unsafe { tcsetattr(0, 0, &self.orig_state); }
46 }
47}
48
49pub fn start_reader() -> (thread::JoinHandle<()>, mpsc::Receiver<Command>) {
50 let (sender, cmd_receiver) = mpsc::sync_channel(100);
51 (thread::spawn(move || {
52 let stdin = std::io::stdin();
53 let mut file = stdin.lock();
54 let mut ch = [0u8; 8];
55 loop {
56/*
57\e char -> alt-char (including alt-[)
58\e [ char -> A - up B - down C - right D - left F - end H - home (or \e[OF/OH)
59\e [ O P-S -> F1-F4
60\e [ num ~ -> 5 - PgUp, 6 - PgDn, 15, 17-24 - F5,F6-F12
61*/
62 match file.read(&mut ch) {
63 Ok(1) => {
64 match ch[0] {
65 b'\n' => { sender.send(Command::Next).unwrap(); },
66 b' ' => { sender.send(Command::Pause).unwrap(); },
67 b'q' | b'Q' | 0o33 => {
68 sender.send(Command::Quit).unwrap();
69 break;
70 },
71 b'+' => { sender.send(Command::VolumeUp).unwrap(); },
72 b'-' => { sender.send(Command::VolumeDown).unwrap(); },
73 b'd' | b'D' => { sender.send(Command::Debug).unwrap(); },
74 b'm' | b'M' => { sender.send(Command::Mute).unwrap(); },
0a727e05
KS
75 b'j' | b'J' => {
76 sender.send(Command::PauseDisplay).unwrap();
77 let cstate = CmdLineState::new_normal();
78 // wait so that the main thread stops displaying
79 thread::sleep(std::time::Duration::from_millis(500));
80 print!("\nJump to: ");
81 let mut str = String::new();
82 let ret = file.read_line(&mut str);
83 cstate.restore();
84 sender.send(Command::ResumeDisplay).unwrap();
85
86 if ret.is_ok() && str.len() > 1 {
87 str.pop(); // newline
88 if let Ok(NATimePoint::Milliseconds(time)) = str.parse::<NATimePoint>() {
89 sender.send(Command::Seek(time)).unwrap();
90 } else {
91 println!("wrong time");
92 }
93 }
94 },
b043bd0a
KS
95 _ => {},
96 };
97 },
98 Ok(3) => {
99 if ch[0] == 0o33 {
100 if ch[1] == b'[' {
101 match ch[2] {
102 b'D' => { sender.send(Command::Back(1)).unwrap(); },
103 b'B' => { sender.send(Command::Back(2)).unwrap(); },
104 b'C' => { sender.send(Command::Forward(1)).unwrap(); },
105 b'A' => { sender.send(Command::Forward(2)).unwrap(); },
106 b'F' => { sender.send(Command::Repeat).unwrap(); },
107 b'H' => { sender.send(Command::Next).unwrap(); },
108 _ => {},
109 };
110 } else if ch[1] == b'O' {
111 match ch[2] {
112 b'F' => { sender.send(Command::Repeat).unwrap(); },
113 b'H' => { sender.send(Command::Next).unwrap(); },
114 _ => {},
115 };
116 }
117 }
118 },
119 Ok(4) => {
120 if ch[0] == 0o33 && ch[1] == b'[' && ch[3] == b'~' {
121 match ch[2] {
122 b'5' => { sender.send(Command::Forward(3)).unwrap(); },
123 b'6' => { sender.send(Command::Back(3)).unwrap(); },
124 _ => {},
125 };
126 }
127 },
128 Ok(_) => {},
129 Err(_) => break,
130 }
131 }
132 }), cmd_receiver)
0a727e05 133}