From e5d39591191d4390820c8d778c6949c9baed00c5 Mon Sep 17 00:00:00 2001 From: Koxiaet Date: Sun, 22 Nov 2020 12:52:15 +0000 Subject: [PATCH] Add support for any event tracking (#502) --- src/event.rs | 54 +++-- src/event/ansi.rs | 12 +- src/event/sys/unix/parse.rs | 368 +++++++++++++++------------------ src/event/sys/windows/parse.rs | 39 ++-- src/event/sys/windows/poll.rs | 7 +- 5 files changed, 231 insertions(+), 249 deletions(-) diff --git a/src/event.rs b/src/event.rs index 27954de..25dc389 100644 --- a/src/event.rs +++ b/src/event.rs @@ -285,7 +285,7 @@ pub enum Event { /// ## Mouse Buttons /// /// Some platforms/terminals do not report mouse button for the -/// `MouseEvent::Up` and `MouseEvent::Drag` events. `MouseButton::Left` +/// `MouseEventKind::Up` and `MouseEventKind::Drag` events. `MouseButton::Left` /// is returned if we don't know which button was used. /// /// ## Key Modifiers @@ -295,27 +295,41 @@ pub enum Event { /// `Ctrl` + left mouse button click as a right mouse button click. #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)] -pub enum MouseEvent { - /// Pressed mouse button. - /// - /// Contains mouse button, pressed pointer location (column, row), and additional key modifiers. - Down(MouseButton, u16, u16, KeyModifiers), - /// Released mouse button. - /// - /// Contains mouse button, released pointer location (column, row), and additional key modifiers. - Up(MouseButton, u16, u16, KeyModifiers), - /// Moved mouse pointer while pressing a mouse button. - /// - /// Contains the pressed mouse button, released pointer location (column, row), and additional key modifiers. - Drag(MouseButton, u16, u16, KeyModifiers), +pub struct MouseEvent { + /// The kind of mouse event that was caused. + pub kind: MouseEventKind, + /// The column that the event occurred on. + pub column: u16, + /// The row that the event occurred on. + pub row: u16, + /// The key modifiers active when the event occurred. + pub modifiers: KeyModifiers, +} + +/// A mouse event kind. +/// +/// # Platform-specific Notes +/// +/// ## Mouse Buttons +/// +/// Some platforms/terminals do not report mouse button for the +/// `MouseEventKind::Up` and `MouseEventKind::Drag` events. `MouseButton::Left` +/// is returned if we don't know which button was used. +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)] +pub enum MouseEventKind { + /// Pressed mouse button. Contains the button that was pressed. + Down(MouseButton), + /// Released mouse button. Contains the button that was released. + Up(MouseButton), + /// Moved the mouse cursor while pressing the contained mouse button. + Drag(MouseButton), + /// Moved the mouse cursor while not pressing a mouse button. + Moved, /// Scrolled mouse wheel downwards (towards the user). - /// - /// Contains the scroll location (column, row), and additional key modifiers. - ScrollDown(u16, u16, KeyModifiers), + ScrollDown, /// Scrolled mouse wheel upwards (away from the user). - /// - /// Contains the scroll location (column, row), and additional key modifiers. - ScrollUp(u16, u16, KeyModifiers), + ScrollUp, } /// Represents a mouse button. diff --git a/src/event/ansi.rs b/src/event/ansi.rs index 5e5b837..b125950 100644 --- a/src/event/ansi.rs +++ b/src/event/ansi.rs @@ -3,15 +3,23 @@ use crate::csi; pub(crate) const ENABLE_MOUSE_MODE_CSI_SEQUENCE: &str = concat!( + // Normal tracking: Send mouse X & Y on button press and release csi!("?1000h"), + // Button-event tracking: Report button motion events (dragging) csi!("?1002h"), + // Any-event tracking: Report all motion events + csi!("?1003h"), + // RXVT mouse mode: Allows mouse coordinates of >223 csi!("?1015h"), - csi!("?1006h") + // SGR mouse mode: Allows mouse coordinates of >223, preferred over RXVT mode + csi!("?1006h"), ); pub(crate) const DISABLE_MOUSE_MODE_CSI_SEQUENCE: &str = concat!( + // The above, in reverse order. csi!("?1006l"), csi!("?1015l"), + csi!("?1003l"), csi!("?1002l"), - csi!("?1000l") + csi!("?1000l"), ); diff --git a/src/event/sys/unix/parse.rs b/src/event/sys/unix/parse.rs index cd686ba..aba8ef5 100644 --- a/src/event/sys/unix/parse.rs +++ b/src/event/sys/unix/parse.rs @@ -1,5 +1,5 @@ use crate::{ - event::{Event, KeyCode, KeyEvent, KeyModifiers, MouseButton, MouseEvent}, + event::{Event, KeyCode, KeyEvent, KeyModifiers, MouseButton, MouseEvent, MouseEventKind}, ErrorKind, Result, }; @@ -141,8 +141,8 @@ pub(crate) fn parse_csi(buffer: &[u8]) -> Result> { code: KeyCode::BackTab, modifiers: KeyModifiers::SHIFT, })), - b'M' => return parse_csi_x10_mouse(buffer), - b'<' => return parse_csi_xterm_mouse(buffer), + b'M' => return parse_csi_normal_mouse(buffer), + b'<' => return parse_csi_sgr_mouse(buffer), b'0'..=b'9' => { // Numbered escape code. if buffer.len() == 3 { @@ -285,54 +285,24 @@ pub(crate) fn parse_csi_rxvt_mouse(buffer: &[u8]) -> Result(&mut split)?; + let cb = next_parsed::(&mut split)? + .checked_sub(32) + .ok_or_else(could_not_parse_event_error)?; + let (kind, modifiers) = parse_cb(cb)?; + let cx = next_parsed::(&mut split)? - 1; let cy = next_parsed::(&mut split)? - 1; - let mut modifiers = KeyModifiers::empty(); - - if cb & 0b0000_0100 == 0b0000_0100 { - modifiers |= KeyModifiers::SHIFT; - } - - if cb & 0b0000_1000 == 0b0000_1000 { - modifiers |= KeyModifiers::ALT; - } - - if cb & 0b0001_0000 == 0b0001_0000 { - modifiers |= KeyModifiers::CONTROL; - } - - let event = if cb & 0b0110_0000 == 0b0110_0000 { - if cb & 0b0000_0001 == 0b0000_0001 { - MouseEvent::ScrollDown(cx, cy, modifiers) - } else { - MouseEvent::ScrollUp(cx, cy, modifiers) - } - } else { - let drag = cb & 0b0100_0000 == 0b0100_0000; - - match (cb & 0b0000_0011, drag) { - (0b0000_0000, false) => MouseEvent::Down(MouseButton::Left, cx, cy, modifiers), - (0b0000_0010, false) => MouseEvent::Down(MouseButton::Right, cx, cy, modifiers), - (0b0000_0001, false) => MouseEvent::Down(MouseButton::Middle, cx, cy, modifiers), - - (0b0000_0000, true) => MouseEvent::Drag(MouseButton::Left, cx, cy, modifiers), - (0b0000_0010, true) => MouseEvent::Drag(MouseButton::Right, cx, cy, modifiers), - (0b0000_0001, true) => MouseEvent::Drag(MouseButton::Middle, cx, cy, modifiers), - - (0b0000_0011, false) => MouseEvent::Up(MouseButton::Left, cx, cy, modifiers), - - _ => return Err(could_not_parse_event_error()), - } - }; - - Ok(Some(InternalEvent::Event(Event::Mouse(event)))) + Ok(Some(InternalEvent::Event(Event::Mouse(MouseEvent { + kind, + column: cx, + row: cy, + modifiers, + })))) } -pub(crate) fn parse_csi_x10_mouse(buffer: &[u8]) -> Result> { - // X10 emulation mouse encoding: ESC [ M CB Cx Cy (6 characters only). - // NOTE (@imdaveho): cannot find documentation on this +pub(crate) fn parse_csi_normal_mouse(buffer: &[u8]) -> Result> { + // Normal mouse encoding: ESC [ M CB Cx Cy (6 characters only). assert!(buffer.starts_with(&[b'\x1B', b'[', b'M'])); // ESC [ M @@ -340,51 +310,26 @@ pub(crate) fn parse_csi_x10_mouse(buffer: &[u8]) -> Result return Ok(None); } - let cb = buffer[3] - 0x30; + let cb = buffer[3] + .checked_sub(32) + .ok_or_else(could_not_parse_event_error)?; + let (kind, modifiers) = parse_cb(cb)?; + // See http://www.xfree86.org/current/ctlseqs.html#Mouse%20Tracking // The upper left character position on the terminal is denoted as 1,1. // Subtract 1 to keep it synced with cursor let cx = u16::from(buffer[4].saturating_sub(32)) - 1; let cy = u16::from(buffer[5].saturating_sub(32)) - 1; - let mut modifiers = KeyModifiers::empty(); - - if cb & 0b0000_0100 == 0b0000_0100 { - modifiers |= KeyModifiers::SHIFT; - } - - if cb & 0b0000_1000 == 0b0000_1000 { - modifiers |= KeyModifiers::ALT; - } - - if cb & 0b0001_0000 == 0b0001_0000 { - modifiers |= KeyModifiers::CONTROL; - } - - let mouse_input_event = match cb & 0b0000_0011 { - 0 => { - if cb & 0b0100_0000 == 0b0100_0000 { - MouseEvent::ScrollUp(cx, cy, modifiers) - } else { - MouseEvent::Down(MouseButton::Left, cx, cy, modifiers) - } - } - 1 => { - if cb & 0b0100_0000 == 0b0100_0000 { - MouseEvent::ScrollDown(cx, cy, modifiers) - } else { - MouseEvent::Down(MouseButton::Middle, cx, cy, modifiers) - } - } - 2 => MouseEvent::Down(MouseButton::Right, cx, cy, modifiers), - 3 => MouseEvent::Up(MouseButton::Left, cx, cy, modifiers), - _ => return Err(could_not_parse_event_error()), - }; - - Ok(Some(InternalEvent::Event(Event::Mouse(mouse_input_event)))) + Ok(Some(InternalEvent::Event(Event::Mouse(MouseEvent { + kind, + column: cx, + row: cy, + modifiers, + })))) } -pub(crate) fn parse_csi_xterm_mouse(buffer: &[u8]) -> Result> { +pub(crate) fn parse_csi_sgr_mouse(buffer: &[u8]) -> Result> { // ESC [ < Cb ; Cx ; Cy (;) (M or m) assert!(buffer.starts_with(&[b'\x1B', b'[', b'<'])); // ESC [ < @@ -397,7 +342,8 @@ pub(crate) fn parse_csi_xterm_mouse(buffer: &[u8]) -> Result(&mut split)?; + let cb = next_parsed::(&mut split)?; + let (kind, modifiers) = parse_cb(cb)?; // See http://www.xfree86.org/current/ctlseqs.html#Mouse%20Tracking // The upper left character position on the terminal is denoted as 1,1. @@ -405,50 +351,74 @@ pub(crate) fn parse_csi_xterm_mouse(buffer: &[u8]) -> Result(&mut split)? - 1; let cy = next_parsed::(&mut split)? - 1; + // When button 3 in Cb is used to represent mouse release, you can't tell which button was + // released. SGR mode solves this by having the sequence end with a lowercase m if it's a + // button release and an uppercase M if it's a buton press. + // + // We've already checked that the last character is a lowercase or uppercase M at the start of + // this function, so we just need one if. + let kind = if buffer.last() == Some(&b'm') { + match kind { + MouseEventKind::Down(button) => MouseEventKind::Up(button), + other => other, + } + } else { + kind + }; + + Ok(Some(InternalEvent::Event(Event::Mouse(MouseEvent { + kind, + column: cx, + row: cy, + modifiers, + })))) +} + +/// Cb is the byte of a mouse input that contains the button being used, the key modifiers being +/// held and whether the mouse is dragging or not. +/// +/// Bit layout of cb, from low to high: +/// +/// - button number +/// - button number +/// - shift +/// - meta (alt) +/// - control +/// - mouse is dragging +/// - button number +/// - button number +fn parse_cb(cb: u8) -> Result<(MouseEventKind, KeyModifiers)> { + let button_number = (cb & 0b0000_0011) | ((cb & 0b1100_0000) >> 4); + let dragging = cb & 0b0010_0000 == 0b0010_0000; + + let kind = match (button_number, dragging) { + (0, false) => MouseEventKind::Down(MouseButton::Left), + (1, false) => MouseEventKind::Down(MouseButton::Middle), + (2, false) => MouseEventKind::Down(MouseButton::Right), + (0, true) => MouseEventKind::Drag(MouseButton::Left), + (1, true) => MouseEventKind::Drag(MouseButton::Middle), + (2, true) => MouseEventKind::Drag(MouseButton::Right), + (3, false) => MouseEventKind::Up(MouseButton::Left), + (3, true) | (4, true) | (5, true) => MouseEventKind::Moved, + (4, false) => MouseEventKind::ScrollUp, + (5, false) => MouseEventKind::ScrollDown, + // We do not support other buttons. + _ => return Err(could_not_parse_event_error()), + }; + let mut modifiers = KeyModifiers::empty(); if cb & 0b0000_0100 == 0b0000_0100 { modifiers |= KeyModifiers::SHIFT; } - if cb & 0b0000_1000 == 0b0000_1000 { modifiers |= KeyModifiers::ALT; } - if cb & 0b0001_0000 == 0b0001_0000 { modifiers |= KeyModifiers::CONTROL; } - let event = if cb & 0b0100_0000 == 0b0100_0000 { - if cb & 0b0000_0001 == 0b0000_0001 { - MouseEvent::ScrollDown(cx, cy, modifiers) - } else { - MouseEvent::ScrollUp(cx, cy, modifiers) - } - } else { - let up = match buffer.last().unwrap() { - b'm' => true, - b'M' => false, - _ => return Err(could_not_parse_event_error()), - }; - - let drag = cb & 0b0010_0000 == 0b0010_0000; - - match (cb & 0b0000_0011, up, drag) { - (0, true, _) => MouseEvent::Up(MouseButton::Left, cx, cy, modifiers), - (0, false, false) => MouseEvent::Down(MouseButton::Left, cx, cy, modifiers), - (0, false, true) => MouseEvent::Drag(MouseButton::Left, cx, cy, modifiers), - (1, true, _) => MouseEvent::Up(MouseButton::Middle, cx, cy, modifiers), - (1, false, false) => MouseEvent::Down(MouseButton::Middle, cx, cy, modifiers), - (1, false, true) => MouseEvent::Drag(MouseButton::Middle, cx, cy, modifiers), - (2, true, _) => MouseEvent::Up(MouseButton::Right, cx, cy, modifiers), - (2, false, false) => MouseEvent::Down(MouseButton::Right, cx, cy, modifiers), - (2, false, true) => MouseEvent::Drag(MouseButton::Right, cx, cy, modifiers), - _ => return Err(could_not_parse_event_error()), - } - }; - - Ok(Some(InternalEvent::Event(Event::Mouse(event)))) + Ok((kind, modifiers)) } pub(crate) fn parse_utf8_char(buffer: &[u8]) -> Result> { @@ -499,20 +469,20 @@ mod tests { #[test] fn test_esc_key() { assert_eq!( - parse_event("\x1B".as_bytes(), false).unwrap(), + parse_event(b"\x1B", false).unwrap(), Some(InternalEvent::Event(Event::Key(KeyCode::Esc.into()))), ); } #[test] fn test_possible_esc_sequence() { - assert_eq!(parse_event("\x1B".as_bytes(), true).unwrap(), None,); + assert_eq!(parse_event(b"\x1B", true).unwrap(), None,); } #[test] fn test_alt_key() { assert_eq!( - parse_event("\x1Bc".as_bytes(), false).unwrap(), + parse_event(b"\x1Bc", false).unwrap(), Some(InternalEvent::Event(Event::Key(KeyEvent::new( KeyCode::Char('c'), KeyModifiers::ALT @@ -527,19 +497,19 @@ mod tests { // parse_csi_cursor_position assert_eq!( - parse_event("\x1B[20;10R".as_bytes(), false).unwrap(), + parse_event(b"\x1B[20;10R", false).unwrap(), Some(InternalEvent::CursorPosition(9, 19)) ); // parse_csi assert_eq!( - parse_event("\x1B[D".as_bytes(), false).unwrap(), + parse_event(b"\x1B[D", false).unwrap(), Some(InternalEvent::Event(Event::Key(KeyCode::Left.into()))), ); // parse_csi_modifier_key_code assert_eq!( - parse_event("\x1B[2D".as_bytes(), false).unwrap(), + parse_event(b"\x1B[2D", false).unwrap(), Some(InternalEvent::Event(Event::Key(KeyEvent::new( KeyCode::Left, KeyModifiers::SHIFT @@ -548,41 +518,41 @@ mod tests { // parse_csi_special_key_code assert_eq!( - parse_event("\x1B[3~".as_bytes(), false).unwrap(), + parse_event(b"\x1B[3~", false).unwrap(), Some(InternalEvent::Event(Event::Key(KeyCode::Delete.into()))), ); // parse_csi_rxvt_mouse assert_eq!( - parse_event("\x1B[32;30;40;M".as_bytes(), false).unwrap(), - Some(InternalEvent::Event(Event::Mouse(MouseEvent::Down( - MouseButton::Left, - 29, - 39, - KeyModifiers::empty(), - )))) + parse_event(b"\x1B[32;30;40;M", false).unwrap(), + Some(InternalEvent::Event(Event::Mouse(MouseEvent { + kind: MouseEventKind::Down(MouseButton::Left), + column: 29, + row: 39, + modifiers: KeyModifiers::empty(), + }))) ); - // parse_csi_x10_mouse + // parse_csi_normal_mouse assert_eq!( - parse_event("\x1B[M0\x60\x70".as_bytes(), false).unwrap(), - Some(InternalEvent::Event(Event::Mouse(MouseEvent::Down( - MouseButton::Left, - 63, - 79, - KeyModifiers::empty(), - )))) + parse_event(b"\x1B[M0\x60\x70", false).unwrap(), + Some(InternalEvent::Event(Event::Mouse(MouseEvent { + kind: MouseEventKind::Down(MouseButton::Left), + column: 63, + row: 79, + modifiers: KeyModifiers::CONTROL, + }))) ); - // parse_csi_xterm_mouse + // parse_csi_sgr_mouse assert_eq!( - parse_event("\x1B[<0;20;10;M".as_bytes(), false).unwrap(), - Some(InternalEvent::Event(Event::Mouse(MouseEvent::Down( - MouseButton::Left, - 19, - 9, - KeyModifiers::empty(), - )))) + parse_event(b"\x1B[<0;20;10;M", false).unwrap(), + Some(InternalEvent::Event(Event::Mouse(MouseEvent { + kind: MouseEventKind::Down(MouseButton::Left), + column: 19, + row: 9, + modifiers: KeyModifiers::empty(), + }))) ); // parse_utf8_char @@ -598,7 +568,7 @@ mod tests { #[test] fn test_parse_event() { assert_eq!( - parse_event("\t".as_bytes(), false).unwrap(), + parse_event(b"\t", false).unwrap(), Some(InternalEvent::Event(Event::Key(KeyCode::Tab.into()))), ); } @@ -606,7 +576,7 @@ mod tests { #[test] fn test_parse_csi_cursor_position() { assert_eq!( - parse_csi_cursor_position("\x1B[20;10R".as_bytes()).unwrap(), + parse_csi_cursor_position(b"\x1B[20;10R").unwrap(), Some(InternalEvent::CursorPosition(9, 19)) ); } @@ -614,7 +584,7 @@ mod tests { #[test] fn test_parse_csi() { assert_eq!( - parse_csi("\x1B[D".as_bytes()).unwrap(), + parse_csi(b"\x1B[D").unwrap(), Some(InternalEvent::Event(Event::Key(KeyCode::Left.into()))), ); } @@ -622,7 +592,7 @@ mod tests { #[test] fn test_parse_csi_modifier_key_code() { assert_eq!( - parse_csi_modifier_key_code("\x1B[2D".as_bytes()).unwrap(), + parse_csi_modifier_key_code(b"\x1B[2D").unwrap(), Some(InternalEvent::Event(Event::Key(KeyEvent::new( KeyCode::Left, KeyModifiers::SHIFT @@ -633,7 +603,7 @@ mod tests { #[test] fn test_parse_csi_special_key_code() { assert_eq!( - parse_csi_special_key_code("\x1B[3~".as_bytes()).unwrap(), + parse_csi_special_key_code(b"\x1B[3~").unwrap(), Some(InternalEvent::Event(Event::Key(KeyCode::Delete.into()))), ); } @@ -641,7 +611,7 @@ mod tests { #[test] fn test_parse_csi_special_key_code_multiple_values_not_supported() { assert_eq!( - parse_csi_special_key_code("\x1B[3;2~".as_bytes()).unwrap(), + parse_csi_special_key_code(b"\x1B[3;2~").unwrap(), Some(InternalEvent::Event(Event::Key(KeyEvent::new( KeyCode::Delete, KeyModifiers::SHIFT @@ -652,66 +622,66 @@ mod tests { #[test] fn test_parse_csi_rxvt_mouse() { assert_eq!( - parse_csi_rxvt_mouse("\x1B[32;30;40;M".as_bytes()).unwrap(), - Some(InternalEvent::Event(Event::Mouse(MouseEvent::Down( - MouseButton::Left, - 29, - 39, - KeyModifiers::empty(), - )))) + parse_csi_rxvt_mouse(b"\x1B[32;30;40;M").unwrap(), + Some(InternalEvent::Event(Event::Mouse(MouseEvent { + kind: MouseEventKind::Down(MouseButton::Left), + column: 29, + row: 39, + modifiers: KeyModifiers::empty(), + }))) ); } #[test] - fn test_parse_csi_x10_mouse() { + fn test_parse_csi_normal_mouse() { assert_eq!( - parse_csi_x10_mouse("\x1B[M0\x60\x70".as_bytes()).unwrap(), - Some(InternalEvent::Event(Event::Mouse(MouseEvent::Down( - MouseButton::Left, - 63, - 79, - KeyModifiers::empty(), - )))) + parse_csi_normal_mouse(b"\x1B[M0\x60\x70").unwrap(), + Some(InternalEvent::Event(Event::Mouse(MouseEvent { + kind: MouseEventKind::Down(MouseButton::Left), + column: 63, + row: 79, + modifiers: KeyModifiers::CONTROL, + }))) ); } #[test] - fn test_parse_csi_xterm_mouse() { + fn test_parse_csi_sgr_mouse() { assert_eq!( - parse_csi_xterm_mouse("\x1B[<0;20;10;M".as_bytes()).unwrap(), - Some(InternalEvent::Event(Event::Mouse(MouseEvent::Down( - MouseButton::Left, - 19, - 9, - KeyModifiers::empty(), - )))) + parse_csi_sgr_mouse(b"\x1B[<0;20;10;M").unwrap(), + Some(InternalEvent::Event(Event::Mouse(MouseEvent { + kind: MouseEventKind::Down(MouseButton::Left), + column: 19, + row: 9, + modifiers: KeyModifiers::empty(), + }))) ); assert_eq!( - parse_csi_xterm_mouse("\x1B[<0;20;10M".as_bytes()).unwrap(), - Some(InternalEvent::Event(Event::Mouse(MouseEvent::Down( - MouseButton::Left, - 19, - 9, - KeyModifiers::empty(), - )))) + parse_csi_sgr_mouse(b"\x1B[<0;20;10M").unwrap(), + Some(InternalEvent::Event(Event::Mouse(MouseEvent { + kind: MouseEventKind::Down(MouseButton::Left), + column: 19, + row: 9, + modifiers: KeyModifiers::empty(), + }))) ); assert_eq!( - parse_csi_xterm_mouse("\x1B[<0;20;10;m".as_bytes()).unwrap(), - Some(InternalEvent::Event(Event::Mouse(MouseEvent::Up( - MouseButton::Left, - 19, - 9, - KeyModifiers::empty(), - )))) + parse_csi_sgr_mouse(b"\x1B[<0;20;10;m").unwrap(), + Some(InternalEvent::Event(Event::Mouse(MouseEvent { + kind: MouseEventKind::Up(MouseButton::Left), + column: 19, + row: 9, + modifiers: KeyModifiers::empty(), + }))) ); assert_eq!( - parse_csi_xterm_mouse("\x1B[<0;20;10m".as_bytes()).unwrap(), - Some(InternalEvent::Event(Event::Mouse(MouseEvent::Up( - MouseButton::Left, - 19, - 9, - KeyModifiers::empty(), - )))) + parse_csi_sgr_mouse(b"\x1B[<0;20;10m").unwrap(), + Some(InternalEvent::Event(Event::Mouse(MouseEvent { + kind: MouseEventKind::Up(MouseButton::Left), + column: 19, + row: 9, + modifiers: KeyModifiers::empty(), + }))) ); } @@ -720,7 +690,7 @@ mod tests { // https://www.php.net/manual/en/reference.pcre.pattern.modifiers.php#54805 // 'Valid ASCII' => "a", - assert_eq!(parse_utf8_char("a".as_bytes()).unwrap(), Some('a'),); + assert_eq!(parse_utf8_char(b"a").unwrap(), Some('a'),); // 'Valid 2 Octet Sequence' => "\xc3\xb1", assert_eq!(parse_utf8_char(&[0xC3, 0xB1]).unwrap(), Some('ñ'),); @@ -762,7 +732,7 @@ mod tests { #[test] fn test_parse_char_event_lowercase() { assert_eq!( - parse_event("c".as_bytes(), false).unwrap(), + parse_event(b"c", false).unwrap(), Some(InternalEvent::Event(Event::Key(KeyEvent::new( KeyCode::Char('c'), KeyModifiers::empty() @@ -773,7 +743,7 @@ mod tests { #[test] fn test_parse_char_event_uppercase() { assert_eq!( - parse_event("C".as_bytes(), false).unwrap(), + parse_event(b"C", false).unwrap(), Some(InternalEvent::Event(Event::Key(KeyEvent::new( KeyCode::Char('C'), KeyModifiers::SHIFT diff --git a/src/event/sys/windows/parse.rs b/src/event/sys/windows/parse.rs index 9c1adf0..8f733b4 100644 --- a/src/event/sys/windows/parse.rs +++ b/src/event/sys/windows/parse.rs @@ -10,7 +10,7 @@ use winapi::um::{ }; use crate::{ - event::{Event, KeyCode, KeyEvent, KeyModifiers, MouseButton}, + event::{Event, KeyCode, KeyEvent, KeyModifiers, MouseButton, MouseEventKind}, Result, }; @@ -142,32 +142,20 @@ fn parse_mouse_event_record(event: &MouseEvent) -> Result { if button_state.release_button() { // in order to read the up button type, we have to check the last down input record. - Some(crate::event::MouseEvent::Up( - MouseButton::Left, - xpos, - ypos, - modifiers, - )) + Some(MouseEventKind::Up(MouseButton::Left)) } else { - Some(crate::event::MouseEvent::Down( - button, xpos, ypos, modifiers, - )) + Some(MouseEventKind::Down(button)) } } EventFlags::MouseMoved => { - // Click + Move - // Only register when mouse is not released - // because unix systems share this behaviour. - if !button_state.release_button() { - Some(crate::event::MouseEvent::Drag( - button, xpos, ypos, modifiers, - )) + if button_state.release_button() { + Some(MouseEventKind::Moved) } else { - None + Some(MouseEventKind::Drag(button)) } } EventFlags::MouseWheeled => { @@ -175,14 +163,21 @@ fn parse_mouse_event_record(event: &MouseEvent) -> Result None, // double click not supported by unix terminals EventFlags::MouseHwheeled => None, // horizontal scroll not supported by unix terminals - }) + }; + + Ok(kind.map(|kind| crate::event::MouseEvent { + kind, + column: xpos, + row: ypos, + modifiers, + })) } diff --git a/src/event/sys/windows/poll.rs b/src/event/sys/windows/poll.rs index bd2f23c..67e4cb9 100644 --- a/src/event/sys/windows/poll.rs +++ b/src/event/sys/windows/poll.rs @@ -22,14 +22,9 @@ pub(crate) struct WinApiPoll { } impl WinApiPoll { - #[cfg(not(feature = "event-stream"))] - pub(crate) fn new() -> Result { - Ok(WinApiPoll {}) - } - - #[cfg(feature = "event-stream")] pub(crate) fn new() -> Result { Ok(WinApiPoll { + #[cfg(feature = "event-stream")] waker: Waker::new()?, }) }