use std::fmt::Debug;
use std::io;
use std::ops::Range;
use std::sync::{Arc, Mutex};
use bitflags::bitflags;
use crate::virtual_keyboard::{Bind, VirtualKeyboard};
use crate::{DeviceHandler, Error, HandledDeviceRef, Handler, Rgb};
pub type Binds = [[Option<Bind>; 29]; 3];
pub type Colors = [Option<Rgb>; 3];
const JS_DEADZONE: Range<i32> = (127 - 50)..(127 + 50);
#[derive(Debug)]
pub struct StaticHandler {
keyboard: Arc<Mutex<VirtualKeyboard>>,
binds: Arc<Binds>,
colors: Colors,
}
#[derive(Clone, Debug)]
pub struct StaticDeviceHandler {
keyboard: Arc<Mutex<VirtualKeyboard>>,
binds: Arc<Binds>,
colors: Colors,
held: HeldDirections,
device_ref: HandledDeviceRef,
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct HeldDirections: u8 {
const UP = 1 << 0;
const DOWN = 1 << 1;
const LEFT = 1 << 2;
const RIGHT = 1 << 3;
}
}
impl StaticHandler {
pub fn new(keyboard: Arc<Mutex<VirtualKeyboard>>, binds: Binds, colors: Colors) -> Self {
StaticHandler {
keyboard,
binds: Arc::new(binds),
colors,
}
}
}
impl Handler for StaticHandler {
#[allow(refining_impl_trait)]
fn handler_for_device(&self, device_ref: HandledDeviceRef) -> StaticDeviceHandler {
device_ref.set_mode(1);
if let Some(color) = self.colors[0] {
device_ref
.set_backlight(color)
.unwrap_or_else(backlight_error);
}
StaticDeviceHandler {
keyboard: self.keyboard.clone(),
binds: self.binds.clone(),
colors: self.colors,
held: HeldDirections::empty(),
device_ref,
}
}
}
impl StaticDeviceHandler {
fn lookup_bind(&self, idx: u16) -> Option<Bind> {
self.binds[(self.device_ref.mode() - 1) as usize][idx as usize]
}
fn exec_bind_action(
&mut self,
key: u16,
action: fn(&mut VirtualKeyboard, Bind) -> io::Result<()>,
) {
if let Some(bind) = self.lookup_bind(key - 1) {
let mut keyboard = self.keyboard.lock().unwrap();
action(&mut keyboard, bind).unwrap_or_else(|err| virtual_keyboard_error(err, bind));
}
}
fn check_axis(&mut self, val: i32, top_flag: HeldDirections, bottom_flag: HeldDirections) {
let previous = self.held.intersection(bottom_flag | top_flag);
let mut next = HeldDirections::empty();
if val < JS_DEADZONE.start {
next.insert(top_flag)
} else if val > JS_DEADZONE.end {
next.insert(bottom_flag)
}
if next != previous {
let to_press = next.difference(previous);
let to_release = previous.difference(next);
self.held.insert(to_press);
self.held.remove(to_release);
self.axis_action(to_press, VirtualKeyboard::key_down);
self.axis_action(to_release, VirtualKeyboard::key_up);
}
}
fn axis_action(
&mut self,
flags: HeldDirections,
action: fn(&mut VirtualKeyboard, Bind) -> io::Result<()>,
) {
let mut keyboard = self.keyboard.lock().unwrap();
flags
.iter()
.filter_map(|flag| {
let idx = match flag {
HeldDirections::UP => 25,
HeldDirections::DOWN => 26,
HeldDirections::LEFT => 27,
HeldDirections::RIGHT => 28,
any => panic!("Invalid flag: {any:?}"),
};
self.lookup_bind(idx)
})
.for_each(|bind| {
action(&mut keyboard, bind).unwrap_or_else(|err| virtual_keyboard_error(err, bind))
})
}
}
impl DeviceHandler for StaticDeviceHandler {
fn g_key_down(&mut self, key: u16) {
self.exec_bind_action(key, VirtualKeyboard::key_down);
}
fn g_key_up(&mut self, key: u16) {
self.exec_bind_action(key, VirtualKeyboard::key_up);
}
fn m_key_down(&mut self, key: u16) {
if let Some(color) = self.colors[(key - 1) as usize] {
self.device_ref
.set_backlight(color)
.unwrap_or_else(backlight_error);
}
self.axis_action(self.held, VirtualKeyboard::key_up);
self.held = HeldDirections::empty();
}
fn x_axis(&mut self, value: i32) {
self.check_axis(value, HeldDirections::LEFT, HeldDirections::RIGHT)
}
fn y_axis(&mut self, value: i32) {
self.check_axis(value, HeldDirections::UP, HeldDirections::DOWN)
}
}
fn virtual_keyboard_error(error: io::Error, bind: Bind) {
log::error!(
"Could not press key ({:} {:}): {:}",
bind.0,
bind.1.0,
error
);
}
fn backlight_error(err: Error) {
log::error!("Could not change backlight: {}", err);
}