diff --git a/src/engine.rs b/src/engine.rs index 85153ef..c8a4db4 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1167,8 +1167,9 @@ impl Engine { key: Some(key), keymod, repeat, + scan: Some(scan), } => { - let evt = KeyEvent::new(key, keymod, repeat); + let evt = KeyEvent::new(key, keymod, repeat, scan); if !app.on_key_pressed(state, evt)? { state.ui.keys.press(key, keymod); } @@ -1177,8 +1178,9 @@ impl Engine { key: Some(key), keymod, repeat, + scan: Some(scan), } => { - let evt = KeyEvent::new(key, keymod, repeat); + let evt = KeyEvent::new(key, keymod, repeat, scan); if !app.on_key_released(state, evt)? { state.ui.keys.release(key, keymod); } diff --git a/src/event.rs b/src/event.rs index c6991db..bb9ded9 100644 --- a/src/event.rs +++ b/src/event.rs @@ -32,6 +32,8 @@ pub enum Event { keymod: KeyMod, /// Whether this is a key-repeat event. repeat: bool, + /// Scancode of key being pressed. + scan: Option, }, /// User key release event. KeyUp { @@ -41,6 +43,8 @@ pub enum Event { keymod: KeyMod, /// Whether this is a key-repeat event. repeat: bool, + /// Scancode of key being pressed. + scan: Option, }, /// User text entry event. TextInput { @@ -260,14 +264,17 @@ pub struct KeyEvent { pub keymod: KeyMod, /// Whether this is a key-repeat event. pub repeat: bool, + /// Specific scancode for this event. + pub scan: Scan, } impl KeyEvent { - pub(crate) const fn new(key: Key, keymod: KeyMod, repeat: bool) -> Self { + pub(crate) const fn new(key: Key, keymod: KeyMod, repeat: bool, scan: Scan) -> Self { Self { key, keymod, repeat, + scan, } } } @@ -380,6 +387,123 @@ impl Default for Key { } } +/// Keyboard scancode (sorted by SDL_SCANCODE value) +#[allow(missing_docs)] +#[non_exhaustive] +#[rustfmt::skip] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub enum Scan { + // Default value + Unhandled /* 0 */, + // Letters + A /* 4 */, B /* 5 */, C /* 6 */, D /* 7 */, E /* 8 */, F /* 9 */, G /* 10 */, + H /* 11 */, I /* 12 */, J /* 13 */, K /* 14 */, L /* 15 */, M /* 16 */, N /* 17 */, + O /* 18 */, P /* 19 */, Q /* 20 */, R /* 21 */, S /* 22 */, T /* 23 */, U /* 24 */, + V /* 25 */, W /* 26 */, X /* 27 */, Y /* 28 */, Z /* 29 */, + // Digits (top row) + Num1 /* 30 */, Num2 /* 31 */, Num3 /* 32 */, Num4 /* 33 */, Num5 /* 34 */, + Num6 /* 35 */, Num7 /* 36 */, Num8 /* 37 */, Num9 /* 38 */, Num0 /* 39 */, + // Other standard keys + Return /* 40 */, Escape /* 41 */, Backspace /* 42 */, Tab /* 43 */, + Space /* 44 */, Minus /* 45 */, Equals /* 46 */, + LeftBracket /* 47 */, RightBracket /* 48 */, Backslash /* 49 */, + NonUsHash /* 50 */, Semicolon /* 51 */, Apostrophe /* 52 */, Grave /* 53 */, + Comma /* 54 */, Period /* 55 */, Slash /* 56 */, CapsLock /* 57 */, + // Function keys + F1 /* 58 */, F2 /* 59 */, F3 /* 60 */, F4 /* 61 */, F5 /* 62 */, F6 /* 63 */, + F7 /* 64 */, F8 /* 65 */, F9 /* 66 */, F10 /* 67 */, F11 /* 68 */, F12 /* 69 */, + // More standard keys + PrintScreen /* 70 */, ScrollLock /* 71 */, Pause /* 72 */, Insert /* 73 */, + Home /* 74 */, PageUp /* 75 */, Delete /* 76 */, End /* 77 */, PageDown /* 78 */, + Right /* 79 */, Left /* 80 */, Down /* 81 */, Up /* 82 */, + // Lock on PC, Clear on Mac + NumLockClear /* 83 */, + // Numeric keypad part 1 + KpDivide /* 84 */, KpMultiply /* 85 */, KpMinus /* 86 */, KpPlus /* 87 */, KpEnter /* 88 */, + Kp1 /* 89 */, Kp2 /* 90 */, Kp3 /* 91 */, Kp4 /* 92 */, Kp5 /* 93 */, + Kp6 /* 94 */, Kp7 /* 95 */, Kp8 /* 96 */, Kp9 /* 97 */, Kp0 /* 98 */, + KpPeriod /* 99 */, + // Key between LShift and W for ISO layout + NonUsBackslash /* 100 */, + // ??? + Application /* 101 */, Power /* 102 */, + // Numeric keypad part 2 + KpEquals /* 103 */, + // More function keys + F13 /* 104 */, F14 /* 105 */, F15 /* 106 */, F16 /* 107 */, F17 /* 108 */, F18 /* 109 */, + F19 /* 110 */, F20 /* 111 */, F21 /* 112 */, F22 /* 113 */, F23 /* 114 */, F24 /* 115 */, + // More shortcut keys + Execute /* 116 */, Help /* 117 */, Menu /* 118 */, Select /* 119 */, Stop /* 120 */, + Again /* 121 */, Undo /* 122 */, Cut /* 123 */, Copy /* 124 */, Paste /* 125 */, + Find /* 126 */, + // Audio part 1 + Mute /* 127 */, VolumeUp /* 128 */, VolumeDown /* 129 */, + // Numeric keypad part 3 + KpComma /* 133 */, KpEqualsAS400 /* 134 */, + // International? + International1 /* 135 */, International2 /* 136 */, International3 /* 137 */, + International4 /* 138 */, International5 /* 139 */, International6 /* 140 */, + International7 /* 141 */, International8 /* 142 */, International9 /* 143 */, + // Language? + Lang1 /* 144 */, Lang2 /* 145 */, Lang3 /* 146 */, + Lang4 /* 147 */, Lang5 /* 148 */, Lang6 /* 149 */, + Lang7 /* 150 */, Lang8 /* 151 */, Lang9 /* 152 */, + // Even more shortcut keys + AltErase /* 153 */, SysReq /* 154 */, Cancel /* 155 */, Clear /* 156 */, + Prior /* 157 */, Return2 /* 158 */, Separator /* 159 */, Out /* 160 */, + Oper /* 161 */, ClearAgain /* 162 */, CrSel /* 163 */, ExSel /* 164 */, + // Numeric keypad part 4 + Kp00 /* 176 */, Kp000 /* 177 */, + ThousandsSeparator /* 178 */, DecimalSeparator /* 179 */, + CurrencyUnit /* 180 */, CurrencySubUnit /* 181 */, + KpLeftParen /* 182 */, KpRightParen /* 183 */, + KpLeftBrace /* 184 */, KpRightBrace /* 185 */, + KpTab /* 186 */, KpBackspace /* 187 */, + KpA /* 188 */, KpB /* 189 */, + KpC /* 190 */, KpD /* 191 */, + KpE /* 192 */, KpF /* 193 */, + KpXor /* 194 */, KpPower /* 195 */, + KpPercent /* 196 */, KpLess /* 197 */, + KpGreater /* 198 */, KpAmpersand /* 199 */, + KpDblAmpersand /* 200 */, KpVerticalBar /* 201 */, + KpDblVerticalBar /* 202 */, KpColon /* 203 */, + KpHash /* 204 */, KpSpace /* 205 */, + KpAt /* 206 */, KpExclam /* 207 */, + KpMemStore /* 208 */, KpMemRecall /* 209 */, + KpMemClear /* 210 */, KpMemAdd /* 211 */, + KpMemSubtract /* 212 */, KpMemMultiply /* 213 */, + KpMemDivide /* 214 */, KpPlusMinus /* 215 */, + KpClear /* 216 */, KpClearEntry /* 217 */, + KpBinary /* 218 */, KpOctal /* 219 */, + KpDecimal /* 220 */, KpHexadecimal /* 221 */, + // Modifier keys + LCtrl /* 224 */, LShift /* 225 */, LAlt /* 226 */, LGui /* 227 */, + RCtrl /* 228 */, RShift /* 229 */, RAlt /* 230 */, RGui /* 231 */, + // ??? + Mode /* 257 */, + // Audio part 2 + AudioNext /* 258 */, AudioPrev /* 259 */, AudioStop /* 260 */, + AudioPlay /* 261 */, AudioMute /* 262 */, MediaSelect /* 263 */, + // Multimedia keys + Www /* 264 */, Mail /* 265 */, Calculator /* 266 */, + Computer /* 267 */, AcSearch /* 268 */, AcHome /* 269 */, + AcBack /* 270 */, AcForward /* 271 */, AcStop /* 272 */, + AcRefresh /* 273 */, AcBookmarks /* 274 */, BrightnessDown /* 275 */, + BrightnessUp /* 276 */, DisplaySwitch /* 277 */, KbdIllumToggle /* 278 */, + KbdIllumDown /* 279 */, KbdIllumUp /* 280 */, Eject /* 281 */, + Sleep /* 282 */, App1 /* 283 */, App2 /* 284 */, + // Audio part 3 + AudioRewind /* 285 */, AudioFastForward /* 286 */, + // This is the end. +} + +impl Default for Scan { + fn default() -> Self { + Self::Unhandled + } +} + /// A Joystick axis. #[non_exhaustive] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/src/lib.rs b/src/lib.rs index b088927..a618a84 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,7 +78,7 @@ pub mod prelude { pub use super::error::{Error as PixError, Result as PixResult}; pub use super::event::{ Axis, ControllerButton, ControllerEvent, ControllerId, ControllerUpdate, Event, HatState, - Key, KeyEvent, KeyMod, Mouse, WindowEvent, + Key, KeyEvent, KeyMod, Scan, Mouse, WindowEvent, }; pub use super::gui::theme::{self, ColorType, Font, Theme}; pub use super::image::{Image, PixelFormat}; diff --git a/src/renderer/sdl/event.rs b/src/renderer/sdl/event.rs index 2170b85..9280686 100644 --- a/src/renderer/sdl/event.rs +++ b/src/renderer/sdl/event.rs @@ -4,7 +4,7 @@ use sdl2::{ controller::{Axis as SdlAxis, Button as SdlButton}, event::{Event as SdlEvent, WindowEvent as SdlWindowEvent}, joystick::HatState as SdlHatState, - keyboard::{Keycode as SdlKeycode, Mod as SdlMod}, + keyboard::{Keycode as SdlKeycode, Mod as SdlMod, Scancode as SdlScancode}, mouse::MouseButton as SdlMouseButton, }; @@ -26,21 +26,25 @@ impl From for Event { keycode, keymod, repeat, + scancode, .. } => Self::KeyDown { key: keycode.map(Into::into), keymod: keymod.into(), repeat, + scan: scancode.map(Into::into), }, SdlEvent::KeyUp { keycode, keymod, repeat, + scancode, .. } => Self::KeyUp { key: keycode.map(Into::into), keymod: keymod.into(), repeat, + scan: scancode.map(Into::into), }, SdlEvent::TextInput { text, .. } => Self::TextInput { text }, SdlEvent::MouseMotion { @@ -365,6 +369,261 @@ impl From for Key { } } +#[doc(hidden)] +impl From for Scan { + fn from(scancode: SdlScancode) -> Self { + match scancode { + SdlScancode::A => Self::A, + SdlScancode::B => Self::B, + SdlScancode::C => Self::C, + SdlScancode::D => Self::D, + SdlScancode::E => Self::E, + SdlScancode::F => Self::F, + SdlScancode::G => Self::G, + SdlScancode::H => Self::H, + SdlScancode::I => Self::I, + SdlScancode::J => Self::J, + SdlScancode::K => Self::K, + SdlScancode::L => Self::L, + SdlScancode::M => Self::M, + SdlScancode::N => Self::N, + SdlScancode::O => Self::O, + SdlScancode::P => Self::P, + SdlScancode::Q => Self::Q, + SdlScancode::R => Self::R, + SdlScancode::S => Self::S, + SdlScancode::T => Self::T, + SdlScancode::U => Self::U, + SdlScancode::V => Self::V, + SdlScancode::W => Self::W, + SdlScancode::X => Self::X, + SdlScancode::Y => Self::Y, + SdlScancode::Z => Self::Z, + SdlScancode::Num1 => Self::Num1, + SdlScancode::Num2 => Self::Num2, + SdlScancode::Num3 => Self::Num3, + SdlScancode::Num4 => Self::Num4, + SdlScancode::Num5 => Self::Num5, + SdlScancode::Num6 => Self::Num6, + SdlScancode::Num7 => Self::Num7, + SdlScancode::Num8 => Self::Num8, + SdlScancode::Num9 => Self::Num9, + SdlScancode::Num0 => Self::Num0, + SdlScancode::Return => Self::Return, + SdlScancode::Escape => Self::Escape, + SdlScancode::Backspace => Self::Backspace, + SdlScancode::Tab => Self::Tab, + SdlScancode::Space => Self::Space, + SdlScancode::Minus => Self::Minus, + SdlScancode::Equals => Self::Equals, + SdlScancode::LeftBracket => Self::LeftBracket, + SdlScancode::RightBracket => Self::RightBracket, + SdlScancode::Backslash => Self::Backslash, + SdlScancode::NonUsHash => Self::NonUsHash, + SdlScancode::Semicolon => Self::Semicolon, + SdlScancode::Apostrophe => Self::Apostrophe, + SdlScancode::Grave => Self::Grave, + SdlScancode::Comma => Self::Comma, + SdlScancode::Period => Self::Period, + SdlScancode::Slash => Self::Slash, + SdlScancode::CapsLock => Self::CapsLock, + SdlScancode::F1 => Self::F1, + SdlScancode::F2 => Self::F2, + SdlScancode::F3 => Self::F3, + SdlScancode::F4 => Self::F4, + SdlScancode::F5 => Self::F5, + SdlScancode::F6 => Self::F6, + SdlScancode::F7 => Self::F7, + SdlScancode::F8 => Self::F8, + SdlScancode::F9 => Self::F9, + SdlScancode::F10 => Self::F10, + SdlScancode::F11 => Self::F11, + SdlScancode::F12 => Self::F12, + SdlScancode::PrintScreen => Self::PrintScreen, + SdlScancode::ScrollLock => Self::ScrollLock, + SdlScancode::Pause => Self::Pause, + SdlScancode::Insert => Self::Insert, + SdlScancode::Home => Self::Home, + SdlScancode::PageUp => Self::PageUp, + SdlScancode::Delete => Self::Delete, + SdlScancode::End => Self::End, + SdlScancode::PageDown => Self::PageDown, + SdlScancode::Right => Self::Right, + SdlScancode::Left => Self::Left, + SdlScancode::Down => Self::Down, + SdlScancode::Up => Self::Up, + SdlScancode::NumLockClear => Self::NumLockClear, + SdlScancode::KpDivide => Self::KpDivide, + SdlScancode::KpMultiply => Self::KpMultiply, + SdlScancode::KpMinus => Self::KpMinus, + SdlScancode::KpPlus => Self::KpPlus, + SdlScancode::KpEnter => Self::KpEnter, + SdlScancode::Kp1 => Self::Kp1, + SdlScancode::Kp2 => Self::Kp2, + SdlScancode::Kp3 => Self::Kp3, + SdlScancode::Kp4 => Self::Kp4, + SdlScancode::Kp5 => Self::Kp5, + SdlScancode::Kp6 => Self::Kp6, + SdlScancode::Kp7 => Self::Kp7, + SdlScancode::Kp8 => Self::Kp8, + SdlScancode::Kp9 => Self::Kp9, + SdlScancode::Kp0 => Self::Kp0, + SdlScancode::KpPeriod => Self::KpPeriod, + SdlScancode::NonUsBackslash => Self::NonUsBackslash, + SdlScancode::Application => Self::Application, + SdlScancode::Power => Self::Power, + SdlScancode::KpEquals => Self::KpEquals, + SdlScancode::F13 => Self::F13, + SdlScancode::F14 => Self::F14, + SdlScancode::F15 => Self::F15, + SdlScancode::F16 => Self::F16, + SdlScancode::F17 => Self::F17, + SdlScancode::F18 => Self::F18, + SdlScancode::F19 => Self::F19, + SdlScancode::F20 => Self::F20, + SdlScancode::F21 => Self::F21, + SdlScancode::F22 => Self::F22, + SdlScancode::F23 => Self::F23, + SdlScancode::F24 => Self::F24, + SdlScancode::Execute => Self::Execute, + SdlScancode::Help => Self::Help, + SdlScancode::Menu => Self::Menu, + SdlScancode::Select => Self::Select, + SdlScancode::Stop => Self::Stop, + SdlScancode::Again => Self::Again, + SdlScancode::Undo => Self::Undo, + SdlScancode::Cut => Self::Cut, + SdlScancode::Copy => Self::Copy, + SdlScancode::Paste => Self::Paste, + SdlScancode::Find => Self::Find, + SdlScancode::Mute => Self::Mute, + SdlScancode::VolumeUp => Self::VolumeUp, + SdlScancode::VolumeDown => Self::VolumeDown, + SdlScancode::KpComma => Self::KpComma, + SdlScancode::KpEqualsAS400 => Self::KpEqualsAS400, + SdlScancode::International1 => Self::International1, + SdlScancode::International2 => Self::International2, + SdlScancode::International3 => Self::International3, + SdlScancode::International4 => Self::International4, + SdlScancode::International5 => Self::International5, + SdlScancode::International6 => Self::International6, + SdlScancode::International7 => Self::International7, + SdlScancode::International8 => Self::International8, + SdlScancode::International9 => Self::International9, + SdlScancode::Lang1 => Self::Lang1, + SdlScancode::Lang2 => Self::Lang2, + SdlScancode::Lang3 => Self::Lang3, + SdlScancode::Lang4 => Self::Lang4, + SdlScancode::Lang5 => Self::Lang5, + SdlScancode::Lang6 => Self::Lang6, + SdlScancode::Lang7 => Self::Lang7, + SdlScancode::Lang8 => Self::Lang8, + SdlScancode::Lang9 => Self::Lang9, + SdlScancode::AltErase => Self::AltErase, + SdlScancode::SysReq => Self::SysReq, + SdlScancode::Cancel => Self::Cancel, + SdlScancode::Clear => Self::Clear, + SdlScancode::Prior => Self::Prior, + SdlScancode::Return2 => Self::Return2, + SdlScancode::Separator => Self::Separator, + SdlScancode::Out => Self::Out, + SdlScancode::Oper => Self::Oper, + SdlScancode::ClearAgain => Self::ClearAgain, + SdlScancode::CrSel => Self::CrSel, + SdlScancode::ExSel => Self::ExSel, + SdlScancode::Kp00 => Self::Kp00, + SdlScancode::Kp000 => Self::Kp000, + SdlScancode::ThousandsSeparator => Self::ThousandsSeparator, + SdlScancode::DecimalSeparator => Self::DecimalSeparator, + SdlScancode::CurrencyUnit => Self::CurrencyUnit, + SdlScancode::CurrencySubUnit => Self::CurrencySubUnit, + SdlScancode::KpLeftParen => Self::KpLeftParen, + SdlScancode::KpRightParen => Self::KpRightParen, + SdlScancode::KpLeftBrace => Self::KpLeftBrace, + SdlScancode::KpRightBrace => Self::KpRightBrace, + SdlScancode::KpTab => Self::KpTab, + SdlScancode::KpBackspace => Self::KpBackspace, + SdlScancode::KpA => Self::KpA, + SdlScancode::KpB => Self::KpB, + SdlScancode::KpC => Self::KpC, + SdlScancode::KpD => Self::KpD, + SdlScancode::KpE => Self::KpE, + SdlScancode::KpF => Self::KpF, + SdlScancode::KpXor => Self::KpXor, + SdlScancode::KpPower => Self::KpPower, + SdlScancode::KpPercent => Self::KpPercent, + SdlScancode::KpLess => Self::KpLess, + SdlScancode::KpGreater => Self::KpGreater, + SdlScancode::KpAmpersand => Self::KpAmpersand, + SdlScancode::KpDblAmpersand => Self::KpDblAmpersand, + SdlScancode::KpVerticalBar => Self::KpVerticalBar, + SdlScancode::KpDblVerticalBar => Self::KpDblVerticalBar, + SdlScancode::KpColon => Self::KpColon, + SdlScancode::KpHash => Self::KpHash, + SdlScancode::KpSpace => Self::KpSpace, + SdlScancode::KpAt => Self::KpAt, + SdlScancode::KpExclam => Self::KpExclam, + SdlScancode::KpMemStore => Self::KpMemStore, + SdlScancode::KpMemRecall => Self::KpMemRecall, + SdlScancode::KpMemClear => Self::KpMemClear, + SdlScancode::KpMemAdd => Self::KpMemAdd, + SdlScancode::KpMemSubtract => Self::KpMemSubtract, + SdlScancode::KpMemMultiply => Self::KpMemMultiply, + SdlScancode::KpMemDivide => Self::KpMemDivide, + SdlScancode::KpPlusMinus => Self::KpPlusMinus, + SdlScancode::KpClear => Self::KpClear, + SdlScancode::KpClearEntry => Self::KpClearEntry, + SdlScancode::KpBinary => Self::KpBinary, + SdlScancode::KpOctal => Self::KpOctal, + SdlScancode::KpDecimal => Self::KpDecimal, + SdlScancode::KpHexadecimal => Self::KpHexadecimal, + SdlScancode::LCtrl => Self::LCtrl, + SdlScancode::LShift => Self::LShift, + SdlScancode::LAlt => Self::LAlt, + SdlScancode::LGui => Self::LGui, + SdlScancode::RCtrl => Self::RCtrl, + SdlScancode::RShift => Self::RShift, + SdlScancode::RAlt => Self::RAlt, + SdlScancode::RGui => Self::RGui, + SdlScancode::Mode => Self::Mode, + SdlScancode::AudioNext => Self::AudioNext, + SdlScancode::AudioPrev => Self::AudioPrev, + SdlScancode::AudioStop => Self::AudioStop, + SdlScancode::AudioPlay => Self::AudioPlay, + SdlScancode::AudioMute => Self::AudioMute, + SdlScancode::MediaSelect => Self::MediaSelect, + SdlScancode::Www => Self::Www, + SdlScancode::Mail => Self::Mail, + SdlScancode::Calculator => Self::Calculator, + SdlScancode::Computer => Self::Computer, + SdlScancode::AcSearch => Self::AcSearch, + SdlScancode::AcHome => Self::AcHome, + SdlScancode::AcBack => Self::AcBack, + SdlScancode::AcForward => Self::AcForward, + SdlScancode::AcStop => Self::AcStop, + SdlScancode::AcRefresh => Self::AcRefresh, + SdlScancode::AcBookmarks => Self::AcBookmarks, + SdlScancode::BrightnessDown => Self::BrightnessDown, + SdlScancode::BrightnessUp => Self::BrightnessUp, + SdlScancode::DisplaySwitch => Self::DisplaySwitch, + SdlScancode::KbdIllumToggle => Self::KbdIllumToggle, + SdlScancode::KbdIllumDown => Self::KbdIllumDown, + SdlScancode::KbdIllumUp => Self::KbdIllumUp, + SdlScancode::Eject => Self::Eject, + SdlScancode::Sleep => Self::Sleep, + SdlScancode::App1 => Self::App1, + SdlScancode::App2 => Self::App2, + // Undefined? + // SdlScancode::AudioRewind => Self::AudioRewind, + // SdlScancode::AudioFastForward => Self::AudioFastForward, + scancode => { + warn!("Unhandled SDL `Scancode`: {:?}", scancode); + Self::Unhandled + } + } + } +} + #[doc(hidden)] impl From for KeyMod { fn from(keymod: SdlMod) -> Self {