aboutsummaryrefslogtreecommitdiff
path: root/src/event.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/event.rs')
-rw-r--r--src/event.rs237
1 files changed, 148 insertions, 89 deletions
diff --git a/src/event.rs b/src/event.rs
index 2987fce0..f91b3129 100644
--- a/src/event.rs
+++ b/src/event.rs
@@ -7,7 +7,7 @@ use std::time::{Instant};
use serde_json as json;
use parking_lot::MutexGuard;
-use glutin::{self, ElementState};
+use glutin::{self, ModifiersState, Event, ElementState};
use copypasta::{Clipboard, Load, Store};
use config::{self, Config};
@@ -37,6 +37,9 @@ pub struct ActionContext<'a, N: 'a> {
pub size_info: &'a SizeInfo,
pub mouse: &'a mut Mouse,
pub selection_modified: bool,
+ pub received_count: &'a mut usize,
+ pub suppress_chars: &'a mut bool,
+ pub last_modifiers: &'a mut ModifiersState,
}
impl<'a, N: Notify + 'a> input::ActionContext for ActionContext<'a, N> {
@@ -108,6 +111,21 @@ impl<'a, N: Notify + 'a> input::ActionContext for ActionContext<'a, N> {
fn mouse_mut(&mut self) -> &mut Mouse {
self.mouse
}
+
+ #[inline]
+ fn received_count(&mut self) -> &mut usize {
+ &mut self.received_count
+ }
+
+ #[inline]
+ fn suppress_chars(&mut self) -> &mut bool {
+ &mut self.suppress_chars
+ }
+
+ #[inline]
+ fn last_modifiers(&mut self) -> &mut ModifiersState {
+ &mut self.last_modifiers
+ }
}
pub enum ClickState {
@@ -164,6 +182,10 @@ pub struct Processor<N> {
pub selection: Option<Selection>,
hide_cursor_when_typing: bool,
hide_cursor: bool,
+ received_count: usize,
+ suppress_chars: bool,
+ last_modifiers: ModifiersState,
+ pending_events: Vec<Event>,
}
/// Notify that the terminal was resized
@@ -202,6 +224,10 @@ impl<N: Notify> Processor<N> {
size_info: size_info,
hide_cursor_when_typing: config.hide_cursor_when_typing(),
hide_cursor: false,
+ received_count: 0,
+ suppress_chars: false,
+ last_modifiers: Default::default(),
+ pending_events: Vec::with_capacity(4),
}
}
@@ -210,77 +236,95 @@ impl<N: Notify> Processor<N> {
/// Doesn't take self mutably due to borrow checking. Kinda uggo but w/e.
fn handle_event<'a>(
processor: &mut input::Processor<'a, ActionContext<'a, N>>,
- event: glutin::Event,
+ event: Event,
ref_test: bool,
resize_tx: &mpsc::Sender<(u32, u32)>,
hide_cursor: &mut bool,
) {
match event {
- glutin::Event::Closed => {
- if ref_test {
- // dump grid state
- let grid = processor.ctx.terminal.grid();
-
- let serialized_grid = json::to_string(&grid)
- .expect("serialize grid");
-
- let serialized_size = json::to_string(processor.ctx.terminal.size_info())
- .expect("serialize size");
-
- File::create("./grid.json")
- .and_then(|mut f| f.write_all(serialized_grid.as_bytes()))
- .expect("write grid.json");
-
- File::create("./size.json")
- .and_then(|mut f| f.write_all(serialized_size.as_bytes()))
- .expect("write size.json");
- }
-
- // FIXME should do a more graceful shutdown
- ::std::process::exit(0);
- },
- glutin::Event::Resized(w, h) => {
- resize_tx.send((w, h)).expect("send new size");
- processor.ctx.terminal.dirty = true;
- },
- glutin::Event::KeyboardInput(state, _code, key, mods, string) => {
- // Ensure that key event originates from our window. For example using a shortcut
- // to switch windows could generate a release key event.
- if state == ElementState::Pressed {
- *hide_cursor = true;
+ // Pass on device events
+ Event::DeviceEvent { .. } => (),
+ Event::WindowEvent { event, .. } => {
+ use glutin::WindowEvent::*;
+ match event {
+ Closed => {
+ if ref_test {
+ // dump grid state
+ let grid = processor.ctx.terminal.grid();
+
+ let serialized_grid = json::to_string(&grid)
+ .expect("serialize grid");
+
+ let serialized_size = json::to_string(processor.ctx.terminal.size_info())
+ .expect("serialize size");
+
+ File::create("./grid.json")
+ .and_then(|mut f| f.write_all(serialized_grid.as_bytes()))
+ .expect("write grid.json");
+
+ File::create("./size.json")
+ .and_then(|mut f| f.write_all(serialized_size.as_bytes()))
+ .expect("write size.json");
+ }
+
+ // FIXME should do a more graceful shutdown
+ ::std::process::exit(0);
+ },
+ Resized(w, h) => {
+ resize_tx.send((w, h)).expect("send new size");
+ processor.ctx.terminal.dirty = true;
+ },
+ KeyboardInput { input, .. } => {
+ let glutin::KeyboardInput { state, virtual_keycode, modifiers, .. } = input;
+ processor.process_key(state, virtual_keycode, &modifiers);
+ if state == ElementState::Pressed {
+ // Hide cursor while typing
+ *hide_cursor = true;
+ }
+ },
+ ReceivedCharacter(c) => {
+ processor.received_char(c);
+ },
+ MouseInput { state, button, .. } => {
+ *hide_cursor = false;
+ processor.mouse_input(state, button);
+ processor.ctx.terminal.dirty = true;
+ },
+ MouseMoved { position: (x, y), .. } => {
+ let x = x as i32;
+ let y = y as i32;
+ let x = limit(x, 0, processor.ctx.size_info.width as i32);
+ let y = limit(y, 0, processor.ctx.size_info.height as i32);
+
+ *hide_cursor = false;
+ processor.mouse_moved(x as u32, y as u32);
+
+ if !processor.ctx.selection.is_none() {
+ processor.ctx.terminal.dirty = true;
+ }
+ },
+ MouseWheel { delta, phase, .. } => {
+ *hide_cursor = false;
+ processor.on_mouse_wheel(delta, phase);
+ },
+ Refresh => {
+ processor.ctx.terminal.dirty = true;
+ },
+ Focused(is_focused) => {
+ if is_focused {
+ processor.ctx.terminal.dirty = true;
+ } else {
+ *hide_cursor = false;
+ }
+
+ processor.on_focus_change(is_focused);
+ }
+ _ => (),
}
- processor.process_key(state, key, mods, string);
- },
- glutin::Event::MouseInput(state, button) => {
- *hide_cursor = false;
- processor.mouse_input(state, button);
- processor.ctx.terminal.dirty = true;
},
- glutin::Event::MouseMoved(x, y) => {
- let x = limit(x, 0, processor.ctx.size_info.width as i32);
- let y = limit(y, 0, processor.ctx.size_info.height as i32);
-
- *hide_cursor = false;
- processor.mouse_moved(x as u32, y as u32);
- },
- glutin::Event::MouseWheel(scroll_delta, touch_phase) => {
- *hide_cursor = false;
- processor.on_mouse_wheel(scroll_delta, touch_phase);
- },
- glutin::Event::Refresh |
- glutin::Event::Awakened => {
+ Event::Awakened => {
processor.ctx.terminal.dirty = true;
- },
- glutin::Event::Focused(is_focused) => {
- if is_focused {
- processor.ctx.terminal.dirty = true;
- } else {
- *hide_cursor = false;
- }
-
- processor.on_focus_change(is_focused);
}
- _ => (),
}
}
@@ -296,32 +340,28 @@ impl<N: Notify> Processor<N> {
// be blocked the entire time we wait for input!
let mut terminal;
+ self.pending_events.clear();
+
{
// Ditto on lazy initialization for context and processor.
let context;
let mut processor: input::Processor<ActionContext<N>>;
- // Convenience macro which curries most arguments to handle_event.
- macro_rules! process {
- ($event:expr) => {
- if self.print_events {
- println!("glutin event: {:?}", $event);
- }
- Processor::handle_event(
- &mut processor,
- $event,
- self.ref_test,
- &self.resize_tx,
- &mut self.hide_cursor,
- )
- }
- }
+ let print_events = self.print_events;
- let event = if self.wait_for_event {
- window.wait_events().next()
- } else {
- None
- };
+ let ref_test = self.ref_test;
+ let resize_tx = &self.resize_tx;
+
+ if self.wait_for_event {
+ // A Vec is used here since wait_events can potentially yield
+ // multiple events before the interrupt is handled. For example,
+ // Resize and Moved events.
+ let pending_events = &mut self.pending_events;
+ window.wait_events(|e| {
+ pending_events.push(e);
+ glutin::ControlFlow::Break
+ });
+ }
terminal = term.lock();
@@ -332,21 +372,40 @@ impl<N: Notify> Processor<N> {
mouse: &mut self.mouse,
size_info: &self.size_info,
selection_modified: false,
+ received_count: &mut self.received_count,
+ suppress_chars: &mut self.suppress_chars,
+ last_modifiers: &mut self.last_modifiers,
};
processor = input::Processor {
ctx: context,
mouse_config: &self.mouse_config,
key_bindings: &self.key_bindings[..],
- mouse_bindings: &self.mouse_bindings[..]
+ mouse_bindings: &self.mouse_bindings[..],
};
- if let Some(event) = event {
- process!(event);
- }
+ // Scope needed to that hide_cursor isn't borrowed after the scope
+ // ends.
+ {
+ let hide_cursor = &mut self.hide_cursor;
+ let mut process = |event| {
+ if print_events {
+ println!("glutin event: {:?}", event);
+ }
+ Processor::handle_event(
+ &mut processor,
+ event,
+ ref_test,
+ resize_tx,
+ hide_cursor,
+ );
+ };
+
+ for event in self.pending_events.drain(..) {
+ process(event);
+ }
- for event in window.poll_events() {
- process!(event);
+ window.poll_events(process);
}
if self.hide_cursor_when_typing {