Produce mouse events in termion backend

This commit is contained in:
Alexandre Bury 2017-10-12 21:24:17 -07:00
parent ab1f4a2ba6
commit acd12326e1
2 changed files with 107 additions and 49 deletions

View File

@ -51,7 +51,7 @@ version = "0.11"
[dependencies.termion] [dependencies.termion]
optional = true optional = true
version = "1.4.0" version = "1.5.0"
[dev-dependencies] [dev-dependencies]
rand = "0.3" rand = "0.3"

View File

@ -5,24 +5,28 @@ extern crate chan_signal;
use self::termion::color as tcolor; use self::termion::color as tcolor;
use self::termion::event::Event as TEvent; use self::termion::event::Event as TEvent;
use self::termion::event::Key as TKey; use self::termion::event::Key as TKey;
use self::termion::input::TermRead; use self::termion::event::MouseButton as TMouseButton;
use self::termion::raw::IntoRawMode; use self::termion::event::MouseEvent as TMouseEvent;
use self::termion::input::{MouseTerminal, TermRead};
use self::termion::raw::{IntoRawMode, RawTerminal};
use self::termion::screen::AlternateScreen; use self::termion::screen::AlternateScreen;
use self::termion::style as tstyle; use self::termion::style as tstyle;
use backend; use backend;
use chan; use chan;
use event::{Event, Key}; use event::{Event, Key, MouseButton, MouseEvent};
use std::cell::Cell; use std::cell::Cell;
use std::io::Write; use std::io::{Stdout, Write};
use std::thread; use std::thread;
use theme; use theme;
use vec::Vec2;
pub struct Concrete { pub struct Concrete {
terminal: AlternateScreen<termion::raw::RawTerminal<::std::io::Stdout>>, terminal: AlternateScreen<MouseTerminal<RawTerminal<Stdout>>>,
current_style: Cell<theme::ColorPair>, current_style: Cell<theme::ColorPair>,
input: chan::Receiver<Event>, input: chan::Receiver<TEvent>,
resize: chan::Receiver<chan_signal::Signal>, resize: chan::Receiver<chan_signal::Signal>,
timeout: Option<u32>, timeout: Option<u32>,
last_button: Option<MouseButton>,
} }
trait Effectable { trait Effectable {
@ -51,6 +55,79 @@ impl Concrete {
with_color(&colors.front, |c| print!("{}", tcolor::Fg(c))); with_color(&colors.front, |c| print!("{}", tcolor::Fg(c)));
with_color(&colors.back, |c| print!("{}", tcolor::Bg(c))); with_color(&colors.back, |c| print!("{}", tcolor::Bg(c)));
} }
fn map_key(&mut self, event: TEvent) -> Event {
match event {
TEvent::Unsupported(bytes) => Event::Unknown(bytes),
TEvent::Key(TKey::Esc) => Event::Key(Key::Esc),
TEvent::Key(TKey::Backspace) => Event::Key(Key::Backspace),
TEvent::Key(TKey::Left) => Event::Key(Key::Left),
TEvent::Key(TKey::Right) => Event::Key(Key::Right),
TEvent::Key(TKey::Up) => Event::Key(Key::Up),
TEvent::Key(TKey::Down) => Event::Key(Key::Down),
TEvent::Key(TKey::Home) => Event::Key(Key::Home),
TEvent::Key(TKey::End) => Event::Key(Key::End),
TEvent::Key(TKey::PageUp) => Event::Key(Key::PageUp),
TEvent::Key(TKey::PageDown) => Event::Key(Key::PageDown),
TEvent::Key(TKey::Delete) => Event::Key(Key::Del),
TEvent::Key(TKey::Insert) => Event::Key(Key::Ins),
TEvent::Key(TKey::F(i)) if i < 12 => Event::Key(Key::from_f(i)),
TEvent::Key(TKey::F(j)) => Event::Unknown(vec![j]),
TEvent::Key(TKey::Char('\n')) => Event::Key(Key::Enter),
TEvent::Key(TKey::Char('\t')) => Event::Key(Key::Tab),
TEvent::Key(TKey::Char(c)) => Event::Char(c),
TEvent::Key(TKey::Ctrl('c')) => Event::Exit,
TEvent::Key(TKey::Ctrl(c)) => Event::CtrlChar(c),
TEvent::Key(TKey::Alt(c)) => Event::AltChar(c),
TEvent::Mouse(TMouseEvent::Press(btn, x, y)) => {
let position = (x - 1, y - 1).into();
let event = match btn {
TMouseButton::Left => MouseEvent::Press(MouseButton::Left),
TMouseButton::Middle => {
MouseEvent::Press(MouseButton::Middle)
}
TMouseButton::Right => {
MouseEvent::Press(MouseButton::Right)
}
TMouseButton::WheelUp => MouseEvent::WheelUp,
TMouseButton::WheelDown => MouseEvent::WheelDown,
};
if let MouseEvent::Press(btn) = event {
self.last_button = Some(btn);
}
Event::Mouse {
event,
position,
offset: Vec2::zero(),
}
}
TEvent::Mouse(TMouseEvent::Release(x, y))
if self.last_button.is_some() =>
{
let event = MouseEvent::Release(self.last_button.unwrap());
let position = (x - 1, y - 1).into();
Event::Mouse {
event,
position,
offset: Vec2::zero(),
}
}
TEvent::Mouse(TMouseEvent::Hold(x, y))
if self.last_button.is_some() =>
{
let event = MouseEvent::Hold(self.last_button.unwrap());
let position = (x - 1, y - 1).into();
Event::Mouse {
event,
position,
offset: Vec2::zero(),
}
}
_ => Event::Unknown(vec![]),
}
}
} }
impl backend::Backend for Concrete { impl backend::Backend for Concrete {
@ -59,14 +136,16 @@ impl backend::Backend for Concrete {
let resize = chan_signal::notify(&[chan_signal::Signal::WINCH]); let resize = chan_signal::notify(&[chan_signal::Signal::WINCH]);
let terminal = AlternateScreen::from( // TODO: lock stdout
let terminal = AlternateScreen::from(MouseTerminal::from(
::std::io::stdout().into_raw_mode().unwrap(), ::std::io::stdout().into_raw_mode().unwrap(),
); ));
let (sender, receiver) = chan::async(); let (sender, receiver) = chan::async();
thread::spawn(move || for key in ::std::io::stdin().events() { thread::spawn(move || for key in ::std::io::stdin().events() {
if let Ok(key) = key { if let Ok(key) = key {
sender.send(map_key(key)) sender.send(key)
} }
}); });
@ -76,6 +155,7 @@ impl backend::Backend for Concrete {
input: receiver, input: receiver,
resize: resize, resize: resize,
timeout: None, timeout: None,
last_button: None,
}; };
backend backend
@ -148,49 +228,27 @@ impl backend::Backend for Concrete {
} }
fn poll_event(&mut self) -> Event { fn poll_event(&mut self) -> Event {
let input = &self.input; let result;
let resize = &self.resize; {
let input = &self.input;
let resize = &self.resize;
if let Some(timeout) = self.timeout { if let Some(timeout) = self.timeout {
let timeout = chan::after_ms(timeout); let timeout = chan::after_ms(timeout);
chan_select!{ chan_select!{
timeout.recv() => return Event::Refresh, timeout.recv() => return Event::Refresh,
resize.recv() => return Event::WindowResize, resize.recv() => return Event::WindowResize,
input.recv() -> input => return input.unwrap(), input.recv() -> input => result = Some(input.unwrap()),
} }
} else { } else {
chan_select!{ chan_select!{
resize.recv() => return Event::WindowResize, resize.recv() => return Event::WindowResize,
input.recv() -> input => return input.unwrap(), input.recv() -> input => result = Some(input.unwrap()),
}
} }
} }
}
}
fn map_key(event: TEvent) -> Event { self.map_key(result.unwrap())
match event {
TEvent::Unsupported(bytes) => Event::Unknown(bytes),
TEvent::Key(TKey::Esc) => Event::Key(Key::Esc),
TEvent::Key(TKey::Backspace) => Event::Key(Key::Backspace),
TEvent::Key(TKey::Left) => Event::Key(Key::Left),
TEvent::Key(TKey::Right) => Event::Key(Key::Right),
TEvent::Key(TKey::Up) => Event::Key(Key::Up),
TEvent::Key(TKey::Down) => Event::Key(Key::Down),
TEvent::Key(TKey::Home) => Event::Key(Key::Home),
TEvent::Key(TKey::End) => Event::Key(Key::End),
TEvent::Key(TKey::PageUp) => Event::Key(Key::PageUp),
TEvent::Key(TKey::PageDown) => Event::Key(Key::PageDown),
TEvent::Key(TKey::Delete) => Event::Key(Key::Del),
TEvent::Key(TKey::Insert) => Event::Key(Key::Ins),
TEvent::Key(TKey::F(i)) if i < 12 => Event::Key(Key::from_f(i)),
TEvent::Key(TKey::F(j)) => Event::Unknown(vec![j]),
TEvent::Key(TKey::Char('\n')) => Event::Key(Key::Enter),
TEvent::Key(TKey::Char('\t')) => Event::Key(Key::Tab),
TEvent::Key(TKey::Char(c)) => Event::Char(c),
TEvent::Key(TKey::Ctrl('c')) => Event::Exit,
TEvent::Key(TKey::Ctrl(c)) => Event::CtrlChar(c),
TEvent::Key(TKey::Alt(c)) => Event::AltChar(c),
_ => Event::Unknown(vec![]),
} }
} }