1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-23 05:12:40 +03:00

term: support utf8 mouse reporting (DECSET 1005)

This commit is contained in:
Wez Furlong 2022-10-10 22:52:53 -07:00
parent cb31c35b99
commit ed63d728bf
3 changed files with 58 additions and 44 deletions

View File

@ -41,6 +41,8 @@ As features stabilize some brief notes about them will accumulate here.
event. event.
* [pane:inject_output](config/lua/pane/inject_output.md) method * [pane:inject_output](config/lua/pane/inject_output.md) method
* [ResetTerminal](config/lua/keyassignment/ResetTerminal.md) key assignment * [ResetTerminal](config/lua/keyassignment/ResetTerminal.md) key assignment
* Support for Utf8 mouse reporting (DECSET 1005).
[#2613](https://github.com/wez/wezterm/issues/2613)
#### Fixed #### Fixed
* Wayland: key repeat gets stuck after pressing two keys in quick succession. * Wayland: key repeat gets stuck after pressing two keys in quick succession.

View File

@ -55,6 +55,7 @@ pub(crate) enum CharSet {
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum MouseEncoding { pub(crate) enum MouseEncoding {
X10, X10,
Utf8,
SGR, SGR,
SgrPixels, SgrPixels,
} }
@ -1760,6 +1761,25 @@ impl TerminalState {
); );
} }
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::Utf8Mouse)) => {
self.mouse_encoding = MouseEncoding::Utf8;
self.last_mouse_move.take();
}
Mode::ResetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::Utf8Mouse)) => {
self.mouse_encoding = MouseEncoding::X10;
self.last_mouse_move.take();
}
Mode::QueryDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::Utf8Mouse)) => {
self.decqrm_response(
mode,
true,
match self.mouse_encoding {
MouseEncoding::Utf8 => true,
_ => false,
},
);
}
Mode::SetDecPrivateMode(DecPrivateMode::Code( Mode::SetDecPrivateMode(DecPrivateMode::Code(
DecPrivateModeCode::SixelScrollsRight, DecPrivateModeCode::SixelScrollsRight,
)) => { )) => {
@ -1821,9 +1841,6 @@ impl TerminalState {
DecPrivateModeCode::XTermAltSendsEscape, DecPrivateModeCode::XTermAltSendsEscape,
)) => {} )) => {}
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::Utf8Mouse))
| Mode::ResetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::Utf8Mouse)) => {}
Mode::SetDecPrivateMode(DecPrivateMode::Unspecified(_)) Mode::SetDecPrivateMode(DecPrivateMode::Unspecified(_))
| Mode::ResetDecPrivateMode(DecPrivateMode::Unspecified(_)) | Mode::ResetDecPrivateMode(DecPrivateMode::Unspecified(_))
| Mode::SaveDecPrivateMode(DecPrivateMode::Unspecified(_)) | Mode::SaveDecPrivateMode(DecPrivateMode::Unspecified(_))

View File

@ -4,15 +4,38 @@ use crate::TerminalState;
use anyhow::bail; use anyhow::bail;
impl TerminalState { impl TerminalState {
/// Encode a coordinate value using X10 encoding. /// Encode a coordinate value using X10 encoding or Utf8 encoding.
/// X10 has a theoretical maximum coordinate value of 255-33, but /// Out of bounds coords are reported as the 0 byte value.
/// because we emit UTF-8 we are effectively capped at the maximum fn encode_coord(&self, value: i64, dest: &mut Vec<u8>) {
/// single byte character value of 127, with coordinates capping // Convert to 1-based and offset into the printable character range
/// out at 127-33. let value = value + 1 + 32;
/// This isn't "fixable" in X10 encoding, applications should if self.mouse_encoding == MouseEncoding::Utf8 {
/// use the superior SGR mouse encoding scheme instead. if value < 0x800 {
fn legacy_mouse_coord(position: i64) -> char { let mut utf8 = [0; 2];
position.max(0).saturating_add(1 + 32).min(127) as u8 as char dest.extend_from_slice(
(char::from_u32(value as u32).unwrap())
.encode_utf8(&mut utf8)
.as_bytes(),
);
} else {
// out of range
dest.push(0);
}
} else if value < 0x100 {
dest.push(value as u8);
} else {
// out of range
dest.push(0);
}
}
fn encode_x10_or_utf8(&mut self, event: MouseEvent, button: i8) -> anyhow::Result<()> {
let mut buf = vec![b'\x1b', b'[', b'M', (32 + button) as u8];
self.encode_coord(event.x as i64, &mut buf);
self.encode_coord(event.y, &mut buf);
self.writer.write(&buf)?;
self.writer.flush()?;
Ok(())
} }
fn mouse_report_button_number(&self, event: &MouseEvent) -> (i8, MouseButton) { fn mouse_report_button_number(&self, event: &MouseEvent) -> (i8, MouseButton) {
@ -76,14 +99,7 @@ impl TerminalState {
)?; )?;
self.writer.flush()?; self.writer.flush()?;
} else if self.mouse_tracking || self.button_event_mouse || self.any_event_mouse { } else if self.mouse_tracking || self.button_event_mouse || self.any_event_mouse {
write!( self.encode_x10_or_utf8(event, button)?;
self.writer,
"\x1b[M{}{}{}",
(32 + button) as u8 as char,
Self::legacy_mouse_coord(event.x as i64),
Self::legacy_mouse_coord(event.y),
)?;
self.writer.flush()?;
} else if self.screen.is_alt_screen_active() { } else if self.screen.is_alt_screen_active() {
// Send cursor keys instead (equivalent to xterm's alternateScroll mode) // Send cursor keys instead (equivalent to xterm's alternateScroll mode)
for _ in 0..self.config.alternate_buffer_wheel_scroll_speed() { for _ in 0..self.config.alternate_buffer_wheel_scroll_speed() {
@ -132,14 +148,7 @@ impl TerminalState {
)?; )?;
self.writer.flush()?; self.writer.flush()?;
} else { } else {
write!( self.encode_x10_or_utf8(event, button)?;
self.writer,
"\x1b[M{}{}{}",
(32 + button) as u8 as char,
Self::legacy_mouse_coord(event.x as i64),
Self::legacy_mouse_coord(event.y),
)?;
self.writer.flush()?;
} }
Ok(()) Ok(())
@ -176,14 +185,7 @@ impl TerminalState {
self.writer.flush()?; self.writer.flush()?;
} else { } else {
let release_button = 3; let release_button = 3;
write!( self.encode_x10_or_utf8(event, release_button)?;
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()?;
} }
} }
} }
@ -242,14 +244,7 @@ impl TerminalState {
)?; )?;
self.writer.flush()?; self.writer.flush()?;
} else { } else {
write!( self.encode_x10_or_utf8(event, button)?;
self.writer,
"\x1b[M{}{}{}",
(32 + button) as u8 as char,
Self::legacy_mouse_coord(event.x as i64),
Self::legacy_mouse_coord(event.y),
)?;
self.writer.flush()?;
} }
} }
Ok(()) Ok(())