1
0
mirror of https://github.com/4yn/slidershim.git synced 2024-11-30 16:24:27 +01:00

keyboard out, untested

This commit is contained in:
4yn 2022-01-28 23:07:27 +08:00
parent 7e842971e7
commit 7d5b552aec
7 changed files with 234 additions and 4 deletions

1
src-tauri/Cargo.lock generated
View File

@ -2749,6 +2749,7 @@ dependencies = [
"serde_json",
"tauri",
"tauri-build",
"winapi",
]
[[package]]

View File

@ -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" ]

View File

@ -17,6 +17,21 @@ impl ControllerState {
extra_state: [0; 3],
}
}
pub fn flat(&self, sensitivity: &u8) -> Vec<bool> {
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 {

View File

@ -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::<INPUT>() as c_int,
);
}
}
}
}

View File

@ -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<bool> = 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 => {

View File

@ -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;

View File

@ -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<JoinHandle<()>>,
stop_signal: Arc<AtomicBool>,
}
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();
}
}
}