1
0
Fork 0
mirror of https://github.com/alacritty/alacritty.git synced 2024-11-11 13:51:01 -05:00

Extend SGR and VT200 (normal) mouse support

With this commit, Alacritty now reports presses and releases of all
three mouse buttons properly, dragging events with all three buttons,
and mouse movement events where no button is pressed.

It does not report more than three buttons due to inherent limitations
of the VT200 and SGR protocol modes. It does not report modifier keys on
mouse buttons due to practical considerations.

Fixes #714, #506.
This commit is contained in:
Celti Burroughs 2018-01-26 14:28:43 -07:00 committed by Joe Wilm
parent 5dad4919a2
commit fb43c73a38
3 changed files with 92 additions and 50 deletions

View file

@ -148,6 +148,8 @@ pub struct Mouse {
pub x: u32,
pub y: u32,
pub left_button_state: ElementState,
pub middle_button_state: ElementState,
pub right_button_state: ElementState,
pub last_click_timestamp: Instant,
pub click_state: ClickState,
pub scroll_px: i32,
@ -164,6 +166,8 @@ impl Default for Mouse {
y: 0,
last_click_timestamp: Instant::now(),
left_button_state: ElementState::Released,
middle_button_state: ElementState::Released,
right_button_state: ElementState::Released,
click_state: ClickState::None,
scroll_px: 0,
line: Line(0),

View file

@ -278,21 +278,33 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
};
self.ctx.mouse_mut().cell_side = cell_side;
if self.ctx.mouse_mut().left_button_state == ElementState::Pressed {
let report_mode = mode::TermMode::MOUSE_REPORT_CLICK | mode::TermMode::MOUSE_MOTION;
if modifiers.shift || !self.ctx.terminal_mode().intersects(report_mode) {
self.ctx.update_selection(Point {
line: point.line,
col: point.col
}, cell_side);
} else if self.ctx.terminal_mode().contains(mode::TermMode::MOUSE_MOTION)
// Only report motion when changing cells
&& (
prev_line != self.ctx.mouse_mut().line
|| prev_col != self.ctx.mouse_mut().column
)
{
self.mouse_report(32, ElementState::Pressed);
let report_mode = mode::TermMode::MOUSE_REPORT_CLICK;
let motion_mode = mode::TermMode::MOUSE_MOTION | mode::TermMode::MOUSE_DRAG;
if self.ctx.mouse_mut().left_button_state == ElementState::Pressed
&& (
modifiers.shift
|| !self.ctx.terminal_mode().intersects(report_mode | motion_mode)
)
{
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_mut().line
|| prev_col != self.ctx.mouse_mut().column
)
{
if self.ctx.mouse_mut().left_button_state == ElementState::Pressed {
self.mouse_report(32 + 0, ElementState::Pressed);
} else if self.ctx.mouse_mut().middle_button_state == ElementState::Pressed {
self.mouse_report(32 + 1, ElementState::Pressed);
} else if self.ctx.mouse_mut().right_button_state == ElementState::Pressed {
self.mouse_report(32 + 2, ElementState::Pressed);
} else if self.ctx.terminal_mode().contains(mode::TermMode::MOUSE_MOTION) {
self.mouse_report(32 + 3, ElementState::Pressed);
}
}
}
@ -330,7 +342,11 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
if self.ctx.terminal_mode().contains(mode::TermMode::SGR_MOUSE) {
self.sgr_mouse_report(button, state);
} else {
self.normal_mouse_report(button);
if let ElementState::Released = state {
self.normal_mouse_report(3);
} else {
self.normal_mouse_report(button);
}
}
}
@ -346,7 +362,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
}
}
pub fn on_mouse_press(&mut self, modifiers: ModifiersState) {
pub fn on_mouse_press(&mut self, button: MouseButton, modifiers: ModifiersState) {
let now = Instant::now();
let elapsed = self.ctx.mouse_mut().last_click_timestamp.elapsed();
self.ctx.mouse_mut().last_click_timestamp = now;
@ -362,9 +378,15 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
},
_ => {
self.ctx.clear_selection();
let report_modes = mode::TermMode::MOUSE_REPORT_CLICK | mode::TermMode::MOUSE_MOTION;
let report_modes = mode::TermMode::MOUSE_REPORT_CLICK | mode::TermMode::MOUSE_DRAG | mode::TermMode::MOUSE_MOTION;
if !modifiers.shift && self.ctx.terminal_mode().intersects(report_modes) {
self.mouse_report(0, ElementState::Pressed);
match button {
MouseButton::Left => self.mouse_report(0, ElementState::Pressed),
MouseButton::Middle => self.mouse_report(1, ElementState::Pressed),
MouseButton::Right => self.mouse_report(2, ElementState::Pressed),
// Can't properly report more than three buttons.
MouseButton::Other(_) => (),
};
return;
}
@ -373,11 +395,17 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
};
}
pub fn on_mouse_release(&mut self, modifiers: ModifiersState) {
let report_modes = mode::TermMode::MOUSE_REPORT_CLICK | mode::TermMode::MOUSE_MOTION;
pub fn on_mouse_release(&mut self, button: MouseButton, modifiers: ModifiersState) {
let report_modes = mode::TermMode::MOUSE_REPORT_CLICK | mode::TermMode::MOUSE_DRAG | mode::TermMode::MOUSE_MOTION;
if !modifiers.shift && self.ctx.terminal_mode().intersects(report_modes)
{
self.mouse_report(3, ElementState::Released);
match button {
MouseButton::Left => self.mouse_report(0, ElementState::Released),
MouseButton::Middle => self.mouse_report(1, ElementState::Released),
MouseButton::Right => self.mouse_report(2, ElementState::Released),
// Can't properly report more than three buttons.
MouseButton::Other(_) => (),
};
return;
}
@ -385,7 +413,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
}
pub fn on_mouse_wheel(&mut self, delta: MouseScrollDelta, phase: TouchPhase) {
let mouse_modes = mode::TermMode::MOUSE_REPORT_CLICK | mode::TermMode::MOUSE_MOTION | mode::TermMode::SGR_MOUSE;
let mouse_modes = mode::TermMode::MOUSE_REPORT_CLICK | mode::TermMode::MOUSE_DRAG | mode::TermMode::MOUSE_MOTION | mode::TermMode::SGR_MOUSE;
if !self.ctx.terminal_mode().intersects(mouse_modes | mode::TermMode::ALT_SCREEN) {
return;
}
@ -466,17 +494,20 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
}
pub fn mouse_input(&mut self, state: ElementState, button: MouseButton, modifiers: ModifiersState) {
if let MouseButton::Left = button {
let state = mem::replace(&mut self.ctx.mouse_mut().left_button_state, state);
if self.ctx.mouse_mut().left_button_state != state {
match self.ctx.mouse_mut().left_button_state {
ElementState::Pressed => {
self.on_mouse_press(modifiers);
},
ElementState::Released => {
self.on_mouse_release(modifiers);
}
}
let button_state = match button {
MouseButton::Left => Some(mem::replace(&mut self.ctx.mouse_mut().left_button_state, state)),
MouseButton::Middle => Some(mem::replace(&mut self.ctx.mouse_mut().middle_button_state, state)),
MouseButton::Right => Some(mem::replace(&mut self.ctx.mouse_mut().right_button_state, state)),
// Can't properly report more than three buttons.
MouseButton::Other(_) => None,
};
if let Some(button_state) = button_state {
if button_state != state {
match state {
ElementState::Pressed => self.on_mouse_press(button, modifiers),
ElementState::Released => self.on_mouse_release(button, modifiers),
};
}
}

View file

@ -418,20 +418,21 @@ impl<'a> Iterator for RenderableCellsIter<'a> {
pub mod mode {
bitflags! {
pub struct TermMode: u16 {
const SHOW_CURSOR = 0b0_0000_0000_0001;
const APP_CURSOR = 0b0_0000_0000_0010;
const APP_KEYPAD = 0b0_0000_0000_0100;
const MOUSE_REPORT_CLICK = 0b0_0000_0000_1000;
const BRACKETED_PASTE = 0b0_0000_0001_0000;
const SGR_MOUSE = 0b0_0000_0010_0000;
const MOUSE_MOTION = 0b0_0000_0100_0000;
const LINE_WRAP = 0b0_0000_1000_0000;
const LINE_FEED_NEW_LINE = 0b0_0001_0000_0000;
const ORIGIN = 0b0_0010_0000_0000;
const INSERT = 0b0_0100_0000_0000;
const FOCUS_IN_OUT = 0b0_1000_0000_0000;
const ALT_SCREEN = 0b1_0000_0000_0000;
const ANY = 0b1_1111_1111_1111;
const SHOW_CURSOR = 0b00_0000_0000_0001;
const APP_CURSOR = 0b00_0000_0000_0010;
const APP_KEYPAD = 0b00_0000_0000_0100;
const MOUSE_REPORT_CLICK = 0b00_0000_0000_1000;
const BRACKETED_PASTE = 0b00_0000_0001_0000;
const SGR_MOUSE = 0b00_0000_0010_0000;
const MOUSE_MOTION = 0b00_0000_0100_0000;
const LINE_WRAP = 0b00_0000_1000_0000;
const LINE_FEED_NEW_LINE = 0b00_0001_0000_0000;
const ORIGIN = 0b00_0010_0000_0000;
const INSERT = 0b00_0100_0000_0000;
const FOCUS_IN_OUT = 0b00_1000_0000_0000;
const ALT_SCREEN = 0b01_0000_0000_0000;
const MOUSE_DRAG = 0b10_0000_0000_0000;
const ANY = 0b11_1111_1111_1111;
const NONE = 0;
}
}
@ -1832,7 +1833,10 @@ impl ansi::Handler for Term {
self.mode.insert(mode::TermMode::MOUSE_REPORT_CLICK);
self.set_mouse_cursor(MouseCursor::Arrow);
},
ansi::Mode::ReportCellMouseMotion |
ansi::Mode::ReportCellMouseMotion => {
self.mode.insert(mode::TermMode::MOUSE_DRAG);
self.set_mouse_cursor(MouseCursor::Arrow);
},
ansi::Mode::ReportAllMouseMotion => {
self.mode.insert(mode::TermMode::MOUSE_MOTION);
self.set_mouse_cursor(MouseCursor::Arrow);
@ -1869,7 +1873,10 @@ impl ansi::Handler for Term {
self.mode.remove(mode::TermMode::MOUSE_REPORT_CLICK);
self.set_mouse_cursor(MouseCursor::Text);
},
ansi::Mode::ReportCellMouseMotion |
ansi::Mode::ReportCellMouseMotion => {
self.mode.remove(mode::TermMode::MOUSE_DRAG);
self.set_mouse_cursor(MouseCursor::Text);
},
ansi::Mode::ReportAllMouseMotion => {
self.mode.remove(mode::TermMode::MOUSE_MOTION);
self.set_mouse_cursor(MouseCursor::Text);