diff options
author | Christian Duerr <chrisduerr@users.noreply.github.com> | 2018-11-01 19:35:37 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-11-01 19:35:37 +0000 |
commit | 2c37da48b580237ff48f5e841015134dd459b41d (patch) | |
tree | 0dbfc89c525d820d00f1fe6889c7a6f71cc45ede | |
parent | a7d95540384c0b37e75a4bedb0bff688fee7dcf1 (diff) | |
download | alacritty-2c37da48b580237ff48f5e841015134dd459b41d.tar.gz alacritty-2c37da48b580237ff48f5e841015134dd459b41d.zip |
Fix mouse pasting in mouse mode with shift
It is now possible to paste in mouse mode again by making use of the
`shift` key while pressing the mouse button reserved for PasteSelection.
All mouse bindings are now also matching the modifiers in a relaxed way,
so extra modifiers are ignored.
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | src/config.rs | 11 | ||||
-rw-r--r-- | src/input.rs | 75 |
3 files changed, 51 insertions, 37 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 94eb9d9f..1ed8fa98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Moved `cursor_style` to `cursor.style` - Moved `unfocused_hollow_cursor` to `cursor.unfocused_hollow` - Moved `hide_cursor_when_typing` to `mouse.hide_when_typing` +- Mouse bindings now ignore additional modifiers ### Removed @@ -32,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed rendering cursors other than rectangular with the RustType backend - Selection memory leak and glitches in the alternate screen buffer - Invalid default configuration on macOS and Linux +- Middle mouse pasting if mouse mode is enabled ## Version 0.2.1 diff --git a/src/config.rs b/src/config.rs index 9664d5df..ae26f76e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -106,17 +106,6 @@ pub struct Url { pub modifiers: ModifiersState, } -impl Url { - // Make sure that modifiers in the config are always present, - // but ignore surplus modifiers. - pub fn mods_match_relaxed(&self, mods: ModifiersState) -> bool { - !((self.modifiers.shift && !mods.shift) - || (self.modifiers.ctrl && !mods.ctrl) - || (self.modifiers.alt && !mods.alt) - || (self.modifiers.logo && !mods.logo)) - } -} - fn deserialize_modifiers<'a, D>(deserializer: D) -> ::std::result::Result<ModifiersState, D::Error> where D: de::Deserializer<'a> { diff --git a/src/input.rs b/src/input.rs index 9532dc4d..5c4436bd 100644 --- a/src/input.rs +++ b/src/input.rs @@ -113,7 +113,8 @@ impl<T: Eq> Binding<T> { &self, mode: TermMode, mods: ModifiersState, - input: &T + input: &T, + relaxed: bool, ) -> bool { // Check input first since bindings are stored in one big list. This is // the most likely item to fail so prioritizing it here allows more @@ -121,15 +122,15 @@ impl<T: Eq> Binding<T> { self.trigger == *input && self.mode_matches(mode) && self.not_mode_matches(mode) && - self.mods_match(mods) + self.mods_match(mods, relaxed) } } impl<T> Binding<T> { /// Execute the action associate with this binding #[inline] - fn execute<A: ActionContext>(&self, ctx: &mut A) { - self.action.execute(ctx) + fn execute<A: ActionContext>(&self, ctx: &mut A, mouse_mode: bool) { + self.action.execute(ctx, mouse_mode) } #[inline] @@ -143,13 +144,12 @@ impl<T> Binding<T> { } /// Check that two mods descriptions for equivalence - /// - /// Optimized to use single check instead of four (one per modifier) #[inline] - fn mods_match(&self, mods: ModifiersState) -> bool { - assert_eq_size!(ModifiersState, u32); - unsafe { - mem::transmute_copy::<_, u32>(&self.mods) == mem::transmute_copy::<_, u32>(&mods) + fn mods_match(&self, mods: ModifiersState, relaxed: bool) -> bool { + if relaxed { + self.mods.relaxed_eq(mods) + } else { + self.mods == mods } } } @@ -204,7 +204,7 @@ pub enum Action { impl Action { #[inline] - fn execute<A: ActionContext>(&self, ctx: &mut A) { + fn execute<A: ActionContext>(&self, ctx: &mut A, mouse_mode: bool) { match *self { Action::Esc(ref s) => { ctx.scroll(Scroll::Bottom); @@ -223,8 +223,7 @@ impl Action { }, Action::PasteSelection => { // Only paste if mouse events are not captured by an application - let mouse_modes = TermMode::MOUSE_REPORT_CLICK | TermMode::MOUSE_DRAG | TermMode::MOUSE_MOTION; - if !ctx.terminal_mode().intersects(mouse_modes) { + if !mouse_mode { Clipboard::new() .and_then(|clipboard| clipboard.load_selection() ) .map(|contents| { self.paste(ctx, &contents) }) @@ -313,6 +312,21 @@ impl Action { } } +trait RelaxedEq<T: ?Sized = Self> { + fn relaxed_eq(&self, other: T) -> bool; +} + +impl RelaxedEq for ModifiersState { + // Make sure that modifiers in the config are always present, + // but ignore surplus modifiers. + fn relaxed_eq(&self, other: Self) -> bool { + !((self.shift && !other.shift) + || (self.ctrl && !other.ctrl) + || (self.alt && !other.alt) + || (self.logo && !other.logo)) + } +} + impl From<&'static str> for Action { fn from(s: &'static str) -> Action { Action::Esc(s.into()) @@ -344,13 +358,16 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { self.ctx.mouse_mut().block_url_launcher = true; } - if self.ctx.mouse().left_button_state == ElementState::Pressed && - ( modifiers.shift || !self.ctx.terminal_mode().intersects(report_mode)) + if self.ctx.mouse().left_button_state == ElementState::Pressed + && (modifiers.shift || !self.ctx.terminal_mode().intersects(report_mode)) { - self.ctx.update_selection(Point { - line: point.line, - col: point.col - }, cell_side); + self.ctx.update_selection( + Point { + line: point.line, + col: point.col, + }, + cell_side, + ); } else if self.ctx.terminal_mode().intersects(motion_mode) // Only report motion when changing cells && (prev_line != self.ctx.mouse().line || prev_col != self.ctx.mouse().column) @@ -520,7 +537,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { // Spawn URL launcher when clicking on URLs fn launch_url(&self, modifiers: ModifiersState) -> Option<()> { - if !self.mouse_config.url.mods_match_relaxed(modifiers) + if !self.mouse_config.url.modifiers.relaxed_eq(modifiers) || self.ctx.mouse().block_url_launcher { return None; @@ -711,10 +728,11 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { self.ctx.terminal_mode(), input.modifiers, &Key::Scancode(input.scancode), + false, ), _ => if let Some(key) = input.virtual_keycode { let key = Key::from_glutin_input(key); - binding.is_triggered_by(self.ctx.terminal_mode(), input.modifiers, &key) + binding.is_triggered_by(self.ctx.terminal_mode(), input.modifiers, &key, false) } else { false }, @@ -722,7 +740,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { if is_triggered { // binding was triggered; run the action - binding.execute(&mut self.ctx); + binding.execute(&mut self.ctx, false); has_binding = true; } } @@ -739,9 +757,14 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { fn process_mouse_bindings(&mut self, mods: ModifiersState, button: MouseButton) -> bool { let mut has_binding = false; for binding in self.mouse_bindings { - if binding.is_triggered_by(self.ctx.terminal_mode(), mods, &button) { + if binding.is_triggered_by(self.ctx.terminal_mode(), mods, &button, true) { // binding was triggered; run the action - binding.execute(&mut self.ctx); + let mouse_mode = !mods.shift && self.ctx.terminal_mode().intersects( + TermMode::MOUSE_REPORT_CLICK + | TermMode::MOUSE_DRAG + | TermMode::MOUSE_MOTION + ); + binding.execute(&mut self.ctx, mouse_mode); has_binding = true; } } @@ -944,9 +967,9 @@ mod tests { #[test] fn $name() { if $triggers { - assert!($binding.is_triggered_by($mode, $mods, &KEY)); + assert!($binding.is_triggered_by($mode, $mods, &KEY, false)); } else { - assert!(!$binding.is_triggered_by($mode, $mods, &KEY)); + assert!(!$binding.is_triggered_by($mode, $mods, &KEY, false)); } } } |