use super::NativeManager;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
pub const CONTROLLER_MAX: usize = 64;
#[repr(C)]
struct TimeVal {
tv_sec: isize,
tv_usec: isize,
}
#[repr(C)]
struct Event {
ev_time: TimeVal,
ev_type: i16,
ev_code: i16,
ev_value: i32,
}
#[derive(Copy, Clone)]
#[repr(u8)]
pub enum Btn {
Left = 0u8,
Right = 1,
Up = 2,
Down = 3,
X = 4,
A = 5,
Y = 6,
B = 7,
L = 8,
R = 9,
W = 10,
Z = 11,
F = 12,
E = 13,
D = 14,
C = 15,
}
impl From<Btn> for u8 {
fn from(b: Btn) -> Self {
b as u8
}
}
#[derive(Debug)]
pub struct Device {
native_handle: u32,
hardware_id: u32,
abs_min: i32,
abs_max: i32,
joyx: AtomicUsize,
joyy: AtomicUsize,
camx: AtomicUsize,
camy: AtomicUsize,
trgl: AtomicUsize,
trgr: AtomicUsize,
btns: AtomicUsize,
plug: AtomicUsize,
}
impl std::fmt::Display for Device {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
let joy: (f32, f32) = (gfloat(&self.joyx), gfloat(&self.joyy));
let cam: (f32, f32) = (gfloat(&self.camx), gfloat(&self.camy));
let lrt: (f32, f32) = (gfloat(&self.trgl), gfloat(&self.trgr));
let b_btn: char = if self.btn(Btn::B) == Some(true) {
'▣'
} else {
'□'
};
let a_btn: char = if self.btn(Btn::A) == Some(true) {
'▣'
} else {
'□'
};
let y_btn: char = if self.btn(Btn::Y) == Some(true) {
'▣'
} else {
'□'
};
let x_btn: char = if self.btn(Btn::X) == Some(true) {
'▣'
} else {
'□'
};
let dl: char = if self.btn(Btn::Left) == Some(true) {
'▣'
} else {
'□'
};
let dr: char = if self.btn(Btn::Right) == Some(true) {
'▣'
} else {
'□'
};
let du: char = if self.btn(Btn::Up) == Some(true) {
'▣'
} else {
'□'
};
let dd: char = if self.btn(Btn::Down) == Some(true) {
'▣'
} else {
'□'
};
let w_btn: char = if self.btn(Btn::W) == Some(true) {
'▣'
} else {
'□'
};
let z_btn: char = if self.btn(Btn::Z) == Some(true) {
'▣'
} else {
'□'
};
let l_btn: char = if self.btn(Btn::L) == Some(true) {
'▣'
} else {
'□'
};
let r_btn: char = if self.btn(Btn::R) == Some(true) {
'▣'
} else {
'□'
};
let d_btn: char = if self.btn(Btn::D) == Some(true) {
'▣'
} else {
'□'
};
let c_btn: char = if self.btn(Btn::C) == Some(true) {
'▣'
} else {
'□'
};
let f_btn: char = if self.btn(Btn::F) == Some(true) {
'▣'
} else {
'□'
};
let e_btn: char = if self.btn(Btn::E) == Some(true) {
'▣'
} else {
'□'
};
write!(
f,
"j({:.2},{:.2}) c({:.2},{:.2}) T({:.2},{:.2}) b{} a{} y{} x{} ←{} →{} \
↑{} ↓{} l{} r{} w{} z{} f{} e{} d{} c{}",
joy.0,
joy.1,
cam.0,
cam.1,
lrt.0,
lrt.1,
b_btn,
a_btn,
y_btn,
x_btn,
dl,
dr,
du,
dd,
l_btn,
r_btn,
w_btn,
z_btn,
f_btn,
e_btn,
d_btn,
c_btn,
)
}
}
impl Device {
pub fn joy(&self) -> Option<(f32, f32)> {
Some((gfloat(&self.joyx), gfloat(&self.joyy)))
}
pub fn cam(&self) -> Option<(f32, f32)> {
#[allow(clippy::single_match)]
match self.hardware_id {
0x_07B5_0316 => return None,
_ => {}
}
Some((gfloat(&self.camx), gfloat(&self.camy)))
}
pub fn lrt(&self) -> Option<(f32, f32)> {
Some((gfloat(&self.trgl), gfloat(&self.trgr)))
}
pub fn btn<B: Into<u8>>(&self, b: B) -> Option<bool> {
Some(self.btns.load(Ordering::Relaxed) & (1 << (b.into())) != 0)
}
}
fn afloat(float: &AtomicUsize, fnc: &Fn(f32) -> f32) {
let old: [u8; 8] = float.load(Ordering::Relaxed).to_ne_bytes();
let old: f32 = f32::from_bits(u32::from_ne_bytes([old[0], old[1], old[2], old[3]]));
let new: [u8; 4] = fnc(old).to_bits().to_ne_bytes();
let new: usize = usize::from_ne_bytes([new[0], new[1], new[2], new[3], 0, 0, 0, 0]);
float.store(new, Ordering::Relaxed);
}
fn gfloat(float: &AtomicUsize) -> f32 {
let rtn: [u8; 8] = float.load(Ordering::Relaxed).to_ne_bytes();
let rtn: f32 = f32::from_bits(u32::from_ne_bytes([rtn[0], rtn[1], rtn[2], rtn[3]]));
rtn
}
pub struct Port {
manager: NativeManager,
count: AtomicUsize,
controllers: [Device; CONTROLLER_MAX],
}
impl Default for Port {
fn default() -> Self {
Self::new()
}
}
impl Port {
pub fn new() -> Port {
let manager = NativeManager::new();
let controllers = unsafe { std::mem::zeroed() };
let count = AtomicUsize::new(0);
let mut port = Port {
manager,
count,
controllers,
};
for stick in 0..port.manager.num_plugged_in() {
port.add_stick(stick);
}
port
}
fn add_stick(&mut self, index: usize) {
let (min, max, _) = self.manager.get_abs(index);
self.count.fetch_add(1, Ordering::Relaxed);
self.controllers[index] = Device {
native_handle: index as u32,
hardware_id: self.manager.get_id(index).0,
abs_min: min,
abs_max: max,
joyx: AtomicUsize::new(0),
joyy: AtomicUsize::new(0),
camx: AtomicUsize::new(0),
camy: AtomicUsize::new(0),
trgl: AtomicUsize::new(0),
trgr: AtomicUsize::new(0),
btns: AtomicUsize::new(0),
plug: AtomicUsize::new(1),
};
}
pub fn poll(&mut self) -> Option<u8> {
if let Some(fd) = crate::ffi::epoll_wait(self.manager.fd) {
if fd == self.manager.inotify {
let (is_add, index) = crate::ffi::inotify_read(&mut self.manager)?;
println!("Controller Count Changed {} {}", is_add, index);
if is_add {
self.add_stick(index);
return Some(index as u8);
} else {
return None;
}
}
for i in 0..self.controllers.len() {
let (devfd, is_out, ne) = self
.manager
.get_fd(self.controllers[i].native_handle as usize);
if ne {
continue;
}
if is_out {
self.count.fetch_sub(1, Ordering::Relaxed);
self.manager.disconnect(fd);
continue;
}
if devfd != fd {
continue;
}
while joystick_poll_event(fd, &mut self.controllers[i]) {}
return Some(i as u8);
}
}
None
}
pub fn get(&self, stick: u8) -> Option<&Device> {
if self.controllers[stick as usize]
.plug
.load(Ordering::Relaxed)
== 1
{
Some(&self.controllers[stick as usize])
} else {
None
}
}
pub fn swap(&mut self, a: u8, b: u8) {
self.controllers.swap(a as usize, b as usize);
}
#[allow(unused)]
pub fn name(&self, a: u8) -> String {
"Unknown".to_string()
}
pub fn count(&self) -> u8 {
self.count.load(Ordering::Relaxed) as u8
}
}
fn joystick_poll_event(fd: i32, device: &mut Device) -> bool {
extern "C" {
fn read(fd: i32, buf: *mut Event, count: usize) -> isize;
}
let mut js = unsafe { std::mem::uninitialized() };
let bytes = unsafe { read(fd, &mut js, std::mem::size_of::<Event>()) };
if bytes != (std::mem::size_of::<Event>() as isize) {
return false;
}
fn edit<B: Into<u8>>(is: bool, device: &mut Device, b: B) {
if is {
device.btns.fetch_or(1 << b.into(), Ordering::Relaxed);
} else {
device.btns.fetch_and(!(1 << b.into()), Ordering::Relaxed);
}
}
let a = if device.hardware_id == 0x_0E6F_0501
{
Btn::B
} else {
Btn::A
};
let b = if device.hardware_id == 0x_0E6F_0501
{
Btn::A
} else {
Btn::B
};
let x = if device.hardware_id == 0x_054C_0268
{
Btn::Y
} else {
Btn::X
};
let y = if device.hardware_id == 0x_054C_0268
{
Btn::X
} else {
Btn::Y
};
match js.ev_type {
0x01 => {
let is = js.ev_value == 1;
match js.ev_code - 0x120 {
0 | 19 => edit(is, device, x),
1 | 17 => edit(is, device, a),
2 | 16 => edit(is, device, b),
3 | 20 => edit(is, device, y),
4 | 24 => edit(is, device, Btn::L),
5 | 25 => edit(is, device, Btn::R),
6 | 22 => edit(is, device, Btn::W),
7 | 23 => edit(is, device, Btn::Z),
8 | 26 => edit(is, device, Btn::F),
9 | 27 => edit(is, device, Btn::E),
10 => println!("Button 10 is Unknown"),
12 | 256 => edit(is, device, Btn::Up),
13 | 259 => edit(is, device, Btn::Right),
14 | 257 => edit(is, device, Btn::Down),
15 | 258 => edit(is, device, Btn::Left),
18 => println!("Button 18 is Unknown"),
21 => println!("Button 21 is Unknown"),
28 => println!("Button 28 is Unknown"),
29 => edit(is, device, Btn::D),
30 => edit(is, device, Btn::C),
a => println!("Button {} is Unknown", a),
}
}
0x03 => {
let value = if device.hardware_id == 0x_0079_1844 {
let pad = (device.abs_max - device.abs_min) / 4;
transform(device.abs_min + pad, device.abs_max - pad, js.ev_value)
} else {
transform(device.abs_min, device.abs_max, js.ev_value)
};
let value2 = if device.hardware_id == 0x_0079_1844 {
transform2(32, 95, js.ev_value)
} else {
transform2(0, 127, js.ev_value)
};
let (cam_x, cam_y, lrt_l, lrt_r) = match device.hardware_id {
0x_0079_1844 => (5, 2, 3, 4),
_ => (3, 4, 2, 5),
};
match js.ev_code {
0 => afloat(&device.joyx, &|_| value),
1 => afloat(&device.joyy, &|_| value),
16 => {
if js.ev_value < 0 {
edit(true, device, Btn::Left);
edit(false, device, Btn::Right);
} else if js.ev_value > 0 {
edit(false, device, Btn::Left);
edit(true, device, Btn::Right);
} else {
edit(false, device, Btn::Left);
edit(false, device, Btn::Right);
}
}
17 => {
if js.ev_value < 0 {
edit(true, device, Btn::Up);
edit(false, device, Btn::Down);
} else if js.ev_value > 0 {
edit(false, device, Btn::Up);
edit(true, device, Btn::Down);
} else {
edit(false, device, Btn::Up);
edit(false, device, Btn::Down);
}
}
40 => {}
a => {
if a == cam_x {
afloat(&device.camx, &|_| {
value
});
} else if a == cam_y {
afloat(&device.camy, &|_| {
value
});
} else if a == lrt_l {
if value2 > 0.99 {
edit(true, device, Btn::L)
} else {
edit(false, device, Btn::L)
}
afloat(&device.trgl, &|_| {
value2
});
} else if a == lrt_r {
if value2 > 0.99 {
edit(true, device, Btn::R)
} else {
edit(false, device, Btn::R)
}
afloat(&device.trgr, &|_| {
value2
});
}
}
}
}
_ => {}
}
true
}
fn deadzone(min: i32, max: i32, val: i32) -> (i32, i32) {
let range = max - min;
let halfr = range >> 1;
let deadz = halfr >> 2;
let midpt = min + halfr;
let value = val - midpt;
let value = if value < deadz {
if value > -deadz {
0
} else {
value + deadz
}
} else {
value - deadz
};
(value, (range >> 1) - deadz)
}
fn transform(min: i32, max: i32, val: i32) -> f32 {
let (value, full) = deadzone(min, max, val);
((value * 127) / full).max(-127).min(127) as f32 / 127.0
}
fn transform2(min: i32, max: i32, val: i32) -> f32 {
((val * 255) / (max - min)).max(0).min(255) as f32 / 255.0
}
#[cfg(test)]
mod tests {
}