Skip to content

Commit

Permalink
term, gui: allow tracking multiple buttons
Browse files Browse the repository at this point in the history
We were previously only remembering the most recently pressed
button, but that's a lossy thing to do.

This commit remembers the button presses so that we can correctly
report all press/release events.

refs: #973
  • Loading branch information
wez committed Aug 8, 2021
1 parent 19206cc commit 6d9957e
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 46 deletions.
17 changes: 14 additions & 3 deletions term/src/terminalstate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ pub struct TerminalState {
mouse_tracking: bool,
/// Button events enabled
button_event_mouse: bool,
current_mouse_button: MouseButton,
current_mouse_buttons: Vec<MouseButton>,
last_mouse_move: Option<MouseEvent>,
cursor_visible: bool,

Expand Down Expand Up @@ -441,7 +441,7 @@ impl TerminalState {
g1_charset: CharSet::DecLineDrawing,
shift_out: false,
newline_mode: false,
current_mouse_button: MouseButton::None,
current_mouse_buttons: vec![],
tabs: TabStop::new(size.physical_cols, 8),
title: "wezterm".to_string(),
icon_title: None,
Expand Down Expand Up @@ -597,7 +597,18 @@ impl TerminalState {
/// Advise the terminal about a change in its focus state
pub fn focus_changed(&mut self, focused: bool) {
if !focused {
self.current_mouse_button = MouseButton::None;
// notify app of release of buttons
let buttons = self.current_mouse_buttons.clone();
for b in buttons {
self.mouse_event(MouseEvent {
kind: MouseEventKind::Release,
button: b,
modifiers: KeyModifiers::NONE,
x: 0,
y: 0,
})
.ok();
}
}
if self.focus_tracking {
write!(self.writer, "{}{}", CSI, if focused { "I" } else { "O" }).ok();
Expand Down
71 changes: 38 additions & 33 deletions term/src/terminalstate/mouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ impl TerminalState {
position.max(0).saturating_add(1 + 32).min(127) as u8 as char
}

fn mouse_report_button_number(&self, event: &MouseEvent) -> i8 {
fn mouse_report_button_number(&self, event: &MouseEvent) -> (i8, MouseButton) {
let button = match event.button {
MouseButton::None => self.current_mouse_button,
MouseButton::None => self
.current_mouse_buttons
.last()
.copied()
.unwrap_or(MouseButton::None),
b => b,
};
let mut code = match button {
Expand All @@ -38,11 +42,11 @@ impl TerminalState {
code += 16;
}

code
(code, button)
}

fn mouse_wheel(&mut self, event: MouseEvent) -> anyhow::Result<()> {
let button = self.mouse_report_button_number(&event);
let (button, _button) = self.mouse_report_button_number(&event);

if self.sgr_mouse
&& (self.mouse_tracking || self.button_event_mouse || self.any_event_mouse)
Expand Down Expand Up @@ -81,13 +85,14 @@ impl TerminalState {
}

fn mouse_button_press(&mut self, event: MouseEvent) -> anyhow::Result<()> {
self.current_mouse_button = event.button;
let (button, event_button) = self.mouse_report_button_number(&event);
self.current_mouse_buttons.retain(|&b| b != event_button);
self.current_mouse_buttons.push(event_button);

if !(self.mouse_tracking || self.button_event_mouse || self.any_event_mouse) {
return Ok(());
}

let button = self.mouse_report_button_number(&event);
if self.sgr_mouse {
write!(
self.writer,
Expand All @@ -112,39 +117,38 @@ impl TerminalState {
}

fn mouse_button_release(&mut self, event: MouseEvent) -> anyhow::Result<()> {
if self.current_mouse_button != MouseButton::None
&& (self.mouse_tracking || self.button_event_mouse || self.any_event_mouse)
{
if self.sgr_mouse {
let release_button = self.mouse_report_button_number(&event);
self.current_mouse_button = MouseButton::None;
write!(
self.writer,
"\x1b[<{};{};{}m",
release_button,
event.x + 1,
event.y + 1
)?;
self.writer.flush()?;
} else {
let release_button = 3;
self.current_mouse_button = MouseButton::None;
write!(
self.writer,
"\x1b[M{}{}{}",
(32 + release_button) as u8 as char,
Self::legacy_mouse_coord(event.x as i64),
Self::legacy_mouse_coord(event.y),
)?;
self.writer.flush()?;
let (release_button, button) = self.mouse_report_button_number(&event);
if !self.current_mouse_buttons.is_empty() {
self.current_mouse_buttons.retain(|&b| b != button);
if self.mouse_tracking || self.button_event_mouse || self.any_event_mouse {
if self.sgr_mouse {
write!(
self.writer,
"\x1b[<{};{};{}m",
release_button,
event.x + 1,
event.y + 1
)?;
self.writer.flush()?;
} else {
let release_button = 3;
write!(
self.writer,
"\x1b[M{}{}{}",
(32 + release_button) as u8 as char,
Self::legacy_mouse_coord(event.x as i64),
Self::legacy_mouse_coord(event.y),
)?;
self.writer.flush()?;
}
}
}

Ok(())
}

fn mouse_move(&mut self, event: MouseEvent) -> anyhow::Result<()> {
let reportable = self.any_event_mouse || self.current_mouse_button != MouseButton::None;
let reportable = self.any_event_mouse || !self.current_mouse_buttons.is_empty();
// Note: self.mouse_tracking on its own is for clicks, not drags!
if reportable && (self.button_event_mouse || self.any_event_mouse) {
match self.last_mouse_move.as_ref() {
Expand All @@ -155,7 +159,8 @@ impl TerminalState {
}
self.last_mouse_move.replace(event.clone());

let button = 32 + self.mouse_report_button_number(&event);
let (button, _button) = self.mouse_report_button_number(&event);
let button = 32 + button;

if self.sgr_mouse {
write!(
Expand Down
3 changes: 1 addition & 2 deletions term/src/terminalstate/performer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::input::MouseButton;
use crate::terminal::Alert;
use crate::terminalstate::{default_color_map, CharSet, TabStop};
use crate::{ClipboardSelection, Position, TerminalState, VisibleRowIndex};
Expand Down Expand Up @@ -483,7 +482,7 @@ impl<'a> Performer<'a> {
self.sixel_scrolls_right = false;
self.any_event_mouse = false;
self.button_event_mouse = false;
self.current_mouse_button = MouseButton::None;
self.current_mouse_buttons.clear();
self.cursor_visible = true;
self.g0_charset = CharSet::Ascii;
self.g1_charset = CharSet::DecLineDrawing;
Expand Down
6 changes: 3 additions & 3 deletions wezterm-gui/src/termwindow/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ pub struct TermWindow {

window_background: Option<Arc<ImageData>>,

current_mouse_button: Option<MousePress>,
current_mouse_buttons: Vec<MousePress>,

/// Keeps track of double and triple clicks
last_mouse_click: Option<LastMouseClick>,
Expand Down Expand Up @@ -280,7 +280,7 @@ impl TermWindow {

if self.focused.is_none() {
self.last_mouse_click = None;
self.current_mouse_button = None;
self.current_mouse_buttons.clear();
}

// Reset the cursor blink phase
Expand Down Expand Up @@ -477,7 +477,7 @@ impl TermWindow {
last_scroll_info: RenderableDimensions::default(),
tab_state: RefCell::new(HashMap::new()),
pane_state: RefCell::new(HashMap::new()),
current_mouse_button: None,
current_mouse_buttons: vec![],
last_mouse_click: None,
current_highlight: None,
shape_cache: RefCell::new(LruCache::new(
Expand Down
9 changes: 5 additions & 4 deletions wezterm-gui/src/termwindow/mouseevent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl super::TermWindow {

match event.kind {
WMEK::Release(ref press) => {
self.current_mouse_button = None;
self.current_mouse_buttons.retain(|p| p != press);
if press == &MousePress::Left && self.scroll_drag_start.take().is_some() {
// Completed a scrollbar drag
return;
Expand All @@ -102,7 +102,8 @@ impl super::TermWindow {
Some(click) => click.add(button),
};
self.last_mouse_click = Some(click);
self.current_mouse_button = Some(press.clone());
self.current_mouse_buttons.retain(|p| p != press);
self.current_mouse_buttons.push(*press);
}

WMEK::VertWheel(amount) if !pane.is_mouse_grabbed() && !pane.is_alt_screen_active() => {
Expand Down Expand Up @@ -475,12 +476,12 @@ impl super::TermWindow {
}
}
WMEK::Move => {
if self.current_mouse_button.is_some() {
if !self.current_mouse_buttons.is_empty() {
if let Some(LastMouseClick { streak, button, .. }) =
self.last_mouse_click.as_ref()
{
if Some(*button)
== self.current_mouse_button.as_ref().map(mouse_press_to_tmb)
== self.current_mouse_buttons.last().map(mouse_press_to_tmb)
{
Some(MouseEventTrigger::Drag {
streak: *streak,
Expand Down
2 changes: 1 addition & 1 deletion wezterm-input-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ bitflags! {
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum MousePress {
Left,
Right,
Expand Down

0 comments on commit 6d9957e

Please # to comment.