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,
|
||||
/// ?1000
|
||||
ReportMouseClicks = 1000,
|
||||
/// ?1002
|
||||
ReportMouseMotion = 1002,
|
||||
/// ?1006
|
||||
SgrMouse = 1006,
|
||||
/// ?1049
|
||||
SwapScreenAndSetRestoreCursor = 1049,
|
||||
/// ?2004
|
||||
|
@ -267,6 +271,8 @@ impl Mode {
|
|||
12 => Mode::BlinkingCursor,
|
||||
25 => Mode::ShowCursor,
|
||||
1000 => Mode::ReportMouseClicks,
|
||||
1002 => Mode::ReportMouseMotion,
|
||||
1006 => Mode::SgrMouse,
|
||||
1049 => Mode::SwapScreenAndSetRestoreCursor,
|
||||
2004 => Mode::BracketedPaste,
|
||||
_ => return None
|
||||
|
|
|
@ -62,7 +62,7 @@ pub struct Line(pub usize);
|
|||
|
||||
impl fmt::Display for Line {
|
||||
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 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Column({})", self.0)
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
58
src/input.rs
58
src/input.rs
|
@ -18,11 +18,8 @@
|
|||
//! 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
|
||||
//! determine what to do when a non-modifier key is pressed.
|
||||
//!
|
||||
//! TODO would be nice to generalize this so it could work with other windowing
|
||||
//! APIs
|
||||
//!
|
||||
//! TODO handling xmodmap would be good
|
||||
use std::mem;
|
||||
|
||||
use copypasta::{Clipboard, Load, Store};
|
||||
use glutin::{ElementState, VirtualKeyCode, MouseButton};
|
||||
use glutin::{Mods, mods};
|
||||
|
@ -188,15 +185,12 @@ impl From<&'static str> for Action {
|
|||
impl<'a, N: Notify + 'a> Processor<'a, N> {
|
||||
#[inline]
|
||||
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.y = y;
|
||||
|
||||
if let Some(point) = self.ctx.size_info.pixels_to_coords(x as usize, y as usize) {
|
||||
self.ctx.mouse.line = point.line;
|
||||
self.ctx.mouse.column = point.col;
|
||||
let prev_line = mem::replace(&mut self.ctx.mouse.line, point.line);
|
||||
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 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
|
||||
};
|
||||
|
||||
if self.ctx.mouse.left_button_state == ElementState::Pressed &&
|
||||
!self.ctx.terminal.mode().contains(mode::MOUSE_REPORT_CLICK)
|
||||
{
|
||||
if self.ctx.mouse.left_button_state == ElementState::Pressed {
|
||||
let report_mode = mode::MOUSE_REPORT_CLICK | mode::MOUSE_MOTION;
|
||||
if !self.ctx.terminal.mode().intersects(report_mode) {
|
||||
self.ctx.selection.update(Point {
|
||||
line: point.line,
|
||||
col: point.col
|
||||
}, 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);
|
||||
|
||||
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) {
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
@ -245,7 +266,7 @@ impl<'a, N: Notify + 'a> Processor<'a, N> {
|
|||
}
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
@ -304,10 +325,9 @@ impl<'a, N: Notify + 'a> Processor<'a, N> {
|
|||
|
||||
pub fn mouse_input(&mut self, state: ElementState, button: MouseButton) {
|
||||
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 {
|
||||
self.ctx.mouse.left_button_state = state;
|
||||
match state {
|
||||
match self.ctx.mouse.left_button_state {
|
||||
ElementState::Pressed => {
|
||||
self.on_mouse_press();
|
||||
},
|
||||
|
|
|
@ -180,6 +180,8 @@ pub mod mode {
|
|||
const APP_KEYPAD = 0b00000100,
|
||||
const MOUSE_REPORT_CLICK = 0b00001000,
|
||||
const BRACKETED_PASTE = 0b00010000,
|
||||
const SGR_MOUSE = 0b00100000,
|
||||
const MOUSE_MOTION = 0b01000000,
|
||||
const ANY = 0b11111111,
|
||||
const NONE = 0b00000000,
|
||||
}
|
||||
|
@ -987,7 +989,9 @@ impl ansi::Handler for Term {
|
|||
ansi::Mode::ShowCursor => self.mode.insert(mode::SHOW_CURSOR),
|
||||
ansi::Mode::CursorKeys => self.mode.insert(mode::APP_CURSOR),
|
||||
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::SgrMouse => self.mode.insert(mode::SGR_MOUSE),
|
||||
_ => {
|
||||
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::CursorKeys => self.mode.remove(mode::APP_CURSOR),
|
||||
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::SgrMouse => self.mode.remove(mode::SGR_MOUSE),
|
||||
_ => {
|
||||
debug_println!(".. ignoring unset_mode");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue