Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for functional key codes from kitty keyboard protocol #691

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
45 changes: 20 additions & 25 deletions examples/event-match-modifiers.rs
Expand Up @@ -45,29 +45,24 @@ fn match_event(read_event: Event) {
}

fn main() {
match_event(Event::Key(KeyEvent {
modifiers: KeyModifiers::CONTROL,
code: KeyCode::Char('z'),
kind: KeyEventKind::Press,
}));
match_event(Event::Key(KeyEvent {
modifiers: KeyModifiers::SHIFT,
code: KeyCode::Left,
kind: KeyEventKind::Press,
}));
match_event(Event::Key(KeyEvent {
modifiers: KeyModifiers::ALT,
code: KeyCode::Delete,
kind: KeyEventKind::Press,
}));
match_event(Event::Key(KeyEvent {
modifiers: KeyModifiers::ALT | KeyModifiers::SHIFT,
code: KeyCode::Right,
kind: KeyEventKind::Press,
}));
match_event(Event::Key(KeyEvent {
modifiers: KeyModifiers::ALT | KeyModifiers::CONTROL,
code: KeyCode::Home,
kind: KeyEventKind::Press,
}));
match_event(Event::Key(KeyEvent::new(
KeyCode::Char('z'),
KeyModifiers::CONTROL,
)));
match_event(Event::Key(KeyEvent::new(
KeyCode::Left,
KeyModifiers::SHIFT,
)));
match_event(Event::Key(KeyEvent::new(
KeyCode::Delete,
KeyModifiers::ALT,
)));
match_event(Event::Key(KeyEvent::new(
KeyCode::Right,
KeyModifiers::ALT | KeyModifiers::SHIFT,
)));
match_event(Event::Key(KeyEvent::new(
KeyCode::Home,
KeyModifiers::ALT | KeyModifiers::CONTROL,
)));
}
173 changes: 166 additions & 7 deletions src/event.rs
Expand Up @@ -377,7 +377,7 @@ impl Command for PushKeyboardEnhancementFlags {
fn execute_winapi(&self) -> Result<()> {
Err(io::Error::new(
io::ErrorKind::Unsupported,
"Keyboard progressive enhancement not implemented on Windows.",
"Keyboard progressive enhancement not implemented for the legacy Windows API.",
))
}

Expand All @@ -404,7 +404,7 @@ impl Command for PopKeyboardEnhancementFlags {
fn execute_winapi(&self) -> Result<()> {
Err(io::Error::new(
io::ErrorKind::Unsupported,
"Keyboard progressive enhancement not implemented on Windows.",
"Keyboard progressive enhancement not implemented for the legacy Windows API.",
))
}

Expand Down Expand Up @@ -553,6 +553,15 @@ pub enum KeyEventKind {
Release,
}

bitflags! {
/// Represents extra state about the key event.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct KeyEventState: u8 {
/// The key event origins from the keypad.
const KEYPAD = 0b0000_0001;
pianohacker marked this conversation as resolved.
Show resolved Hide resolved
}
}

/// Represents a key event.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialOrd, Clone, Copy)]
Expand All @@ -563,6 +572,11 @@ pub struct KeyEvent {
pub modifiers: KeyModifiers,
/// Kind of event.
pub kind: KeyEventKind,
/// Keyboard state.
pianohacker marked this conversation as resolved.
Show resolved Hide resolved
///
/// Only set if [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
/// [`PushKeyboardEnhancementFlags`].
pub state: KeyEventState,
}

impl KeyEvent {
Expand All @@ -571,6 +585,7 @@ impl KeyEvent {
code,
modifiers,
kind: KeyEventKind::Press,
state: KeyEventState::empty(),
}
}

Expand All @@ -583,6 +598,21 @@ impl KeyEvent {
code,
modifiers,
kind,
state: KeyEventState::empty(),
}
}

pub const fn new_with_kind_and_state(
code: KeyCode,
modifiers: KeyModifiers,
kind: KeyEventKind,
state: KeyEventState,
) -> KeyEvent {
KeyEvent {
code,
modifiers,
kind,
state,
}
}

