Add support for any event tracking (#502)

This commit is contained in:
Koxiaet 2020-11-22 12:52:15 +00:00 committed by GitHub
parent 30ce6364a9
commit e5d3959119
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 231 additions and 249 deletions

View File

@ -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.

View File

@ -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"),
);

View File

@ -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<Option<InternalEvent>> {
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<Option<InternalEvent
.map_err(|_| could_not_parse_event_error())?;
let mut split = s.split(';');
let cb = next_parsed::<u16>(&mut split)?;
let cb = next_parsed::<u8>(&mut split)?
.checked_sub(32)
.ok_or_else(could_not_parse_event_error)?;
let (kind, modifiers) = parse_cb(cb)?;
let cx = next_parsed::<u16>(&mut split)? - 1;
let cy = next_parsed::<u16>(&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<Option<InternalEvent>> {
// 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<Option<InternalEvent>> {
// 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<Option<InternalEvent>
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<Option<InternalEvent>> {
pub(crate) fn parse_csi_sgr_mouse(buffer: &[u8]) -> Result<Option<InternalEvent>> {
// 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<Option<InternalEven
.map_err(|_| could_not_parse_event_error())?;
let mut split = s.split(';');
let cb = next_parsed::<u16>(&mut split)?;
let cb = next_parsed::<u8>(&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<Option<InternalEven
let cx = next_parsed::<u16>(&mut split)? - 1;
let cy = next_parsed::<u16>(&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<Option<char>> {
@ -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

View File

@ -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<Option<crate::event::M
MouseButton::Left
};
Ok(match event.event_flags {
let kind = match event.event_flags {
EventFlags::PressOrRelease => {
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<Option<crate::event::M
// from https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str
// if `button_state` is negative then the wheel was rotated backward, toward the user.
if button_state.scroll_down() {
Some(crate::event::MouseEvent::ScrollDown(xpos, ypos, modifiers))
Some(MouseEventKind::ScrollDown)
} else if button_state.scroll_up() {
Some(crate::event::MouseEvent::ScrollUp(xpos, ypos, modifiers))
Some(MouseEventKind::ScrollUp)
} else {
None
}
}
EventFlags::DoubleClick => 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,
}))
}

View File

@ -22,14 +22,9 @@ pub(crate) struct WinApiPoll {
}
impl WinApiPoll {
#[cfg(not(feature = "event-stream"))]
pub(crate) fn new() -> Result<WinApiPoll> {
Ok(WinApiPoll {})
}
#[cfg(feature = "event-stream")]
pub(crate) fn new() -> Result<WinApiPoll> {
Ok(WinApiPoll {
#[cfg(feature = "event-stream")]
waker: Waker::new()?,
})
}