summaryrefslogtreecommitdiffstats
path: root/src/util
diff options
context:
space:
mode:
authorJiayi Zhao <jeff.no.zhao@gmail.com>2020-02-08 20:58:03 -0500
committerJiayi Zhao <jeff.no.zhao@gmail.com>2020-02-08 20:58:55 -0500
commit656582a6c867c25667661be9b327b4cc73859d7d (patch)
treefe03a1822b752a747da099aeb33a610fb3590067 /src/util
parent7a603efb9b3024438bdce8899fd21bcf353e3832 (diff)
change to using termion's keyboard handling
- user input is now on a seperate thread - this allows for other threads to be added as well - keymap configs have changed to be more user friendly
Diffstat (limited to 'src/util')
-rw-r--r--src/util/event.rs83
-rw-r--r--src/util/key_mapping.rs64
-rw-r--r--src/util/mod.rs78
3 files changed, 225 insertions, 0 deletions
diff --git a/src/util/event.rs b/src/util/event.rs
new file mode 100644
index 0000000..c6559cf
--- /dev/null
+++ b/src/util/event.rs
@@ -0,0 +1,83 @@
+use std::io;
+use std::sync::mpsc;
+use std::thread;
+use std::time::Duration;
+
+use termion::event::Key;
+use termion::input::TermRead;
+
+#[derive(Debug)]
+pub enum Event<I> {
+ Input(I),
+ Tick,
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct Config {
+ pub tick_rate: Duration,
+}
+
+impl Default for Config {
+ fn default() -> Config {
+ Config {
+ tick_rate: Duration::from_millis(250),
+ }
+ }
+}
+
+/// A small event handler that wrap termion input and tick events. Each event
+/// type is handled in its own thread and returned to a common `Receiver`
+pub struct Events {
+ rx: mpsc::Receiver<Event<Key>>,
+ input_handle: thread::JoinHandle<()>,
+// tick_handle: thread::JoinHandle<()>,
+}
+
+impl Events {
+ pub fn new() -> Events {
+ Events::with_config(Config::default())
+ }
+
+ pub fn with_config(config: Config) -> Events {
+ let (tx, rx) = mpsc::channel();
+ let input_handle = {
+ let tx = tx.clone();
+ thread::spawn(move || {
+ let stdin = io::stdin();
+ for evt in stdin.keys() {
+ match evt {
+ Ok(key) => {
+ if let Err(e) = tx.send(Event::Input(key)) {
+ eprintln!("Err: {:#?}", e);
+ return;
+ }
+ }
+ Err(e) => {}
+ }
+ }
+ })
+ };
+/*
+ let tick_handle = {
+ let tx = tx.clone();
+ thread::spawn(move || {
+ let tx = tx.clone();
+ loop {
+ tx.send(Event::Tick).unwrap();
+ thread::sleep(config.tick_rate);
+ }
+ })
+ };
+*/
+ Events {
+ rx,
+ input_handle,
+// tick_handle,
+ }
+ }
+
+ pub fn next(&self) -> Result<Event<Key>, mpsc::RecvError> {
+ self.rx.recv()
+ }
+}
+
diff --git a/src/util/key_mapping.rs b/src/util/key_mapping.rs
new file mode 100644
index 0000000..9d7c182
--- /dev/null
+++ b/src/util/key_mapping.rs
@@ -0,0 +1,64 @@
+use termion::event::Key;
+
+pub fn str_to_key(s: &str) -> Option<Key> {
+ if s.len() == 0 {
+ return None;
+ }
+
+ let key = match s {
+ "backspace" => Some(Key::Backspace),
+ "left" => Some(Key::Left),
+ "right" => Some(Key::Right),
+ "up" => Some(Key::Up),
+ "down" => Some(Key::Down),
+ "home" => Some(Key::Home),
+ "end" => Some(Key::End),
+ "page_up" => Some(Key::PageUp),
+ "page_down" => Some(Key::PageDown),
+ "delete" => Some(Key::Delete),
+ "insert" => Some(Key::Insert),
+ "escape" => Some(Key::Esc),
+ "tab" => Some(Key::BackTab),
+ "f1" => Some(Key::F(1)),
+ "f2" => Some(Key::F(2)),
+ "f3" => Some(Key::F(3)),
+ "f4" => Some(Key::F(4)),
+ "f5" => Some(Key::F(5)),
+ "f6" => Some(Key::F(6)),
+ "f7" => Some(Key::F(7)),
+ "f8" => Some(Key::F(8)),
+ "f9" => Some(Key::F(9)),
+ "f10" => Some(Key::F(10)),
+ "f11" => Some(Key::F(11)),
+ "f12" => Some(Key::F(12)),
+ _ => None,
+ };
+
+ if let Some(a) = key {
+ return key;
+ }
+
+ if s.starts_with("ctrl+") {
+ let ch = s.chars().skip("ctrl+".len()).next();
+ let key = match ch {
+ Some(ch) => Some(Key::Ctrl(ch)),
+ None => None,
+ };
+ return key;
+ } else if s.starts_with("alt+") {
+ let ch = s.chars().skip("alt+".len()).next();
+ let key = match ch {
+ Some(ch) => Some(Key::Alt(ch)),
+ None => None,
+ };
+ return key;
+ } else if s.len() == 1 {
+ let ch = s.chars().next();
+ let key = match ch {
+ Some(ch) => Some(Key::Char(ch)),
+ None => None,
+ };
+ return key;
+ }
+ return None;
+}
diff --git a/src/util/mod.rs b/src/util/mod.rs
new file mode 100644
index 0000000..94ead10
--- /dev/null
+++ b/src/util/mod.rs
@@ -0,0 +1,78 @@
+pub mod event;
+pub mod key_mapping;
+
+use rand::distributions::{Distribution, Uniform};
+use rand::rngs::ThreadRng;
+
+#[derive(Clone)]
+pub struct RandomSignal {
+ distribution: Uniform<u64>,
+ rng: ThreadRng,
+}
+
+impl RandomSignal {
+ pub fn new(lower: u64, upper: u64) -> RandomSignal {
+ RandomSignal {
+ distribution: Uniform::new(lower, upper),
+ rng: rand::thread_rng(),
+ }
+ }
+}
+
+impl Iterator for RandomSignal {
+ type Item = u64;
+ fn next(&mut self) -> Option<u64> {
+ Some(self.distribution.sample(&mut self.rng))
+ }
+}
+
+#[derive(Clone)]
+pub struct SinSignal {
+ x: f64,
+ interval: f64,
+ period: f64,
+ scale: f64,
+}
+
+impl SinSignal {
+ pub fn new(interval: f64, period: f64, scale: f64) -> SinSignal {
+ SinSignal {
+ x: 0.0,
+ interval,
+ period,
+ scale,
+ }
+ }
+}
+
+impl Iterator for SinSignal {
+ type Item = (f64, f64);
+ fn next(&mut self) -> Option<Self::Item> {
+ let point = (self.x, (self.x * 1.0 / self.period).sin() * self.scale);
+ self.x += self.interval;
+ Some(point)
+ }
+}
+
+pub struct TabsState<'a> {
+ pub titles: Vec<&'a str>,
+ pub index: usize,
+}
+
+impl<'a> TabsState<'a> {
+ pub fn new(titles: Vec<&'a str>) -> TabsState {
+ TabsState { titles, index: 0 }
+ }
+ pub fn next(&mut self) {
+ self.index = (self.index + 1) % self.titles.len();
+ }
+
+ pub fn previous(&mut self) {
+ if self.index > 0 {
+ self.index -= 1;
+ } else {
+ self.index = self.titles.len() - 1;
+ }
+ }
+}
+