ソースを参照

core/hid: Fully emulate motion from button

german77 4 年 前
コミット
136eb9c4c2

+ 5 - 0
src/common/input.h

@@ -110,9 +110,14 @@ struct MotionSensor {
 };
 
 struct MotionStatus {
+    // Gyroscope vector measurement in radians/s.
     MotionSensor gyro{};
+    // Acceleration vector measurement in G force
     MotionSensor accel{};
+    // Time since last measurement in microseconds
     u64 delta_timestamp{};
+    // Request to update after reading the value
+    bool force_update{};
 };
 
 struct TouchStatus {

+ 10 - 1
src/core/hid/emulated_controller.cpp

@@ -644,6 +644,7 @@ void EmulatedController::SetMotion(Common::Input::CallbackStatus callback, std::
     });
     emulated.UpdateRotation(raw_status.delta_timestamp);
     emulated.UpdateOrientation(raw_status.delta_timestamp);
+    force_update_motion = raw_status.force_update;
 
     if (is_configuring) {
         TriggerOnChange(ControllerTriggerType::Motion, false);
@@ -653,7 +654,7 @@ void EmulatedController::SetMotion(Common::Input::CallbackStatus callback, std::
     auto& motion = controller.motion_state[index];
     motion.accel = emulated.GetAcceleration();
     motion.gyro = emulated.GetGyroscope();
-    motion.rotation = emulated.GetGyroscope();
+    motion.rotation = emulated.GetRotations();
     motion.orientation = emulated.GetOrientation();
     motion.is_at_rest = emulated.IsMoving(motion_sensitivity);
 
@@ -962,6 +963,14 @@ NpadGcTriggerState EmulatedController::GetTriggers() const {
 }
 
 MotionState EmulatedController::GetMotions() const {
+    if (force_update_motion) {
+        for (auto& device : motion_devices) {
+            if (!device) {
+                continue;
+            }
+            device->ForceUpdate();
+        }
+    }
     return controller.motion_state;
 }
 

+ 1 - 0
src/core/hid/emulated_controller.h

@@ -355,6 +355,7 @@ private:
     bool is_connected{false};
     bool is_configuring{false};
     f32 motion_sensitivity{0.01f};
+    bool force_update_motion{false};
 
     // Temporary values to avoid doing changes while the controller is on configuration mode
     NpadType tmp_npad_type{NpadType::None};

+ 43 - 35
src/core/hid/input_converter.cpp

@@ -74,45 +74,53 @@ Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatu
     Common::Input::MotionStatus status{};
     switch (callback.type) {
     case Common::Input::InputType::Button: {
+        Common::Input::AnalogProperties properties{
+            .deadzone = 0.0f,
+            .range = 1.0f,
+            .offset = 0.0f,
+        };
+        status.delta_timestamp = 5000;
+        status.force_update = true;
+        status.accel.x = {
+            .value = 0.0f,
+            .raw_value = 0.0f,
+            .properties = properties,
+        };
+        status.accel.y = {
+            .value = 0.0f,
+            .raw_value = 0.0f,
+            .properties = properties,
+        };
+        status.accel.z = {
+            .value = 0.0f,
+            .raw_value = -1.0f,
+            .properties = properties,
+        };
+        status.gyro.x = {
+            .value = 0.0f,
+            .raw_value = 0.0f,
+            .properties = properties,
+        };
+        status.gyro.y = {
+            .value = 0.0f,
+            .raw_value = 0.0f,
+            .properties = properties,
+        };
+        status.gyro.z = {
+            .value = 0.0f,
+            .raw_value = 0.0f,
+            .properties = properties,
+        };
         if (TransformToButton(callback).value) {
             std::random_device device;
             std::mt19937 gen(device());
             std::uniform_int_distribution<s16> distribution(-1000, 1000);
-            Common::Input::AnalogProperties properties{
-                .deadzone = 0.0,
-                .range = 1.0f,
-                .offset = 0.0,
-            };
-            status.accel.x = {
-                .value = 0,
-                .raw_value = static_cast<f32>(distribution(gen)) * 0.001f,
-                .properties = properties,
-            };
-            status.accel.y = {
-                .value = 0,
-                .raw_value = static_cast<f32>(distribution(gen)) * 0.001f,
-                .properties = properties,
-            };
-            status.accel.z = {
-                .value = 0,
-                .raw_value = static_cast<f32>(distribution(gen)) * 0.001f,
-                .properties = properties,
-            };
-            status.gyro.x = {
-                .value = 0,
-                .raw_value = static_cast<f32>(distribution(gen)) * 0.001f,
-                .properties = properties,
-            };
-            status.gyro.y = {
-                .value = 0,
-                .raw_value = static_cast<f32>(distribution(gen)) * 0.001f,
-                .properties = properties,
-            };
-            status.gyro.z = {
-                .value = 0,
-                .raw_value = static_cast<f32>(distribution(gen)) * 0.001f,
-                .properties = properties,
-            };
+            status.accel.x.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
+            status.accel.y.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
+            status.accel.z.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
+            status.gyro.x.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
+            status.gyro.y.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
+            status.gyro.z.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
         }
         break;
     }

+ 16 - 0
src/core/hid/motion_input.h

@@ -56,15 +56,31 @@ private:
     Common::Vec3f integral_error;
     Common::Vec3f derivative_error;
 
+    // Quaternion containing the device orientation
     Common::Quaternion<f32> quat{{0.0f, 0.0f, -1.0f}, 0.0f};
+
+    // Number of full rotations in each axis
     Common::Vec3f rotations;
+
+    // Acceleration vector measurement in G force
     Common::Vec3f accel;
+
+    // Gyroscope vector measurement in radians/s.
     Common::Vec3f gyro;
+
+    // Vector to be substracted from gyro measurements
     Common::Vec3f gyro_drift;
 
+    // Minimum gyro amplitude to detect if the device is moving
     f32 gyro_threshold = 0.0f;
+
+    // Number of invalid sequential data
     u32 reset_counter = 0;
+
+    // If the provided data is invalid the device will be autocalibrated
     bool reset_enabled = true;
+
+    // Use accelerometer values to calculate position
     bool only_accelerometer = true;
 };
 

+ 12 - 0
src/input_common/helpers/stick_from_buttons.cpp

@@ -36,6 +36,8 @@ public:
         left->SetCallback(button_left_callback);
         right->SetCallback(button_right_callback);
         modifier->SetCallback(button_modifier_callback);
+        last_x_axis_value = 0.0f;
+        last_y_axis_value = 0.0f;
     }
 
     bool IsAngleGreater(float old_angle, float new_angle) const {
@@ -199,6 +201,8 @@ public:
             .type = Common::Input::InputType::Stick,
             .stick_status = GetStatus(),
         };
+        last_x_axis_value = status.stick_status.x.raw_value;
+        last_y_axis_value = status.stick_status.y.raw_value;
         TriggerOnChange(status);
     }
 
