Event::Unknown now carries the unknown bytes rather than a i32

And termion has been updated to use termion::Event::Unsupported
This commit is contained in:
Alexandre Bury 2017-03-25 11:01:25 -07:00
parent 79212d4be6
commit 2cd2787119
10 changed files with 75 additions and 57 deletions

View File

@ -50,7 +50,7 @@ version = "0.8"
[dependencies.termion] [dependencies.termion]
optional = true optional = true
version = "1.1.1" version = "1.3.0"
[dev-dependencies] [dev-dependencies]
rand = "0.3" rand = "0.3"

View File

@ -1,9 +1,9 @@
extern crate ncurses; extern crate ncurses;
use backend;
use event::{Event, Key};
use self::super::find_closest; use self::super::find_closest;
use backend;
use event::{Event, Key};
use theme::{Color, ColorStyle, Effect}; use theme::{Color, ColorStyle, Effect};
use utf8; use utf8;
@ -226,6 +226,11 @@ fn parse_ncurses_char(ch: i32) -> Event {
// Values 8-10 (H,I,J) are used by other commands, // Values 8-10 (H,I,J) are used by other commands,
// so we probably won't receive them. Meh~ // so we probably won't receive them. Meh~
c @ 1...25 => Event::CtrlChar((b'a' + (c - 1) as u8) as char), c @ 1...25 => Event::CtrlChar((b'a' + (c - 1) as u8) as char),
_ => Event::Unknown(ch), other => {
// Split the i32 into 4 bytes
Event::Unknown((0..4)
.map(|i| ((other >> (8 * i)) & 0xFF) as u8)
.collect())
}
} }
} }

View File

@ -1,10 +1,10 @@
extern crate pancurses; extern crate pancurses;
use backend;
use event::{Event, Key};
use self::super::find_closest; use self::super::find_closest;
use backend;
use event::{Event, Key};
use theme::{Color, ColorStyle, Effect}; use theme::{Color, ColorStyle, Effect};
use utf8; use utf8;
@ -23,9 +23,7 @@ impl backend::Backend for Concrete {
pancurses::curs_set(0); pancurses::curs_set(0);
window.bkgd(pancurses::ColorPair(ColorStyle::Background.id() as u8)); window.bkgd(pancurses::ColorPair(ColorStyle::Background.id() as u8));
Concrete { Concrete { window: window }
window: window,
}
} }
fn screen_size(&self) -> (usize, usize) { fn screen_size(&self) -> (usize, usize) {
@ -88,7 +86,9 @@ impl backend::Backend for Concrete {
// TODO: wait for a very short delay. If more keys are // TODO: wait for a very short delay. If more keys are
// pipelined, it may be an escape sequence. // pipelined, it may be an escape sequence.
pancurses::Input::Character('\u{7f}') | pancurses::Input::Character('\u{7f}') |
pancurses::Input::Character('\u{8}') => Event::Key(Key::Backspace), pancurses::Input::Character('\u{8}') => {
Event::Key(Key::Backspace)
}
pancurses::Input::Character('\u{9}') => Event::Key(Key::Tab), pancurses::Input::Character('\u{9}') => Event::Key(Key::Tab),
pancurses::Input::Character('\u{1b}') => Event::Key(Key::Esc), pancurses::Input::Character('\u{1b}') => Event::Key(Key::Esc),
pancurses::Input::Character(c) if 32 <= (c as u32) && pancurses::Input::Character(c) if 32 <= (c as u32) &&
@ -103,10 +103,22 @@ impl backend::Backend for Concrete {
}) })
.unwrap()) .unwrap())
} }
pancurses::Input::Character(c) => Event::Unknown(c as i32), pancurses::Input::Character(c) => {
let mut bytes = [0u8; 4];
Event::Unknown(c.encode_utf8(&mut bytes)
.as_bytes()
.to_vec())
}
// TODO: Some key combos are not recognized by pancurses, // TODO: Some key combos are not recognized by pancurses,
// but are sent as Unknown. We could still parse them here. // but are sent as Unknown. We could still parse them here.
pancurses::Input::Unknown(i) => Event::Unknown(i), pancurses::Input::Unknown(other) => {
Event::Unknown((0..4)
.map(|i| {
((other >> (8 * i)) & 0xFF) as
u8
})
.collect())
}
// TODO: I honestly have no fucking idea what KeyCodeYes is // TODO: I honestly have no fucking idea what KeyCodeYes is
pancurses::Input::KeyCodeYes => Event::Refresh, pancurses::Input::KeyCodeYes => Event::Refresh,
pancurses::Input::KeyBreak => Event::Key(Key::PauseBreak), pancurses::Input::KeyBreak => Event::Key(Key::PauseBreak),

