Skip to main content

dualsense_tools/virtual_controller/
axis_value.rs

1use std::f32::consts::PI;
2
3use crate::{Radians, state::DualsenseAxisValue};
4
5/// Represents the value of an axis in the [0; 255] range
6#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
7pub struct AxisValue(u8);
8
9impl Default for AxisValue {
10    fn default() -> Self {
11        Self(127)
12    }
13}
14
15impl AxisValue {
16    /// Returns the ratio in a [0; 1] range
17    pub fn as_ratio(&self) -> f32 {
18        ((self.0 as f32) / (u8::MAX as f32)).clamp(0.0, 1.0)
19    }
20}
21
22impl From<DualsenseAxisValue> for AxisValue {
23    fn from(val: DualsenseAxisValue) -> Self {
24        AxisValue(val.into())
25    }
26}
27
28impl From<u8> for AxisValue {
29    fn from(val: u8) -> Self {
30        AxisValue(val)
31    }
32}
33
34impl From<Radians> for AxisValue {
35    /// Converts an angle in the [-PI, PI] range into an AxisValue
36    fn from(val: Radians) -> Self {
37        let value = ((val.get_angle() / PI) + 0.5) * (u8::MAX as f32);
38        AxisValue(value as u8)
39    }
40}
41
42#[test]
43fn axis_value_from_dualsense_value() {
44    let ds_values: [DualsenseAxisValue; 5] = [0, 100, 128, 200, 255].map(|v| v.into());
45    let expected_values: [AxisValue; 5] = [0, 100, 128, 200, 255].map(|v| v.into());
46    let got_values: [AxisValue; 5] = ds_values.map(|v| v.into());
47
48    assert_eq!(expected_values, got_values)
49}
50
51#[test]
52fn axis_value_from_radians() {
53    let radians_values: [Radians; _] =
54        [0., PI, PI / 2., PI * 3. / 2., PI * 2., -PI / 2.].map(|v| v.into());
55    let expected_values: [AxisValue; _] = [127, 255, 255, 255, 255, 0].map(|v| v.into());
56    let got_values: [AxisValue; _] = radians_values.map(|v| v.into());
57
58    assert_eq!(expected_values, got_values)
59}