@@ -215,6 +219,12 @@ public:
             .type = Common::Input::InputType::Stick,
             .stick_status = GetStatus(),
         };
+        if (last_x_axis_value == status.stick_status.x.raw_value &&
+            last_y_axis_value == status.stick_status.y.raw_value) {
+            return;
+        }
+        last_x_axis_value = status.stick_status.x.raw_value;
+        last_y_axis_value = status.stick_status.y.raw_value;
         TriggerOnChange(status);
     }
 
@@ -265,6 +275,8 @@ private:
     bool left_status;
     bool right_status;
     bool modifier_status;
+    float last_x_axis_value;
+    float last_y_axis_value;
     const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false};
     std::chrono::time_point<std::chrono::steady_clock> last_update;
 };

+ 10 - 1
src/input_common/helpers/touch_from_buttons.cpp

@@ -16,10 +16,15 @@ public:
         : button(std::move(button_)), touch_id(touch_id_), x(x_), y(y_) {
         Common::Input::InputCallback button_up_callback{
             [this](Common::Input::CallbackStatus callback_) { UpdateButtonStatus(callback_); }};
+        last_button_value = false;
         button->SetCallback(button_up_callback);
         button->ForceUpdate();
     }
 
+    void ForceUpdate() override {
+        button->ForceUpdate();
+    }
+
     Common::Input::TouchStatus GetStatus(bool pressed) const {
         const Common::Input::ButtonStatus button_status{
             .value = pressed,
@@ -47,11 +52,15 @@ public:
             .type = Common::Input::InputType::Touch,
             .touch_status = GetStatus(button_callback.button_status.value),
         };
-        TriggerOnChange(status);
+        if (last_button_value != button_callback.button_status.value) {
+            last_button_value = button_callback.button_status.value;
+            TriggerOnChange(status);
+        }
     }
 
 private:
     Button button;
+    bool last_button_value;
     const int touch_id;
     const float x;
     const float y;