]>
Commit | Line | Data |
---|---|---|
b043bd0a KS |
1 | use libc::{termios, tcgetattr, tcsetattr}; |
2 | use std::sync::mpsc; | |
0a727e05 | 3 | use std::io::{Read, BufRead}; |
b043bd0a | 4 | use std::thread; |
0a727e05 | 5 | use nihav_core::frame::NATimePoint; |
b043bd0a KS |
6 | |
7 | #[derive(Clone,Copy,Debug,PartialEq)] | |
8 | pub 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 | ||
24 | pub struct CmdLineState { | |
25 | orig_state: termios | |
26 | } | |
27 | impl CmdLineState { | |
28 | pub fn new() -> Self { | |
9d321987 | 29 | let mut orig_state: termios = unsafe { let tmp = std::mem::MaybeUninit::uninit(); tmp.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 { |
9d321987 | 37 | let mut orig_state: termios = unsafe { let tmp = std::mem::MaybeUninit::uninit(); tmp.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 | ||
49 | pub 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 | } |