Add support for SGR mouse reporting
According to: http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
This commit is contained in:
parent
a86dfd1a11
commit
82bfc41af7
|
@ -249,6 +249,10 @@ pub enum Mode {
|
||||||
ShowCursor = 25,
|
ShowCursor = 25,
|
||||||
/// ?1000
|
/// ?1000
|
||||||
ReportMouseClicks = 1000,
|
ReportMouseClicks = 1000,
|
||||||
|
/// ?1002
|
||||||
|
ReportMouseMotion = 1002,
|
||||||
|
/// ?1006
|
||||||
|
SgrMouse = 1006,
|
||||||
/// ?1049
|
/// ?1049
|
||||||
SwapScreenAndSetRestoreCursor = 1049,
|
SwapScreenAndSetRestoreCursor = 1049,
|
||||||
/// ?2004
|
/// ?2004
|
||||||
|
@ -267,6 +271,8 @@ impl Mode {
|
||||||
12 => Mode::BlinkingCursor,
|
12 => Mode::BlinkingCursor,
|
||||||
25 => Mode::ShowCursor,
|
25 => Mode::ShowCursor,
|
||||||
1000 => Mode::ReportMouseClicks,
|
1000 => Mode::ReportMouseClicks,
|
||||||
|
1002 => Mode::ReportMouseMotion,
|
||||||
|
1006 => Mode::SgrMouse,
|
||||||
1049 => Mode::SwapScreenAndSetRestoreCursor,
|
1049 => Mode::SwapScreenAndSetRestoreCursor,
|
||||||
2004 => Mode::BracketedPaste,
|
2004 => Mode::BracketedPaste,
|
||||||
_ => return None
|
_ => return None
|
||||||
|
|
|
@ -62,7 +62,7 @@ pub struct Line(pub usize);
|
||||||
|
|
||||||
impl fmt::Display for Line {
|
impl fmt::Display for Line {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "Line({})", self.0)
|
write!(f, "{}", self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ pub struct Column(pub usize);
|
||||||
|
|
||||||
impl fmt::Display for Column {
|
impl fmt::Display for Column {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "Column({})", self.0)
|
write!(f, "{}", self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
66
src/input.rs
66
src/input.rs
|
@ -18,11 +18,8 @@
|
||||||
//! In order to figure that out, state about which modifier keys are pressed
|
//! In order to figure that out, state about which modifier keys are pressed
|
||||||
//! needs to be tracked. Additionally, we need a bit of a state machine to
|
//! needs to be tracked. Additionally, we need a bit of a state machine to
|
||||||
//! determine what to do when a non-modifier key is pressed.
|
//! determine what to do when a non-modifier key is pressed.
|
||||||
//!
|
use std::mem;
|
||||||
//! TODO would be nice to generalize this so it could work with other windowing
|
|
||||||
//! APIs
|
|
||||||
//!
|
|
||||||
//! TODO handling xmodmap would be good
|
|
||||||
use copypasta::{Clipboard, Load, Store};
|
use copypasta::{Clipboard, Load, Store};
|
||||||
use glutin::{ElementState, VirtualKeyCode, MouseButton};
|
use glutin::{ElementState, VirtualKeyCode, MouseButton};
|
||||||
use glutin::{Mods, mods};
|
use glutin::{Mods, mods};
|
||||||
|
@ -188,15 +185,12 @@ impl From<&'static str> for Action {
|
||||||
impl<'a, N: Notify + 'a> Processor<'a, N> {
|
impl<'a, N: Notify + 'a> Processor<'a, N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mouse_moved(&mut self, x: u32, y: u32) {
|
pub fn mouse_moved(&mut self, x: u32, y: u32) {
|
||||||
// Record mouse position within window. Pixel coordinates are *not*
|
|
||||||
// translated to grid coordinates here since grid coordinates are rarely
|
|
||||||
// needed and the mouse position updates frequently.
|
|
||||||
self.ctx.mouse.x = x;
|
self.ctx.mouse.x = x;
|
||||||
self.ctx.mouse.y = y;
|
self.ctx.mouse.y = y;
|
||||||
|
|
||||||
if let Some(point) = self.ctx.size_info.pixels_to_coords(x as usize, y as usize) {
|
if let Some(point) = self.ctx.size_info.pixels_to_coords(x as usize, y as usize) {
|
||||||
self.ctx.mouse.line = point.line;
|
let prev_line = mem::replace(&mut self.ctx.mouse.line, point.line);
|
||||||
self.ctx.mouse.column = point.col;
|
let prev_col = mem::replace(&mut self.ctx.mouse.column, point.col);
|
||||||
|
|
||||||
let cell_x = x as usize % self.ctx.size_info.cell_width as usize;
|
let cell_x = x as usize % self.ctx.size_info.cell_width as usize;
|
||||||
let half_cell_width = (self.ctx.size_info.cell_width / 2.0) as usize;
|
let half_cell_width = (self.ctx.size_info.cell_width / 2.0) as usize;
|
||||||
|
@ -207,18 +201,28 @@ impl<'a, N: Notify + 'a> Processor<'a, N> {
|
||||||
Side::Left
|
Side::Left
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.ctx.mouse.left_button_state == ElementState::Pressed &&
|
if self.ctx.mouse.left_button_state == ElementState::Pressed {
|
||||||
!self.ctx.terminal.mode().contains(mode::MOUSE_REPORT_CLICK)
|
let report_mode = mode::MOUSE_REPORT_CLICK | mode::MOUSE_MOTION;
|
||||||
{
|
if !self.ctx.terminal.mode().intersects(report_mode) {
|
||||||
self.ctx.selection.update(Point {
|
self.ctx.selection.update(Point {
|
||||||
line: point.line,
|
line: point.line,
|
||||||
col: point.col
|
col: point.col
|
||||||
}, self.ctx.mouse.cell_side);
|
}, self.ctx.mouse.cell_side);
|
||||||
|
} else if self.ctx.terminal.mode().contains(mode::MOUSE_MOTION) {
|
||||||
|
// Only report motion when changing cells
|
||||||
|
if prev_line != self.ctx.mouse.line || prev_col != self.ctx.mouse.column {
|
||||||
|
self.mouse_report(0 + 32);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mouse_report(&mut self, button: u8) {
|
pub fn mouse_moved_cells(&mut self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn normal_mouse_report(&mut self, button: u8) {
|
||||||
let (line, column) = (self.ctx.mouse.line, self.ctx.mouse.column);
|
let (line, column) = (self.ctx.mouse.line, self.ctx.mouse.column);
|
||||||
|
|
||||||
if line < Line(223) && column < Column(223) {
|
if line < Line(223) && column < Column(223) {
|
||||||
|
@ -235,8 +239,25 @@ impl<'a, N: Notify + 'a> Processor<'a, N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sgr_mouse_report(&mut self, button: u8, release: bool) {
|
||||||
|
let (line, column) = (self.ctx.mouse.line, self.ctx.mouse.column);
|
||||||
|
let c = if release { 'm' } else { 'M' };
|
||||||
|
|
||||||
|
let msg = format!("\x1b[<{};{};{}{}", button, column + 1, line + 1, c);
|
||||||
|
self.ctx.notifier.notify(msg.into_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mouse_report(&mut self, button: u8) {
|
||||||
|
if self.ctx.terminal.mode().contains(mode::SGR_MOUSE) {
|
||||||
|
let release = self.ctx.mouse.left_button_state != ElementState::Pressed;
|
||||||
|
self.sgr_mouse_report(button, release);
|
||||||
|
} else {
|
||||||
|
self.normal_mouse_report(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn on_mouse_press(&mut self) {
|
pub fn on_mouse_press(&mut self) {
|
||||||
if self.ctx.terminal.mode().contains(mode::MOUSE_REPORT_CLICK) {
|
if self.ctx.terminal.mode().intersects(mode::MOUSE_REPORT_CLICK | mode::MOUSE_MOTION) {
|
||||||
self.mouse_report(0);
|
self.mouse_report(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -245,7 +266,7 @@ impl<'a, N: Notify + 'a> Processor<'a, N> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_mouse_release(&mut self) {
|
pub fn on_mouse_release(&mut self) {
|
||||||
if self.ctx.terminal.mode().contains(mode::MOUSE_REPORT_CLICK) {
|
if self.ctx.terminal.mode().intersects(mode::MOUSE_REPORT_CLICK | mode::MOUSE_MOTION) {
|
||||||
self.mouse_report(3);
|
self.mouse_report(3);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -304,10 +325,9 @@ impl<'a, N: Notify + 'a> Processor<'a, N> {
|
||||||
|
|
||||||
pub fn mouse_input(&mut self, state: ElementState, button: MouseButton) {
|
pub fn mouse_input(&mut self, state: ElementState, button: MouseButton) {
|
||||||
if let MouseButton::Left = button {
|
if let MouseButton::Left = button {
|
||||||
// TODO handle state changes
|
let state = mem::replace(&mut self.ctx.mouse.left_button_state, state);
|
||||||
if self.ctx.mouse.left_button_state != state {
|
if self.ctx.mouse.left_button_state != state {
|
||||||
self.ctx.mouse.left_button_state = state;
|
match self.ctx.mouse.left_button_state {
|
||||||
match state {
|
|
||||||
ElementState::Pressed => {
|
ElementState::Pressed => {
|
||||||
self.on_mouse_press();
|
self.on_mouse_press();
|
||||||
},
|
},
|
||||||
|
|
|
@ -180,6 +180,8 @@ pub mod mode {
|
||||||
const APP_KEYPAD = 0b00000100,
|
const APP_KEYPAD = 0b00000100,
|
||||||
const MOUSE_REPORT_CLICK = 0b00001000,
|
const MOUSE_REPORT_CLICK = 0b00001000,
|
||||||
const BRACKETED_PASTE = 0b00010000,
|
const BRACKETED_PASTE = 0b00010000,
|
||||||
|
const SGR_MOUSE = 0b00100000,
|
||||||
|
const MOUSE_MOTION = 0b01000000,
|
||||||
const ANY = 0b11111111,
|
const ANY = 0b11111111,
|
||||||
const NONE = 0b00000000,
|
const NONE = 0b00000000,
|
||||||
}
|
}
|
||||||
|
@ -987,7 +989,9 @@ impl ansi::Handler for Term {
|
||||||
ansi::Mode::ShowCursor => self.mode.insert(mode::SHOW_CURSOR),
|
ansi::Mode::ShowCursor => self.mode.insert(mode::SHOW_CURSOR),
|
||||||
ansi::Mode::CursorKeys => self.mode.insert(mode::APP_CURSOR),
|
ansi::Mode::CursorKeys => self.mode.insert(mode::APP_CURSOR),
|
||||||
ansi::Mode::ReportMouseClicks => self.mode.insert(mode::MOUSE_REPORT_CLICK),
|
ansi::Mode::ReportMouseClicks => self.mode.insert(mode::MOUSE_REPORT_CLICK),
|
||||||
|
ansi::Mode::ReportMouseMotion => self.mode.insert(mode::MOUSE_MOTION),
|
||||||
ansi::Mode::BracketedPaste => self.mode.insert(mode::BRACKETED_PASTE),
|
ansi::Mode::BracketedPaste => self.mode.insert(mode::BRACKETED_PASTE),
|
||||||
|
ansi::Mode::SgrMouse => self.mode.insert(mode::SGR_MOUSE),
|
||||||
_ => {
|
_ => {
|
||||||
debug_println!(".. ignoring set_mode");
|
debug_println!(".. ignoring set_mode");
|
||||||
}
|
}
|
||||||
|
@ -1002,7 +1006,9 @@ impl ansi::Handler for Term {
|
||||||
ansi::Mode::ShowCursor => self.mode.remove(mode::SHOW_CURSOR),
|
ansi::Mode::ShowCursor => self.mode.remove(mode::SHOW_CURSOR),
|
||||||
ansi::Mode::CursorKeys => self.mode.remove(mode::APP_CURSOR),
|
ansi::Mode::CursorKeys => self.mode.remove(mode::APP_CURSOR),
|
||||||
ansi::Mode::ReportMouseClicks => self.mode.remove(mode::MOUSE_REPORT_CLICK),
|
ansi::Mode::ReportMouseClicks => self.mode.remove(mode::MOUSE_REPORT_CLICK),
|
||||||
|
ansi::Mode::ReportMouseMotion => self.mode.remove(mode::MOUSE_MOTION),
|
||||||
ansi::Mode::BracketedPaste => self.mode.remove(mode::BRACKETED_PASTE),
|
ansi::Mode::BracketedPaste => self.mode.remove(mode::BRACKETED_PASTE),
|
||||||
|
ansi::Mode::SgrMouse => self.mode.remove(mode::SGR_MOUSE),
|
||||||
_ => {
|
_ => {
|
||||||
debug_println!(".. ignoring unset_mode");
|
debug_println!(".. ignoring unset_mode");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue