+#[derive(Debug, Default)]
+pub struct Button {
+ id: u8,
+ pub time_pressed: Duration,
+ pub time_released: Duration,
+ pub is_pressed: bool,
+ pub was_pressed: bool,
+ pub toggle: bool,
+}
+
+impl Button {
+ fn update(&mut self, device: &Joystick, dt: Duration) {
+ self.was_pressed = self.is_pressed;
+ self.is_pressed = match device.button(self.id as u32) {
+ Ok(true) => {
+ if !self.was_pressed {
+ self.time_pressed = 0.seconds();
+ self.toggle = !self.toggle;
+ }
+ self.time_pressed += dt;
+ true
+ }
+ Ok(false) => {
+ if self.was_pressed {
+ self.time_released = 0.seconds();
+ }
+ self.time_released += dt;
+ false
+ }
+ Err(_) => { panic!("invalid button {}", self.id) }
+ }
+ }
+}
+
+#[derive(Debug, Default)]
+pub struct Axis {
+ id: u8,
+ pub val: f32,
+}
+
+impl Axis {
+ #[allow(dead_code)]
+ fn update(&mut self, device: &Joystick, _dt: Duration) {
+ self.val = match device.axis(self.id as u32) {
+ Ok(val) => val as f32 / 32768.0,
+ Err(_) => panic!("invalid axis {}", self.id),
+ }
+ }
+}
+
+#[derive(Debug, Default)]
+pub struct Stick {
+ idx: u8,
+ idy: u8,
+ pub x: f32,
+ pub y: f32,
+ pub a: Angle,
+}
+
+impl Stick {
+ fn update(&mut self, device: &Joystick, _dt: Duration) {
+ self.x = match device.axis(self.idx as u32) {
+ Ok(val) => val as f32 / 32768.0,
+ Err(_) => panic!("invalid x axis {}", self.idx),
+ };
+ self.y = match device.axis(self.idy as u32) {
+ Ok(val) => val as f32 / 32768.0,
+ Err(_) => panic!("invalid y axis {}", self.idy),
+ };
+ self.a = point!(self.x as f64, self.y as f64).to_angle();
+ }
+
+ #[inline(always)] #[allow(dead_code)] pub fn up(&self) -> bool { self.y < -0.99 }
+ #[inline(always)] #[allow(dead_code)] pub fn down(&self) -> bool { self.y > 0.99 }
+ #[inline(always)] #[allow(dead_code)] pub fn left(&self) -> bool { self.x < -0.99 }
+ #[inline(always)] #[allow(dead_code)] pub fn right(&self) -> bool { self.x > 0.99 }
+
+ pub fn to_axis_point(&self) -> Point<f64> {
+ point!(self.x as f64, self.y as f64)
+ }
+
+ pub fn to_point(&self) -> Point<f64> {
+ let p = point!(self.x as f64, self.y as f64);
+ if p.length() > 1.0 {
+ p.normalized()
+ } else {
+ p
+ }
+ }
+}
+
+impl From<&Stick> for Point<f64> {
+ fn from(item: &Stick) -> Self {
+ Self {
+ x: item.x as f64,
+ y: item.y as f64,
+ }
+ }
+}
+
+impl From<&Stick> for (f64, f64) {
+ fn from(item: &Stick) -> Self {
+ (item.x as f64, item.y as f64)
+ }
+}
+
+#[derive(Eq, PartialEq, Hash)]
+enum DeviceControls {
+ AxisLX,
+ AxisLY,
+ AxisRX,
+ AxisRY,
+ AxisL2,
+ AxisR2,
+ ButtonA,
+ ButtonB,
+ ButtonY,
+ ButtonX,
+ ButtonSelect,
+ ButtonStart,
+ ButtonHome,
+ ButtonL3,
+ ButtonR3,
+ ButtonL1,
+ ButtonR1,
+ ButtonL2,
+ ButtonR2,
+ ButtonUp,
+ ButtonDown,
+ ButtonLeft,
+ ButtonRight,