Skip to content

Commit 7f197ff

Browse files
committed
feat: added xbox joypad, separated c_bindings
Added test using SDL
1 parent 0b57533 commit 7f197ff

File tree

9 files changed

+221
-22
lines changed

9 files changed

+221
-22
lines changed

bindings/rust/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ pkg-config = "0.3.30"
2222
input = "0.9.0"
2323
rustix = { version = "0.38.18", features = ["fs"] }
2424
approx = "0.5.1"
25+
sdl2 = "0.37.0"

bindings/rust/src/c_bindings.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#![allow(non_upper_case_globals)]
2+
#![allow(non_camel_case_types)]
3+
#![allow(non_snake_case)]
4+
#![allow(dead_code)]
5+
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

bindings/rust/src/common.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use std::ffi::{CString};
2+
use crate::c_bindings;
23

34
#[allow(dead_code)]
45
pub struct InputtinoDeviceDefinition {
5-
pub def: super::InputtinoDeviceDefinition,
6+
pub def: c_bindings::InputtinoDeviceDefinition,
67
// Keep those around since we are passing them as pointers
78
name: CString,
89
phys: CString,
@@ -14,7 +15,7 @@ impl InputtinoDeviceDefinition {
1415
let name = CString::new(name).unwrap();
1516
let phys = CString::new(phys).unwrap();
1617
let uniq = CString::new(uniq).unwrap();
17-
let def = super::InputtinoDeviceDefinition {
18+
let def = c_bindings::InputtinoDeviceDefinition {
1819
name: name.as_ptr(),
1920
vendor_id: vendor_id,
2021
product_id: product_id,
@@ -59,7 +60,7 @@ macro_rules! make_device {
5960
($fn_call:expr, $device:expr) => {
6061
{
6162
let error_str = std::ptr::null_mut();
62-
let error_handler = super::InputtinoErrorHandler {
63+
let error_handler = crate::c_bindings::InputtinoErrorHandler {
6364
eh: Some(error_handler_fn),
6465
user_data: error_str,
6566
};

bindings/rust/src/joypad_xbox.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use std::ffi::{c_int, c_void};
2+
use crate::{get_nodes, make_device};
3+
use crate::common::{InputtinoDeviceDefinition, error_handler_fn};
4+
use crate::c_bindings::{inputtino_joypad_xone_create, inputtino_joypad_xone_destroy, inputtino_joypad_xone_get_nodes, inputtino_joypad_xone_set_on_rumble, inputtino_joypad_xone_set_pressed_buttons, inputtino_joypad_xone_set_stick, inputtino_joypad_xone_set_triggers};
5+
6+
// re-export INPUTTINO_JOYPAD_BTN and INPUTTINO_JOYPAD_STICK_POSITION
7+
pub use crate::c_bindings::{INPUTTINO_JOYPAD_BTN, INPUTTINO_JOYPAD_STICK_POSITION};
8+
9+
pub struct InputtinoXOneJoypad {
10+
joypad: *mut crate::c_bindings::InputtinoXOneJoypad,
11+
on_rumble_fn: Box<dyn FnMut(i32, i32) -> ()>,
12+
}
13+
14+
impl InputtinoXOneJoypad {
15+
pub fn new(device: &InputtinoDeviceDefinition) -> Result<Self, String> {
16+
unsafe {
17+
let dev = make_device!(inputtino_joypad_xone_create, device);
18+
match dev {
19+
Ok(joypad) => {
20+
Ok(InputtinoXOneJoypad { joypad, on_rumble_fn: Box::new(|_, _| {}) })
21+
}
22+
Err(e) => Err(e),
23+
}
24+
}
25+
}
26+
27+
pub fn get_nodes(&self) -> Result<Vec<String>, String> {
28+
unsafe {
29+
get_nodes!(inputtino_joypad_xone_get_nodes, self.joypad)
30+
}
31+
}
32+
33+
pub fn set_pressed(&self, buttons: i32) {
34+
unsafe {
35+
inputtino_joypad_xone_set_pressed_buttons(self.joypad, buttons);
36+
}
37+
}
38+
39+
pub fn set_triggers(&self, left_trigger: i16, right_trigger: i16) {
40+
unsafe {
41+
inputtino_joypad_xone_set_triggers(self.joypad, left_trigger, right_trigger);
42+
}
43+
}
44+
45+
pub fn set_stick(&self, stick_type: INPUTTINO_JOYPAD_STICK_POSITION, x: i16, y: i16) {
46+
unsafe {
47+
inputtino_joypad_xone_set_stick(self.joypad, stick_type, x, y);
48+
}
49+
}
50+
51+
pub fn set_on_rumble(&mut self, on_rumble_fn: impl FnMut(i32, i32) -> () + 'static) {
52+
self.on_rumble_fn = Box::new(on_rumble_fn);
53+
unsafe {
54+
let state_ptr = self as *const _ as *mut c_void;
55+
inputtino_joypad_xone_set_on_rumble(self.joypad, Some(on_rumble_c_fn), state_ptr);
56+
}
57+
}
58+
}
59+
60+
impl Drop for InputtinoXOneJoypad {
61+
fn drop(&mut self) {
62+
unsafe {
63+
inputtino_joypad_xone_destroy(self.joypad);
64+
}
65+
}
66+
}
67+
68+
#[allow(dead_code)]
69+
pub unsafe extern "C" fn on_rumble_c_fn(left_motor: c_int, right_motor: c_int, user_data: *mut ::core::ffi::c_void) {
70+
println!("on_rumble_c_fn {:?}-{:?}", left_motor, right_motor);
71+
let joypad: &mut InputtinoXOneJoypad = &mut *(user_data as *mut InputtinoXOneJoypad);
72+
((*joypad).on_rumble_fn)(left_motor, right_motor);
73+
}

bindings/rust/src/keyboard.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use crate::common::{error_handler_fn, InputtinoDeviceDefinition};
2-
use crate::{get_nodes, inputtino_keyboard_create, inputtino_keyboard_get_nodes, make_device};
2+
use crate::{get_nodes, make_device};
3+
use crate::c_bindings::{inputtino_keyboard_create, inputtino_keyboard_get_nodes, inputtino_keyboard_press, inputtino_keyboard_release, inputtino_keyboard_destroy};
34

45
pub struct InputtinoKeyboard {
5-
kb: *mut super::InputtinoKeyboard,
6+
kb: *mut crate::c_bindings::InputtinoKeyboard,
67
}
78

89
impl InputtinoKeyboard {
@@ -24,21 +25,21 @@ impl InputtinoKeyboard {
2425

2526
pub fn press_key(&self, key: i16) {
2627
unsafe {
27-
super::inputtino_keyboard_press(self.kb, key);
28+
inputtino_keyboard_press(self.kb, key);
2829
}
2930
}
3031

3132
pub fn release_key(&self, key: i16) {
3233
unsafe {
33-
super::inputtino_keyboard_release(self.kb, key);
34+
inputtino_keyboard_release(self.kb, key);
3435
}
3536
}
3637
}
3738

3839
impl Drop for InputtinoKeyboard {
3940
fn drop(&mut self) {
4041
unsafe {
41-
super::inputtino_keyboard_destroy(self.kb);
42+
inputtino_keyboard_destroy(self.kb);
4243
}
4344
}
4445
}

bindings/rust/src/lib.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
#![allow(non_upper_case_globals)]
2-
#![allow(non_camel_case_types)]
3-
#![allow(non_snake_case)]
4-
5-
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
6-
71
pub mod common;
82
pub mod mouse;
93
pub mod keyboard;
4+
pub mod joypad_xbox;
5+
mod c_bindings;

bindings/rust/src/mouse.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
use crate::{get_nodes, inputtino_mouse_create, inputtino_mouse_destroy, inputtino_mouse_get_nodes, inputtino_mouse_move, inputtino_mouse_move_absolute, inputtino_mouse_press_button, inputtino_mouse_release_button, inputtino_mouse_scroll_horizontal, inputtino_mouse_scroll_vertical, make_device};
1+
use crate::{get_nodes, make_device};
22
use crate::common::{InputtinoDeviceDefinition, error_handler_fn};
3+
use crate::c_bindings::{inputtino_mouse_create, inputtino_mouse_destroy, inputtino_mouse_get_nodes, inputtino_mouse_move, inputtino_mouse_move_absolute, inputtino_mouse_press_button, inputtino_mouse_release_button, inputtino_mouse_scroll_horizontal, inputtino_mouse_scroll_vertical};
4+
5+
pub use crate::c_bindings::{INPUTTINO_MOUSE_BUTTON};
36

47
pub struct InputtinoMouse {
5-
mouse: *mut super::InputtinoMouse,
8+
mouse: *mut crate::c_bindings::InputtinoMouse,
69
}
710

811
impl InputtinoMouse {
@@ -34,13 +37,13 @@ impl InputtinoMouse {
3437
}
3538
}
3639

37-
pub fn press_button(&self, button: super::INPUTTINO_MOUSE_BUTTON) {
40+
pub fn press_button(&self, button: INPUTTINO_MOUSE_BUTTON) {
3841
unsafe {
3942
inputtino_mouse_press_button(self.mouse, button);
4043
}
4144
}
4245

43-
pub fn release_button(&self, button: super::INPUTTINO_MOUSE_BUTTON) {
46+
pub fn release_button(&self, button: INPUTTINO_MOUSE_BUTTON) {
4447
unsafe {
4548
inputtino_mouse_release_button(self.mouse, button);
4649
}
@@ -77,7 +80,7 @@ mod tests {
7780
let device_name = CString::new("Rusty Mouse").unwrap();
7881
let device_phys = CString::new("Rusty Mouse Phys").unwrap();
7982
let device_uniq = CString::new("Rusty Mouse Uniq").unwrap();
80-
let def = crate::InputtinoDeviceDefinition {
83+
let def = crate::c_bindings::InputtinoDeviceDefinition {
8184
name: device_name.as_ptr(),
8285
vendor_id: 0,
8386
product_id: 0,
@@ -87,7 +90,7 @@ mod tests {
8790
};
8891
// TODO: test this somehow
8992
let error_str = std::ptr::null_mut();
90-
let error_handler = crate::InputtinoErrorHandler {
93+
let error_handler = crate::c_bindings::InputtinoErrorHandler {
9194
eh: Some(error_handler_fn),
9295
user_data: error_str,
9396
};

bindings/rust/tests/joypad_xbox.rs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
use inputtino_rs::common::InputtinoDeviceDefinition;
2+
use inputtino_rs::joypad_xbox::{InputtinoXOneJoypad, INPUTTINO_JOYPAD_BTN, INPUTTINO_JOYPAD_STICK_POSITION};
3+
4+
#[test]
5+
fn test_xbox_joypad() {
6+
let device = InputtinoDeviceDefinition::new("Rusty XOne controller", 0x045e, 0x02dd, 0x0100, "00:11:22:33:44", "00:11:22:33:44");
7+
let mut joypad = InputtinoXOneJoypad::new(&device).unwrap();
8+
9+
let nodes = joypad.get_nodes().unwrap();
10+
{
11+
assert_eq!(nodes.len(), 2);
12+
assert!(nodes[0].starts_with("/dev/input/event"));
13+
assert!(nodes[1].starts_with("/dev/input/js"));
14+
}
15+
16+
let sdl = sdl2::init().unwrap();
17+
let joystick_subsystem = sdl.game_controller().unwrap();
18+
let mut sdl_js = joystick_subsystem.open(0).unwrap();
19+
let mut event_pump = sdl.event_pump().unwrap();
20+
21+
for event in event_pump.poll_iter() {
22+
match event {
23+
sdl2::event::Event::JoyDeviceAdded { which, .. } => {
24+
assert_eq!(which, 0);
25+
}
26+
sdl2::event::Event::ControllerDeviceAdded { which, .. } => {
27+
assert_eq!(which, 0);
28+
}
29+
_ => panic!("Unexpected event : {:?}", event),
30+
}
31+
}
32+
33+
assert_eq!(sdl_js.name(), "Xbox One Controller");
34+
assert!(sdl_js.has_rumble());
35+
36+
{
37+
joypad.set_pressed(INPUTTINO_JOYPAD_BTN::A as i32);
38+
for event in event_pump.wait_timeout_iter(50) {
39+
match event {
40+
sdl2::event::Event::ControllerButtonDown { button, .. } => {
41+
assert_eq!(button, sdl2::controller::Button::A);
42+
}
43+
sdl2::event::Event::JoyButtonDown { button_idx, .. } => {
44+
assert_eq!(button_idx, sdl2::controller::Button::A as u8);
45+
break;
46+
}
47+
_ => panic!("Unexpected event : {:?}", event),
48+
}
49+
}
50+
}
51+
52+
{
53+
joypad.set_triggers(0, 0);
54+
for event in event_pump.wait_timeout_iter(50) {
55+
match event {
56+
sdl2::event::Event::ControllerAxisMotion { axis, value, .. } => {
57+
assert_eq!(axis, sdl2::controller::Axis::TriggerLeft);
58+
assert_eq!(value, 0);
59+
}
60+
sdl2::event::Event::JoyAxisMotion { axis_idx, value, .. } => {
61+
assert_eq!(axis_idx, sdl2::controller::Axis::TriggerLeft as u8);
62+
assert_eq!(value, 0);
63+
break;
64+
}
65+
_ => panic!("Unexpected event : {:?}", event),
66+
}
67+
}
68+
}
69+
70+
{
71+
joypad.set_stick(INPUTTINO_JOYPAD_STICK_POSITION::LS, 0, 0);
72+
for event in event_pump.wait_timeout_iter(50) {
73+
match event {
74+
sdl2::event::Event::ControllerAxisMotion { axis, value, .. } => {
75+
assert_eq!(axis, sdl2::controller::Axis::LeftX);
76+
assert_eq!(value, 0);
77+
}
78+
sdl2::event::Event::JoyAxisMotion { axis_idx, value, .. } => {
79+
assert_eq!(axis_idx, sdl2::controller::Axis::LeftX as u8);
80+
assert_eq!(value, 0);
81+
break;
82+
}
83+
_ => panic!("Unexpected event : {:?}", event),
84+
}
85+
}
86+
}
87+
88+
{
89+
joypad.set_stick(INPUTTINO_JOYPAD_STICK_POSITION::RS, 0, 0);
90+
for event in event_pump.wait_timeout_iter(50) {
91+
match event {
92+
sdl2::event::Event::ControllerAxisMotion { axis, value, .. } => {
93+
assert_eq!(axis, sdl2::controller::Axis::RightX);
94+
assert_eq!(value, 0);
95+
}
96+
sdl2::event::Event::JoyAxisMotion { axis_idx, value, .. } => {
97+
assert_eq!(axis_idx, sdl2::controller::Axis::RightX as u8);
98+
assert_eq!(value, 0);
99+
break;
100+
}
101+
_ => panic!("Unexpected event : {:?}", event),
102+
}
103+
}
104+
}
105+
106+
{
107+
joypad.set_on_rumble(move |left, right| {
108+
assert_eq!(left, 100);
109+
assert_eq!(right, 200);
110+
});
111+
let res = sdl_js.set_rumble(100, 200, 150);
112+
assert!(res.is_ok());
113+
std::thread::sleep(std::time::Duration::from_millis(25));
114+
joypad.set_on_rumble(move |left, right| {
115+
assert_eq!(left, 0);
116+
assert_eq!(right, 0);
117+
});
118+
std::thread::sleep(std::time::Duration::from_millis(125));
119+
}
120+
}

bindings/rust/tests/mouse.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
extern crate approx;
33

44
use inputtino_rs::{
5-
INPUTTINO_MOUSE_BUTTON,
6-
mouse::InputtinoMouse,
5+
mouse::{InputtinoMouse, INPUTTINO_MOUSE_BUTTON},
76
common::InputtinoDeviceDefinition,
87
};
98
use input::{Event, Libinput};

0 commit comments

Comments
 (0)