diff --git a/CHANGELOG.md b/CHANGELOG.md index b29c6c1d..c7edd33c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Alternate scroll escape sequence (`CSI ? 1007 h` / `CSI ? 1007 l`) - Print name of launch command if Alacritty failed to execute it - Live reload font settings from config +- UTF-8 mouse mode escape sequence (`CSI ? 1005 h` / `CSI ? 1005 l`) ### Changed diff --git a/alacritty/src/input.rs b/alacritty/src/input.rs index 422d6a3f..5a852662 100644 --- a/alacritty/src/input.rs +++ b/alacritty/src/input.rs @@ -368,19 +368,36 @@ impl<'a, T: EventListener, A: ActionContext> Processor<'a, T, A> { pub fn normal_mouse_report(&mut self, button: u8) { let (line, column) = (self.ctx.mouse().line, self.ctx.mouse().column); + let utf8 = self.ctx.terminal().mode().contains(TermMode::UTF8_MOUSE); - if line < Line(223) && column < Column(223) { - let msg = vec![ - b'\x1b', - b'[', - b'M', - 32 + button, - 32 + 1 + column.0 as u8, - 32 + 1 + line.0 as u8, - ]; + let max_point = if utf8 { 2015 } else { 223 }; - self.ctx.write_to_pty(msg); + if line >= Line(max_point) || column >= Column(max_point) { + return; } + + let mut msg = vec![b'\x1b', b'[', b'M', 32 + button]; + + let mouse_pos_encode = |pos: usize| -> Vec { + let pos = 32 + 1 + pos; + let first = 0xC0 + pos / 64; + let second = 0x80 + (pos & 63); + vec![first as u8, second as u8] + }; + + if utf8 && column >= Column(95) { + msg.append(&mut mouse_pos_encode(column.0)); + } else { + msg.push(32 + 1 + column.0 as u8); + } + + if utf8 && line >= Line(95) { + msg.append(&mut mouse_pos_encode(line.0)); + } else { + msg.push(32 + 1 + line.0 as u8); + } + + self.ctx.write_to_pty(msg); } pub fn sgr_mouse_report(&mut self, button: u8, state: ElementState) { diff --git a/alacritty_terminal/src/ansi.rs b/alacritty_terminal/src/ansi.rs index a05904df..55c064e1 100644 --- a/alacritty_terminal/src/ansi.rs +++ b/alacritty_terminal/src/ansi.rs @@ -406,6 +406,8 @@ pub enum Mode { ReportAllMouseMotion = 1003, /// ?1004 ReportFocusInOut = 1004, + /// ?1005 + Utf8Mouse = 1005, /// ?1006 SgrMouse = 1006, /// ?1007 @@ -439,6 +441,7 @@ impl Mode { 1002 => Mode::ReportCellMouseMotion, 1003 => Mode::ReportAllMouseMotion, 1004 => Mode::ReportFocusInOut, + 1005 => Mode::Utf8Mouse, 1006 => Mode::SgrMouse, 1007 => Mode::AlternateScroll, 1049 => Mode::SwapScreenAndSetRestoreCursor, diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs index f7b37b23..570dc7f3 100644 --- a/alacritty_terminal/src/term/mod.rs +++ b/alacritty_terminal/src/term/mod.rs @@ -436,23 +436,24 @@ pub mod mode { bitflags! { pub struct TermMode: u16 { - const SHOW_CURSOR = 0b000_0000_0000_0001; - const APP_CURSOR = 0b000_0000_0000_0010; - const APP_KEYPAD = 0b000_0000_0000_0100; - const MOUSE_REPORT_CLICK = 0b000_0000_0000_1000; - const BRACKETED_PASTE = 0b000_0000_0001_0000; - const SGR_MOUSE = 0b000_0000_0010_0000; - const MOUSE_MOTION = 0b000_0000_0100_0000; - const LINE_WRAP = 0b000_0000_1000_0000; - const LINE_FEED_NEW_LINE = 0b000_0001_0000_0000; - const ORIGIN = 0b000_0010_0000_0000; - const INSERT = 0b000_0100_0000_0000; - const FOCUS_IN_OUT = 0b000_1000_0000_0000; - const ALT_SCREEN = 0b001_0000_0000_0000; - const MOUSE_DRAG = 0b010_0000_0000_0000; - const MOUSE_MODE = 0b010_0000_0100_1000; - const ALTERNATE_SCROLL = 0b100_0000_0000_0000; - const ANY = 0b111_1111_1111_1111; + const SHOW_CURSOR = 0b0000_0000_0000_0001; + const APP_CURSOR = 0b0000_0000_0000_0010; + const APP_KEYPAD = 0b0000_0000_0000_0100; + const MOUSE_REPORT_CLICK = 0b0000_0000_0000_1000; + const BRACKETED_PASTE = 0b0000_0000_0001_0000; + const SGR_MOUSE = 0b0000_0000_0010_0000; + const MOUSE_MOTION = 0b0000_0000_0100_0000; + const LINE_WRAP = 0b0000_0000_1000_0000; + const LINE_FEED_NEW_LINE = 0b0000_0001_0000_0000; + const ORIGIN = 0b0000_0010_0000_0000; + const INSERT = 0b0000_0100_0000_0000; + const FOCUS_IN_OUT = 0b0000_1000_0000_0000; + const ALT_SCREEN = 0b0001_0000_0000_0000; + const MOUSE_DRAG = 0b0010_0000_0000_0000; + const MOUSE_MODE = 0b0010_0000_0100_1000; + const UTF8_MOUSE = 0b0100_0000_0000_0000; + const ALTERNATE_SCROLL = 0b1000_0000_0000_0000; + const ANY = 0b1111_1111_1111_1111; const NONE = 0; } } @@ -1867,6 +1868,7 @@ impl ansi::Handler for Term { ansi::Mode::ReportFocusInOut => self.mode.insert(TermMode::FOCUS_IN_OUT), ansi::Mode::BracketedPaste => self.mode.insert(TermMode::BRACKETED_PASTE), ansi::Mode::SgrMouse => self.mode.insert(TermMode::SGR_MOUSE), + ansi::Mode::Utf8Mouse => self.mode.insert(TermMode::UTF8_MOUSE), ansi::Mode::AlternateScroll => self.mode.insert(TermMode::ALTERNATE_SCROLL), ansi::Mode::LineWrap => self.mode.insert(TermMode::LINE_WRAP), ansi::Mode::LineFeedNewLine => self.mode.insert(TermMode::LINE_FEED_NEW_LINE), @@ -1908,6 +1910,7 @@ impl ansi::Handler for Term { ansi::Mode::ReportFocusInOut => self.mode.remove(TermMode::FOCUS_IN_OUT), ansi::Mode::BracketedPaste => self.mode.remove(TermMode::BRACKETED_PASTE), ansi::Mode::SgrMouse => self.mode.remove(TermMode::SGR_MOUSE), + ansi::Mode::Utf8Mouse => self.mode.remove(TermMode::UTF8_MOUSE), ansi::Mode::AlternateScroll => self.mode.remove(TermMode::ALTERNATE_SCROLL), ansi::Mode::LineWrap => self.mode.remove(TermMode::LINE_WRAP), ansi::Mode::LineFeedNewLine => self.mode.remove(TermMode::LINE_FEED_NEW_LINE),