diff --git a/helix-view/src/input.rs b/helix-view/src/input.rs index 30fa72c49653..bda0520e0b51 100644 --- a/helix-view/src/input.rs +++ b/helix-view/src/input.rs @@ -4,7 +4,7 @@ use helix_core::unicode::{segmentation::UnicodeSegmentation, width::UnicodeWidth use serde::de::{self, Deserialize, Deserializer}; use std::fmt; -pub use crate::keyboard::{KeyCode, KeyModifiers}; +pub use crate::keyboard::{KeyCode, KeyModifiers, MediaKeyCode, ModifierKeyCode}; #[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Hash)] pub enum Event { @@ -119,6 +119,40 @@ pub(crate) mod keys { pub(crate) const MINUS: &str = "minus"; pub(crate) const LESS_THAN: &str = "lt"; pub(crate) const GREATER_THAN: &str = "gt"; + pub(crate) const CAPS_LOCK: &str = "capslock"; + pub(crate) const SCROLL_LOCK: &str = "scrolllock"; + pub(crate) const NUM_LOCK: &str = "numlock"; + pub(crate) const PRINT_SCREEN: &str = "printscreen"; + pub(crate) const PAUSE: &str = "pause"; + pub(crate) const MENU: &str = "menu"; + pub(crate) const KEYPAD_BEGIN: &str = "keypadbegin"; + pub(crate) const PLAY: &str = "play"; + pub(crate) const PAUSE_MEDIA: &str = "pausemedia"; + pub(crate) const PLAY_PAUSE: &str = "playpause"; + pub(crate) const REVERSE: &str = "reverse"; + pub(crate) const STOP: &str = "stop"; + pub(crate) const FAST_FORWARD: &str = "fastforward"; + pub(crate) const REWIND: &str = "rewind"; + pub(crate) const TRACK_NEXT: &str = "tracknext"; + pub(crate) const TRACK_PREVIOUS: &str = "trackprevious"; + pub(crate) const RECORD: &str = "record"; + pub(crate) const LOWER_VOLUME: &str = "lowervolume"; + pub(crate) const RAISE_VOLUME: &str = "raisevolume"; + pub(crate) const MUTE_VOLUME: &str = "mutevolume"; + pub(crate) const LEFT_SHIFT: &str = "leftshift"; + pub(crate) const LEFT_CONTROL: &str = "leftcontrol"; + pub(crate) const LEFT_ALT: &str = "leftalt"; + pub(crate) const LEFT_SUPER: &str = "leftsuper"; + pub(crate) const LEFT_HYPER: &str = "lefthyper"; + pub(crate) const LEFT_META: &str = "leftmeta"; + pub(crate) const RIGHT_SHIFT: &str = "rightshift"; + pub(crate) const RIGHT_CONTROL: &str = "rightcontrol"; + pub(crate) const RIGHT_ALT: &str = "rightalt"; + pub(crate) const RIGHT_SUPER: &str = "rightsuper"; + pub(crate) const RIGHT_HYPER: &str = "righthyper"; + pub(crate) const RIGHT_META: &str = "rightmeta"; + pub(crate) const ISO_LEVEL_3_SHIFT: &str = "isolevel3shift"; + pub(crate) const ISO_LEVEL_5_SHIFT: &str = "isolevel5shift"; } impl fmt::Display for KeyEvent { @@ -163,6 +197,44 @@ impl fmt::Display for KeyEvent { KeyCode::Char('>') => f.write_str(keys::GREATER_THAN)?, KeyCode::F(i) => f.write_fmt(format_args!("F{}", i))?, KeyCode::Char(c) => f.write_fmt(format_args!("{}", c))?, + KeyCode::CapsLock => f.write_str(keys::CAPS_LOCK)?, + KeyCode::ScrollLock => f.write_str(keys::SCROLL_LOCK)?, + KeyCode::NumLock => f.write_str(keys::NUM_LOCK)?, + KeyCode::PrintScreen => f.write_str(keys::PRINT_SCREEN)?, + KeyCode::Pause => f.write_str(keys::PAUSE)?, + KeyCode::Menu => f.write_str(keys::MENU)?, + KeyCode::KeypadBegin => f.write_str(keys::KEYPAD_BEGIN)?, + KeyCode::Media(MediaKeyCode::Play) => f.write_str(keys::PLAY)?, + KeyCode::Media(MediaKeyCode::Pause) => f.write_str(keys::PAUSE_MEDIA)?, + KeyCode::Media(MediaKeyCode::PlayPause) => f.write_str(keys::PLAY_PAUSE)?, + KeyCode::Media(MediaKeyCode::Stop) => f.write_str(keys::STOP)?, + KeyCode::Media(MediaKeyCode::Reverse) => f.write_str(keys::REVERSE)?, + KeyCode::Media(MediaKeyCode::FastForward) => f.write_str(keys::FAST_FORWARD)?, + KeyCode::Media(MediaKeyCode::Rewind) => f.write_str(keys::REWIND)?, + KeyCode::Media(MediaKeyCode::TrackNext) => f.write_str(keys::TRACK_NEXT)?, + KeyCode::Media(MediaKeyCode::TrackPrevious) => f.write_str(keys::TRACK_PREVIOUS)?, + KeyCode::Media(MediaKeyCode::Record) => f.write_str(keys::RECORD)?, + KeyCode::Media(MediaKeyCode::LowerVolume) => f.write_str(keys::LOWER_VOLUME)?, + KeyCode::Media(MediaKeyCode::RaiseVolume) => f.write_str(keys::RAISE_VOLUME)?, + KeyCode::Media(MediaKeyCode::MuteVolume) => f.write_str(keys::MUTE_VOLUME)?, + KeyCode::Modifier(ModifierKeyCode::LeftShift) => f.write_str(keys::LEFT_SHIFT)?, + KeyCode::Modifier(ModifierKeyCode::LeftControl) => f.write_str(keys::LEFT_CONTROL)?, + KeyCode::Modifier(ModifierKeyCode::LeftAlt) => f.write_str(keys::LEFT_ALT)?, + KeyCode::Modifier(ModifierKeyCode::LeftSuper) => f.write_str(keys::LEFT_SUPER)?, + KeyCode::Modifier(ModifierKeyCode::LeftHyper) => f.write_str(keys::LEFT_HYPER)?, + KeyCode::Modifier(ModifierKeyCode::LeftMeta) => f.write_str(keys::LEFT_META)?, + KeyCode::Modifier(ModifierKeyCode::RightShift) => f.write_str(keys::RIGHT_SHIFT)?, + KeyCode::Modifier(ModifierKeyCode::RightControl) => f.write_str(keys::RIGHT_CONTROL)?, + KeyCode::Modifier(ModifierKeyCode::RightAlt) => f.write_str(keys::RIGHT_ALT)?, + KeyCode::Modifier(ModifierKeyCode::RightSuper) => f.write_str(keys::RIGHT_SUPER)?, + KeyCode::Modifier(ModifierKeyCode::RightHyper) => f.write_str(keys::RIGHT_HYPER)?, + KeyCode::Modifier(ModifierKeyCode::RightMeta) => f.write_str(keys::RIGHT_META)?, + KeyCode::Modifier(ModifierKeyCode::IsoLevel3Shift) => { + f.write_str(keys::ISO_LEVEL_3_SHIFT)? + } + KeyCode::Modifier(ModifierKeyCode::IsoLevel5Shift) => { + f.write_str(keys::ISO_LEVEL_5_SHIFT)? + } }; Ok(()) } @@ -192,6 +264,40 @@ impl UnicodeWidthStr for KeyEvent { KeyCode::F(1..=9) => 2, KeyCode::F(_) => 3, KeyCode::Char(c) => c.width().unwrap_or(0), + KeyCode::CapsLock => keys::CAPS_LOCK.len(), + KeyCode::ScrollLock => keys::SCROLL_LOCK.len(), + KeyCode::NumLock => keys::NUM_LOCK.len(), + KeyCode::PrintScreen => keys::PRINT_SCREEN.len(), + KeyCode::Pause => keys::PAUSE.len(), + KeyCode::Menu => keys::MENU.len(), + KeyCode::KeypadBegin => keys::KEYPAD_BEGIN.len(), + KeyCode::Media(MediaKeyCode::Play) => keys::PLAY.len(), + KeyCode::Media(MediaKeyCode::Pause) => keys::PAUSE_MEDIA.len(), + KeyCode::Media(MediaKeyCode::PlayPause) => keys::PLAY_PAUSE.len(), + KeyCode::Media(MediaKeyCode::Stop) => keys::STOP.len(), + KeyCode::Media(MediaKeyCode::Reverse) => keys::REVERSE.len(), + KeyCode::Media(MediaKeyCode::FastForward) => keys::FAST_FORWARD.len(), + KeyCode::Media(MediaKeyCode::Rewind) => keys::REWIND.len(), + KeyCode::Media(MediaKeyCode::TrackNext) => keys::TRACK_NEXT.len(), + KeyCode::Media(MediaKeyCode::TrackPrevious) => keys::TRACK_PREVIOUS.len(), + KeyCode::Media(MediaKeyCode::Record) => keys::RECORD.len(), + KeyCode::Media(MediaKeyCode::LowerVolume) => keys::LOWER_VOLUME.len(), + KeyCode::Media(MediaKeyCode::RaiseVolume) => keys::RAISE_VOLUME.len(), + KeyCode::Media(MediaKeyCode::MuteVolume) => keys::MUTE_VOLUME.len(), + KeyCode::Modifier(ModifierKeyCode::LeftShift) => keys::LEFT_SHIFT.len(), + KeyCode::Modifier(ModifierKeyCode::LeftControl) => keys::LEFT_CONTROL.len(), + KeyCode::Modifier(ModifierKeyCode::LeftAlt) => keys::LEFT_ALT.len(), + KeyCode::Modifier(ModifierKeyCode::LeftSuper) => keys::LEFT_SUPER.len(), + KeyCode::Modifier(ModifierKeyCode::LeftHyper) => keys::LEFT_HYPER.len(), + KeyCode::Modifier(ModifierKeyCode::LeftMeta) => keys::LEFT_META.len(), + KeyCode::Modifier(ModifierKeyCode::RightShift) => keys::RIGHT_SHIFT.len(), + KeyCode::Modifier(ModifierKeyCode::RightControl) => keys::RIGHT_CONTROL.len(), + KeyCode::Modifier(ModifierKeyCode::RightAlt) => keys::RIGHT_ALT.len(), + KeyCode::Modifier(ModifierKeyCode::RightSuper) => keys::RIGHT_SUPER.len(), + KeyCode::Modifier(ModifierKeyCode::RightHyper) => keys::RIGHT_HYPER.len(), + KeyCode::Modifier(ModifierKeyCode::RightMeta) => keys::RIGHT_META.len(), + KeyCode::Modifier(ModifierKeyCode::IsoLevel3Shift) => keys::ISO_LEVEL_3_SHIFT.len(), + KeyCode::Modifier(ModifierKeyCode::IsoLevel5Shift) => keys::ISO_LEVEL_5_SHIFT.len(), }; if self.modifiers.contains(KeyModifiers::SHIFT) { width += 2; @@ -235,6 +341,40 @@ impl std::str::FromStr for KeyEvent { keys::MINUS => KeyCode::Char('-'), keys::LESS_THAN => KeyCode::Char('<'), keys::GREATER_THAN => KeyCode::Char('>'), + keys::CAPS_LOCK => KeyCode::CapsLock, + keys::SCROLL_LOCK => KeyCode::ScrollLock, + keys::NUM_LOCK => KeyCode::NumLock, + keys::PRINT_SCREEN => KeyCode::PrintScreen, + keys::PAUSE => KeyCode::Pause, + keys::MENU => KeyCode::Menu, + keys::KEYPAD_BEGIN => KeyCode::KeypadBegin, + keys::PLAY => KeyCode::Media(MediaKeyCode::Play), + keys::PAUSE_MEDIA => KeyCode::Media(MediaKeyCode::Pause), + keys::PLAY_PAUSE => KeyCode::Media(MediaKeyCode::PlayPause), + keys::STOP => KeyCode::Media(MediaKeyCode::Stop), + keys::REVERSE => KeyCode::Media(MediaKeyCode::Reverse), + keys::FAST_FORWARD => KeyCode::Media(MediaKeyCode::FastForward), + keys::REWIND => KeyCode::Media(MediaKeyCode::Rewind), + keys::TRACK_NEXT => KeyCode::Media(MediaKeyCode::TrackNext), + keys::TRACK_PREVIOUS => KeyCode::Media(MediaKeyCode::TrackPrevious), + keys::RECORD => KeyCode::Media(MediaKeyCode::Record), + keys::LOWER_VOLUME => KeyCode::Media(MediaKeyCode::LowerVolume), + keys::RAISE_VOLUME => KeyCode::Media(MediaKeyCode::RaiseVolume), + keys::MUTE_VOLUME => KeyCode::Media(MediaKeyCode::MuteVolume), + keys::LEFT_SHIFT => KeyCode::Modifier(ModifierKeyCode::LeftShift), + keys::LEFT_CONTROL => KeyCode::Modifier(ModifierKeyCode::LeftControl), + keys::LEFT_ALT => KeyCode::Modifier(ModifierKeyCode::LeftAlt), + keys::LEFT_SUPER => KeyCode::Modifier(ModifierKeyCode::LeftSuper), + keys::LEFT_HYPER => KeyCode::Modifier(ModifierKeyCode::LeftHyper), + keys::LEFT_META => KeyCode::Modifier(ModifierKeyCode::LeftMeta), + keys::RIGHT_SHIFT => KeyCode::Modifier(ModifierKeyCode::RightShift), + keys::RIGHT_CONTROL => KeyCode::Modifier(ModifierKeyCode::RightControl), + keys::RIGHT_ALT => KeyCode::Modifier(ModifierKeyCode::RightAlt), + keys::RIGHT_SUPER => KeyCode::Modifier(ModifierKeyCode::RightSuper), + keys::RIGHT_HYPER => KeyCode::Modifier(ModifierKeyCode::RightHyper), + keys::RIGHT_META => KeyCode::Modifier(ModifierKeyCode::RightMeta), + keys::ISO_LEVEL_3_SHIFT => KeyCode::Modifier(ModifierKeyCode::IsoLevel3Shift), + keys::ISO_LEVEL_5_SHIFT => KeyCode::Modifier(ModifierKeyCode::IsoLevel5Shift), single if single.chars().count() == 1 => KeyCode::Char(single.chars().next().unwrap()), function if function.len() > 1 && function.starts_with('F') => { let function: String = function.chars().skip(1).collect(); diff --git a/helix-view/src/keyboard.rs b/helix-view/src/keyboard.rs index 84cfebf160d7..cf673e113ce2 100644 --- a/helix-view/src/keyboard.rs +++ b/helix-view/src/keyboard.rs @@ -53,6 +53,164 @@ impl From for KeyModifiers { } } +/// Represents a media key (as part of [`KeyCode::Media`]). +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)] +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, +} + +#[cfg(feature = "term")] +impl From for crossterm::event::MediaKeyCode { + fn from(media_key_code: MediaKeyCode) -> Self { + use crossterm::event::MediaKeyCode as CMediaKeyCode; + + match media_key_code { + MediaKeyCode::Play => CMediaKeyCode::Play, + MediaKeyCode::Pause => CMediaKeyCode::Pause, + MediaKeyCode::PlayPause => CMediaKeyCode::PlayPause, + MediaKeyCode::Reverse => CMediaKeyCode::Reverse, + MediaKeyCode::Stop => CMediaKeyCode::Stop, + MediaKeyCode::FastForward => CMediaKeyCode::FastForward, + MediaKeyCode::Rewind => CMediaKeyCode::Rewind, + MediaKeyCode::TrackNext => CMediaKeyCode::TrackNext, + MediaKeyCode::TrackPrevious => CMediaKeyCode::TrackPrevious, + MediaKeyCode::Record => CMediaKeyCode::Record, + MediaKeyCode::LowerVolume => CMediaKeyCode::LowerVolume, + MediaKeyCode::RaiseVolume => CMediaKeyCode::RaiseVolume, + MediaKeyCode::MuteVolume => CMediaKeyCode::MuteVolume, + } + } +} + +#[cfg(feature = "term")] +impl From for MediaKeyCode { + fn from(val: crossterm::event::MediaKeyCode) -> Self { + use crossterm::event::MediaKeyCode as CMediaKeyCode; + + match val { + CMediaKeyCode::Play => MediaKeyCode::Play, + CMediaKeyCode::Pause => MediaKeyCode::Pause, + CMediaKeyCode::PlayPause => MediaKeyCode::PlayPause, + CMediaKeyCode::Reverse => MediaKeyCode::Reverse, + CMediaKeyCode::Stop => MediaKeyCode::Stop, + CMediaKeyCode::FastForward => MediaKeyCode::FastForward, + CMediaKeyCode::Rewind => MediaKeyCode::Rewind, + CMediaKeyCode::TrackNext => MediaKeyCode::TrackNext, + CMediaKeyCode::TrackPrevious => MediaKeyCode::TrackPrevious, + CMediaKeyCode::Record => MediaKeyCode::Record, + CMediaKeyCode::LowerVolume => MediaKeyCode::LowerVolume, + CMediaKeyCode::RaiseVolume => MediaKeyCode::RaiseVolume, + CMediaKeyCode::MuteVolume => MediaKeyCode::MuteVolume, + } + } +} + +/// Represents a media key (as part of [`KeyCode::Modifier`]). +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)] +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, +} + +#[cfg(feature = "term")] +impl From for crossterm::event::ModifierKeyCode { + fn from(modifier_key_code: ModifierKeyCode) -> Self { + use crossterm::event::ModifierKeyCode as CModifierKeyCode; + + match modifier_key_code { + ModifierKeyCode::LeftShift => CModifierKeyCode::LeftShift, + ModifierKeyCode::LeftControl => CModifierKeyCode::LeftControl, + ModifierKeyCode::LeftAlt => CModifierKeyCode::LeftAlt, + ModifierKeyCode::LeftSuper => CModifierKeyCode::LeftSuper, + ModifierKeyCode::LeftHyper => CModifierKeyCode::LeftHyper, + ModifierKeyCode::LeftMeta => CModifierKeyCode::LeftMeta, + ModifierKeyCode::RightShift => CModifierKeyCode::RightShift, + ModifierKeyCode::RightControl => CModifierKeyCode::RightControl, + ModifierKeyCode::RightAlt => CModifierKeyCode::RightAlt, + ModifierKeyCode::RightSuper => CModifierKeyCode::RightSuper, + ModifierKeyCode::RightHyper => CModifierKeyCode::RightHyper, + ModifierKeyCode::RightMeta => CModifierKeyCode::RightMeta, + ModifierKeyCode::IsoLevel3Shift => CModifierKeyCode::IsoLevel3Shift, + ModifierKeyCode::IsoLevel5Shift => CModifierKeyCode::IsoLevel5Shift, + } + } +} + +#[cfg(feature = "term")] +impl From for ModifierKeyCode { + fn from(val: crossterm::event::ModifierKeyCode) -> Self { + use crossterm::event::ModifierKeyCode as CModifierKeyCode; + + match val { + CModifierKeyCode::LeftShift => ModifierKeyCode::LeftShift, + CModifierKeyCode::LeftControl => ModifierKeyCode::LeftControl, + CModifierKeyCode::LeftAlt => ModifierKeyCode::LeftAlt, + CModifierKeyCode::LeftSuper => ModifierKeyCode::LeftSuper, + CModifierKeyCode::LeftHyper => ModifierKeyCode::LeftHyper, + CModifierKeyCode::LeftMeta => ModifierKeyCode::LeftMeta, + CModifierKeyCode::RightShift => ModifierKeyCode::RightShift, + CModifierKeyCode::RightControl => ModifierKeyCode::RightControl, + CModifierKeyCode::RightAlt => ModifierKeyCode::RightAlt, + CModifierKeyCode::RightSuper => ModifierKeyCode::RightSuper, + CModifierKeyCode::RightHyper => ModifierKeyCode::RightHyper, + CModifierKeyCode::RightMeta => ModifierKeyCode::RightMeta, + CModifierKeyCode::IsoLevel3Shift => ModifierKeyCode::IsoLevel3Shift, + CModifierKeyCode::IsoLevel5Shift => ModifierKeyCode::IsoLevel5Shift, + } + } +} + /// Represents a key. #[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)] pub enum KeyCode { @@ -94,6 +252,24 @@ pub enum KeyCode { Null, /// Escape key. Esc, + /// CapsLock key. + CapsLock, + /// ScrollLock key. + ScrollLock, + /// NumLock key. + NumLock, + /// PrintScreen key. + PrintScreen, + /// Pause key. + Pause, + /// Menu key. + Menu, + /// KeypadBegin key. + KeypadBegin, + /// A media key. + Media(MediaKeyCode), + /// A modifier key. + Modifier(ModifierKeyCode), } #[cfg(feature = "term")] @@ -119,6 +295,15 @@ impl From for crossterm::event::KeyCode { KeyCode::Char(character) => CKeyCode::Char(character), KeyCode::Null => CKeyCode::Null, KeyCode::Esc => CKeyCode::Esc, + KeyCode::CapsLock => CKeyCode::CapsLock, + KeyCode::ScrollLock => CKeyCode::ScrollLock, + KeyCode::NumLock => CKeyCode::NumLock, + KeyCode::PrintScreen => CKeyCode::PrintScreen, + KeyCode::Pause => CKeyCode::Pause, + KeyCode::Menu => CKeyCode::Menu, + KeyCode::KeypadBegin => CKeyCode::KeypadBegin, + KeyCode::Media(media_key_code) => CKeyCode::Media(media_key_code.into()), + KeyCode::Modifier(modifier_key_code) => CKeyCode::Modifier(modifier_key_code.into()), } } } @@ -147,17 +332,15 @@ impl From for KeyCode { CKeyCode::Char(character) => KeyCode::Char(character), CKeyCode::Null => KeyCode::Null, CKeyCode::Esc => KeyCode::Esc, - CKeyCode::CapsLock - | CKeyCode::ScrollLock - | CKeyCode::NumLock - | CKeyCode::PrintScreen - | CKeyCode::Pause - | CKeyCode::Menu - | CKeyCode::KeypadBegin - | CKeyCode::Media(_) - | CKeyCode::Modifier(_) => unreachable!( - "Shouldn't get this key without enabling DISAMBIGUATE_ESCAPE_CODES in crossterm" - ), + CKeyCode::CapsLock => KeyCode::CapsLock, + CKeyCode::ScrollLock => KeyCode::ScrollLock, + CKeyCode::NumLock => KeyCode::NumLock, + CKeyCode::PrintScreen => KeyCode::PrintScreen, + CKeyCode::Pause => KeyCode::Pause, + CKeyCode::Menu => KeyCode::Menu, + CKeyCode::KeypadBegin => KeyCode::KeypadBegin, + CKeyCode::Media(media_key_code) => KeyCode::Media(media_key_code.into()), + CKeyCode::Modifier(modifier_key_code) => KeyCode::Modifier(modifier_key_code.into()), } } }