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