use super::params::CsiParams;
use super::{Event, Mods, MouseButton, MouseEvent, MouseKind};
use crate::base::Point;
pub(crate) fn decode_sgr(p: &CsiParams, final_byte: u8) -> Option<Event> {
let b = p.get_or(0, 0);
let x = p.get_or(1, 1);
let y = p.get_or(2, 1);
let pos = Point::new(x.max(1) as i32 - 1, y.max(1) as i32 - 1);
let mut mods = Mods::NONE;
if b & 4 != 0 {
mods = mods | Mods::SHIFT;
}
if b & 8 != 0 {
mods = mods | Mods::ALT;
}
if b & 16 != 0 {
mods = mods | Mods::CTRL;
}
let motion = b & 32 != 0;
let wheel = b & 64 != 0;
let extra = b & 128 != 0;
let low = b & 3;
let (kind, button) = if wheel {
let kind = match low {
0 => MouseKind::WheelUp,
1 => MouseKind::WheelDown,
2 => MouseKind::WheelLeft,
_ => MouseKind::WheelRight,
};
(kind, MouseButton::None)
} else {
let button = match (extra, low) {
(false, 0) => MouseButton::Left,
(false, 1) => MouseButton::Middle,
(false, 2) => MouseButton::Right,
(false, _) => MouseButton::None, (true, 0) => MouseButton::Back,
(true, 1) => MouseButton::Forward,
(true, _) => MouseButton::None, };
let kind = if motion {
if button == MouseButton::None {
MouseKind::Move
} else {
MouseKind::Drag
}
} else if final_byte == b'm' {
MouseKind::Up
} else {
MouseKind::Down
};
(kind, button)
};
Some(Event::Mouse(MouseEvent::new(kind, button, pos, mods)))
}
#[cfg(test)]
mod tests {
use super::super::Parser;
use super::*;
fn mouse(bytes: &[u8]) -> MouseEvent {
let mut p = Parser::new();
let mut out = Vec::new();
p.feed(bytes, &mut out);
assert_eq!(out.len(), 1, "one event expected: {out:?}");
match out.remove(0) {
Event::Mouse(m) => m,
other => panic!("expected mouse, got {other:?}"),
}
}
#[test]
fn press_release_have_real_buttons() {
let m = mouse(b"\x1b[<0;1;1M");
assert_eq!((m.kind, m.button), (MouseKind::Down, MouseButton::Left));
assert_eq!(m.pos, Point::ZERO); let m = mouse(b"\x1b[<0;1;1m");
assert_eq!((m.kind, m.button), (MouseKind::Up, MouseButton::Left));
let m = mouse(b"\x1b[<2;80;24M");
assert_eq!((m.kind, m.button), (MouseKind::Down, MouseButton::Right));
assert_eq!(m.pos, Point::new(79, 23));
let m = mouse(b"\x1b[<1;5;5m");
assert_eq!((m.kind, m.button), (MouseKind::Up, MouseButton::Middle));
}
#[test]
fn drag_and_motion() {
let m = mouse(b"\x1b[<32;10;5M"); assert_eq!((m.kind, m.button), (MouseKind::Drag, MouseButton::Left));
let m = mouse(b"\x1b[<35;10;5M"); assert_eq!((m.kind, m.button), (MouseKind::Move, MouseButton::None));
}
#[test]
fn wheel_all_directions() {
assert_eq!(mouse(b"\x1b[<64;1;1M").kind, MouseKind::WheelUp);
assert_eq!(mouse(b"\x1b[<65;1;1M").kind, MouseKind::WheelDown);
assert_eq!(mouse(b"\x1b[<66;1;1M").kind, MouseKind::WheelLeft);
assert_eq!(mouse(b"\x1b[<67;1;1M").kind, MouseKind::WheelRight);
}
#[test]
fn modifiers_ride_along() {
let m = mouse(b"\x1b[<16;3;4M"); assert_eq!(m.mods, Mods::CTRL);
assert_eq!(m.button, MouseButton::Left);
let m = mouse(b"\x1b[<28;3;4M"); assert_eq!(m.mods, Mods::SHIFT | Mods::ALT | Mods::CTRL);
let m = mouse(b"\x1b[<69;2;2M"); assert_eq!((m.kind, m.mods), (MouseKind::WheelDown, Mods::SHIFT));
}
#[test]
fn back_forward_buttons() {
let m = mouse(b"\x1b[<128;1;1M");
assert_eq!((m.kind, m.button), (MouseKind::Down, MouseButton::Back));
let m = mouse(b"\x1b[<129;1;1m");
assert_eq!((m.kind, m.button), (MouseKind::Up, MouseButton::Forward));
}
#[test]
fn zero_coordinates_clamp() {
let m = mouse(b"\x1b[<0;0;0M"); assert_eq!(m.pos, Point::ZERO);
}
}