1
0
mirror of https://github.com/4yn/slidershim.git synced 2024-11-27 23:10:49 +01:00
This commit is contained in:
4yn 2022-01-29 02:20:34 +08:00
parent e097eacdd0
commit 5694d39577
9 changed files with 170 additions and 207 deletions

View File

@ -8,8 +8,9 @@ fn main() {
let config = Config::from_str(
r#"{
"deviceMode": "yuancon",
"outputMode": "none",
"ledMode": "reactive-8"
"outputMode": "kb-32-tasoller",
"ledMode": "reactive-8",
"keyboardSensitivity": 50
}"#,
);

View File

@ -3,5 +3,6 @@
windows_subsystem = "windows"
)]
#![feature(div_duration)]
#![feature(more_qualified_paths)]
pub mod slider_io;

View File

@ -3,6 +3,7 @@
windows_subsystem = "windows"
)]
#![feature(div_duration)]
#![feature(more_qualified_paths)]
mod slider_io;

View File

@ -69,7 +69,7 @@ impl HidDeviceJob {
}
}
pub fn from_config(mode: &DeviceMode, state: &FullState) -> Self {
pub fn from_config(state: &FullState, mode: &DeviceMode) -> Self {
match mode {
DeviceMode::Yuancon => Self::new(
state.clone(),

View File

@ -90,14 +90,15 @@ impl KeyboardOutput {
}
}
pub fn tick(&mut self, controller_state: &ControllerState, sensitivity: &u8) {
pub fn tick(&mut self, flat_controller_state: &Vec<bool>) {
self
.next_keys
.iter_mut()
.zip(controller_state.flat(sensitivity))
.zip(flat_controller_state)
.for_each(|(a, b)| {
*a = b;
*a = *b;
});
// println!("{:?}", self.next_keys);
self.send();
}
@ -109,7 +110,12 @@ impl KeyboardOutput {
fn send(&mut self) {
self.n_kb_buf = 0;
for (i, (n, l)) in self.next_keys.iter().zip(self.last_keys.iter()).enumerate() {
for (i, (n, l)) in self
.next_keys
.iter_mut()
.zip(self.last_keys.iter_mut())
.enumerate()
{
match (*n, *l) {
(false, true) => {
let inner: &mut KEYBDINPUT = unsafe { self.kb_buf[self.n_kb_buf as usize].u.ki_mut() };
@ -125,6 +131,7 @@ impl KeyboardOutput {
}
_ => {}
}
*l = *n;
}
if self.n_kb_buf != 0 {

View File

@ -1,11 +1,6 @@
use std::{
borrow::BorrowMut,
ops::{Deref, DerefMut},
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
thread::{self, JoinHandle},
ops::DerefMut,
thread,
time::{Duration, Instant},
};
@ -13,148 +8,114 @@ use palette::{FromColor, Hsv, Srgb};
use crate::slider_io::{
config::{LedMode, ReactiveLayout},
controller_state::{ControllerState, FullState, LedState},
controller_state::{FullState, LedState},
worker::Job,
};
fn update_reactive(
controller_state: &ControllerState,
led_state: &mut LedState,
reactive_layout: &ReactiveLayout,
sensitivity: &u8,
) {
let splits = match reactive_layout {
ReactiveLayout::Four => 4,
ReactiveLayout::Eight => 8,
ReactiveLayout::Sixteen => 16,
};
let buttons_per_split = 32 / splits;
type LedCallback = fn(&Vec<bool>, &mut LedState) -> ();
let banks: Vec<bool> = controller_state
.flat(sensitivity)
.chunks(buttons_per_split)
.take(splits)
.map(|x| x.iter().any(|x| *x))
.collect();
pub struct LedJob {
state: FullState,
mode: LedMode,
sensitivity: u8,
// controller_state
// .ground_state
// .chunks(buttons_per_split)
// .map(|x| x.iter().max().unwrap() > &sensitivity)
// .collect();
splits: usize,
buttons_per_split: usize,
}
// (0..splits)
// .map(|i| {
// controller_state.ground_state[i * buttons_per_split..(i + 1) * buttons_per_split]
// .iter()
// .max()
// .unwrap()
// > &sensitivity
// })
// .collect();
led_state
.led_state
.chunks_mut(3)
.enumerate()
.for_each(|(idx, chunk)| match (idx + 1) % buttons_per_split {
0 => {
chunk[0] = 255;
chunk[1] = 0;
chunk[2] = 255;
}
_ => match banks[idx / buttons_per_split] {
true => {
chunk[0] = 255;
chunk[1] = 0;
chunk[2] = 255;
}
false => {
chunk[0] = 255;
chunk[1] = 255;
chunk[2] = 0;
}
impl LedJob {
pub fn new(state: &FullState, mode: &LedMode) -> Self {
let splits = match mode {
LedMode::Reactive { layout } => match layout {
ReactiveLayout::Four => 4,
ReactiveLayout::Eight => 8,
ReactiveLayout::Sixteen => 16,
},
});
_ => 16,
};
// println!("{:?}", controller_state.ground_state);
// println!("{:?}", banks);
// println!("{:?}", led_state.led_state);
led_state.dirty = true;
}
fn update_attract(led_state: &mut LedState) {
let now = Instant::now();
let theta = (now - led_state.start).div_duration_f64(Duration::from_secs(4)) % 1.0;
led_state
.led_state
.chunks_mut(3)
.enumerate()
.for_each(|(idx, chunk)| {
let slice_theta = (&theta + (idx as f64) / 31.0) % 1.0;
let color = Srgb::from_color(Hsv::new(slice_theta * 360.0, 1.0, 1.0)).into_format::<u8>();
chunk[0] = color.red;
chunk[1] = color.green;
chunk[2] = color.blue;
});
// println!("{} {:?}", theta, led_state.led_state);
led_state.dirty = true;
}
pub struct LedThread {
thread: Option<JoinHandle<()>>,
stop_signal: Arc<AtomicBool>,
}
impl LedThread {
pub fn new(state: &FullState, mode: LedMode) -> Self {
let stop_signal = Arc::new(AtomicBool::new(false));
let stop_signal_clone = Arc::clone(&stop_signal);
let controller_state = state.clone_controller();
let led_state = state.clone_led();
Self {
thread: Some(thread::spawn(move || loop {
// println!("Led thread: {:?}", mode);
match &mode {
LedMode::Reactive { layout } => {
let controller_state_handle = controller_state.lock().unwrap();
let mut led_state_handle = led_state.lock().unwrap();
update_reactive(
controller_state_handle.deref(),
led_state_handle.deref_mut(),
layout,
&20,
)
}
LedMode::Attract => {
let mut led_state_handle = led_state.lock().unwrap();
update_attract(led_state_handle.deref_mut());
}
_ => {}
}
state: state.clone(),
mode: mode.clone(),
sensitivity: 20,
{
if stop_signal_clone.load(Ordering::SeqCst) {
break;
}
}
thread::sleep(Duration::from_millis(33))
})),
stop_signal,
splits,
buttons_per_split: 32 / splits,
}
}
fn calc_lights(&self, flat_controller_state: &Vec<bool>, led_state: &mut LedState) {
match self.mode {
LedMode::Reactive { .. } => {
let banks: Vec<bool> = flat_controller_state
.chunks(self.buttons_per_split)
.take(self.splits)
.map(|x| x.iter().any(|x| *x))
.collect();
led_state
.led_state
.chunks_mut(3)
.enumerate()
.for_each(|(idx, chunk)| match (idx + 1) % self.buttons_per_split {
0 => {
chunk[0] = 255;
chunk[1] = 0;
chunk[2] = 255;
}
_ => match banks[idx / self.buttons_per_split] {
true => {
chunk[0] = 255;
chunk[1] = 0;
chunk[2] = 255;
}
false => {
chunk[0] = 255;
chunk[1] = 255;
chunk[2] = 0;
}
},
})
}
LedMode::Attract => {
let now = Instant::now();
let theta = (now - led_state.start).div_duration_f64(Duration::from_secs(4)) % 1.0;
led_state
.led_state
.chunks_mut(3)
.enumerate()
.for_each(|(idx, chunk)| {
let slice_theta = (&theta + (idx as f64) / 31.0) % 1.0;
let color =
Srgb::from_color(Hsv::new(slice_theta * 360.0, 1.0, 1.0)).into_format::<u8>();
chunk[0] = color.red;
chunk[1] = color.green;
chunk[2] = color.blue;
});
}
_ => panic!("Not implemented"),
}
led_state.dirty = true;
}
}
impl Drop for LedThread {
fn drop(&mut self) {
self.stop_signal.swap(true, Ordering::SeqCst);
if self.thread.is_some() {
self.thread.take().unwrap().join().ok();
impl Job for LedJob {
fn setup(&mut self) {}
fn tick(&mut self) {
let flat_controller_state: Vec<bool>;
{
let controller_state_handle = self.state.controller_state.lock().unwrap();
flat_controller_state = controller_state_handle.flat(&self.sensitivity);
}
{
let mut led_state_handle = self.state.led_state.lock().unwrap();
self.calc_lights(&flat_controller_state, led_state_handle.deref_mut());
}
thread::sleep(Duration::from_millis(33));
}
fn teardown(&mut self) {}
}

View File

@ -1,30 +1,31 @@
use crate::slider_io::{
config::Config, controller_state::FullState, device::HidDeviceJob, led::LedThread, worker::Worker,
config::Config, controller_state::FullState, device::HidDeviceJob, led::LedJob,
output::KeyboardOutputJob, worker::Worker,
};
pub struct Manager {
state: FullState,
config: Config,
// device_thread: DeviceThread,
device_worker: Worker,
led_thread: LedThread,
output_worker: Worker,
led_worker: Worker,
}
impl Manager {
pub fn new(config: Config) -> Self {
let state = FullState::new();
// let device_thread = DeviceThread::new(&state, config.device_mode.clone());
let device_worker = Worker::new(HidDeviceJob::from_config(&config.device_mode, &state));
let led_thread = LedThread::new(&state, config.led_mode.clone());
let device_worker = Worker::new(HidDeviceJob::from_config(&state, &config.device_mode));
let output_worker = Worker::new(KeyboardOutputJob::new(&state, &config.output_mode));
let led_worker = Worker::new(LedJob::new(&state, &config.led_mode));
println!("Starting manager with config: {:?}", config);
Self {
state,
config,
// device_thread,
device_worker,
led_thread,
output_worker,
led_worker,
}
}
}

View File

@ -1,8 +1,11 @@
pub mod config;
pub mod controller_state;
pub mod device;
pub mod keyboard;
pub mod led;
pub mod manager;
pub mod output;
pub mod worker;
pub mod keyboard;
pub mod device;
pub mod led;
pub mod output;
pub mod manager;

View File

@ -1,64 +1,52 @@
use std::{
ops::Deref,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
thread::{self, JoinHandle},
time::Duration,
thread,
time::{Duration, Instant},
};
use crate::slider_io::{config::OutputMode, controller_state::FullState, keyboard};
use crate::slider_io::{
config::{KeyboardLayout, OutputMode},
controller_state::FullState,
keyboard::KeyboardOutput,
worker::Job,
};
pub struct OutputThread {
thread: Option<JoinHandle<()>>,
stop_signal: Arc<AtomicBool>,
pub struct KeyboardOutputJob {
state: FullState,
sensitivity: u8,
keyboard_output: KeyboardOutput,
}
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 KeyboardOutputJob {
pub fn new(state: &FullState, mode: &OutputMode) -> Self {
match mode {
OutputMode::Keyboard {
layout,
sensitivity,
} => Self {
state: state.clone(),
sensitivity: *sensitivity,
keyboard_output: KeyboardOutput::new(layout.clone()),
},
_ => panic!("Not implemented"),
}
}
}
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();
impl Job for KeyboardOutputJob {
fn setup(&mut self) {}
fn tick(&mut self) {
let flat_controller_state: Vec<bool>;
{
let controller_state_handle = self.state.controller_state.lock().unwrap();
flat_controller_state = controller_state_handle.flat(&self.sensitivity);
}
self.keyboard_output.tick(&flat_controller_state);
thread::sleep(Duration::from_millis(10));
}
fn teardown(&mut self) {
self.keyboard_output.reset();
}
}