aboutsummaryrefslogtreecommitdiff
path: root/alacritty_terminal/src/input.rs
diff options
context:
space:
mode:
Diffstat (limited to 'alacritty_terminal/src/input.rs')
-rw-r--r--alacritty_terminal/src/input.rs130
1 files changed, 96 insertions, 34 deletions
diff --git a/alacritty_terminal/src/input.rs b/alacritty_terminal/src/input.rs
index 5784d9c2..3144e23f 100644
--- a/alacritty_terminal/src/input.rs
+++ b/alacritty_terminal/src/input.rs
@@ -25,7 +25,7 @@ use std::time::Instant;
use glutin::{
ElementState, KeyboardInput, ModifiersState, MouseButton, MouseCursor, MouseScrollDelta,
- TouchPhase,
+ TouchPhase, VirtualKeyCode,
};
use crate::ansi::{ClearMode, Handler};
@@ -73,7 +73,7 @@ pub trait ActionContext {
fn mouse_coords(&self) -> Option<Point>;
fn received_count(&mut self) -> &mut usize;
fn suppress_chars(&mut self) -> &mut bool;
- fn last_modifiers(&mut self) -> &mut ModifiersState;
+ fn modifiers(&mut self) -> &mut Modifiers;
fn scroll(&mut self, scroll: Scroll);
fn hide_window(&mut self);
fn terminal(&self) -> &Term;
@@ -84,6 +84,47 @@ pub trait ActionContext {
fn toggle_simple_fullscreen(&mut self);
}
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Modifiers {
+ mods: ModifiersState,
+ lshift: bool,
+ rshift: bool,
+}
+
+impl Modifiers {
+ pub fn update(&mut self, input: KeyboardInput) {
+ match input.virtual_keycode {
+ Some(VirtualKeyCode::LShift) => self.lshift = input.state == ElementState::Pressed,
+ Some(VirtualKeyCode::RShift) => self.rshift = input.state == ElementState::Pressed,
+ _ => (),
+ }
+
+ self.mods = input.modifiers;
+ }
+
+ pub fn shift(self) -> bool {
+ self.lshift || self.rshift
+ }
+
+ pub fn ctrl(self) -> bool {
+ self.mods.ctrl
+ }
+
+ pub fn logo(self) -> bool {
+ self.mods.logo
+ }
+
+ pub fn alt(self) -> bool {
+ self.mods.alt
+ }
+}
+
+impl From<Modifiers> for ModifiersState {
+ fn from(mods: Modifiers) -> ModifiersState {
+ ModifiersState { shift: mods.shift(), ..mods.mods }
+ }
+}
+
/// Describes a state and action to take in that state
///
/// This is the shared component of `MouseBinding` and `KeyBinding`
@@ -381,41 +422,48 @@ impl From<&'static str> for Action {
}
}
-enum MousePosition {
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub enum MouseState {
Url(Url),
MessageBar,
MessageBarButton,
- Terminal,
+ Mouse,
+ Text,
}
impl<'a, A: ActionContext + 'a> Processor<'a, A> {
- fn mouse_position(&mut self, point: Point, modifiers: ModifiersState) -> MousePosition {
+ fn mouse_state(&mut self, point: Point) -> MouseState {
let mouse_mode =
TermMode::MOUSE_MOTION | TermMode::MOUSE_DRAG | TermMode::MOUSE_REPORT_CLICK;
// Check message bar before URL to ignore URLs in the message bar
if let Some(message) = self.message_at_point(Some(point)) {
if self.message_close_at_point(point, message) {
- return MousePosition::MessageBarButton;
+ return MouseState::MessageBarButton;
} else {
- return MousePosition::MessageBar;
+ return MouseState::MessageBar;
}
}
// Check for URL at point with required modifiers held
- if self.mouse_config.url.mods().relaxed_eq(modifiers)
- && (!self.ctx.terminal().mode().intersects(mouse_mode) || modifiers.shift)
+ let mods = *self.ctx.modifiers();
+ if self.mouse_config.url.mods().relaxed_eq(mods.into())
+ && (!self.ctx.terminal().mode().intersects(mouse_mode) || mods.shift())
&& self.mouse_config.url.launcher.is_some()
{
let buffer_point = self.ctx.terminal().visible_to_buffer(point);
if let Some(url) =
self.ctx.terminal().urls().drain(..).find(|url| url.contains(buffer_point))
{
- return MousePosition::Url(url);
+ return MouseState::Url(url);
}
}
- MousePosition::Terminal
+ if self.ctx.terminal().mode().intersects(mouse_mode) && !self.ctx.modifiers().shift() {
+ MouseState::Mouse
+ } else {
+ MouseState::Text
+ }
}
#[inline]
@@ -445,27 +493,18 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
// Don't launch URLs if mouse has moved
self.ctx.mouse_mut().block_url_launcher = true;
- match self.mouse_position(point, modifiers) {
- MousePosition::Url(url) => {
+ let mouse_state = self.mouse_state(point);
+ self.update_mouse_cursor(mouse_state);
+ match mouse_state {
+ MouseState::Url(url) => {
let url_bounds = url.linear_bounds(self.ctx.terminal());
self.ctx.terminal_mut().set_url_highlight(url_bounds);
- self.ctx.terminal_mut().set_mouse_cursor(MouseCursor::Hand);
- self.ctx.terminal_mut().dirty = true;
},
- MousePosition::MessageBar => {
+ MouseState::MessageBar | MouseState::MessageBarButton => {
self.ctx.terminal_mut().reset_url_highlight();
- self.ctx.terminal_mut().set_mouse_cursor(MouseCursor::Default);
return;
},
- MousePosition::MessageBarButton => {
- self.ctx.terminal_mut().reset_url_highlight();
- self.ctx.terminal_mut().set_mouse_cursor(MouseCursor::Hand);
- return;
- },
- MousePosition::Terminal => {
- self.ctx.terminal_mut().reset_url_highlight();
- self.ctx.terminal_mut().reset_mouse_cursor();
- },
+ _ => self.ctx.terminal_mut().reset_url_highlight(),
}
if self.ctx.mouse().left_button_state == ElementState::Pressed
@@ -798,9 +837,20 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
/// Process key input
pub fn process_key(&mut self, input: KeyboardInput) {
+ self.ctx.modifiers().update(input);
+
+ // Update mouse cursor for temporarily disabling mouse mode
+ if input.virtual_keycode == Some(VirtualKeyCode::LShift)
+ || input.virtual_keycode == Some(VirtualKeyCode::RShift)
+ {
+ if let Some(point) = self.ctx.mouse_coords() {
+ let mouse_state = self.mouse_state(point);
+ self.update_mouse_cursor(mouse_state);
+ }
+ }
+
match input.state {
ElementState::Pressed => {
- *self.ctx.last_modifiers() = input.modifiers;
*self.ctx.received_count() = 0;
*self.ctx.suppress_chars() = false;
@@ -830,7 +880,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
if self.alt_send_esc
&& *self.ctx.received_count() == 0
- && self.ctx.last_modifiers().alt
+ && self.ctx.modifiers().alt()
&& utf8_len == 1
{
bytes.insert(0, b'\x1b');
@@ -934,8 +984,9 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
ElementState::Released => self.copy_selection(),
ElementState::Pressed => {
if self.message_close_at_point(point, message) {
+ let mouse_state = self.mouse_state(point);
+ self.update_mouse_cursor(mouse_state);
self.ctx.terminal_mut().message_buffer_mut().pop();
- self.ctx.terminal_mut().reset_mouse_cursor();
}
self.ctx.clear_selection();
@@ -950,6 +1001,17 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
}
self.ctx.copy_selection(ClipboardType::Selection);
}
+
+ #[inline]
+ fn update_mouse_cursor(&mut self, mouse_state: MouseState) {
+ let mouse_cursor = match mouse_state {
+ MouseState::Url(_) | MouseState::MessageBarButton => MouseCursor::Hand,
+ MouseState::Text => MouseCursor::Text,
+ _ => MouseCursor::Default,
+ };
+
+ self.ctx.terminal_mut().set_mouse_cursor(mouse_cursor);
+ }
}
#[cfg(test)]
@@ -968,7 +1030,7 @@ mod tests {
use crate::selection::Selection;
use crate::term::{SizeInfo, Term, TermMode};
- use super::{Action, Binding, Processor};
+ use super::{Action, Binding, Modifiers, Processor};
const KEY: VirtualKeyCode = VirtualKeyCode::Key0;
@@ -1112,7 +1174,7 @@ mod tests {
pub last_action: MultiClick,
pub received_count: usize,
pub suppress_chars: bool,
- pub last_modifiers: ModifiersState,
+ pub modifiers: Modifiers,
pub window_changes: &'a mut WindowChanges,
}
@@ -1189,8 +1251,8 @@ mod tests {
&mut self.suppress_chars
}
- fn last_modifiers(&mut self) -> &mut ModifiersState {
- &mut self.last_modifiers
+ fn modifiers(&mut self) -> &mut Modifiers {
+ &mut self.modifiers
}
}
@@ -1232,7 +1294,7 @@ mod tests {
last_action: MultiClick::None,
received_count: 0,
suppress_chars: false,
- last_modifiers: ModifiersState::default(),
+ modifiers: Default::default(),
window_changes: &mut WindowChanges::default(),
};