View File

@ -2,22 +2,22 @@ extern crate termion;
extern crate chan_signal; extern crate chan_signal;
use ::backend;
use chan;
use ::event::{Event, Key};
use self::termion::color as tcolor; use self::termion::color as tcolor;
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::input::TermRead;
use self::termion::raw::IntoRawMode; use self::termion::raw::IntoRawMode;
use self::termion::style as tstyle; use self::termion::style as tstyle;
use backend;
use chan;
use event::{Event, Key};
use std::cell::Cell; use std::cell::Cell;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fmt; use std::fmt;
use std::io::Write; use std::io::Write;
use std::thread; use std::thread;
use std::time;
use ::theme; use theme;
pub struct Concrete { pub struct Concrete {
terminal: termion::raw::RawTerminal<::std::io::Stdout>, terminal: termion::raw::RawTerminal<::std::io::Stdout>,
@ -84,7 +84,7 @@ impl backend::Backend for Concrete {
let terminal = ::std::io::stdout().into_raw_mode().unwrap(); let terminal = ::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().keys() { 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(map_key(key))
} }
@ -185,29 +185,30 @@ impl backend::Backend for Concrete {
} }
} }
fn map_key(key: TKey) -> Event { fn map_key(event: TEvent) -> Event {
match key { match event {
TKey::Esc => Event::Key(Key::Esc), TEvent::Unsupported(bytes) => Event::Unknown(bytes),
TKey::Backspace => Event::Key(Key::Backspace), TEvent::Key(TKey::Esc) => Event::Key(Key::Esc),
TKey::Left => Event::Key(Key::Left), TEvent::Key(TKey::Backspace) => Event::Key(Key::Backspace),
TKey::Right => Event::Key(Key::Right), TEvent::Key(TKey::Left) => Event::Key(Key::Left),
TKey::Up => Event::Key(Key::Up), TEvent::Key(TKey::Right) => Event::Key(Key::Right),
TKey::Down => Event::Key(Key::Down), TEvent::Key(TKey::Up) => Event::Key(Key::Up),
TKey::Home => Event::Key(Key::Home), TEvent::Key(TKey::Down) => Event::Key(Key::Down),
TKey::End => Event::Key(Key::End), TEvent::Key(TKey::Home) => Event::Key(Key::Home),
TKey::PageUp => Event::Key(Key::PageUp), TEvent::Key(TKey::End) => Event::Key(Key::End),
TKey::PageDown => Event::Key(Key::PageDown), TEvent::Key(TKey::PageUp) => Event::Key(Key::PageUp),
TKey::Delete => Event::Key(Key::Del), TEvent::Key(TKey::PageDown) => Event::Key(Key::PageDown),
TKey::Insert => Event::Key(Key::Ins), TEvent::Key(TKey::Delete) => Event::Key(Key::Del),
TKey::F(i) if i < 12 => Event::Key(Key::from_f(i)), TEvent::Key(TKey::Insert) => Event::Key(Key::Ins),
TKey::F(j) => Event::Unknown(-(j as i32)), TEvent::Key(TKey::F(i)) if i < 12 => Event::Key(Key::from_f(i)),
TKey::Char('\n') => Event::Key(Key::Enter), TEvent::Key(TKey::F(j)) => Event::Unknown(vec![j]),
TKey::Char('\t') => Event::Key(Key::Tab), TEvent::Key(TKey::Char('\n')) => Event::Key(Key::Enter),
TKey::Char(c) => Event::Char(c), TEvent::Key(TKey::Char('\t')) => Event::Key(Key::Tab),
TKey::Ctrl('c') => Event::Exit, TEvent::Key(TKey::Char(c)) => Event::Char(c),
TKey::Ctrl(c) => Event::CtrlChar(c), TEvent::Key(TKey::Ctrl('c')) => Event::Exit,
TKey::Alt(c) => Event::AltChar(c), TEvent::Key(TKey::Ctrl(c)) => Event::CtrlChar(c),
_ => Event::Unknown(-1), TEvent::Key(TKey::Alt(c)) => Event::AltChar(c),
_ => Event::Unknown(vec![]),
} }
} }

