use super::InputEvent;
use std::mem::MaybeUninit;
use std::sync::mpsc;
use windows_sys::Win32::System::Console::{
GetStdHandle, ReadConsoleInputW, INPUT_RECORD, STD_INPUT_HANDLE,
};
use windows_sys::Win32::UI::Input::KeyboardAndMouse::{
VK_BACK, VK_C, VK_CONTROL, VK_D, VK_DOWN, VK_END, VK_HOME, VK_LEFT, VK_RETURN, VK_RIGHT,
VK_SHIFT, VK_TAB, VK_UP,
};
const BUF_SIZE: usize = 1;
pub fn input_thread(log_ch: mpsc::Sender<InputEvent>) {
let handle = unsafe { GetStdHandle(STD_INPUT_HANDLE) };
let mut buf: [INPUT_RECORD; BUF_SIZE] = unsafe { MaybeUninit::zeroed().assume_init() };
let mut eventnum = 0;
let mut is_ctrl = false;
let mut surrogate: u32 = 0;
loop {
let flag =
unsafe { ReadConsoleInputW(handle, buf.as_mut_ptr(), BUF_SIZE as _, &mut eventnum) };
if flag != 1 {
break;
}
let mut end = false;
for i in 0..eventnum {
let event = buf[i as usize];
match event.EventType {
0x0001 => {
let record = unsafe { event.Event.KeyEvent };
if record.wVirtualKeyCode == VK_CONTROL {
is_ctrl = record.bKeyDown == 1;
}
if record.bKeyDown == 1 {
if is_ctrl
&& (record.wVirtualKeyCode == VK_C || record.wVirtualKeyCode == VK_D)
{
end = true;
break;
}
match record.wVirtualKeyCode {
VK_BACK => log_ch.send(InputEvent::Delete).unwrap(),
VK_LEFT => log_ch.send(InputEvent::Left).unwrap(),
VK_RIGHT => log_ch.send(InputEvent::Right).unwrap(),
VK_UP => log_ch.send(InputEvent::HistoryPrev).unwrap(),
VK_DOWN => log_ch.send(InputEvent::HistoryNext).unwrap(),
VK_HOME => log_ch.send(InputEvent::LineStart).unwrap(),
VK_END => log_ch.send(InputEvent::LineEnd).unwrap(),
VK_RETURN => log_ch.send(InputEvent::NewLine).unwrap(),
VK_TAB => log_ch.send(InputEvent::Complete).unwrap(),
VK_SHIFT => (),
_ => {
let val =
std::char::from_u32(unsafe { record.uChar.UnicodeChar } as _);
match val {
Some(c) => {
log_ch.send(InputEvent::Input(String::from(c))).unwrap()
}
None => {
if surrogate != 0 {
let val = std::char::from_u32(
surrogate
| unsafe { record.uChar.UnicodeChar } as u32,
);
if let Some(c) = val {
log_ch
.send(InputEvent::Input(String::from(c)))
.unwrap();
}
surrogate = 0;
} else {
surrogate = unsafe { record.uChar.UnicodeChar } as _;
}
}
}
}
}
}
}
_ => continue,
}
}
if end {
break;
}
}
log_ch.send(InputEvent::End).unwrap();
}