win32console/structs/
input_event.rs

1use crate::structs::coord::Coord;
2use winapi::um::wincon::{FROM_LEFT_1ST_BUTTON_PRESSED, FROM_LEFT_2ND_BUTTON_PRESSED, FROM_LEFT_3RD_BUTTON_PRESSED, FROM_LEFT_4TH_BUTTON_PRESSED, KEY_EVENT_RECORD, MOUSE_EVENT_RECORD, RIGHTMOST_BUTTON_PRESSED};
3use std::convert::TryFrom;
4
5/// Represents a `KEY_EVENT_RECORD` which describes a keyboard input event
6/// in a console `INPUT_RECORD` structure.
7///
8/// link: `https://docs.microsoft.com/en-us/windows/console/key-event-record-str`
9#[derive(Debug, Copy, Clone, PartialEq, Eq)]
10pub struct KeyEventRecord {
11    /// If the key is pressed, this member is TRUE. Otherwise, this member is
12    /// FALSE (the key is released).
13    pub key_down: bool,
14    /// The repeat count, which indicates that a key is being held down.
15    /// For example, when a key is held down, you might get five events with
16    /// this member equal to 1, one event with this member equal to 5, or
17    /// multiple events with this member greater than or equal to 1.
18    pub repeat_count: u16,
19    /// A virtual-key code that identifies the given key in a
20    /// device-independent manner.
21    pub virtual_key_code: u16,
22    /// The virtual scan code of the given key that represents the
23    /// device-dependent value generated by the keyboard hardware.
24    pub virtual_scan_code: u16,
25    /// The translated Unicode character (as a WCHAR, or utf-16 value)
26    pub u_char: char,
27    /// The state of the control keys.
28    pub control_key_state: ControlKeyState,
29}
30
31/// Represents a `MOUSE_EVENT_RECORD` which describes a mouse input event
32/// in a console `INPUT_RECORD` structure.
33///
34/// link: `https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str`
35#[derive(Debug, Copy, Clone, PartialEq, Eq)]
36pub struct MouseEventRecord {
37    /// Contains the location of the cursor, in terms of the console screen buffer's character-cell coordinates.
38    pub mouse_position: Coord,
39    /// The status of the mouse buttons.
40    /// The least significant bit corresponds to the leftmost mouse button. T
41    /// he next least significant bit corresponds to the rightmost mouse button.
42    /// The next bit indicates the next-to-leftmost mouse button. The bits then correspond left to right to the mouse buttons.
43    /// A bit is 1 if the button was pressed.
44    pub button_state: ButtonState,
45    /// The state of the control keys.
46    pub control_key_state: ControlKeyState,
47    /// The type of mouse event.
48    /// If this value is zero, it indicates a mouse button being pressed or released.
49    pub event_flags: EventFlags,
50}
51
52/// Represents the state of the mouse buttons.
53///
54/// link: `https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str#members`
55#[derive(Debug, Copy, Clone, PartialEq, Eq)]
56pub struct ButtonState(i32);
57
58/// Represents the state of the control keys.
59///
60/// link: `https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str#members`
61#[derive(Debug, Copy, Clone, PartialEq, Eq)]
62pub struct ControlKeyState(u32);
63
64/// Represents the type of mouse event.
65///
66/// link: `https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str#members`
67#[repr(u32)]
68#[derive(Debug, Copy, Clone, PartialEq, Eq)]
69pub enum EventFlags {
70    /// The button is being pressed or released.
71    PressOrRelease = 0x0000,
72    /// If the high word of the dwButtonState member contains a positive value, the wheel was rotated to the right.
73    /// Otherwise, the wheel was rotated to the left.
74    MouseMoved = 0x0001,
75    /// The second click (button press) of a double-click occurred.
76    /// The first click is returned as a regular button-press event.
77    DoubleClick = 0x0002,
78    /// A change in mouse position occurred.
79    /// The vertical mouse wheel was moved,
80    /// if the high word of the dwButtonState member contains a positive value,
81    /// the wheel was rotated forward, away from the user.
82    /// Otherwise, the wheel was rotated backward, toward the user.
83    MouseWheeled = 0x0004,
84    /// The horizontal mouse wheel was moved.
85    MouseHwheeled = 0x0008,
86}
87
88impl ControlKeyState {
89    /// The right ALT key is pressed.
90    pub const RIGHT_ALT_PRESSED: u32 = 0x0001;
91    /// The left ALT key is pressed.
92    pub const LEFT_ALT_PRESSED: u32 = 0x0002;
93    /// The right CTRL key is pressed.
94    pub const RIGHT_CTRL_PRESSED: u32 = 0x0004;
95    /// The left CTRL key is pressed.
96    pub const LEFT_CTRL_PRESSED: u32 = 0x0008;
97    /// The SHIFT key is pressed.
98    pub const SHIFT_PRESSED: u32 = 0x0010;
99    /// The NUM LOCK light is on.
100    pub const NUM_LOCK_ON: u32 = 0x0020;
101    /// The SCROLL LOCK light is on.
102    pub const SCROLL_LOCK_ON: u32 = 0x0040;
103    /// The CAPS LOCK light is on.
104    pub const CAPS_LOCK_ON: u32 = 0x0080;
105    /// The key is enhanced.
106    pub const ENHANCED_KEY: u32 = 0x0100;
107
108    /// Creates a new [ControlKeyState] with the given state.
109    #[inline]
110    pub fn new(state: u32) -> Self{
111        ControlKeyState(state)
112    }
113
114    /// Checks whether this state contains the specified.
115    ///
116    /// # Example
117    ///
118    /// Basic usages:
119    /// ```
120    /// use win32console::console::WinConsole;
121    /// use win32console::structs::input_record::InputRecord::KeyEvent;
122    /// use win32console::structs::input_event::ControlKeyState;
123    /// let input = WinConsole::output().read_single_input().unwrap();
124    ///
125    /// match input{
126    ///     KeyEvent(e) => {
127    ///         if e.control_key_state.has_state(ControlKeyState::CAPS_LOCK_ON){
128    ///             println!("{}", "CapsLock is on")
129    ///         }
130    ///         else{
131    ///             println!("{}", "CapsLock not on")
132    ///         }
133    ///     }
134    ///     _ => {}
135    /// }
136    /// ```
137    #[inline]
138    pub fn has_state(&self, state: u32) -> bool {
139        (state & self.0) != 0
140    }
141
142    #[inline]
143    pub fn get_state(&self) -> u32 {
144        self.0
145    }
146
147    #[inline]
148    pub fn is_alt_pressed(&self) -> bool {
149        self.has_state(ControlKeyState::RIGHT_ALT_PRESSED)
150            || self.has_state(ControlKeyState::LEFT_ALT_PRESSED)
151    }
152
153    #[inline]
154    pub fn is_ctrl_pressed(&self) -> bool {
155        self.has_state(ControlKeyState::RIGHT_CTRL_PRESSED)
156            || self.has_state(ControlKeyState::LEFT_CTRL_PRESSED)
157    }
158
159    #[inline]
160    pub fn is_shift_pressed(&self) -> bool {
161        self.has_state(ControlKeyState::SHIFT_PRESSED)
162    }
163
164    #[inline]
165    pub fn is_num_lock_on(&self) -> bool {
166        self.has_state(ControlKeyState::NUM_LOCK_ON)
167    }
168
169    #[inline]
170    pub fn is_caps_lock_on(&self) -> bool {
171        self.has_state(ControlKeyState::CAPS_LOCK_ON)
172    }
173
174    #[inline]
175    pub fn is_scroll_lock_on(&self) -> bool {
176        self.has_state(ControlKeyState::SCROLL_LOCK_ON)
177    }
178
179    #[inline]
180    pub fn is_enhanced_key(&self) -> bool {
181        self.has_state(ControlKeyState::ENHANCED_KEY)
182    }
183}
184
185impl ButtonState {
186    /// Returns whether the button is released or pressed.
187    #[inline]
188    pub fn release_button(&self) -> bool {
189        self.0 == 0
190    }
191
192    /// Returns whether the left button was pressed.
193    #[inline]
194    pub fn left_button(&self) -> bool {
195        self.0 as u32 & FROM_LEFT_1ST_BUTTON_PRESSED != 0
196    }
197
198    /// Returns whether the right button was pressed.
199    #[inline]
200    pub fn right_button(&self) -> bool {
201        self.0 as u32
202            & (RIGHTMOST_BUTTON_PRESSED
203                | FROM_LEFT_3RD_BUTTON_PRESSED
204                | FROM_LEFT_4TH_BUTTON_PRESSED)
205            != 0
206    }
207
208    /// Returns whether the right button was pressed.
209    #[inline]
210    pub fn middle_button(&self) -> bool {
211        self.0 as u32 & FROM_LEFT_2ND_BUTTON_PRESSED != 0
212    }
213
214    /// Returns whether there is a down scroll.
215    #[inline]
216    pub fn scroll_down(&self) -> bool {
217        self.0 < 0
218    }
219
220    /// Returns whether there is a up scroll.
221    #[inline]
222    pub fn scroll_up(&self) -> bool {
223        self.0 > 0
224    }
225
226    /// Returns the raw state.
227    #[inline]
228    pub fn get_state(&self) -> i32 {
229        self.0
230    }
231}
232
233impl Into<KEY_EVENT_RECORD> for KeyEventRecord{
234    fn into(self) -> KEY_EVENT_RECORD {
235        KEY_EVENT_RECORD{
236            bKeyDown: self.key_down.into(),
237            wRepeatCount: self.repeat_count,
238            wVirtualKeyCode: self.virtual_key_code,
239            wVirtualScanCode: self.virtual_scan_code,
240            uChar: unsafe {
241                let mut buf = [0u16];
242                self.u_char.encode_utf16(&mut buf);
243                std::mem::transmute(buf)
244            },
245            dwControlKeyState: self.control_key_state.get_state()
246        }
247    }
248}
249
250impl Into<MOUSE_EVENT_RECORD> for MouseEventRecord{
251    fn into(self) -> MOUSE_EVENT_RECORD {
252        MOUSE_EVENT_RECORD{
253            dwMousePosition: self.mouse_position.into(),
254            dwButtonState: self.button_state.get_state() as u32,
255            dwControlKeyState: self.control_key_state.get_state(),
256            dwEventFlags: self.event_flags as u32
257        }
258    }
259}
260
261impl From<KEY_EVENT_RECORD> for KeyEventRecord {
262    #[inline]
263    fn from(record: KEY_EVENT_RECORD) -> Self {
264        KeyEventRecord {
265            key_down: record.bKeyDown != 0,
266            repeat_count: record.wRepeatCount,
267            virtual_key_code: record.wVirtualKeyCode,
268            virtual_scan_code: record.wVirtualScanCode,
269            u_char: unsafe{ char::try_from(*record.uChar.UnicodeChar() as u32).ok().unwrap() },
270            control_key_state: ControlKeyState(record.dwControlKeyState),
271        }
272    }
273}
274
275impl From<u32> for EventFlags {
276    fn from(event: u32) -> Self {
277        match event {
278            0x0000 => EventFlags::PressOrRelease,
279            0x0001 => EventFlags::MouseMoved,
280            0x0002 => EventFlags::DoubleClick,
281            0x0004 => EventFlags::MouseWheeled,
282            0x0008 => EventFlags::MouseHwheeled,
283            _ => panic!("Event flag {} does not exist.", event),
284        }
285    }
286}
287
288impl From<MOUSE_EVENT_RECORD> for MouseEventRecord {
289    #[inline]
290    fn from(event: MOUSE_EVENT_RECORD) -> Self {
291        MouseEventRecord {
292            mouse_position: event.dwMousePosition.into(),
293            button_state: event.dwButtonState.into(),
294            control_key_state: ControlKeyState(event.dwControlKeyState),
295            event_flags: event.dwEventFlags.into(),
296        }
297    }
298}
299
300impl From<u32> for ButtonState {
301    #[inline]
302    fn from(state: u32) -> Self {
303        ButtonState(state as i32)
304    }
305}
306
307#[cfg(test)]
308mod tests{
309    use super::*;
310
311    #[test]
312    fn key_event_into_test(){
313        let mut key_event : KeyEventRecord = unsafe { std::mem::zeroed() };
314        key_event.control_key_state = ControlKeyState::new(4);
315        key_event.u_char = 'a';
316        key_event.virtual_scan_code = 4;
317        key_event.virtual_key_code = 8;
318        key_event.repeat_count = 16;
319        key_event.virtual_scan_code = 32;
320
321        let raw_key_event : KEY_EVENT_RECORD = key_event.into();
322
323        assert_eq!(key_event.virtual_scan_code, raw_key_event.wVirtualScanCode);
324        assert_eq!(key_event.repeat_count, raw_key_event.wRepeatCount);
325        assert_eq!(key_event.virtual_key_code, raw_key_event.wVirtualKeyCode);
326        assert_eq!(key_event.control_key_state.get_state(), raw_key_event.dwControlKeyState);
327        assert_eq!(key_event.key_down, raw_key_event.bKeyDown != 0);
328        assert_eq!(key_event.u_char, unsafe {
329            char::try_from(*raw_key_event.uChar.UnicodeChar() as u32).unwrap()
330        });
331    }
332
333    #[test]
334    fn mouse_event_into_test(){
335        let mouse_event : MouseEventRecord = unsafe { std::mem::zeroed() };
336        let raw_mouse_event : MOUSE_EVENT_RECORD = mouse_event.into();
337
338        assert_eq!(mouse_event.control_key_state.get_state(), raw_mouse_event.dwControlKeyState);
339        assert_eq!(mouse_event.event_flags as u32, raw_mouse_event.dwEventFlags);
340        assert_eq!(mouse_event.button_state.get_state() as u32, raw_mouse_event.dwButtonState);
341        assert_eq!(mouse_event.mouse_position, Coord::from(raw_mouse_event.dwMousePosition));
342    }
343}