View File

@ -186,7 +186,7 @@ impl Key {
} }
/// Represents an event as seen by the application. /// Represents an event as seen by the application.
#[derive(PartialEq,Eq,Clone,Copy,Hash,Debug)] #[derive(PartialEq,Eq,Clone,Hash,Debug)]
pub enum Event { pub enum Event {
/// Event fired when the window is resized. /// Event fired when the window is resized.
WindowResize, WindowResize,
@ -217,7 +217,7 @@ pub enum Event {
CtrlAlt(Key), CtrlAlt(Key),
/// An unknown event was received. /// An unknown event was received.
Unknown(i32), Unknown(Vec<u8>),
#[doc(hidden)] #[doc(hidden)]
/// The application is about to exit. /// The application is about to exit.

View File

@ -594,7 +594,7 @@ impl Cursive {
if self.menubar.receive_events() { if self.menubar.receive_events() {
self.menubar.on_event(event).process(self); self.menubar.on_event(event).process(self);
} else { } else {
match self.screen_mut().on_event(event) { match self.screen_mut().on_event(event.clone()) {
// If the event was ignored, // If the event was ignored,
// it is our turn to play with it. // it is our turn to play with it.
EventResult::Ignored => self.on_event(event), EventResult::Ignored => self.on_event(event),

View File

@ -316,7 +316,7 @@ impl View for Dialog {
match self.focus { match self.focus {
// If we are on the content, we can only go down. // If we are on the content, we can only go down.
Focus::Content => { Focus::Content => {
match self.content.on_event(event) { match self.content.on_event(event.clone()) {
EventResult::Ignored if !self.buttons.is_empty() => { EventResult::Ignored if !self.buttons.is_empty() => {
match event { match event {
Event::Key(Key::Down) | Event::Key(Key::Down) |
@ -334,7 +334,7 @@ impl View for Dialog {
} }
// If we are on a button, we have more choice // If we are on a button, we have more choice
Focus::Button(i) => { Focus::Button(i) => {
match self.buttons[i].on_event(event) { match self.buttons[i].on_event(event.clone()) {
EventResult::Ignored => { EventResult::Ignored => {
match event { match event {
// Up goes back to the content // Up goes back to the content

View File

@ -46,7 +46,7 @@ impl<T: View> ViewWrapper for KeyEventView<T> {
wrap_impl!(self.content: T); wrap_impl!(self.content: T);
fn wrap_on_event(&mut self, event: Event) -> EventResult { fn wrap_on_event(&mut self, event: Event) -> EventResult {
match self.content.on_event(event) { match self.content.on_event(event.clone()) {
EventResult::Ignored => { EventResult::Ignored => {
match self.callbacks.get(&event) { match self.callbacks.get(&event) {
None => EventResult::Ignored, None => EventResult::Ignored,

View File

@ -353,7 +353,7 @@ impl View for LinearLayout {
} }
fn on_event(&mut self, event: Event) -> EventResult { fn on_event(&mut self, event: Event) -> EventResult {
match self.children[self.focus].view.on_event(event) { match self.children[self.focus].view.on_event(event.clone()) {
EventResult::Ignored => { EventResult::Ignored => {
match event { match event {
Event::Shift(Key::Tab) if self.focus > 0 => { Event::Shift(Key::Tab) if self.focus > 0 => {

View File

@ -255,7 +255,7 @@ impl View for ListView {
} }
if let Child::Row(_, ref mut view) = self.children[self.focus] { if let Child::Row(_, ref mut view) = self.children[self.focus] {
let result = view.on_event(event); let result = view.on_event(event.clone());
if result.is_consumed() { if result.is_consumed() {
return result; return result;
} }