1 //! This module provides a few structs to wrap common input struts to a rusty interface
2 //!
3 //! Types like:
4 //! - `KEY_EVENT_RECORD`
5 //! - `MOUSE_EVENT_RECORD`
6 //! - `ControlKeyState`
7 //! - `ButtonState`
8 //! - `EventFlags`
9 //! - `InputEventType`
10 //! - `INPUT_RECORD`
11 
12 use winapi::shared::minwindef::DWORD;
13 use winapi::um::wincon::{
14     FOCUS_EVENT, FOCUS_EVENT_RECORD, FROM_LEFT_1ST_BUTTON_PRESSED, FROM_LEFT_2ND_BUTTON_PRESSED,
15     FROM_LEFT_3RD_BUTTON_PRESSED, FROM_LEFT_4TH_BUTTON_PRESSED, INPUT_RECORD, KEY_EVENT,
16     KEY_EVENT_RECORD, MENU_EVENT, MENU_EVENT_RECORD, MOUSE_EVENT, MOUSE_EVENT_RECORD,
17     RIGHTMOST_BUTTON_PRESSED, WINDOW_BUFFER_SIZE_EVENT, WINDOW_BUFFER_SIZE_RECORD,
18 };
19 
20 use super::Coord;
21 
22 /// Describes a keyboard input event in a console INPUT_RECORD structure.
23 /// link: [https://docs.microsoft.com/en-us/windows/console/key-event-record-str]
24 #[derive(Clone, Debug, Eq, PartialEq)]
25 pub struct KeyEventRecord {
26     /// If the key is pressed, this member is TRUE. Otherwise, this member is
27     /// FALSE (the key is released).
28     pub key_down: bool,
29     /// The repeat count, which indicates that a key is being held down.
30     /// For example, when a key is held down, you might get five events with
31     /// this member equal to 1, one event with this member equal to 5, or
32     /// multiple events with this member greater than or equal to 1.
33     pub repeat_count: u16,
34     /// A virtual-key code that identifies the given key in a
35     /// device-independent manner.
36     pub virtual_key_code: u16,
37     /// The virtual scan code of the given key that represents the
38     /// device-dependent value generated by the keyboard hardware.
39     pub virtual_scan_code: u16,
40     /// The translated Unicode character (as a WCHAR, or utf-16 value)
41     pub u_char: u16,
42     /// The state of the control keys.
43     pub control_key_state: ControlKeyState,
44 }
45 
46 impl KeyEventRecord {
47     /// Convert a KEY_EVENT_RECORD to KeyEventRecord. This function is private
48     /// because the KEY_EVENT_RECORD has several union fields for characters
49     /// (u8 vs u16) that we always interpret as u16. We always use the wide
50     /// versions of windows API calls to support this.
51     #[inline]
from_winapi(record: &KEY_EVENT_RECORD) -> Self52     fn from_winapi(record: &KEY_EVENT_RECORD) -> Self {
53         KeyEventRecord {
54             key_down: record.bKeyDown != 0,
55             repeat_count: record.wRepeatCount,
56             virtual_key_code: record.wVirtualKeyCode,
57             virtual_scan_code: record.wVirtualScanCode,
58             u_char: unsafe { *record.uChar.UnicodeChar() },
59             control_key_state: ControlKeyState(record.dwControlKeyState),
60         }
61     }
62 }
63 
64 #[derive(PartialEq, Debug, Copy, Clone, Eq)]
65 pub struct MouseEvent {
66     pub mouse_position: Coord,
67     pub button_state: ButtonState,
68     pub control_key_state: ControlKeyState,
69     pub event_flags: EventFlags,
70 }
71 
72 impl From<MOUSE_EVENT_RECORD> for MouseEvent {
73     #[inline]
from(event: MOUSE_EVENT_RECORD) -> Self74     fn from(event: MOUSE_EVENT_RECORD) -> Self {
75         MouseEvent {
76             mouse_position: event.dwMousePosition.into(),
77             button_state: event.dwButtonState.into(),
78             control_key_state: ControlKeyState(event.dwControlKeyState),
79             event_flags: event.dwEventFlags.into(),
80         }
81     }
82 }
83 
84 /// The status of the mouse buttons.
85 /// The least significant bit corresponds to the leftmost mouse button.
86 /// The next least significant bit corresponds to the rightmost mouse button.
87 /// The next bit indicates the next-to-leftmost mouse button.
88 /// The bits then correspond left to right to the mouse buttons.
89 /// A bit is 1 if the button was pressed.
90 ///
91 /// The state can be one of the following:
92 /// Release = 0x0000,
93 /// // The leftmost mouse button.
94 /// FromLeft1stButtonPressed = 0x0001,
95 /// // The second button from the left.
96 /// FromLeft2ndButtonPressed = 0x0004,
97 /// // The third button from the left.
98 /// FromLeft3rdButtonPressed = 0x0008,
99 /// // The fourth button from the left.
100 /// FromLeft4thButtonPressed = 0x0010,
101 /// // The rightmost mouse button.
102 /// RightmostButtonPressed = 0x0002,
103 /// // This button state is not recognized.
104 /// Unknown = 0x0021,
105 /// // The wheel was rotated backward, toward the user; this will only be activated for `MOUSE_WHEELED ` from `dwEventFlags`
106 /// Negative = 0x0020,
107 ///
108 /// [Ms Docs](https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str#members)
109 #[derive(PartialEq, Debug, Copy, Clone, Eq)]
110 pub struct ButtonState {
111     state: i32,
112 }
113 
114 impl From<DWORD> for ButtonState {
115     #[inline]
from(event: DWORD) -> Self116     fn from(event: DWORD) -> Self {
117         let state = event as i32;
118         ButtonState { state }
119     }
120 }
121 
122 impl ButtonState {
release_button(&self) -> bool123     pub fn release_button(&self) -> bool {
124         self.state == 0
125     }
126 
127     /// Returns whether the left button was pressed.
left_button(&self) -> bool128     pub fn left_button(&self) -> bool {
129         self.state as u32 & FROM_LEFT_1ST_BUTTON_PRESSED != 0
130     }
131 
132     /// Returns whether the right button was pressed.
right_button(&self) -> bool133     pub fn right_button(&self) -> bool {
134         self.state as u32
135             & (RIGHTMOST_BUTTON_PRESSED
136                 | FROM_LEFT_3RD_BUTTON_PRESSED
137                 | FROM_LEFT_4TH_BUTTON_PRESSED)
138             != 0
139     }
140 
141     /// Returns whether the right button was pressed.
middle_button(&self) -> bool142     pub fn middle_button(&self) -> bool {
143         self.state as u32 & FROM_LEFT_2ND_BUTTON_PRESSED != 0
144     }
145 
146     /// Returns whether there is a down scroll.
scroll_down(&self) -> bool147     pub fn scroll_down(&self) -> bool {
148         self.state < 0
149     }
150 
151     /// Returns whether there is a up scroll.
scroll_up(&self) -> bool152     pub fn scroll_up(&self) -> bool {
153         self.state > 0
154     }
155 
156     /// Returns the raw state.
state(&self) -> i32157     pub fn state(&self) -> i32 {
158         self.state
159     }
160 }
161 
162 #[derive(PartialEq, Debug, Copy, Clone, Eq)]
163 pub struct ControlKeyState(u32);
164 
165 impl ControlKeyState {
has_state(&self, state: u32) -> bool166     pub fn has_state(&self, state: u32) -> bool {
167         (state & self.0) != 0
168     }
169 }
170 
171 /// The type of mouse event.
172 /// If this value is zero, it indicates a mouse button being pressed or released.
173 /// Otherwise, this member is one of the following values.
174 ///
175 /// [Ms Docs](https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str#members)
176 #[derive(PartialEq, Debug, Copy, Clone, Eq)]
177 pub enum EventFlags {
178     PressOrRelease = 0x0000,
179     // The second click (button press) of a double-click occurred. The first click is returned as a regular button-press event.
180     DoubleClick = 0x0002,
181     // The horizontal mouse wheel was moved.
182     MouseHwheeled = 0x0008,
183     // If the high word of the dwButtonState member contains a positive value, the wheel was rotated to the right. Otherwise, the wheel was rotated to the left.
184     MouseMoved = 0x0001,
185     // A change in mouse position occurred.
186     // The vertical mouse wheel was moved, if the high word of the dwButtonState member contains a positive value, the wheel was rotated forward, away from the user.
187     // Otherwise, the wheel was rotated backward, toward the user.
188     MouseWheeled = 0x0004,
189 }
190 
191 // TODO: Replace with TryFrom.
192 impl From<DWORD> for EventFlags {
from(event: DWORD) -> Self193     fn from(event: DWORD) -> Self {
194         match event {
195             0x0000 => EventFlags::PressOrRelease,
196             0x0002 => EventFlags::DoubleClick,
197             0x0008 => EventFlags::MouseHwheeled,
198             0x0001 => EventFlags::MouseMoved,
199             0x0004 => EventFlags::MouseWheeled,
200             _ => panic!("Event flag {} does not exist.", event),
201         }
202     }
203 }
204 
205 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
206 pub struct WindowBufferSizeRecord {
207     pub size: Coord,
208 }
209 
210 impl From<WINDOW_BUFFER_SIZE_RECORD> for WindowBufferSizeRecord {
211     #[inline]
from(record: WINDOW_BUFFER_SIZE_RECORD) -> Self212     fn from(record: WINDOW_BUFFER_SIZE_RECORD) -> Self {
213         WindowBufferSizeRecord {
214             size: record.dwSize.into(),
215         }
216     }
217 }
218 
219 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
220 pub struct FocusEventRecord {
221     pub set_focus: bool,
222 }
223 
224 impl From<FOCUS_EVENT_RECORD> for FocusEventRecord {
225     #[inline]
from(record: FOCUS_EVENT_RECORD) -> Self226     fn from(record: FOCUS_EVENT_RECORD) -> Self {
227         FocusEventRecord {
228             set_focus: record.bSetFocus != 0,
229         }
230     }
231 }
232 
233 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
234 pub struct MenuEventRecord {
235     pub command_id: u32,
236 }
237 
238 impl From<MENU_EVENT_RECORD> for MenuEventRecord {
239     #[inline]
from(record: MENU_EVENT_RECORD) -> Self240     fn from(record: MENU_EVENT_RECORD) -> Self {
241         MenuEventRecord {
242             command_id: record.dwCommandId,
243         }
244     }
245 }
246 
247 /// Describes an input event in the console input buffer.
248 /// These records can be read from the input buffer by using the `ReadConsoleInput`
249 /// or `PeekConsoleInput` function, or written to the input buffer by using the
250 /// `WriteConsoleInput` function.
251 ///
252 /// [Ms Docs](https://docs.microsoft.com/en-us/windows/console/input-record-str)
253 #[derive(Clone, Debug, PartialEq, Eq)]
254 pub enum InputRecord {
255     /// The Event member contains a `KEY_EVENT_RECORD` structure with
256     /// information about a keyboard event.
257     KeyEvent(KeyEventRecord),
258     /// The Event member contains a `MOUSE_EVENT_RECORD` structure with
259     /// information about a mouse movement or button press event.
260     MouseEvent(MouseEvent),
261     /// The Event member contains a `WINDOW_BUFFER_SIZE_RECORD` structure with
262     /// information about the new size of the console screen buffer.
263     WindowBufferSizeEvent(WindowBufferSizeRecord),
264     /// The Event member contains a `FOCUS_EVENT_RECORD` structure. These
265     /// events are used internally and should be ignored.
266     FocusEvent(FocusEventRecord),
267     /// The Event member contains a `MENU_EVENT_RECORD` structure. These
268     /// events are used internally and should be ignored.
269     MenuEvent(MenuEventRecord),
270 }
271 
272 impl From<INPUT_RECORD> for InputRecord {
273     #[inline]
from(record: INPUT_RECORD) -> Self274     fn from(record: INPUT_RECORD) -> Self {
275         match record.EventType {
276             KEY_EVENT => InputRecord::KeyEvent(KeyEventRecord::from_winapi(unsafe {
277                 record.Event.KeyEvent()
278             })),
279             MOUSE_EVENT => InputRecord::MouseEvent(unsafe { *record.Event.MouseEvent() }.into()),
280             WINDOW_BUFFER_SIZE_EVENT => InputRecord::WindowBufferSizeEvent(
281                 unsafe { *record.Event.WindowBufferSizeEvent() }.into(),
282             ),
283             FOCUS_EVENT => InputRecord::FocusEvent(unsafe { *record.Event.FocusEvent() }.into()),
284             MENU_EVENT => InputRecord::MenuEvent(unsafe { *record.Event.MenuEvent() }.into()),
285             code => panic!("Unexpected INPUT_RECORD EventType: {}", code),
286         }
287     }
288 }
289