Expand Down Expand Up @@ -610,6 +640,7 @@ impl From<KeyCode> for KeyEvent {
code,
modifiers: KeyModifiers::empty(),
kind: KeyEventKind::Press,
state: KeyEventState::empty(),
}
}
}
Expand All @@ -620,31 +651,104 @@ impl PartialEq for KeyEvent {
code: lhs_code,
modifiers: lhs_modifiers,
kind: lhs_kind,
state: lhs_state,
} = self.normalize_case();
let KeyEvent {
code: rhs_code,
modifiers: rhs_modifiers,
kind: rhs_kind,
state: rhs_state,
} = other.normalize_case();
(lhs_code == rhs_code) && (lhs_modifiers == rhs_modifiers) && (lhs_kind == rhs_kind)
(lhs_code == rhs_code)
&& (lhs_modifiers == rhs_modifiers)
&& (lhs_kind == rhs_kind)
&& (lhs_state == rhs_state)
}
}

impl Eq for KeyEvent {}

impl Hash for KeyEvent {
fn hash<H: Hasher>(&self, state: &mut H) {
fn hash<H: Hasher>(&self, hash_state: &mut H) {
let KeyEvent {
code,
modifiers,
kind,
state,
} = self.normalize_case();
code.hash(state);
modifiers.hash(state);
kind.hash(state);
code.hash(hash_state);
modifiers.hash(hash_state);
kind.hash(hash_state);
state.hash(hash_state);
}
}

/// Represents a media key (as part of [`KeyCode::Media`]).
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum MediaKeyCode {
/// Play media key.
Play,
/// Pause media key.
Pause,
/// Play/Pause media key.
PlayPause,
/// Reverse media key.
Reverse,
/// Stop media key.
Stop,
/// Fast-forward media key.
FastForward,
/// Rewind media key.
Rewind,
/// Next-track media key.
TrackNext,
/// Previous-track media key.
TrackPrevious,
/// Record media key.
Record,
/// Lower-volume media key.
LowerVolume,
/// Raise-volume media key.
RaiseVolume,
/// Mute media key.
MuteVolume,
}

/// Represents a modifier key (as part of [`KeyCode::Modifier`]).
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum ModifierKeyCode {
/// Left Shift key.
LeftShift,
/// Left Control key.
LeftControl,
/// Left Alt key.
LeftAlt,
/// Left Super key.
LeftSuper,
/// Left Hyper key.
LeftHyper,
/// Left Meta key.
LeftMeta,
/// Right Shift key.
RightShift,
/// Right Control key.
RightControl,
/// Right Alt key.
RightAlt,
/// Right Super key.
RightSuper,
/// Right Hyper key.
RightHyper,
/// Right Meta key.
RightMeta,
/// Iso Level3 Shift key.
IsoLevel3Shift,
/// Iso Level5 Shift key.
IsoLevel5Shift,
}

/// Represents a key.
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
Expand Down Expand Up @@ -689,6 +793,61 @@ pub enum KeyCode {
Null,
/// Escape key.
Esc,
/// Caps Lock key.
///
/// **Note:** this key can only be read if
/// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
/// [`PushKeyboardEnhancementFlags`].
CapsLock,
/// Scroll Lock key.
///
/// **Note:** this key can only be read if
/// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
/// [`PushKeyboardEnhancementFlags`].
ScrollLock,
/// Num Lock key.
///
/// **Note:** this key can only be read if
/// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
/// [`PushKeyboardEnhancementFlags`].
NumLock,
pianohacker marked this conversation as resolved.
Show resolved Hide resolved
/// Print Screen key.
///
/// **Note:** this key can only be read if
/// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
/// [`PushKeyboardEnhancementFlags`].
PrintScreen,
/// Pause key.
///
/// **Note:** this key can only be read if
/// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
/// [`PushKeyboardEnhancementFlags`].
Pause,
/// Menu key.
///
/// **Note:** this key can only be read if
/// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
/// [`PushKeyboardEnhancementFlags`].
Menu,
/// The "Begin" key (often mapped to the 5 key when Num Lock is turned on).
///
/// **Note:** this key can only be read if
/// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
/// [`PushKeyboardEnhancementFlags`].
KeypadBegin,
/// A media key.
///
/// **Note:** these keys can only be read if
/// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
/// [`PushKeyboardEnhancementFlags`].
Media(MediaKeyCode),
pianohacker marked this conversation as resolved.
Show resolved Hide resolved
/// A modifier key.
///
/// **Note:** these keys can only be read if **both**
/// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] and
/// [`KeyboardEnhancementFlags::REPORT_ALL_KEYS_AS_ESCAPE_CODES`] have been enabled with
/// [`PushKeyboardEnhancementFlags`].
Modifier(ModifierKeyCode),
}

/// An internal event.
Expand Down