aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Duerr <chrisduerr@users.noreply.github.com>2018-11-01 19:35:37 +0000
committerGitHub <noreply@github.com>2018-11-01 19:35:37 +0000
commit2c37da48b580237ff48f5e841015134dd459b41d (patch)
tree0dbfc89c525d820d00f1fe6889c7a6f71cc45ede
parenta7d95540384c0b37e75a4bedb0bff688fee7dcf1 (diff)
downloadalacritty-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.md2
-rw-r--r--src/config.rs11
-rw-r--r--src/input.rs75
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));
}
}
}