From 7d5b552aec65794e386d462f3a7f12c329a5c94c Mon Sep 17 00:00:00 2001 From: 4yn Date: Fri, 28 Jan 2022 23:07:27 +0800 Subject: [PATCH] keyboard out, untested --- src-tauri/Cargo.lock | 1 + src-tauri/Cargo.toml | 1 + src-tauri/src/slider_io/controller_state.rs | 15 +++ src-tauri/src/slider_io/keyboard.rs | 140 ++++++++++++++++++++ src-tauri/src/slider_io/led.rs | 15 ++- src-tauri/src/slider_io/mod.rs | 2 + src-tauri/src/slider_io/output.rs | 64 +++++++++ 7 files changed, 234 insertions(+), 4 deletions(-) create mode 100644 src-tauri/src/slider_io/keyboard.rs create mode 100644 src-tauri/src/slider_io/output.rs diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 321c7f9..fa4da26 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -2749,6 +2749,7 @@ dependencies = [ "serde_json", "tauri", "tauri-build", + "winapi", ] [[package]] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 32a5cf9..e739546 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -20,6 +20,7 @@ serde = { version = "1.0", features = ["derive"] } tauri = { version = "1.0.0-beta.8", features = ["api-all", "system-tray"] } rusb = "0.9.0" palette = "0.6.0" +winapi = "0.3.9" [features] default = [ "custom-protocol" ] diff --git a/src-tauri/src/slider_io/controller_state.rs b/src-tauri/src/slider_io/controller_state.rs index 26c3785..7710cf8 100644 --- a/src-tauri/src/slider_io/controller_state.rs +++ b/src-tauri/src/slider_io/controller_state.rs @@ -17,6 +17,21 @@ impl ControllerState { extra_state: [0; 3], } } + + pub fn flat(&self, sensitivity: &u8) -> Vec { + self + .ground_state + .iter() + .map(|x| x > sensitivity) + .chain( + self + .air_state + .iter() + .chain(self.extra_state.iter()) + .map(|x| x > &0), + ) + .collect() + } } pub struct LedState { diff --git a/src-tauri/src/slider_io/keyboard.rs b/src-tauri/src/slider_io/keyboard.rs new file mode 100644 index 0000000..e7e6df3 --- /dev/null +++ b/src-tauri/src/slider_io/keyboard.rs @@ -0,0 +1,140 @@ +use std::mem; + +use winapi::{ + ctypes::c_int, + um::winuser::{SendInput, INPUT, INPUT_KEYBOARD, KEYBDINPUT, KEYEVENTF_KEYUP}, +}; + +use crate::slider_io::{config::KeyboardLayout, controller_state::ControllerState}; + +#[rustfmt::skip] +const tasoller_kb_map: [usize; 41] = [ + 0x41 /* A */, 0x31 /* 1 */, 0x5a /* Z */, 0x51 /* Q */, 0x53 /* S */, 0x32 /* 2 */, 0x58 /* X */, 0x57 /* W */, + 0x44 /* D */, 0x33 /* 3 */, 0x43 /* C */, 0x45 /* E */, 0x46 /* F */, 0x34 /* 4 */, 0x56 /* V */, 0x52 /* R */, + 0x47 /* G */, 0x35 /* 5 */, 0x42 /* B */, 0x54 /* T */, 0x48 /* H */, 0x36 /* 6 */, 0x4e /* N */, 0x59 /* Y */, + 0x4a /* J */, 0x37 /* 7 */, 0x4d /* M */, 0x55 /* U */, 0x4b /* K */, 0x38 /* 8 */, 0xbc /* VK_OEM_COMMA */, 0x49 /* I */, + 0xbf, 0xde, 0xbe, // VK_OEM_2, VK_OEM_7, VK_OEM_PERIOD, + 0xba, 0xdd, 0xdb, // VK_OEM_1, VK_OEM_6, VK_OEM_4 + 0x0d, 0x20, 0x1b // VK_RETURN, VK_SPACE, VK_ESCAPE +]; + +#[rustfmt::skip] +const yuancon_kb_map: [usize; 41] = [ + 0x36 /* 6 */, 0x35 /* 5 */, 0x34 /* 4 */, 0x33 /* 3 */, 0x32 /* 2 */, 0x31 /* 1 */, 0x5a /* Z */, 0x59 /* Y */, + 0x58 /* X */, 0x57 /* W */, 0x56 /* V */, 0x55 /* U */, 0x54 /* T */, 0x53 /* S */, 0x52 /* R */, 0x51 /* Q */, + 0x50 /* P */, 0x4f /* O */, 0x4e /* N */, 0x4d /* M */, 0x4c /* L */, 0x4b /* K */, 0x4a /* J */, 0x49 /* I */, + 0x48 /* H */, 0x47 /* G */, 0x46 /* F */, 0x45 /* E */, 0x44 /* D */, 0x43 /* C */, 0x42 /* B */, 0x41 /* A */, + 0xbd, 0xbb, 0xdb, // VK_OEM_MINUS, VK_OEM_PLUS, VK_OEM_4, + 0xdd, 0xdc, 0xba, // VK_OEM_6, VK_OEM_5, VK_OEM_1, + 0x0d, 0x20, 0x1b, // VK_RETURN, VK_SPACE, VK_ESCAPE +]; + +pub struct KeyboardOutput { + ground_to_idx: [usize; 41], + idx_to_keycode: [u16; 41], + keycode_to_idx: [usize; 256], + + next_keys: [bool; 41], + last_keys: [bool; 41], + + kb_buf: [INPUT; 41], + n_kb_buf: u32, +} + +impl KeyboardOutput { + pub fn new(layout: KeyboardLayout) -> Self { + let kb_map = match layout { + KeyboardLayout::Tasoller => &tasoller_kb_map, + KeyboardLayout::Yuancon => &yuancon_kb_map, + KeyboardLayout::Deemo => { + panic!("Not yet") + } + }; + + let mut ground_to_idx = [0 as usize; 41]; + let mut idx_to_keycode = [0 as u16; 41]; + let mut keycode_to_idx = [0xffff as usize; 256]; + let mut keycode_count: usize = 0; + + for (ground, keycode) in kb_map.iter().enumerate() { + if keycode_to_idx[*keycode] == 0xffff { + keycode_to_idx[*keycode] = keycode_count; + idx_to_keycode[keycode_count] = *keycode as u16; + keycode_count += 1; + } + ground_to_idx[ground] = keycode_to_idx[*keycode] + } + + let mut kb_buf = [INPUT { + type_: INPUT_KEYBOARD, + u: unsafe { mem::zeroed() }, + }; 41]; + + for i in kb_buf.iter_mut() { + let mut inner = unsafe { i.u.ki_mut() }; + inner.wVk = 0; + inner.wScan = 0; + inner.dwFlags = 0; + inner.time = 0; + inner.dwExtraInfo = 0; + } + + Self { + ground_to_idx, + idx_to_keycode, + keycode_to_idx, + next_keys: [false; 41], + last_keys: [false; 41], + kb_buf, + n_kb_buf: 0, + } + } + + pub fn tick(&mut self, controller_state: &ControllerState, sensitivity: &u8) { + self + .next_keys + .iter_mut() + .zip(controller_state.flat(sensitivity)) + .for_each(|(a, b)| { + *a = b; + }); + self.send(); + } + + pub fn reset(&mut self) { + self.next_keys.fill(false); + self.send(); + } + + fn send(&mut self) { + self.n_kb_buf = 0; + + for (i, (n, l)) in self.next_keys.iter().zip(self.last_keys.iter()).enumerate() { + match (*n, *l) { + (false, true) => { + let inner: &mut KEYBDINPUT = unsafe { self.kb_buf[self.n_kb_buf as usize].u.ki_mut() }; + inner.wVk = self.idx_to_keycode[i]; + inner.dwFlags = 0; + self.n_kb_buf += 1; + } + (true, false) => { + let inner: &mut KEYBDINPUT = unsafe { self.kb_buf[self.n_kb_buf as usize].u.ki_mut() }; + inner.wVk = self.idx_to_keycode[i]; + inner.dwFlags = KEYEVENTF_KEYUP; + self.n_kb_buf += 1; + } + _ => {} + } + } + + if self.n_kb_buf != 0 { + unsafe { + SendInput( + self.n_kb_buf, + self.kb_buf.as_mut_ptr(), + mem::size_of::() as c_int, + ); + } + } + } +} diff --git a/src-tauri/src/slider_io/led.rs b/src-tauri/src/slider_io/led.rs index 258ccfe..ddd6608 100644 --- a/src-tauri/src/slider_io/led.rs +++ b/src-tauri/src/slider_io/led.rs @@ -20,7 +20,7 @@ fn update_reactive( controller_state: &ControllerState, led_state: &mut LedState, reactive_layout: &ReactiveLayout, - sensitivity: u8, + sensitivity: &u8, ) { let splits = match reactive_layout { ReactiveLayout::Four => 4, @@ -30,11 +30,18 @@ fn update_reactive( let buttons_per_split = 32 / splits; let banks: Vec = controller_state - .ground_state + .flat(sensitivity) .chunks(buttons_per_split) - .map(|x| x.iter().max().unwrap() > &sensitivity) + .take(splits) + .map(|x| x.iter().any(|x| *x)) .collect(); + // controller_state + // .ground_state + // .chunks(buttons_per_split) + // .map(|x| x.iter().max().unwrap() > &sensitivity) + // .collect(); + // (0..splits) // .map(|i| { // controller_state.ground_state[i * buttons_per_split..(i + 1) * buttons_per_split] @@ -120,7 +127,7 @@ impl LedThread { controller_state_handle.deref(), led_state_handle.deref_mut(), layout, - 20, + &20, ) } LedMode::Attract => { diff --git a/src-tauri/src/slider_io/mod.rs b/src-tauri/src/slider_io/mod.rs index e22d6c5..f4c35d7 100644 --- a/src-tauri/src/slider_io/mod.rs +++ b/src-tauri/src/slider_io/mod.rs @@ -2,5 +2,7 @@ pub mod config; pub mod controller_state; pub mod device; pub mod hid; +pub mod keyboard; pub mod led; pub mod manager; +pub mod output; diff --git a/src-tauri/src/slider_io/output.rs b/src-tauri/src/slider_io/output.rs new file mode 100644 index 0000000..73bb3f3 --- /dev/null +++ b/src-tauri/src/slider_io/output.rs @@ -0,0 +1,64 @@ +use std::{ + ops::Deref, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, + thread::{self, JoinHandle}, + time::Duration, +}; + +use crate::slider_io::{config::OutputMode, controller_state::FullState, keyboard}; + +pub struct OutputThread { + thread: Option>, + stop_signal: Arc, +} + +impl OutputThread { + pub fn new(state: &FullState, mode: OutputMode) -> Self { + let controller_state = state.clone_controller(); + let stop_signal = Arc::new(AtomicBool::new(false)); + + let stop_signal_clone = Arc::clone(&stop_signal); + + Self { + thread: Some(match mode { + OutputMode::None => thread::spawn(|| {}), + OutputMode::Keyboard { + layout, + sensitivity, + } => thread::spawn(move || { + let mut keyboard_output = keyboard::KeyboardOutput::new(layout); + loop { + { + let controller_state_handle = controller_state.lock().unwrap(); + keyboard_output.tick(controller_state_handle.deref(), &sensitivity); + } + + { + if stop_signal_clone.load(Ordering::SeqCst) { + break; + } + } + + thread::sleep(Duration::from_millis(10)); + } + + keyboard_output.reset(); + }), + OutputMode::Websocket { .. } => thread::spawn(|| {}), + }), + stop_signal, + } + } +} + +impl Drop for OutputThread { + fn drop(&mut self) { + self.stop_signal.swap(true, Ordering::SeqCst); + if self.thread.is_some() { + self.thread.take().unwrap().join().ok(); + } + } +}