From 866c3c2760ee007b69bb5782e204e543730ed1c6 Mon Sep 17 00:00:00 2001 From: ABeltramo Date: Tue, 6 Aug 2024 20:38:40 +0100 Subject: [PATCH] feat: added switch joypad --- bindings/rust/Cargo.toml | 1 + bindings/rust/src/joypad_switch.rs | 72 +++++++++++ bindings/rust/src/joypad_xbox.rs | 1 - bindings/rust/src/lib.rs | 3 + .../rust/tests/{joypad_xbox.rs => joypads.rs} | 122 ++++++++++++++++++ 5 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 bindings/rust/src/joypad_switch.rs rename bindings/rust/tests/{joypad_xbox.rs => joypads.rs} (50%) diff --git a/bindings/rust/Cargo.toml b/bindings/rust/Cargo.toml index 3a60998..8e85b06 100644 --- a/bindings/rust/Cargo.toml +++ b/bindings/rust/Cargo.toml @@ -23,3 +23,4 @@ input = "0.9.0" rustix = { version = "0.38.18", features = ["fs"] } approx = "0.5.1" sdl2 = "0.37.0" +serial_test = "3.1.1" diff --git a/bindings/rust/src/joypad_switch.rs b/bindings/rust/src/joypad_switch.rs new file mode 100644 index 0000000..af04003 --- /dev/null +++ b/bindings/rust/src/joypad_switch.rs @@ -0,0 +1,72 @@ +use std::ffi::{c_int, c_void}; +use crate::c_bindings::{inputtino_joypad_switch_create, inputtino_joypad_switch_destroy, inputtino_joypad_switch_get_nodes, inputtino_joypad_switch_set_on_rumble, inputtino_joypad_switch_set_pressed_buttons, inputtino_joypad_switch_set_stick, inputtino_joypad_switch_set_triggers}; +use crate::common::{InputtinoDeviceDefinition, error_handler_fn}; +use crate::{get_nodes, make_device}; + +// re-export INPUTTINO_JOYPAD_BTN and INPUTTINO_JOYPAD_STICK_POSITION +pub use crate::c_bindings::{INPUTTINO_JOYPAD_BTN, INPUTTINO_JOYPAD_STICK_POSITION}; + +pub struct InputtinoSwitchJoypad { + joypad: *mut crate::c_bindings::InputtinoSwitchJoypad, + on_rumble_fn: Box ()>, +} + +impl InputtinoSwitchJoypad { + pub fn new(device: &InputtinoDeviceDefinition) -> Result { + unsafe { + let dev = make_device!(inputtino_joypad_switch_create, device); + match dev { + Ok(joypad) => { + Ok(InputtinoSwitchJoypad { joypad, on_rumble_fn: Box::new(|_, _| {}) }) + } + Err(e) => Err(e), + } + } + } + + pub fn get_nodes(&self) -> Result, String> { + unsafe { + get_nodes!(inputtino_joypad_switch_get_nodes, self.joypad) + } + } + + pub fn set_pressed(&self, buttons: i32) { + unsafe { + inputtino_joypad_switch_set_pressed_buttons(self.joypad, buttons); + } + } + + pub fn set_triggers(&self, left_trigger: i16, right_trigger: i16) { + unsafe { + inputtino_joypad_switch_set_triggers(self.joypad, left_trigger, right_trigger); + } + } + + pub fn set_stick(&self, stick_type: INPUTTINO_JOYPAD_STICK_POSITION, x: i16, y: i16) { + unsafe { + inputtino_joypad_switch_set_stick(self.joypad, stick_type, x, y); + } + } + + pub fn set_on_rumble(&mut self, on_rumble_fn: impl FnMut(i32, i32) -> () + 'static) { + self.on_rumble_fn = Box::new(on_rumble_fn); + unsafe { + let state_ptr = self as *const _ as *mut c_void; + inputtino_joypad_switch_set_on_rumble(self.joypad, Some(on_rumble_c_fn), state_ptr); + } + } +} + +impl Drop for InputtinoSwitchJoypad { + fn drop(&mut self) { + unsafe { + inputtino_joypad_switch_destroy(self.joypad); + } + } +} + +#[allow(dead_code)] +pub unsafe extern "C" fn on_rumble_c_fn(left_motor: c_int, right_motor: c_int, user_data: *mut ::core::ffi::c_void) { + let joypad: &mut InputtinoSwitchJoypad = &mut *(user_data as *mut InputtinoSwitchJoypad); + ((*joypad).on_rumble_fn)(left_motor, right_motor); +} diff --git a/bindings/rust/src/joypad_xbox.rs b/bindings/rust/src/joypad_xbox.rs index 5e88352..f5b5dd1 100644 --- a/bindings/rust/src/joypad_xbox.rs +++ b/bindings/rust/src/joypad_xbox.rs @@ -67,7 +67,6 @@ impl Drop for InputtinoXOneJoypad { #[allow(dead_code)] pub unsafe extern "C" fn on_rumble_c_fn(left_motor: c_int, right_motor: c_int, user_data: *mut ::core::ffi::c_void) { - println!("on_rumble_c_fn {:?}-{:?}", left_motor, right_motor); let joypad: &mut InputtinoXOneJoypad = &mut *(user_data as *mut InputtinoXOneJoypad); ((*joypad).on_rumble_fn)(left_motor, right_motor); } diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index 8024e0b..2be6c25 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -2,4 +2,7 @@ pub mod common; pub mod mouse; pub mod keyboard; pub mod joypad_xbox; +pub mod joypad_switch; + +// Private low level automatic c bindings mod c_bindings; diff --git a/bindings/rust/tests/joypad_xbox.rs b/bindings/rust/tests/joypads.rs similarity index 50% rename from bindings/rust/tests/joypad_xbox.rs rename to bindings/rust/tests/joypads.rs index 523853e..2516e8e 100644 --- a/bindings/rust/tests/joypad_xbox.rs +++ b/bindings/rust/tests/joypads.rs @@ -1,7 +1,10 @@ +use serial_test::serial; use inputtino_rs::common::InputtinoDeviceDefinition; +use inputtino_rs::joypad_switch::InputtinoSwitchJoypad; use inputtino_rs::joypad_xbox::{InputtinoXOneJoypad, INPUTTINO_JOYPAD_BTN, INPUTTINO_JOYPAD_STICK_POSITION}; #[test] +#[serial] fn test_xbox_joypad() { let device = InputtinoDeviceDefinition::new("Rusty XOne controller", 0x045e, 0x02dd, 0x0100, "00:11:22:33:44", "00:11:22:33:44"); let mut joypad = InputtinoXOneJoypad::new(&device).unwrap(); @@ -118,3 +121,122 @@ fn test_xbox_joypad() { std::thread::sleep(std::time::Duration::from_millis(125)); } } + +#[test] +#[serial] +fn test_switch_joypad() { + let device = InputtinoDeviceDefinition::new("Rusty Switch controller", 0x045e, 0x02dd, 0x0100, "00:11:22:33:44", "00:11:22:33:44"); + let mut joypad = InputtinoSwitchJoypad::new(&device).unwrap(); + + let nodes = joypad.get_nodes().unwrap(); + { + assert_eq!(nodes.len(), 2); + assert!(nodes[0].starts_with("/dev/input/event")); + assert!(nodes[1].starts_with("/dev/input/js")); + } + + let sdl = sdl2::init().unwrap(); + let joystick_subsystem = sdl.game_controller().unwrap(); + let mut sdl_js = joystick_subsystem.open(0).unwrap(); + let mut event_pump = sdl.event_pump().unwrap(); + + for event in event_pump.poll_iter() { + match event { + sdl2::event::Event::JoyDeviceAdded { which, .. } => { + assert_eq!(which, 0); + } + sdl2::event::Event::ControllerDeviceAdded { which, .. } => { + assert_eq!(which, 0); + } + _ => panic!("Unexpected event : {:?}", event), + } + } + + assert_eq!(sdl_js.name(), "Xbox One Controller"); + assert!(sdl_js.has_rumble()); + + { + joypad.set_pressed(INPUTTINO_JOYPAD_BTN::A as i32); + for event in event_pump.wait_timeout_iter(50) { + match event { + sdl2::event::Event::ControllerButtonDown { button, .. } => { + assert_eq!(button, sdl2::controller::Button::B); + } + sdl2::event::Event::JoyButtonDown { button_idx, .. } => { + assert_eq!(button_idx, sdl2::controller::Button::B as u8); + break; + } + _ => panic!("Unexpected event : {:?}", event), + } + } + } + + { + joypad.set_triggers(0, 0); + for event in event_pump.wait_timeout_iter(50) { + match event { + sdl2::event::Event::ControllerAxisMotion { axis, value, .. } => { + assert_eq!(axis, sdl2::controller::Axis::TriggerLeft); + assert_eq!(value, 0); + } + sdl2::event::Event::JoyAxisMotion { axis_idx, value, .. } => { + assert_eq!(axis_idx, sdl2::controller::Axis::TriggerLeft as u8); + assert_eq!(value, 0); + break; + } + _ => panic!("Unexpected event : {:?}", event), + } + } + } + + { + joypad.set_stick(INPUTTINO_JOYPAD_STICK_POSITION::LS, 0, 0); + for event in event_pump.wait_timeout_iter(50) { + match event { + sdl2::event::Event::ControllerAxisMotion { axis, value, .. } => { + assert_eq!(axis, sdl2::controller::Axis::LeftX); + assert_eq!(value, 0); + } + sdl2::event::Event::JoyAxisMotion { axis_idx, value, .. } => { + assert_eq!(axis_idx, sdl2::controller::Axis::LeftX as u8); + assert_eq!(value, 0); + break; + } + _ => panic!("Unexpected event : {:?}", event), + } + } + } + + { + joypad.set_stick(INPUTTINO_JOYPAD_STICK_POSITION::RS, 0, 0); + for event in event_pump.wait_timeout_iter(50) { + match event { + sdl2::event::Event::ControllerAxisMotion { axis, value, .. } => { + assert_eq!(axis, sdl2::controller::Axis::RightX); + assert_eq!(value, 0); + } + sdl2::event::Event::JoyAxisMotion { axis_idx, value, .. } => { + assert_eq!(axis_idx, sdl2::controller::Axis::RightX as u8); + assert_eq!(value, 0); + break; + } + _ => panic!("Unexpected event : {:?}", event), + } + } + } + + { + joypad.set_on_rumble(move |left, right| { + assert_eq!(left, 100); + assert_eq!(right, 200); + }); + let res = sdl_js.set_rumble(100, 200, 150); + assert!(res.is_ok()); + std::thread::sleep(std::time::Duration::from_millis(25)); + joypad.set_on_rumble(move |left, right| { + assert_eq!(left, 0); + assert_eq!(right, 0); + }); + std::thread::sleep(std::time::Duration::from_millis(125)); + } +}