Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 61 additions & 65 deletions crates/edit/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,8 @@ pub struct InputMouse {
pub position: Point,
/// Scroll delta.
pub scroll: Point,
/// Whether the mouse is being dragged with a button held down.
pub drag: bool,
}

/// Primary result type of the parser.
Expand Down Expand Up @@ -433,43 +435,10 @@ impl<'input> Iterator for Stream<'_, '_, 'input> {
}
}
'm' | 'M' if csi.private_byte == '<' => {
let btn = csi.params[0];
let mut mouse = InputMouse {
state: InputMouseState::None,
modifiers: kbmod::NONE,
position: Default::default(),
scroll: Default::default(),
};

mouse.state = InputMouseState::None;

match csi.params[0] {
btn @ 0..3 if csi.final_byte == 'M' => match btn {
0 => mouse.state = InputMouseState::Left,
1 => mouse.state = InputMouseState::Middle,
2 => mouse.state = InputMouseState::Right,
_ => {}
},
btn @ 64..68 => {
let delta = if (btn & 1) != 0 { 3 } else { -3 };
let idx = if (btn & 2) != 0 { 0 } else { 1 };
mouse.scroll.as_array()[idx] += delta;
mouse.state = InputMouseState::Scroll;
}
_ => {}
}

mouse.modifiers = kbmod::NONE;
mouse.modifiers |=
if (btn & 0x04) != 0 { kbmod::SHIFT } else { kbmod::NONE };
mouse.modifiers |=
if (btn & 0x08) != 0 { kbmod::ALT } else { kbmod::NONE };
mouse.modifiers |=
if (btn & 0x10) != 0 { kbmod::CTRL } else { kbmod::NONE };

mouse.position.x = csi.params[1] as CoordType - 1;
mouse.position.y = csi.params[2] as CoordType - 1;
return Some(Input::Mouse(mouse));
return Self::parse_xterm_mouse(
&csi.params[..csi.param_count],
csi.final_byte,
);
}
'M' if csi.param_count == 0 => {
self.parser.x10_mouse_want = true;
Expand Down Expand Up @@ -547,38 +516,14 @@ impl<'input> Stream<'_, '_, 'input> {
return None;
}

let b = self.parser.x10_mouse_buf[0] as u32;
let x = self.parser.x10_mouse_buf[1] as CoordType - 0x21;
let y = self.parser.x10_mouse_buf[2] as CoordType - 0x21;
let action = match b & 0b11 {
0 => InputMouseState::Left,
1 => InputMouseState::Middle,
2 => InputMouseState::Right,
_ => InputMouseState::None,
};
let modifiers = {
let mut m = kbmod::NONE;
if (b & 0b00100) != 0 {
m |= kbmod::SHIFT;
}
if (b & 0b01000) != 0 {
m |= kbmod::ALT;
}
if (b & 0b10000) != 0 {
m |= kbmod::CTRL;
}
m
};
let b = self.parser.x10_mouse_buf[0] as u16 - 0x20;
let x = self.parser.x10_mouse_buf[1] as u16 - 0x20;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i thought xterm mouse reports had a load-bearing offset of 1, and that's what this 0x21 was for?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We now subtract 1 in the unified parse_xterm_mouse function!

let y = self.parser.x10_mouse_buf[2] as u16 - 0x20;

self.parser.x10_mouse_want = false;
self.parser.x10_mouse_len = 0;

Some(Input::Mouse(InputMouse {
state: action,
modifiers,
position: Point { x, y },
scroll: Default::default(),
}))
Self::parse_xterm_mouse(&[b, x, y], 'M')
}

fn parse_modifiers(csi: &vt::Csi) -> InputKeyMod {
Expand All @@ -595,4 +540,55 @@ impl<'input> Stream<'_, '_, 'input> {
}
modifiers
}

fn parse_xterm_mouse(params: &[u16], final_byte: char) -> Option<Input<'input>> {
const SHIFT: u16 = 0x04;
const ALT: u16 = 0x08;
const CTRL: u16 = 0x10;
const MOTION: u16 = 0x20;
const WHEEL: u16 = 0x40;
const MODIFIERS: u16 = SHIFT | ALT | CTRL;
Comment on lines +545 to +550

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code here is almost identical to before with two changes:

  • Properly mask modifiers, etc., off of btn (now called kind)
  • Handle final_byte just in case


let &[btn, x, y, ..] = params else {
return None;
};

let kind = btn & !MODIFIERS;
let x = x as CoordType - 1;
let y = y as CoordType - 1;
let mut mouse = InputMouse {
state: InputMouseState::None,
modifiers: kbmod::NONE,
position: Point { x, y },
scroll: Default::default(),
drag: false,
};

if final_byte == 'm' {
// M = down, m = release.
// I know there's an InputMouseState::Release, but that's because the internals of tui.rs
// have leaked into intput.rs. input.rs indicates release by the absence of buttons being
// held, which is InputMouseState::None. This makes it more reliable in my opinion.
} else if (WHEEL..WHEEL + 4).contains(&kind) {
let delta = if (kind & 1) != 0 { 3 } else { -3 };
let idx = if (kind & 2) != 0 { 0 } else { 1 };
mouse.scroll.as_array()[idx] += delta;
mouse.state = InputMouseState::Scroll;
} else if (kind & !MOTION) < 3 {
match kind & 3 {
0 => mouse.state = InputMouseState::Left,
1 => mouse.state = InputMouseState::Middle,
2 => mouse.state = InputMouseState::Right,
_ => {}
}
mouse.drag = (kind & MOTION) != 0;
}

mouse.modifiers = kbmod::NONE;
mouse.modifiers |= if (btn & SHIFT) != 0 { kbmod::SHIFT } else { kbmod::NONE };
mouse.modifiers |= if (btn & ALT) != 0 { kbmod::ALT } else { kbmod::NONE };
mouse.modifiers |= if (btn & CTRL) != 0 { kbmod::CTRL } else { kbmod::NONE };

Some(Input::Mouse(mouse))
}
}
Loading