controlmap_parser/
scan_code.rs

1//! Input scan codes with unknown details defined at the following sites.
2//! Direct input enumerator for Skyrim
3//!
4//! Wouldn't windows-sys or other crates be sufficient?
5//! - I wrote a new one because it is not easy to use in windows-sys.
6//!
7//! # References
8//! - [DirectInput keyboard scan codes](https://gist.github.com/tracend/912308)
9//! - [Microsoft Deevice Constants](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ee416859(v=vs.85))
10//! - [Github/Hawkbat/SkyrimControlMapper](https://github.com/Hawkbat/SkyrimControlMapper/blob/12c28d6bae3d5c6c898027fd714cb6ac29b752e7/index.tsx#L198)
11//! - [DirectInput Key Code Table](http://www.flint.jp/misc/?q=dik&lang=en)
12//! - [HumanInterface](https://docs.rs/windows-sys/latest/windows_sys/Win32/Devices/HumanInterfaceDevice/index.html)
13//!   - search DIK(Direst input key)
14use core::{fmt, str::FromStr};
15use num_derive::{FromPrimitive, ToPrimitive};
16use num_traits::FromPrimitive;
17
18#[derive(
19    Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, FromPrimitive, ToPrimitive,
20)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22pub enum MouseCode {
23    #[default]
24    None = 0xff,
25    Mouse1 = 0x0,
26    /// Maybe DIDEVTYPEMOUSE_UNKNOWN
27    Mouse2 = 0x1,
28    /// Maybe DIDEVTYPEMOUSE_TRADITIONAL
29    Mouse3 = 0x2,
30    /// Maybe DIDEVTYPEMOUSE_FINGERSTICK
31    Mouse4 = 0x3,
32    /// Maybe DIDEVTYPEMOUSE_TOUCHPAD
33    Mouse5 = 0x4,
34    ///Maybe DIDEVTYPEMOUSE_TRACKBALL
35    Mouse6 = 0x5,
36    Mouse7 = 0x6,
37    Mouse8 = 0x7,
38    MouseWheelUp = 0x8,
39    MouseWheelDown = 0x9,
40    MouseMove = 0xa,
41
42    // This is the definition from the following website
43    // - See: [Input Script](https://www.creationkit.com/index.php?title=Input_Script)
44    LeftMouseButton = 256,
45    RightMouseButton = 257,
46    MiddleWheelMouseButton = 258,
47    MouseButton3 = 259,
48    MouseButton4 = 260,
49    MouseButton5 = 261,
50    MouseButton6 = 262,
51    MouseButton7 = 263,
52    MouseWheelUp_ = 264,
53    MouseWheelDown_ = 265,
54}
55
56#[allow(non_camel_case_types)]
57#[derive(
58    Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, FromPrimitive, ToPrimitive,
59)]
60#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
61pub enum GamepadCode {
62    #[default]
63    None = 0xff,
64    Up = 0x0001,
65    Down = 0x0002,
66    Left = 0x0004,
67    Right = 0x008,
68    _360_Start = 0x0010,
69    _360_Back = 0x0020,
70    _360_L3 = 0x0040,
71    _360_R3 = 0x0080,
72    _360_LB = 0x0100,
73    _360_RB = 0x0200,
74    _360_A = 0x1000,
75    _360_B = 0x2000,
76    _360_X = 0x4000,
77    _360_Y = 0x8000,
78    _360_LT = 0x0009,
79    _360_RT = 0x000a,
80    _360_LS = 0x000b,
81    _360_RS = 0x000c,
82
83    // This is the definition from the following website
84    // - See: [Input Script](https://www.creationkit.com/index.php?title=Input_Script)
85    DpadUp = 266,
86    DpadDown = 267,
87    DpadLeft = 268,
88    DpadRight = 269,
89    Start = 270,
90    Back = 271,
91    LeftThumb = 272,
92    RightThumb = 273,
93    LeftShoulder = 274,
94    RightShoulder = 275,
95    AButton = 276,
96    BButton = 277,
97    XButton = 278,
98    YButton = 279,
99    LeftTrigger = 280,
100    RightTrigger = 281,
101}
102
103/// - [HumanInterface](https://docs.rs/windows-sys/latest/windows_sys/Win32/Devices/HumanInterfaceDevice/index.html)
104///   - search "DIK_"(Direst input key)
105#[allow(non_camel_case_types)]
106#[derive(
107    Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, FromPrimitive, ToPrimitive,
108)]
109#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
110pub enum KeyboardCode {
111    #[default]
112    None = 0xff,
113    Esc = 0x01,
114    _1 = 0x02,
115    _2 = 0x03,
116    _3 = 0x04,
117    _4 = 0x05,
118    _5 = 0x06,
119    _6 = 0x07,
120    _7 = 0x08,
121    _8 = 0x09,
122    _9 = 0x0a,
123    _0 = 0x0b,
124    Hyphen = 0x0c,
125    Equal = 0x0d,
126    Backspace = 0x0e,
127    Tab = 0x0f,
128    Q = 0x10,
129    W = 0x11,
130    E = 0x12,
131    R = 0x13,
132    T = 0x14,
133    Y = 0x15,
134    U = 0x16,
135    I = 0x17,
136    O = 0x18,
137    P = 0x19,
138    Bracketleft = 0x1a,
139    Bracketright = 0x1b,
140    Enter = 0x1c,
141    LCtrl = 0x1d,
142    A = 0x1e,
143    S = 0x1f,
144    D = 0x20,
145    F = 0x21,
146    G = 0x22,
147    H = 0x23,
148    J = 0x24,
149    K = 0x25,
150    L = 0x26,
151    Semicolon = 0x27,
152    Quotesingle = 0x28,
153    Tilde = 0x29,
154    LShift = 0x2a,
155    Backslash = 0x2b,
156    Z = 0x2c,
157    X = 0x2d,
158    C = 0x2e,
159    V = 0x2f,
160    B = 0x30,
161    N = 0x31,
162    M = 0x32,
163    Comma = 0x33,
164    Period = 0x34,
165    Slash = 0x35,
166    RShift = 0x36,
167    NumpadMult = 0x37,
168    LAlt = 0x38,
169    Space = 0x39,
170    CapsLock = 0x3a,
171    F1 = 0x3b,
172    F2 = 0x3c,
173    F3 = 0x3d,
174    F4 = 0x3e,
175    F5 = 0x3f,
176    F6 = 0x40,
177    F7 = 0x41,
178    F8 = 0x42,
179    F9 = 0x43,
180    F10 = 0x44,
181    NumLock = 0x45,
182    ScrollLock = 0x46,
183    Numpad7 = 0x47,
184    Numpad8 = 0x48,
185    Numpad9 = 0x49,
186    NumpadMinus = 0x4a,
187    Numpad4 = 0x4b,
188    Numpad5 = 0x4c,
189    Numpad6 = 0x4d,
190    NumpadPlus = 0x4e,
191    Numpad1 = 0x4f,
192    Numpad2 = 0x50,
193    Numpad3 = 0x51,
194    Numpad0 = 0x52,
195    NumpadDec = 0x53,
196    DIK_OEM_102 = 0x56,
197    F11 = 0x57,
198    F12 = 0x58,
199    F13 = 0x64,
200    F14 = 0x65,
201    F15 = 0x66,
202    DIK_KANA = 0x70,
203    DIK_ABNT_C1 = 0x73,
204    DIK_CONVERT = 0x79,
205    DIK_NOCONVERT = 0x7b,
206    Unknown = 0x7d,
207    DIK_ABNT_C2 = 0x7e,
208    NumPadEqual = 0x8d,
209    PrevTrack = 0x90,
210    DIK_AT = 0x91,
211    Colon = 0x92,
212    DIK_UNDERLINE = 0x93,
213    DIK_KANJI = 0x94,
214    DIK_STOP = 0x95,
215    DIK_AX = 0x96,
216    DIK_UNLABELED = 0x97,
217    NextTrack = 0x99,
218    NumPadEnter = 0x9c,
219    RCtrl = 0x9d,
220    Mute = 0xa0,
221    Calc = 0xa1,
222    PlayPause = 0xa2,
223    MediaStop = 0xa4,
224    VolMinus = 0xae,
225    VolPlus = 0xb0,
226    WebHome = 0xb2,
227    NumpadComma = 0xb3,
228    NumpadDivide = 0xb5,
229    PrintSrc = 0xb7,
230    RAlt = 0xb8,
231    Pause = 0xc5,
232    Home = 0xc7,
233    UpArrow = 0xc8,
234    PgUp = 0xc9,
235    Left = 0xcb,
236    Right = 0xcd,
237    End = 0xcf,
238    DownArrow = 0xd0,
239    PgDn = 0xd1,
240    Insert = 0xd2,
241    Delete = 0xd3,
242    LWindows = 0xdb,
243    RWindows = 0xdc,
244    Apps = 0xdd,
245    Power = 0xde,
246    Sleep = 0xdf,
247    Wake = 0xe3,
248    WebSearch = 0xe5,
249    WebFavorites = 0xe6,
250    WebRefresh = 0xe7,
251    WebStop = 0xe8,
252    WebForward = 0xe9,
253    WebBack = 0xea,
254    MyComputer = 0xeb,
255    Mail = 0xec,
256    MediaSelect = 0xed,
257}
258
259/// # IntoRaw
260/// cast to usize
261trait ToRaw {
262    /// Get usize by clone.
263    fn to_raw(&self) -> usize;
264}
265
266macro_rules! impl_cast {
267    ($($self:ident),+ $(,)?) => {
268        $(
269            impl ToRaw for $self {
270                fn to_raw(&self) -> usize {
271                    self.clone() as usize
272                }
273            }
274            impl TryFrom<usize> for $self {
275                type Error = ScanCodeError;
276
277                fn try_from(value: usize) -> Result<Self, Self::Error> {
278                    FromPrimitive::from_usize(value)
279                        .ok_or_else(|| ScanCodeError::InvalidDigit(format!("{}", value)))
280                }
281            }
282            impl FromStr for $self {
283                type Err = ScanCodeError;
284
285                fn from_str(s: &str) -> Result<Self, Self::Err> {
286                    let radix = match s.chars().next() {
287                        Some('0') => {
288                            match s.chars().nth(1) {
289                                Some('x') | Some('X') => 16, // Hexadecimal
290                                Some('o') | Some('O') => 8,  // Octal
291                                Some('b') | Some('B') => 2,  // Binary
292                                _ => 10,                     // Decimal
293                            }
294                        }
295                        _ => 10, // Decimal
296                    };
297
298                    let s = if radix != 10 { &s[2..] } else { s };
299                    Self::try_from(
300                        usize::from_str_radix(s, radix)
301                            .map_err(|_| ScanCodeError::InvalidDigit(s.into()))?,
302                    )
303                }
304            }
305            impl fmt::Display for $self {
306                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
307                    write!(f, "0x{:x}", self.to_raw())
308                }
309            }
310        )+
311    };
312}
313
314impl_cast!(GamepadCode, KeyboardCode, MouseCode);
315
316#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
317#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
318pub enum ScanCodeError {
319    #[error("invalid digit found in string. got {0}")]
320    InvalidDigit(String),
321}