mirror of
https://github.com/4yn/slidershim.git
synced 2024-11-27 23:10:49 +01:00
add ds4 hori slider
This commit is contained in:
parent
d4d8d8be09
commit
62551a2f88
4
src-slider_io/Cargo.lock
generated
4
src-slider_io/Cargo.lock
generated
@ -1587,9 +1587,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "vigem-client"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "965e349c8ec4eb36c06878b99952f35b9f459e6912419837ecb85fb5502a6de3"
|
||||
checksum = "5d886912e88b1d3b02a97d933df7829db8fb8561920410805794a48680c212d5"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
@ -29,7 +29,7 @@ image = "0.23.14"
|
||||
rusb = "0.9.0"
|
||||
serialport = "4.0.1"
|
||||
wwserial = {path = "../src-wwserial" }
|
||||
vigem-client = "0.1.1"
|
||||
vigem-client = { version = "0.1.2", features = ["unstable"] }
|
||||
winapi = "0.3.9"
|
||||
ipconfig = "0.3.0"
|
||||
|
||||
|
@ -5,6 +5,7 @@ pub enum ReactiveLayout {
|
||||
Even { splits: usize },
|
||||
Six,
|
||||
Voltex,
|
||||
Hori,
|
||||
Rainbow,
|
||||
}
|
||||
|
||||
@ -109,6 +110,12 @@ impl LightsMode {
|
||||
sensitivity: u8::try_from(v["ledSensitivity"].as_i64()?).ok()?,
|
||||
color: ColorScheme::default(),
|
||||
},
|
||||
"reactive-hori" => LightsMode::Reactive {
|
||||
faster: v["ledFaster"].as_bool()?,
|
||||
layout: ReactiveLayout::Hori,
|
||||
sensitivity: u8::try_from(v["ledSensitivity"].as_i64()?).ok()?,
|
||||
color: ColorScheme::default(),
|
||||
},
|
||||
"attract" => LightsMode::Attract {
|
||||
faster: v["ledFaster"].as_bool()?,
|
||||
},
|
||||
|
@ -9,7 +9,7 @@ use std::{
|
||||
use tokio::time::{interval, Interval};
|
||||
|
||||
use crate::{
|
||||
shared::{utils::Buffer, voltex::VoltexState, worker::AsyncJob},
|
||||
shared::{hori::HoriState, utils::Buffer, voltex::VoltexState, worker::AsyncJob},
|
||||
state::{SliderLights, SliderState},
|
||||
};
|
||||
|
||||
@ -154,6 +154,48 @@ impl LightsJob {
|
||||
}
|
||||
}
|
||||
}
|
||||
ReactiveLayout::Hori => {
|
||||
lights.ground.fill(0);
|
||||
|
||||
// Fixed
|
||||
for idx in [7, 15, 23] {
|
||||
lights.paint(idx, &[64, 64, 64]);
|
||||
}
|
||||
|
||||
let hori_state = HoriState::from_flat(flat_input);
|
||||
|
||||
for (idx, (bt, color)) in hori_state
|
||||
.bt
|
||||
.iter()
|
||||
.zip([
|
||||
&[64, 226, 160],
|
||||
&[255, 105, 248],
|
||||
&[124, 178, 232],
|
||||
&[255, 102, 102],
|
||||
])
|
||||
.enumerate()
|
||||
{
|
||||
let color_f = match bt {
|
||||
true => 1,
|
||||
false => 4,
|
||||
};
|
||||
let adjcolor = [color[0] / color_f, color[1] / color_f, color[2] / color_f];
|
||||
for i in 0..4 {
|
||||
lights.paint(idx * 8 + i * 2, &adjcolor);
|
||||
}
|
||||
}
|
||||
|
||||
for (idx, (a, b)) in hori_state
|
||||
.slider
|
||||
.iter()
|
||||
.zip(hori_state.slider.iter().skip(1))
|
||||
.enumerate()
|
||||
{
|
||||
if *a || *b {
|
||||
lights.paint(1 + idx * 2, &[200, 200, 200]);
|
||||
}
|
||||
}
|
||||
}
|
||||
ReactiveLayout::Rainbow => {
|
||||
let banks: Vec<bool> = flat_input
|
||||
.chunks(2)
|
||||
|
@ -40,6 +40,10 @@ pub enum OutputMode {
|
||||
polling: PollingRate,
|
||||
sensitivity: u8,
|
||||
},
|
||||
Hori {
|
||||
polling: PollingRate,
|
||||
sensitivity: u8,
|
||||
},
|
||||
Websocket {
|
||||
url: String,
|
||||
polling: PollingRate,
|
||||
@ -123,6 +127,10 @@ impl OutputMode {
|
||||
polling: PollingRate::from_str(v["outputPolling"].as_str()?)?,
|
||||
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
|
||||
},
|
||||
"gamepad-hori" => OutputMode::Hori {
|
||||
polling: PollingRate::from_str(v["outputPolling"].as_str()?)?,
|
||||
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
|
||||
},
|
||||
"websocket" => OutputMode::Websocket {
|
||||
url: v["outputWebsocketUrl"].as_str()?.to_string(),
|
||||
polling: PollingRate::from_str(v["outputPolling"].as_str()?)?,
|
||||
|
132
src-slider_io/src/output/hori.rs
Normal file
132
src-slider_io/src/output/hori.rs
Normal file
@ -0,0 +1,132 @@
|
||||
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 {}
|
@ -1,6 +1,7 @@
|
||||
pub mod config;
|
||||
|
||||
mod gamepad;
|
||||
mod hori;
|
||||
mod keyboard;
|
||||
|
||||
pub mod output;
|
||||
|
@ -5,7 +5,9 @@ use tokio::time::{interval, Interval};
|
||||
|
||||
use crate::{shared::worker::AsyncJob, state::SliderState};
|
||||
|
||||
use super::{config::OutputMode, gamepad::GamepadOutput, keyboard::KeyboardOutput};
|
||||
use super::{
|
||||
config::OutputMode, gamepad::GamepadOutput, hori::HoriOutput, keyboard::KeyboardOutput,
|
||||
};
|
||||
|
||||
pub trait OutputHandler: Send {
|
||||
fn tick(&mut self, flat_input: &Vec<bool>) -> bool;
|
||||
@ -64,6 +66,22 @@ impl AsyncJob for OutputJob {
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
OutputMode::Hori {
|
||||
polling,
|
||||
sensitivity,
|
||||
} => {
|
||||
self.sensitivity = sensitivity;
|
||||
let handler = HoriOutput::new();
|
||||
self.timer = interval(Duration::from_micros(polling.to_t_u64()));
|
||||
|
||||
match handler {
|
||||
Some(handler) => {
|
||||
self.handler = Some(Box::new(handler));
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
error!("Not implemented");
|
||||
false
|
||||
|
27
src-slider_io/src/shared/hori.rs
Normal file
27
src-slider_io/src/shared/hori.rs
Normal file
@ -0,0 +1,27 @@
|
||||
pub struct HoriState {
|
||||
pub slider: [bool; 16],
|
||||
pub bt: [bool; 4],
|
||||
}
|
||||
|
||||
impl HoriState {
|
||||
pub fn from_flat(flat_input: &Vec<bool>) -> Self {
|
||||
let mut hori_state = Self {
|
||||
slider: [false; 16],
|
||||
bt: [false; 4],
|
||||
};
|
||||
|
||||
for (idx, i) in flat_input[0..32].iter().enumerate() {
|
||||
match idx % 2 {
|
||||
0 => {
|
||||
hori_state.bt[idx / 8] |= *i;
|
||||
}
|
||||
1 => {
|
||||
hori_state.slider[idx / 2] |= *i;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
hori_state
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
pub mod hori;
|
||||
pub mod serial;
|
||||
pub mod utils;
|
||||
pub mod voltex;
|
||||
|
4
src-tauri/Cargo.lock
generated
4
src-tauri/Cargo.lock
generated
@ -3753,9 +3753,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "vigem-client"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "965e349c8ec4eb36c06878b99952f35b9f459e6912419837ecb85fb5502a6de3"
|
||||
checksum = "5d886912e88b1d3b02a97d933df7829db8fb8561920410805794a48680c212d5"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
@ -304,6 +304,9 @@
|
||||
<option value="gamepad-neardayo"
|
||||
>XBOX 360 Gamepad, Neardayo Layout</option
|
||||
>
|
||||
<option value="gamepad-hori"
|
||||
>DS4, HORI DIVA Future Tone ASC Layout</option
|
||||
>
|
||||
<!-- <option value="websocket">Websocket</option> -->
|
||||
</select>
|
||||
</div>
|
||||
@ -315,11 +318,11 @@
|
||||
32 key layout is recommended for Brokestalgia controllers
|
||||
</div>
|
||||
</div>
|
||||
{:else if deviceMode.slice(0, 10) === "brokenithm" && ["kb-voltex", "kb-neardayo", "gamepad-voltex", "gamepad-neardayo"].includes(outputMode)}
|
||||
{:else if deviceMode.slice(0, 10) === "brokenithm" && ["kb-voltex", "kb-neardayo", "gamepad-voltex", "gamepad-neardayo", "gamepad-hori"].includes(outputMode)}
|
||||
<div class="row">
|
||||
<div class="label" />
|
||||
<div class="input comment">
|
||||
Voltex-like layouts are not recommended for Brokenithm controllers
|
||||
Gamepad layouts are not recommended for Brokenithm controllers
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
@ -401,6 +404,9 @@
|
||||
<option value="reactive-4">Reactive, 4-Zone</option>
|
||||
<option value="reactive-rainbow">Reactive, 16-Zone Rainbow</option>
|
||||
<option value="reactive-voltex">Reactive, Voltex Layout</option>
|
||||
<option value="reactive-hori"
|
||||
>Reactive, DIVA Future Tone Layout</option
|
||||
>
|
||||
<option value="attract">Rainbow Attract Mode</option>
|
||||
<!-- <option value="websocket">Websocket</option> -->
|
||||
<option value="serial">Serial</option>
|
||||
|
Loading…
Reference in New Issue
Block a user