use std::{fmt, str::FromStr};
use crate::{
error::OsError,
platform_impl::{
keycode_from_scancode as platform_keycode_from_scancode,
keycode_to_scancode as platform_keycode_to_scancode,
},
};
impl ModifiersState {
pub fn shift_key(&self) -> bool {
self.intersects(Self::SHIFT)
}
pub fn control_key(&self) -> bool {
self.intersects(Self::CONTROL)
}
pub fn alt_key(&self) -> bool {
self.intersects(Self::ALT)
}
pub fn super_key(&self) -> bool {
self.intersects(Self::SUPER)
}
}
bitflags! {
#[derive(Default)]
pub struct ModifiersState: u32 {
const SHIFT = 0b100 << 0;
const CONTROL = 0b100 << 3;
const ALT = 0b100 << 6;
const SUPER = 0b100 << 9;
}
}
#[cfg(feature = "serde")]
mod modifiers_serde {
use super::ModifiersState;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Default, Serialize, Deserialize)]
#[serde(default)]
#[serde(rename = "ModifiersState")]
pub struct ModifiersStateSerialize {
pub shift_key: bool,
pub control_key: bool,
pub alt_key: bool,
pub super_key: bool,
}
impl Serialize for ModifiersState {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = ModifiersStateSerialize {
shift_key: self.shift_key(),
control_key: self.control_key(),
alt_key: self.alt_key(),
super_key: self.super_key(),
};
s.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for ModifiersState {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let ModifiersStateSerialize {
shift_key,
control_key,
alt_key,
super_key,
} = ModifiersStateSerialize::deserialize(deserializer)?;
let mut m = ModifiersState::empty();
m.set(ModifiersState::SHIFT, shift_key);
m.set(ModifiersState::CONTROL, control_key);
m.set(ModifiersState::ALT, alt_key);
m.set(ModifiersState::SUPER, super_key);
Ok(m)
}
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum NativeKeyCode {
Unidentified,
Windows(u16),
MacOS(u16),
Gtk(u16),
Android(u32),
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum KeyCode {
Unidentified(NativeKeyCode),
Backquote,
Backslash,
BracketLeft,
BracketRight,
Comma,
Digit0,
Digit1,
Digit2,
Digit3,
Digit4,
Digit5,
Digit6,
Digit7,
Digit8,
Digit9,
Equal,
IntlBackslash,
IntlRo,
IntlYen,
KeyA,
KeyB,
KeyC,
KeyD,
KeyE,
KeyF,
KeyG,
KeyH,
KeyI,
KeyJ,
KeyK,
KeyL,
KeyM,
KeyN,
KeyO,
KeyP,
KeyQ,
KeyR,
KeyS,
KeyT,
KeyU,
KeyV,
KeyW,
KeyX,
KeyY,
KeyZ,
Minus,
Period,
Quote,
Semicolon,
Slash,
AltLeft,
AltRight,
Backspace,
CapsLock,
ContextMenu,
ControlLeft,
ControlRight,
Enter,
SuperLeft,
SuperRight,
ShiftLeft,
ShiftRight,
Space,
Tab,
Convert,
KanaMode,
Lang1,
Lang2,
Lang3,
Lang4,
Lang5,
NonConvert,
Delete,
End,
Help,
Home,
Insert,
PageDown,
PageUp,
ArrowDown,
ArrowLeft,
ArrowRight,
ArrowUp,
NumLock,
Numpad0,
Numpad1,
Numpad2,
Numpad3,
Numpad4,
Numpad5,
Numpad6,
Numpad7,
Numpad8,
Numpad9,
NumpadAdd,
NumpadBackspace,
NumpadClear,
NumpadClearEntry,
NumpadComma,
NumpadDecimal,
NumpadDivide,
NumpadEnter,
NumpadEqual,
NumpadHash,
NumpadMemoryAdd,
NumpadMemoryClear,
NumpadMemoryRecall,
NumpadMemoryStore,
NumpadMemorySubtract,
NumpadMultiply,
NumpadParenLeft,
NumpadParenRight,
NumpadStar,
NumpadSubtract,
Escape,
Fn,
FnLock,
PrintScreen,
ScrollLock,
Pause,
BrowserBack,
BrowserFavorites,
BrowserForward,
BrowserHome,
BrowserRefresh,
BrowserSearch,
BrowserStop,
Eject,
LaunchApp1,
LaunchApp2,
LaunchMail,
MediaPlayPause,
MediaSelect,
MediaStop,
MediaTrackNext,
MediaTrackPrevious,
Power,
Sleep,
AudioVolumeDown,
AudioVolumeMute,
AudioVolumeUp,
WakeUp,
Hyper,
Turbo,
Abort,
Resume,
Suspend,
Again,
Copy,
Cut,
Find,
Open,
Paste,
Props,
Select,
Undo,
Hiragana,
Katakana,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
F13,
F14,
F15,
F16,
F17,
F18,
F19,
F20,
F21,
F22,
F23,
F24,
F25,
F26,
F27,
F28,
F29,
F30,
F31,
F32,
F33,
F34,
F35,
}
impl KeyCode {
pub fn to_scancode(self) -> Option<u32> {
platform_keycode_to_scancode(self)
}
pub fn from_scancode(scancode: u32) -> KeyCode {
platform_keycode_from_scancode(scancode)
}
}
impl FromStr for KeyCode {
type Err = OsError;
fn from_str(accelerator_string: &str) -> Result<Self, Self::Err> {
let keycode = match accelerator_string.to_uppercase().as_str() {
"`" | "BACKQUOTE" => KeyCode::Backquote,
"BACKSLASH" => KeyCode::Backslash,
"[" | "BRACKETLEFT" => KeyCode::BracketLeft,
"]" | "BRACKETRIGHT" => KeyCode::BracketRight,
"," | "COMMA" => KeyCode::Comma,
"0" => KeyCode::Digit0,
"1" => KeyCode::Digit1,
"2" => KeyCode::Digit2,
"3" => KeyCode::Digit3,
"4" => KeyCode::Digit4,
"5" => KeyCode::Digit5,
"6" => KeyCode::Digit6,
"7" => KeyCode::Digit7,
"8" => KeyCode::Digit8,
"9" => KeyCode::Digit9,
"NUM0" | "NUMPAD0" => KeyCode::Numpad0,
"NUM1" | "NUMPAD1" => KeyCode::Numpad1,
"NUM2" | "NUMPAD2" => KeyCode::Numpad2,
"NUM3" | "NUMPAD3" => KeyCode::Numpad3,
"NUM4" | "NUMPAD4" => KeyCode::Numpad4,
"NUM5" | "NUMPAD5" => KeyCode::Numpad5,
"NUM6" | "NUMPAD6" => KeyCode::Numpad6,
"NUM7" | "NUMPAD7" => KeyCode::Numpad7,
"NUM8" | "NUMPAD8" => KeyCode::Numpad8,
"NUM9" | "NUMPAD9" => KeyCode::Numpad9,
"=" => KeyCode::Equal,
"-" => KeyCode::Minus,
"." | "PERIOD" => KeyCode::Period,
"'" | "QUOTE" => KeyCode::Quote,
"\\" => KeyCode::IntlBackslash,
"A" => KeyCode::KeyA,
"B" => KeyCode::KeyB,
"C" => KeyCode::KeyC,
"D" => KeyCode::KeyD,
"E" => KeyCode::KeyE,
"F" => KeyCode::KeyF,
"G" => KeyCode::KeyG,
"H" => KeyCode::KeyH,
"I" => KeyCode::KeyI,
"J" => KeyCode::KeyJ,
"K" => KeyCode::KeyK,
"L" => KeyCode::KeyL,
"M" => KeyCode::KeyM,
"N" => KeyCode::KeyN,
"O" => KeyCode::KeyO,
"P" => KeyCode::KeyP,
"Q" => KeyCode::KeyQ,
"R" => KeyCode::KeyR,
"S" => KeyCode::KeyS,
"T" => KeyCode::KeyT,
"U" => KeyCode::KeyU,
"V" => KeyCode::KeyV,
"W" => KeyCode::KeyW,
"X" => KeyCode::KeyX,
"Y" => KeyCode::KeyY,
"Z" => KeyCode::KeyZ,
";" | "SEMICOLON" => KeyCode::Semicolon,
"/" | "SLASH" => KeyCode::Slash,
"BACKSPACE" => KeyCode::Backspace,
"CAPSLOCK" => KeyCode::CapsLock,
"CONTEXTMENU" => KeyCode::ContextMenu,
"ENTER" => KeyCode::Enter,
"SPACE" => KeyCode::Space,
"TAB" => KeyCode::Tab,
"CONVERT" => KeyCode::Convert,
"DELETE" => KeyCode::Delete,
"END" => KeyCode::End,
"HELP" => KeyCode::Help,
"HOME" => KeyCode::Home,
"PAGEDOWN" => KeyCode::PageDown,
"PAGEUP" => KeyCode::PageUp,
"DOWN" => KeyCode::ArrowDown,
"UP" => KeyCode::ArrowUp,
"LEFT" => KeyCode::ArrowLeft,
"RIGHT" => KeyCode::ArrowRight,
"NUMLOCK" => KeyCode::NumLock,
"NUMADD" | "NUMPADADD" => KeyCode::NumpadAdd,
"NUMBACKSPACE" | "NUMPADBACKSPACE" => KeyCode::NumpadBackspace,
"NUMCLEAR" | "NUMPADCLEAR" => KeyCode::NumpadClear,
"NUMCOMMA" | "NUMPADCOMMA" => KeyCode::NumpadComma,
"NUMDIVIDE" | "NUMPADDIVIDE" => KeyCode::NumpadDivide,
"NUMSUBSTRACT" | "NUMPADSUBSTRACT" => KeyCode::NumpadSubtract,
"NUMENTER" | "NUMPADENTER" => KeyCode::NumpadEnter,
"ESC" | "ESCAPE" => KeyCode::Escape,
"FN" => KeyCode::Fn,
"FNLOCK" => KeyCode::FnLock,
"PRINTSCREEN" => KeyCode::PrintScreen,
"SCROLLLOCK" => KeyCode::ScrollLock,
"PAUSE" => KeyCode::Pause,
"VOLUMEMUTE" => KeyCode::AudioVolumeMute,
"VOLUMEDOWN" => KeyCode::AudioVolumeDown,
"VOLUMEUP" => KeyCode::AudioVolumeUp,
"MEDIANEXTTRACK" => KeyCode::MediaTrackNext,
"MEDIAPREVIOUSTRACK" => KeyCode::MediaTrackPrevious,
"MEDIAPLAYPAUSE" => KeyCode::MediaPlayPause,
"LAUNCHMAIL" => KeyCode::LaunchMail,
"SUSPEND" => KeyCode::Suspend,
"F1" => KeyCode::F1,
"F2" => KeyCode::F2,
"F3" => KeyCode::F3,
"F4" => KeyCode::F4,
"F5" => KeyCode::F5,
"F6" => KeyCode::F6,
"F7" => KeyCode::F7,
"F8" => KeyCode::F8,
"F9" => KeyCode::F9,
"F10" => KeyCode::F10,
"F11" => KeyCode::F11,
"F12" => KeyCode::F12,
"F13" => KeyCode::F13,
"F14" => KeyCode::F14,
"F15" => KeyCode::F15,
"F16" => KeyCode::F16,
"F17" => KeyCode::F17,
"F18" => KeyCode::F18,
"F19" => KeyCode::F19,
"F20" => KeyCode::F20,
"F21" => KeyCode::F21,
"F22" => KeyCode::F22,
"F23" => KeyCode::F23,
"F24" => KeyCode::F24,
"F25" => KeyCode::F25,
"F26" => KeyCode::F26,
"F27" => KeyCode::F27,
"F28" => KeyCode::F28,
"F29" => KeyCode::F29,
"F30" => KeyCode::F30,
"F31" => KeyCode::F31,
"F32" => KeyCode::F32,
"F33" => KeyCode::F33,
"F34" => KeyCode::F34,
"F35" => KeyCode::F35,
_ => KeyCode::Unidentified(NativeKeyCode::Unidentified),
};
Ok(keycode)
}
}
impl fmt::Display for KeyCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
&KeyCode::Unidentified(_) => write!(f, "{:?}", "Unidentified"),
val => write!(f, "{:?}", val),
}
}
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Key<'a> {
Character(&'a str),
Unidentified(NativeKeyCode),
Dead(Option<char>),
Alt,
AltGraph,
CapsLock,
Control,
Fn,
FnLock,
NumLock,
ScrollLock,
Shift,
Symbol,
SymbolLock,
Hyper,
Super,
Enter,
Tab,
Space,
ArrowDown,
ArrowLeft,
ArrowRight,
ArrowUp,
End,
Home,
PageDown,
PageUp,
Backspace,
Clear,
Copy,
CrSel,
Cut,
Delete,
EraseEof,
ExSel,
Insert,
Paste,
Redo,
Undo,
Accept,
Again,
Attn,
Cancel,
ContextMenu,
Escape,
Execute,
Find,
Help,
Pause,
Play,
Props,
Select,
ZoomIn,
ZoomOut,
BrightnessDown,
BrightnessUp,
Eject,
LogOff,
Power,
PowerOff,
PrintScreen,
Hibernate,
Standby,
WakeUp,
AllCandidates,
Alphanumeric,
CodeInput,
Compose,
Convert,
FinalMode,
GroupFirst,
GroupLast,
GroupNext,
GroupPrevious,
ModeChange,
NextCandidate,
NonConvert,
PreviousCandidate,
Process,
SingleCandidate,
HangulMode,
HanjaMode,
JunjaMode,
Eisu,
Hankaku,
Hiragana,
HiraganaKatakana,
KanaMode,
KanjiMode,
Katakana,
Romaji,
Zenkaku,
ZenkakuHankaku,
Soft1,
Soft2,
Soft3,
Soft4,
ChannelDown,
ChannelUp,
Close,
MailForward,
MailReply,
MailSend,
MediaClose,
MediaFastForward,
MediaPause,
MediaPlay,
MediaPlayPause,
MediaRecord,
MediaRewind,
MediaStop,
MediaTrackNext,
MediaTrackPrevious,
New,
Open,
Print,
Save,
SpellCheck,
Key11,
Key12,
AudioBalanceLeft,
AudioBalanceRight,
AudioBassBoostDown,
AudioBassBoostToggle,
AudioBassBoostUp,
AudioFaderFront,
AudioFaderRear,
AudioSurroundModeNext,
AudioTrebleDown,
AudioTrebleUp,
AudioVolumeDown,
AudioVolumeUp,
AudioVolumeMute,
MicrophoneToggle,
MicrophoneVolumeDown,
MicrophoneVolumeUp,
MicrophoneVolumeMute,
SpeechCorrectionList,
SpeechInputToggle,
LaunchApplication1,
LaunchApplication2,
LaunchCalendar,
LaunchContacts,
LaunchMail,
LaunchMediaPlayer,
LaunchMusicPlayer,
LaunchPhone,
LaunchScreenSaver,
LaunchSpreadsheet,
LaunchWebBrowser,
LaunchWebCam,
LaunchWordProcessor,
BrowserBack,
BrowserFavorites,
BrowserForward,
BrowserHome,
BrowserRefresh,
BrowserSearch,
BrowserStop,
AppSwitch,
Call,
Camera,
CameraFocus,
EndCall,
GoBack,
GoHome,
HeadsetHook,
LastNumberRedial,
Notification,
MannerMode,
VoiceDial,
TV,
TV3DMode,
TVAntennaCable,
TVAudioDescription,
TVAudioDescriptionMixDown,
TVAudioDescriptionMixUp,
TVContentsMenu,
TVDataService,
TVInput,
TVInputComponent1,
TVInputComponent2,
TVInputComposite1,
TVInputComposite2,
TVInputHDMI1,
TVInputHDMI2,
TVInputHDMI3,
TVInputHDMI4,
TVInputVGA1,
TVMediaContext,
TVNetwork,
TVNumberEntry,
TVPower,
TVRadioService,
TVSatellite,
TVSatelliteBS,
TVSatelliteCS,
TVSatelliteToggle,
TVTerrestrialAnalog,
TVTerrestrialDigital,
TVTimer,
AVRInput,
AVRPower,
ColorF0Red,
ColorF1Green,
ColorF2Yellow,
ColorF3Blue,
ColorF4Grey,
ColorF5Brown,
ClosedCaptionToggle,
Dimmer,
DisplaySwap,
DVR,
Exit,
FavoriteClear0,
FavoriteClear1,
FavoriteClear2,
FavoriteClear3,
FavoriteRecall0,
FavoriteRecall1,
FavoriteRecall2,
FavoriteRecall3,
FavoriteStore0,
FavoriteStore1,
FavoriteStore2,
FavoriteStore3,
Guide,
GuideNextDay,
GuidePreviousDay,
Info,
InstantReplay,
Link,
ListProgram,
LiveContent,
Lock,
MediaApps,
MediaAudioTrack,
MediaLast,
MediaSkipBackward,
MediaSkipForward,
MediaStepBackward,
MediaStepForward,
MediaTopMenu,
NavigateIn,
NavigateNext,
NavigateOut,
NavigatePrevious,
NextFavoriteChannel,
NextUserProfile,
OnDemand,
Pairing,
PinPDown,
PinPMove,
PinPToggle,
PinPUp,
PlaySpeedDown,
PlaySpeedReset,
PlaySpeedUp,
RandomToggle,
RcLowBattery,
RecordSpeedNext,
RfBypass,
ScanChannelsToggle,
ScreenModeNext,
Settings,
SplitScreenToggle,
STBInput,
STBPower,
Subtitle,
Teletext,
VideoModeNext,
Wink,
ZoomToggle,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
F13,
F14,
F15,
F16,
F17,
F18,
F19,
F20,
F21,
F22,
F23,
F24,
F25,
F26,
F27,
F28,
F29,
F30,
F31,
F32,
F33,
F34,
F35,
}
impl<'a> Key<'a> {
pub fn to_text(&self) -> Option<&'a str> {
match self {
Key::Character(ch) => Some(*ch),
Key::Enter => Some("\r"),
Key::Backspace => Some("\x08"),
Key::Tab => Some("\t"),
Key::Space => Some(" "),
Key::Escape => Some("\x1b"),
_ => None,
}
}
}
impl<'a> From<&'a str> for Key<'a> {
fn from(src: &'a str) -> Key<'a> {
Key::Character(src)
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum KeyLocation {
Standard,
Left,
Right,
Numpad,
}