mirror of
https://github.com/alacritty/alacritty.git
synced 2024-11-18 13:55:23 -05:00
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.
This commit is contained in:
parent
a7d9554038
commit
2c37da48b5
3 changed files with 51 additions and 37 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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>
|
||||
{
|
||||
|
|
75
src/input.rs
75
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue