Extract KeyEvent type

The be used in the grandchild commit.
This commit is contained in:
Johannes Altmanninger
2025-03-30 08:33:24 +02:00
parent fabbbba037
commit 855a1f702e
3 changed files with 131 additions and 84 deletions

View File

@@ -142,11 +142,53 @@ pub enum ReadlineCmd {
ReverseRepeatJump,
}
#[derive(Clone, Copy, Debug)]
pub struct KeyEvent {
pub key: Key,
}
impl KeyEvent {
pub(crate) fn new(modifiers: Modifiers, codepoint: char) -> Self {
Self::from(Key::new(modifiers, codepoint))
}
pub(crate) fn from_raw(codepoint: char) -> Self {
Self::from(Key::from_raw(codepoint))
}
pub fn from_single_byte(c: u8) -> Self {
Self::from(Key::from_single_byte(c))
}
}
impl From<Key> for KeyEvent {
fn from(key: Key) -> Self {
Self { key }
}
}
impl std::ops::Deref for KeyEvent {
type Target = Key;
fn deref(&self) -> &Self::Target {
&self.key
}
}
impl std::ops::DerefMut for KeyEvent {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.key
}
}
impl PartialEq<Key> for KeyEvent {
fn eq(&self, key: &Key) -> bool {
&self.key == key
}
}
/// Represents an event on the character input stream.
#[derive(Debug, Clone)]
pub enum CharEventType {
/// A character was entered.
Char(Key),
Char(KeyInputEvent),
/// A readline event.
Readline(ReadlineCmd),
@@ -172,9 +214,9 @@ pub struct ReadlineCmdEvent {
}
#[derive(Debug, Clone)]
pub struct KeyEvent {
pub struct KeyInputEvent {
// The key.
pub key: Key,
pub key: KeyEvent,
// The style to use when inserting characters into the command line.
pub input_style: CharInputStyle,
/// The sequence of characters in the input mapping which generated this event.
@@ -207,7 +249,7 @@ pub enum ImplicitEvent {
#[derive(Debug, Clone)]
pub enum CharEvent {
/// A character was entered.
Key(KeyEvent),
Key(KeyInputEvent),
/// A readline event.
Readline(ReadlineCmdEvent),
@@ -240,7 +282,7 @@ pub fn get_char(&self) -> char {
kevt.key.codepoint
}
pub fn get_key(&self) -> Option<&KeyEvent> {
pub fn get_key(&self) -> Option<&KeyInputEvent> {
match self {
CharEvent::Key(kevt) => Some(kevt),
_ => None,
@@ -262,15 +304,15 @@ pub fn get_command(&self) -> Option<&wstr> {
}
pub fn from_char(c: char) -> CharEvent {
Self::from_key(Key::from_raw(c))
Self::from_key(KeyEvent::from_raw(c))
}
pub fn from_key(key: Key) -> CharEvent {
pub fn from_key(key: KeyEvent) -> CharEvent {
Self::from_key_seq(key, WString::new())
}
pub fn from_key_seq(key: Key, seq: WString) -> CharEvent {
CharEvent::Key(KeyEvent {
pub fn from_key_seq(key: KeyEvent, seq: WString) -> CharEvent {
CharEvent::Key(KeyInputEvent {
key,
input_style: CharInputStyle::Normal,
seq,
@@ -726,7 +768,7 @@ fn try_readch(&mut self, blocking: bool) -> Option<CharEvent> {
let key_with_escape = if read_byte == 0x1b {
self.parse_escape_sequence(&mut buffer, &mut have_escape_prefix)
} else {
canonicalize_control_char(read_byte)
canonicalize_control_char(read_byte).map(KeyEvent::from)
};
if self.paste_is_buffering() {
if read_byte != 0x1b {
@@ -736,7 +778,7 @@ fn try_readch(&mut self, blocking: bool) -> Option<CharEvent> {
}
let mut seq = WString::new();
let mut key = key_with_escape;
if key == Some(Key::from_raw(key::Invalid)) {
if key.is_some_and(|key| key == Key::from_raw(key::Invalid)) {
continue;
}
assert!(key.map_or(true, |key| key.codepoint != key::Invalid));
@@ -780,7 +822,7 @@ fn try_readch(&mut self, blocking: bool) -> Option<CharEvent> {
continue;
};
(
CharEvent::from_key_seq(Key::from_raw(c), seq.clone()),
CharEvent::from_key_seq(KeyEvent::from_raw(c), seq.clone()),
Some(seq.chars().skip(1).map(CharEvent::from_char)),
)
};
@@ -797,7 +839,8 @@ fn try_readch(&mut self, blocking: bool) -> Option<CharEvent> {
}
});
let vintr = shell_modes().c_cc[libc::VINTR];
if vintr != 0 && key == Some(Key::from_single_byte(vintr)) {
if vintr != 0 && key.is_some_and(|key| key == Key::from_single_byte(vintr))
{
FLOG!(
reader,
"Received interrupt key, giving up waiting for response from terminal"
@@ -827,22 +870,22 @@ fn parse_escape_sequence(
&mut self,
buffer: &mut Vec<u8>,
have_escape_prefix: &mut bool,
) -> Option<Key> {
) -> Option<KeyEvent> {
assert!(buffer.len() <= 2);
let recursive_invocation = buffer.len() == 2;
let Some(next) = self.try_readb(buffer) else {
if !self.paste_is_buffering() {
return Some(Key::from_raw(key::Escape));
return Some(KeyEvent::from_raw(key::Escape));
}
return None;
};
let invalid = Key::from_raw(key::Invalid);
let invalid = KeyEvent::from_raw(key::Invalid);
if recursive_invocation && next == b'\x1b' {
return Some(
match self.parse_escape_sequence(buffer, have_escape_prefix) {
Some(mut nested_sequence) => {
if nested_sequence == invalid {
return Some(Key::from_raw(key::Escape));
if nested_sequence == invalid.key {
return Some(KeyEvent::from_raw(key::Escape));
}
nested_sequence.modifiers.alt = true;
nested_sequence
@@ -866,7 +909,7 @@ fn parse_escape_sequence(
match canonicalize_control_char(next) {
Some(mut key) => {
key.modifiers.alt = true;
Some(key)
Some(KeyEvent::from(key))
}
None => {
*have_escape_prefix = true;
@@ -878,7 +921,7 @@ fn parse_escape_sequence(
fn parse_codepoint(
&mut self,
state: &mut mbstate_t,
out_key: &mut Option<Key>,
out_key: &mut Option<KeyEvent>,
out_seq: &mut WString,
buffer: &[u8],
i: usize,
@@ -928,7 +971,7 @@ fn parse_codepoint(
if !fish_reserved_codepoint(res) {
if *have_escape_prefix && i != 0 {
*have_escape_prefix = false;
*out_key = Some(alt(res));
*out_key = Some(KeyEvent::from(alt(res)));
}
*consumed += 1;
out_seq.push(res);
@@ -942,11 +985,11 @@ fn parse_codepoint(
ControlFlow::Continue(true)
}
fn parse_csi(&mut self, buffer: &mut Vec<u8>) -> Option<Key> {
fn parse_csi(&mut self, buffer: &mut Vec<u8>) -> Option<KeyEvent> {
// The maximum number of CSI parameters is defined by NPAR, nominally 16.
let mut params = [[0_u32; 4]; 16];
let Some(mut c) = self.try_readb(buffer) else {
return Some(ctrl('['));
return Some(KeyEvent::from(ctrl('[')));
};
let mut next_char = |zelf: &mut Self| zelf.try_readb(buffer).unwrap_or(0xff);
let private_mode;
@@ -993,10 +1036,7 @@ fn parse_csi(&mut self, buffer: &mut Vec<u8>) -> Option<Key> {
codepoint = shifted_codepoint;
}
}
Key {
modifiers,
codepoint,
}
KeyEvent::new(modifiers, codepoint)
};
let key = match c {
@@ -1013,9 +1053,9 @@ fn parse_csi(&mut self, buffer: &mut Vec<u8>) -> Option<Key> {
return None;
}
match params[0][0] {
23 | 24 => shift(
23 | 24 => KeyEvent::from(shift(
char::from_u32(u32::from(function_key(11)) + params[0][0] - 23).unwrap(), // rxvt style
),
)),
_ => return None,
}
}
@@ -1154,23 +1194,23 @@ fn parse_csi(&mut self, buffer: &mut Vec<u8>) -> Option<Key> {
char::from_u32(u32::from(function_key(11)) + params[0][0] - 23).unwrap(),
None,
),
25 | 26 => {
shift(char::from_u32(u32::from(function_key(3)) + params[0][0] - 25).unwrap())
} // rxvt style
25 | 26 => KeyEvent::from(shift(
char::from_u32(u32::from(function_key(3)) + params[0][0] - 25).unwrap(),
)), // rxvt style
27 => {
let key =
canonicalize_keyed_control_char(char::from_u32(params[2][0]).unwrap());
masked_key(key, None)
}
28 | 29 => {
shift(char::from_u32(u32::from(function_key(5)) + params[0][0] - 28).unwrap())
} // rxvt style
31 | 32 => {
shift(char::from_u32(u32::from(function_key(7)) + params[0][0] - 31).unwrap())
} // rxvt style
33 | 34 => {
shift(char::from_u32(u32::from(function_key(9)) + params[0][0] - 33).unwrap())
} // rxvt style
28 | 29 => KeyEvent::from(shift(
char::from_u32(u32::from(function_key(5)) + params[0][0] - 28).unwrap(),
)), // rxvt style
31 | 32 => KeyEvent::from(shift(
char::from_u32(u32::from(function_key(7)) + params[0][0] - 31).unwrap(),
)), // rxvt style
33 | 34 => KeyEvent::from(shift(
char::from_u32(u32::from(function_key(9)) + params[0][0] - 33).unwrap(),
)), // rxvt style
200 => {
self.paste_start_buffering();
return None;
@@ -1235,7 +1275,7 @@ fn parse_csi(&mut self, buffer: &mut Vec<u8>) -> Option<Key> {
)),
)
}
b'Z' => shift(key::Tab),
b'Z' => KeyEvent::from(shift(key::Tab)),
b'I' => {
self.push_front(CharEvent::Implicit(ImplicitEvent::FocusIn));
return None;
@@ -1263,10 +1303,10 @@ fn disable_mouse_tracking(&mut self) {
self.push_front(CharEvent::Implicit(ImplicitEvent::DisableMouseTracking));
}
fn parse_ss3(&mut self, buffer: &mut Vec<u8>) -> Option<Key> {
fn parse_ss3(&mut self, buffer: &mut Vec<u8>) -> Option<KeyEvent> {
let mut raw_mask = 0;
let Some(mut code) = self.try_readb(buffer) else {
return Some(alt('O'));
return Some(KeyEvent::from(alt('O')));
};
while (b'0'..=b'9').contains(&code) {
raw_mask = raw_mask * 10 + u32::from(code - b'0');
@@ -1275,36 +1315,36 @@ fn parse_ss3(&mut self, buffer: &mut Vec<u8>) -> Option<Key> {
let modifiers = parse_mask(raw_mask.saturating_sub(1));
#[rustfmt::skip]
let key = match code {
b' ' => Key::new(modifiers, key::Space),
b'A' => Key::new(modifiers, key::Up),
b'B' => Key::new(modifiers, key::Down),
b'C' => Key::new(modifiers, key::Right),
b'D' => Key::new(modifiers, key::Left),
b'F' => Key::new(modifiers, key::End),
b'H' => Key::new(modifiers, key::Home),
b'I' => Key::new(modifiers, key::Tab),
b'M' => Key::new(modifiers, key::Enter),
b'P' => Key::new(modifiers, function_key(1)),
b'Q' => Key::new(modifiers, function_key(2)),
b'R' => Key::new(modifiers, function_key(3)),
b'S' => Key::new(modifiers, function_key(4)),
b'X' => Key::new(modifiers, '='),
b'j' => Key::new(modifiers, '*'),
b'k' => Key::new(modifiers, '+'),
b'l' => Key::new(modifiers, ','),
b'm' => Key::new(modifiers, '-'),
b'n' => Key::new(modifiers, '.'),
b'o' => Key::new(modifiers, '/'),
b'p' => Key::new(modifiers, '0'),
b'q' => Key::new(modifiers, '1'),
b'r' => Key::new(modifiers, '2'),
b's' => Key::new(modifiers, '3'),
b't' => Key::new(modifiers, '4'),
b'u' => Key::new(modifiers, '5'),
b'v' => Key::new(modifiers, '6'),
b'w' => Key::new(modifiers, '7'),
b'x' => Key::new(modifiers, '8'),
b'y' => Key::new(modifiers, '9'),
b' ' => KeyEvent::new(modifiers, key::Space),
b'A' => KeyEvent::new(modifiers, key::Up),
b'B' => KeyEvent::new(modifiers, key::Down),
b'C' => KeyEvent::new(modifiers, key::Right),
b'D' => KeyEvent::new(modifiers, key::Left),
b'F' => KeyEvent::new(modifiers, key::End),
b'H' => KeyEvent::new(modifiers, key::Home),
b'I' => KeyEvent::new(modifiers, key::Tab),
b'M' => KeyEvent::new(modifiers, key::Enter),
b'P' => KeyEvent::new(modifiers, function_key(1)),
b'Q' => KeyEvent::new(modifiers, function_key(2)),
b'R' => KeyEvent::new(modifiers, function_key(3)),
b'S' => KeyEvent::new(modifiers, function_key(4)),
b'X' => KeyEvent::new(modifiers, '='),
b'j' => KeyEvent::new(modifiers, '*'),
b'k' => KeyEvent::new(modifiers, '+'),
b'l' => KeyEvent::new(modifiers, ','),
b'm' => KeyEvent::new(modifiers, '-'),
b'n' => KeyEvent::new(modifiers, '.'),
b'o' => KeyEvent::new(modifiers, '/'),
b'p' => KeyEvent::new(modifiers, '0'),
b'q' => KeyEvent::new(modifiers, '1'),
b'r' => KeyEvent::new(modifiers, '2'),
b's' => KeyEvent::new(modifiers, '3'),
b't' => KeyEvent::new(modifiers, '4'),
b'u' => KeyEvent::new(modifiers, '5'),
b'v' => KeyEvent::new(modifiers, '6'),
b'w' => KeyEvent::new(modifiers, '7'),
b'x' => KeyEvent::new(modifiers, '8'),
b'y' => KeyEvent::new(modifiers, '9'),
_ => return None,
};
Some(key)
@@ -1334,10 +1374,10 @@ fn parse_xtversion(&mut self, buffer: &mut Vec<u8>) {
);
}
fn parse_dcs(&mut self, buffer: &mut Vec<u8>) -> Option<Key> {
fn parse_dcs(&mut self, buffer: &mut Vec<u8>) -> Option<KeyEvent> {
assert!(buffer.len() == 2);
let Some(success) = self.try_readb(buffer) else {
return Some(alt('P'));
return Some(KeyEvent::from(alt('P')));
};
let success = match success {
b'0' => false,
@@ -1589,7 +1629,7 @@ fn select_interrupted(&mut self) {}
fn enqueue_interrupt_key(&mut self) {
let vintr = shell_modes().c_cc[libc::VINTR];
if vintr != 0 {
let interrupt_evt = CharEvent::from_key(Key::from_single_byte(vintr));
let interrupt_evt = CharEvent::from_key(KeyEvent::from_single_byte(vintr));
if unblock_input(self.blocking_wait()) {
FLOG!(
reader,
@@ -1629,7 +1669,7 @@ pub(crate) fn unblock_input(mut wait_guard: MutexGuard<Option<BlockingWait>>) ->
true
}
fn invalid_sequence(buffer: &[u8]) -> Option<Key> {
fn invalid_sequence(buffer: &[u8]) -> Option<KeyEvent> {
FLOG!(
reader,
"Error: invalid escape sequence: ",