use winapi::shared::minwindef::DWORD;
use winapi::um::wincon::{
FOCUS_EVENT, FOCUS_EVENT_RECORD, FROM_LEFT_1ST_BUTTON_PRESSED, FROM_LEFT_2ND_BUTTON_PRESSED,
FROM_LEFT_3RD_BUTTON_PRESSED, FROM_LEFT_4TH_BUTTON_PRESSED, INPUT_RECORD, KEY_EVENT,
KEY_EVENT_RECORD, MENU_EVENT, MENU_EVENT_RECORD, MOUSE_EVENT, MOUSE_EVENT_RECORD,
RIGHTMOST_BUTTON_PRESSED, WINDOW_BUFFER_SIZE_EVENT, WINDOW_BUFFER_SIZE_RECORD,
};
use super::Coord;
use crate::ScreenBuffer;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct KeyEventRecord {
pub key_down: bool,
pub repeat_count: u16,
pub virtual_key_code: u16,
pub virtual_scan_code: u16,
pub u_char: u16,
pub control_key_state: ControlKeyState,
}
impl KeyEventRecord {
#[inline]
fn from_winapi(record: &KEY_EVENT_RECORD) -> Self {
KeyEventRecord {
key_down: record.bKeyDown != 0,
repeat_count: record.wRepeatCount,
virtual_key_code: record.wVirtualKeyCode,
virtual_scan_code: record.wVirtualScanCode,
u_char: unsafe { *record.uChar.UnicodeChar() },
control_key_state: ControlKeyState(record.dwControlKeyState),
}
}
}
#[derive(PartialEq, Debug, Copy, Clone, Eq)]
pub struct MouseEvent {
pub mouse_position: Coord,
pub button_state: ButtonState,
pub control_key_state: ControlKeyState,
pub event_flags: EventFlags,
}
impl From<MOUSE_EVENT_RECORD> for MouseEvent {
#[inline]
fn from(event: MOUSE_EVENT_RECORD) -> Self {
MouseEvent {
mouse_position: event.dwMousePosition.into(),
button_state: event.dwButtonState.into(),
control_key_state: ControlKeyState(event.dwControlKeyState),
event_flags: event.dwEventFlags.into(),
}
}
}
#[derive(PartialEq, Debug, Copy, Clone, Eq)]
pub struct ButtonState {
state: i32,
}
impl From<DWORD> for ButtonState {
#[inline]
fn from(event: DWORD) -> Self {
let state = event as i32;
ButtonState { state }
}
}
impl ButtonState {
pub fn release_button(&self) -> bool {
self.state == 0
}
pub fn left_button(&self) -> bool {
self.state as u32 & FROM_LEFT_1ST_BUTTON_PRESSED != 0
}
pub fn right_button(&self) -> bool {
self.state as u32
& (RIGHTMOST_BUTTON_PRESSED
| FROM_LEFT_3RD_BUTTON_PRESSED
| FROM_LEFT_4TH_BUTTON_PRESSED)
!= 0
}
pub fn middle_button(&self) -> bool {
self.state as u32 & FROM_LEFT_2ND_BUTTON_PRESSED != 0
}
pub fn scroll_down(&self) -> bool {
self.state < 0
}
pub fn scroll_up(&self) -> bool {
self.state > 0
}
pub fn scroll_right(&self) -> bool {
self.state > 0
}
pub fn scroll_left(&self) -> bool {
self.state < 0
}
pub fn state(&self) -> i32 {
self.state
}
}
#[derive(PartialEq, Debug, Copy, Clone, Eq)]
pub struct ControlKeyState(u32);
impl ControlKeyState {
pub fn has_state(&self, state: u32) -> bool {
(state & self.0) != 0
}
}
#[derive(PartialEq, Debug, Copy, Clone, Eq)]
pub enum EventFlags {
PressOrRelease = 0x0000,
DoubleClick = 0x0002,
MouseHwheeled = 0x0008,
MouseMoved = 0x0001,
MouseWheeled = 0x0004,
Unknown = 0x0021,
}
impl From<DWORD> for EventFlags {
fn from(event: DWORD) -> Self {
match event {
0x0000 => EventFlags::PressOrRelease,
0x0002 => EventFlags::DoubleClick,
0x0008 => EventFlags::MouseHwheeled,
0x0001 => EventFlags::MouseMoved,
0x0004 => EventFlags::MouseWheeled,
_ => EventFlags::Unknown,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct WindowBufferSizeRecord {
pub size: Coord,
}
impl From<WINDOW_BUFFER_SIZE_RECORD> for WindowBufferSizeRecord {
#[inline]
fn from(record: WINDOW_BUFFER_SIZE_RECORD) -> Self {
WindowBufferSizeRecord {
size: record.dwSize.into(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FocusEventRecord {
pub set_focus: bool,
}
impl From<FOCUS_EVENT_RECORD> for FocusEventRecord {
#[inline]
fn from(record: FOCUS_EVENT_RECORD) -> Self {
FocusEventRecord {
set_focus: record.bSetFocus != 0,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MenuEventRecord {
pub command_id: u32,
}
impl From<MENU_EVENT_RECORD> for MenuEventRecord {
#[inline]
fn from(record: MENU_EVENT_RECORD) -> Self {
MenuEventRecord {
command_id: record.dwCommandId,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum InputRecord {
KeyEvent(KeyEventRecord),
MouseEvent(MouseEvent),
WindowBufferSizeEvent(WindowBufferSizeRecord),
FocusEvent(FocusEventRecord),
MenuEvent(MenuEventRecord),
}
impl From<INPUT_RECORD> for InputRecord {
#[inline]
fn from(record: INPUT_RECORD) -> Self {
match record.EventType {
KEY_EVENT => InputRecord::KeyEvent(KeyEventRecord::from_winapi(unsafe {
record.Event.KeyEvent()
})),
MOUSE_EVENT => InputRecord::MouseEvent(unsafe { *record.Event.MouseEvent() }.into()),
WINDOW_BUFFER_SIZE_EVENT => InputRecord::WindowBufferSizeEvent({
let mut buffer =
unsafe { WindowBufferSizeRecord::from(*record.Event.WindowBufferSizeEvent()) };
let window = ScreenBuffer::current().unwrap().info().unwrap();
let screen_size = window.terminal_size();
buffer.size.y = screen_size.height;
buffer.size.x = screen_size.width;
buffer
}),
FOCUS_EVENT => InputRecord::FocusEvent(unsafe { *record.Event.FocusEvent() }.into()),
MENU_EVENT => InputRecord::MenuEvent(unsafe { *record.Event.MenuEvent() }.into()),
code => panic!("Unexpected INPUT_RECORD EventType: {}", code),
}
}
}