mirror of https://github.com/4yn/slidershim
133 lines
2.8 KiB
Rust
133 lines
2.8 KiB
Rust
use log::error;
|
|
use std::error::Error;
|
|
use vigem_client::{Client, DS4Report, DualShock4Wired, TargetId};
|
|
|
|
use crate::shared::hori::HoriState;
|
|
|
|
use super::output::OutputHandler;
|
|
|
|
pub struct HoriOutput {
|
|
target: DualShock4Wired<Client>,
|
|
gamepad: DS4Report,
|
|
}
|
|
|
|
impl HoriOutput {
|
|
pub fn new() -> Option<Self> {
|
|
let target = Self::get_target();
|
|
|
|
match target {
|
|
Ok(target) => Some(Self {
|
|
target,
|
|
gamepad: DS4Report::default(),
|
|
}),
|
|
Err(e) => {
|
|
error!("Gamepad connection error: {}", e);
|
|
error!("Gamepad connection error: Is ViGEMBus missing?");
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
fn get_target() -> Result<DualShock4Wired<Client>, Box<dyn Error>> {
|
|
let client = Client::connect()?;
|
|
|
|
let mut target = DualShock4Wired::new(client, TargetId::DUALSHOCK4_WIRED);
|
|
target.plugin()?;
|
|
target.wait_ready()?;
|
|
Ok(target)
|
|
}
|
|
|
|
fn update(&mut self) -> bool {
|
|
match self.target.update(&self.gamepad) {
|
|
Ok(_) => true,
|
|
Err(e) => {
|
|
error!("Gamepad update error: {}", e);
|
|
false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl OutputHandler for HoriOutput {
|
|
fn tick(&mut self, flat_input: &Vec<bool>) -> bool {
|
|
let hori_state = HoriState::from_flat(flat_input);
|
|
|
|
let buttons: u16 = hori_state
|
|
.bt
|
|
.iter()
|
|
.zip([
|
|
// https://github.com/ViGEm/ViGEmClient/blob/master/include/ViGEm/Common.h#L117
|
|
1 << 7, // triangle
|
|
1 << 4, // square
|
|
1 << 5, // cross
|
|
1 << 6, // circle
|
|
])
|
|
.fold(0x8, |buttons, (state, code)| {
|
|
buttons
|
|
| match state {
|
|
true => code,
|
|
false => 0,
|
|
}
|
|
});
|
|
|
|
let axis: u32 = hori_state
|
|
.slider
|
|
.iter()
|
|
.enumerate()
|
|
.fold(0, |axis, (idx, state)| {
|
|
axis
|
|
| match state {
|
|
true => 0b11 << ((15 - idx) * 2),
|
|
false => 0,
|
|
}
|
|
})
|
|
^ 0x80808080;
|
|
|
|
let mut dirty = false;
|
|
if self.gamepad.buttons != buttons {
|
|
self.gamepad.buttons = buttons;
|
|
dirty = true;
|
|
}
|
|
|
|
for (idx, state) in [
|
|
&mut self.gamepad.thumb_lx,
|
|
&mut self.gamepad.thumb_ly,
|
|
&mut self.gamepad.thumb_rx,
|
|
&mut self.gamepad.thumb_ry,
|
|
]
|
|
.into_iter()
|
|
.enumerate()
|
|
{
|
|
let slice: u8 = ((axis >> ((3 - idx) * 8)) & 0xff) as u8;
|
|
if *state != slice {
|
|
*state = slice;
|
|
dirty = true;
|
|
}
|
|
}
|
|
|
|
match dirty {
|
|
true => self.update(),
|
|
false => true,
|
|
}
|
|
}
|
|
|
|
fn reset(&mut self) {
|
|
self.gamepad = DS4Report::default();
|
|
self.update();
|
|
}
|
|
}
|
|
|
|
impl Drop for HoriOutput {
|
|
fn drop(&mut self) {
|
|
match self.target.unplug() {
|
|
Ok(_) => {}
|
|
Err(e) => {
|
|
error!("Gamepad unplug error: {}", e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// dammit vigem_client::Event
|
|
unsafe impl Send for HoriOutput {}
|