winapi_easy/
input.rs

1//! Keyboard and hotkeys.
2
3use std::{
4    io,
5    mem,
6};
7
8use num_enum::{
9    FromPrimitive,
10    IntoPrimitive,
11};
12use windows::Win32::UI::Input::KeyboardAndMouse::{
13    GetAsyncKeyState,
14    GetKeyState,
15    SendInput,
16    INPUT,
17    INPUT_0,
18    INPUT_KEYBOARD,
19    INPUT_MOUSE,
20    KEYBDINPUT,
21    KEYEVENTF_KEYUP,
22    MOUSEEVENTF_LEFTDOWN,
23    MOUSEEVENTF_LEFTUP,
24    MOUSEEVENTF_MIDDLEDOWN,
25    MOUSEEVENTF_MIDDLEUP,
26    MOUSEEVENTF_RIGHTDOWN,
27    MOUSEEVENTF_RIGHTUP,
28    MOUSEEVENTF_WHEEL,
29    MOUSEEVENTF_XDOWN,
30    MOUSEEVENTF_XUP,
31    MOUSEINPUT,
32    VIRTUAL_KEY,
33    VK_0,
34    VK_1,
35    VK_2,
36    VK_3,
37    VK_4,
38    VK_5,
39    VK_6,
40    VK_7,
41    VK_8,
42    VK_9,
43    VK_A,
44    VK_ADD,
45    VK_APPS,
46    VK_B,
47    VK_BACK,
48    VK_C,
49    VK_CAPITAL,
50    VK_D,
51    VK_DECIMAL,
52    VK_DELETE,
53    VK_DIVIDE,
54    VK_DOWN,
55    VK_E,
56    VK_END,
57    VK_ESCAPE,
58    VK_F,
59    VK_F1,
60    VK_F10,
61    VK_F11,
62    VK_F12,
63    VK_F2,
64    VK_F3,
65    VK_F4,
66    VK_F5,
67    VK_F6,
68    VK_F7,
69    VK_F8,
70    VK_F9,
71    VK_G,
72    VK_H,
73    VK_HOME,
74    VK_I,
75    VK_INSERT,
76    VK_J,
77    VK_K,
78    VK_L,
79    VK_LBUTTON,
80    VK_LCONTROL,
81    VK_LEFT,
82    VK_LMENU,
83    VK_LSHIFT,
84    VK_LWIN,
85    VK_M,
86    VK_MBUTTON,
87    VK_MULTIPLY,
88    VK_N,
89    VK_NEXT,
90    VK_NUMLOCK,
91    VK_NUMPAD0,
92    VK_NUMPAD1,
93    VK_NUMPAD2,
94    VK_NUMPAD3,
95    VK_NUMPAD4,
96    VK_NUMPAD5,
97    VK_NUMPAD6,
98    VK_NUMPAD7,
99    VK_NUMPAD8,
100    VK_NUMPAD9,
101    VK_O,
102    VK_OEM_1,
103    VK_OEM_102,
104    VK_OEM_2,
105    VK_OEM_3,
106    VK_OEM_4,
107    VK_OEM_5,
108    VK_OEM_6,
109    VK_OEM_7,
110    VK_OEM_8,
111    VK_OEM_COMMA,
112    VK_OEM_MINUS,
113    VK_OEM_PERIOD,
114    VK_OEM_PLUS,
115    VK_P,
116    VK_PAUSE,
117    VK_PRIOR,
118    VK_Q,
119    VK_R,
120    VK_RBUTTON,
121    VK_RCONTROL,
122    VK_RETURN,
123    VK_RIGHT,
124    VK_RMENU,
125    VK_RSHIFT,
126    VK_RWIN,
127    VK_S,
128    VK_SCROLL,
129    VK_SNAPSHOT,
130    VK_SPACE,
131    VK_SUBTRACT,
132    VK_T,
133    VK_TAB,
134    VK_U,
135    VK_UP,
136    VK_V,
137    VK_VOLUME_DOWN,
138    VK_VOLUME_MUTE,
139    VK_VOLUME_UP,
140    VK_W,
141    VK_X,
142    VK_XBUTTON1,
143    VK_XBUTTON2,
144    VK_Y,
145    VK_Z,
146};
147use windows::Win32::UI::WindowsAndMessaging::{
148    WHEEL_DELTA,
149    XBUTTON1,
150    XBUTTON2,
151};
152
153use crate::internal::ReturnValue;
154use private::*;
155
156pub mod hotkeys;
157
158/// A [`KeyboardKey`] or a [`MouseButton`].
159pub trait GenericKey: GenericKeyInternal {
160    fn is_pressed(self) -> io::Result<bool> {
161        let result = unsafe {
162            GetAsyncKeyState(self.into())
163                .if_null_to_error(|| io::ErrorKind::PermissionDenied.into())? as u16
164        };
165        Ok(result >> (u16::BITS - 1) == 1)
166    }
167
168    /// Globally sends a 'press' event (without a corresponding 'release').
169    ///
170    /// This can conflict with existing user key presses. Use [`Self::is_pressed`] to avoid this.
171    fn press(self) -> io::Result<()> {
172        self.send_input(false)
173    }
174
175    /// Globally sends a 'release' event.
176    fn release(self) -> io::Result<()> {
177        self.send_input(true)
178    }
179
180    /// Globally sends a key (or mouse button) combination as if the user had performed it.
181    ///
182    /// This will cause a 'press' event for each key in the list (in the given order),
183    /// followed by a sequence of 'release' events (in the inverse order).
184    fn send_combination(keys: &[Self]) -> io::Result<()> {
185        let raw_input_pairs: Vec<_> = keys
186            .iter()
187            .copied()
188            .map(|key: Self| {
189                let raw_input = key.get_press_raw_input(false);
190                let raw_input_release = key.get_press_raw_input(true);
191                (raw_input, raw_input_release)
192            })
193            .collect();
194        let raw_inputs: Vec<_> = raw_input_pairs
195            .iter()
196            .map(|x| x.0)
197            .chain(raw_input_pairs.iter().rev().map(|x| x.1))
198            .collect();
199        send_raw_inputs(raw_inputs.as_slice())
200    }
201}
202
203// No generic impl to generate better docs
204impl GenericKey for KeyboardKey {}
205impl GenericKey for MouseButton {}
206
207mod private {
208    use super::*;
209
210    pub trait GenericKeyInternal: Copy + Into<i32>
211    where
212        // Declared like this due to IntelliJ bug
213        Self: Into<u16>,
214    {
215        fn send_input(self, is_release: bool) -> io::Result<()> {
216            let raw_input = self.get_press_raw_input(is_release);
217            send_raw_inputs(&[raw_input])
218        }
219        fn get_press_raw_input(self, is_release: bool) -> INPUT;
220    }
221
222    impl GenericKeyInternal for KeyboardKey {
223        fn get_press_raw_input(self, is_release: bool) -> INPUT {
224            let raw_key: u16 = self.into();
225            let raw_keybdinput = KEYBDINPUT {
226                wVk: VIRTUAL_KEY(raw_key),
227                dwFlags: if is_release {
228                    KEYEVENTF_KEYUP
229                } else {
230                    Default::default()
231                },
232                ..Default::default()
233            };
234            INPUT {
235                r#type: INPUT_KEYBOARD,
236                Anonymous: INPUT_0 { ki: raw_keybdinput },
237            }
238        }
239    }
240
241    impl GenericKeyInternal for MouseButton {
242        fn get_press_raw_input(self, is_release: bool) -> INPUT {
243            let (flags, mouse_data) = match (self, is_release) {
244                (MouseButton::Left, false) => (MOUSEEVENTF_LEFTDOWN, 0),
245                (MouseButton::Left, true) => (MOUSEEVENTF_LEFTUP, 0),
246                (MouseButton::Right, false) => (MOUSEEVENTF_RIGHTDOWN, 0),
247                (MouseButton::Right, true) => (MOUSEEVENTF_RIGHTUP, 0),
248                (MouseButton::Middle, false) => (MOUSEEVENTF_MIDDLEDOWN, 0),
249                (MouseButton::Middle, true) => (MOUSEEVENTF_MIDDLEUP, 0),
250                (MouseButton::X1, false) => (MOUSEEVENTF_XDOWN, XBUTTON1),
251                (MouseButton::X1, true) => (MOUSEEVENTF_XUP, XBUTTON1),
252                (MouseButton::X2, false) => (MOUSEEVENTF_XDOWN, XBUTTON2),
253                (MouseButton::X2, true) => (MOUSEEVENTF_XUP, XBUTTON2),
254            };
255            INPUT {
256                r#type: INPUT_MOUSE,
257                Anonymous: INPUT_0 {
258                    mi: MOUSEINPUT {
259                        mouseData: mouse_data.into(),
260                        dwFlags: flags,
261                        ..Default::default()
262                    },
263                },
264            }
265        }
266    }
267}
268
269/// Keyboard key with a virtual key code, usable for hotkeys.
270///
271/// # Related docs
272///
273/// [Microsoft docs for virtual key codes](https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes)
274#[derive(FromPrimitive, IntoPrimitive, Copy, Clone, Eq, PartialEq, Hash, Debug)]
275#[repr(u16)]
276pub enum KeyboardKey {
277    Backspace = VK_BACK.0,
278    Tab = VK_TAB.0,
279    Return = VK_RETURN.0,
280    Pause = VK_PAUSE.0,
281    CapsLock = VK_CAPITAL.0,
282    Esc = VK_ESCAPE.0,
283    Space = VK_SPACE.0,
284    PgUp = VK_PRIOR.0,
285    PgDown = VK_NEXT.0,
286    End = VK_END.0,
287    Home = VK_HOME.0,
288    LeftArrow = VK_LEFT.0,
289    UpArrow = VK_UP.0,
290    RightArrow = VK_RIGHT.0,
291    DownArrow = VK_DOWN.0,
292    PrintScreen = VK_SNAPSHOT.0,
293    Insert = VK_INSERT.0,
294    Delete = VK_DELETE.0,
295    Number0 = VK_0.0,
296    Number1 = VK_1.0,
297    Number2 = VK_2.0,
298    Number3 = VK_3.0,
299    Number4 = VK_4.0,
300    Number5 = VK_5.0,
301    Number6 = VK_6.0,
302    Number7 = VK_7.0,
303    Number8 = VK_8.0,
304    Number9 = VK_9.0,
305    A = VK_A.0,
306    B = VK_B.0,
307    C = VK_C.0,
308    D = VK_D.0,
309    E = VK_E.0,
310    F = VK_F.0,
311    G = VK_G.0,
312    H = VK_H.0,
313    I = VK_I.0,
314    J = VK_J.0,
315    K = VK_K.0,
316    L = VK_L.0,
317    M = VK_M.0,
318    N = VK_N.0,
319    O = VK_O.0,
320    P = VK_P.0,
321    Q = VK_Q.0,
322    R = VK_R.0,
323    S = VK_S.0,
324    T = VK_T.0,
325    U = VK_U.0,
326    V = VK_V.0,
327    W = VK_W.0,
328    X = VK_X.0,
329    Y = VK_Y.0,
330    Z = VK_Z.0,
331    LeftWindows = VK_LWIN.0,
332    RightWindows = VK_RWIN.0,
333    Menu = VK_APPS.0,
334    Numpad0 = VK_NUMPAD0.0,
335    Numpad1 = VK_NUMPAD1.0,
336    Numpad2 = VK_NUMPAD2.0,
337    Numpad3 = VK_NUMPAD3.0,
338    Numpad4 = VK_NUMPAD4.0,
339    Numpad5 = VK_NUMPAD5.0,
340    Numpad6 = VK_NUMPAD6.0,
341    Numpad7 = VK_NUMPAD7.0,
342    Numpad8 = VK_NUMPAD8.0,
343    Numpad9 = VK_NUMPAD9.0,
344    Multiply = VK_MULTIPLY.0,
345    Add = VK_ADD.0,
346    Subtract = VK_SUBTRACT.0,
347    Decimal = VK_DECIMAL.0,
348    Divide = VK_DIVIDE.0,
349    F1 = VK_F1.0,
350    F2 = VK_F2.0,
351    F3 = VK_F3.0,
352    F4 = VK_F4.0,
353    F5 = VK_F5.0,
354    F6 = VK_F6.0,
355    F7 = VK_F7.0,
356    F8 = VK_F8.0,
357    F9 = VK_F9.0,
358    F10 = VK_F10.0,
359    F11 = VK_F11.0,
360    F12 = VK_F12.0,
361    NumLock = VK_NUMLOCK.0,
362    ScrollLock = VK_SCROLL.0,
363    LeftShift = VK_LSHIFT.0,
364    RightShift = VK_RSHIFT.0,
365    LeftCtrl = VK_LCONTROL.0,
366    RightCtrl = VK_RCONTROL.0,
367    LeftAlt = VK_LMENU.0,
368    RightAlt = VK_RMENU.0,
369    VolumeMute = VK_VOLUME_MUTE.0,
370    VolumeDown = VK_VOLUME_DOWN.0,
371    VolumeUp = VK_VOLUME_UP.0,
372    /// Used for miscellaneous characters; it can vary by keyboard.
373    ///
374    /// * For the US standard keyboard, the ';:' key
375    /// * For the German keyboard, the 'ü' key
376    Oem1 = VK_OEM_1.0,
377    /// For any country/region, the '+' key
378    OemPlus = VK_OEM_PLUS.0,
379    /// For any country/region, the ',' key
380    OemComma = VK_OEM_COMMA.0,
381    /// For any country/region, the '-' key
382    OemMinus = VK_OEM_MINUS.0,
383    /// For any country/region, the '.' key
384    OemPeriod = VK_OEM_PERIOD.0,
385    /// Used for miscellaneous characters; it can vary by keyboard.
386    ///
387    /// * For the US standard keyboard, the '/?' key
388    /// * For the German keyboard, the '#'' key
389    Oem2 = VK_OEM_2.0,
390    /// Used for miscellaneous characters; it can vary by keyboard.
391    ///
392    /// * For the US standard keyboard, the '`~' key
393    /// * For the German keyboard, the 'ö' key
394    Oem3 = VK_OEM_3.0,
395    /// Used for miscellaneous characters; it can vary by keyboard.
396    ///
397    /// * For the US standard keyboard, the '[{' key
398    /// * For the German keyboard, the 'ß?' key
399    Oem4 = VK_OEM_4.0,
400    /// Used for miscellaneous characters; it can vary by keyboard.
401    ///
402    /// * For the US standard keyboard, the '\|' key besides 'Enter'
403    /// * For the German keyboard, the '^°' key
404    Oem5 = VK_OEM_5.0,
405    /// Used for miscellaneous characters; it can vary by keyboard.
406    ///
407    /// * For the US standard keyboard, the ']}' key
408    /// * For the German keyboard, the '´`' key
409    Oem6 = VK_OEM_6.0,
410    /// Used for miscellaneous characters; it can vary by keyboard.
411    ///
412    /// * For the US standard keyboard, the 'single-quote/double-quote' key
413    /// * For the German keyboard, the 'ä' key
414    Oem7 = VK_OEM_7.0,
415    Oem8 = VK_OEM_8.0,
416    /// Used for miscellaneous characters; it can vary by keyboard.
417    ///
418    /// * For the US standard keyboard, the '\|' key besides the 'z' key
419    /// * For the German keyboard, the '<>' key
420    Oem102 = VK_OEM_102.0,
421    /// Other virtual key code.
422    #[num_enum(catch_all)]
423    Other(u16),
424}
425
426impl KeyboardKey {
427    /// Returns true if the key has lock functionality (e.g. Caps Lock) and the lock is toggled.
428    pub fn is_lock_toggled(self) -> bool {
429        let result = unsafe { GetKeyState(self.into()) as u16 };
430        result & 1 == 1
431    }
432}
433
434impl From<KeyboardKey> for u32 {
435    fn from(value: KeyboardKey) -> Self {
436        Self::from(u16::from(value))
437    }
438}
439
440impl From<KeyboardKey> for i32 {
441    fn from(value: KeyboardKey) -> Self {
442        u16::from(value) as Self
443    }
444}
445
446fn send_raw_inputs(raw_inputs: &[INPUT]) -> io::Result<()> {
447    let raw_input_size = mem::size_of::<INPUT>()
448        .try_into()
449        .expect("Struct size conversion failed");
450
451    let expected_sent_size =
452        u32::try_from(raw_inputs.len()).expect("Inputs length conversion failed");
453    unsafe {
454        SendInput(raw_inputs, raw_input_size)
455            .if_null_get_last_error()?
456            .if_not_eq_to_error(expected_sent_size, || {
457                io::Error::from(io::ErrorKind::Interrupted)
458            })?;
459    }
460    Ok(())
461}
462
463/// Mouse button.
464///
465/// Note that X-Buttons above #2 are only handled by the mouse driver.
466#[derive(IntoPrimitive, Copy, Clone, Eq, PartialEq, Hash, Debug)]
467#[repr(u16)]
468pub enum MouseButton {
469    Left = VK_LBUTTON.0,
470    Right = VK_RBUTTON.0,
471    Middle = VK_MBUTTON.0,
472    X1 = VK_XBUTTON1.0,
473    X2 = VK_XBUTTON2.0,
474}
475
476impl From<MouseButton> for i32 {
477    fn from(value: MouseButton) -> Self {
478        u16::from(value) as Self
479    }
480}
481
482/// Mouse scroll wheel 'up' or 'down' event, possibly continuous.
483#[derive(Copy, Clone, Eq, PartialEq, Debug)]
484pub enum MouseScrollEvent {
485    /// Single up-scroll event.
486    ///
487    /// Equivalent to [`Self::Continuous`] with a value of [`WHEEL_DELTA`].
488    Up,
489    /// Single down-scroll event.
490    ///
491    /// Equivalent to [`Self::Continuous`] with a value of -[`WHEEL_DELTA`].
492    Down,
493    /// Continuous 'up' (positive value) or 'down' (negative value) scroll event.
494    ///
495    /// Values other than positive or negative [`WHEEL_DELTA`] are used for mouses
496    /// with continuous scroll wheels.
497    Continuous(i16),
498}
499
500impl MouseScrollEvent {
501    const WHEEL_DELTA_INT: i16 = WHEEL_DELTA as _;
502
503    /// Globally sends a single scroll event.
504    pub fn send(self) -> io::Result<()> {
505        self.send_amount(1)
506    }
507
508    /// Globally sends a certain amount of scroll events.
509    pub fn send_amount(self, amount: u8) -> io::Result<()> {
510        let single_delta = match self {
511            MouseScrollEvent::Up => Self::WHEEL_DELTA_INT,
512            MouseScrollEvent::Down => -Self::WHEEL_DELTA_INT,
513            MouseScrollEvent::Continuous(delta) => delta,
514        };
515        // Should never overflow due to data types
516        let mouse_data = i32::from(single_delta) * i32::from(amount);
517        let raw_input = INPUT {
518            r#type: INPUT_MOUSE,
519            Anonymous: INPUT_0 {
520                mi: MOUSEINPUT {
521                    // bit-cast semantics necessary here because negative values should be allowed
522                    mouseData: mouse_data as u32,
523                    dwFlags: MOUSEEVENTF_WHEEL,
524                    ..Default::default()
525                },
526            },
527        };
528        send_raw_inputs(&[raw_input])
529    }
530
531    #[allow(dead_code)]
532    pub(crate) fn from_raw_movement(raw_movement: u16) -> Self {
533        let raw_movement = raw_movement as i16;
534        const WHEEL_DELTA_INT: i16 = WHEEL_DELTA as _;
535        if raw_movement == WHEEL_DELTA_INT {
536            MouseScrollEvent::Up
537        } else if raw_movement == -WHEEL_DELTA_INT {
538            MouseScrollEvent::Down
539        } else {
540            MouseScrollEvent::Continuous(raw_movement)
541        }
542    }
543}