diff --git a/src/common/input.h b/src/common/input.h index 66fb15f0a..bccccaa1c 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -24,6 +24,7 @@ enum class InputType { Analog, Trigger, Motion, + VirtualMotion, Touch, Color, Vibration, diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 4ccb1c596..1489ff786 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -5,6 +5,8 @@ #include #include "common/input.h" +#include "common/math_util.h" +#include "common/quaternion.h" #include "core/hid/input_converter.h" namespace Core::HID { @@ -81,7 +83,7 @@ Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatu Common::Input::MotionStatus status{}; switch (callback.type) { case Common::Input::InputType::Button: { - Common::Input::AnalogProperties properties{ + const Common::Input::AnalogProperties properties{ .deadzone = 0.0f, .range = 1.0f, .offset = 0.0f, @@ -93,31 +95,18 @@ Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatu .raw_value = 0.0f, .properties = properties, }; - status.accel.y = { - .value = 0.0f, - .raw_value = 0.0f, - .properties = properties, - }; + status.delta_timestamp = 5000; + status.force_update = true; + status.accel.x = default_analog_status; + status.accel.y = default_analog_status; 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, - }; + status.gyro.x = default_analog_status; + status.gyro.y = default_analog_status; + status.gyro.z = default_analog_status; if (TransformToButton(callback).value) { std::random_device device; std::mt19937 gen(device()); @@ -134,6 +123,9 @@ Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatu case Common::Input::InputType::Motion: status = callback.motion_status; break; + case Common::Input::InputType::VirtualMotion: + status = GetVirtualMotion(callback.motion_status); + break; default: LOG_ERROR(Input, "Conversion from type {} to motion not implemented", callback.type); break; @@ -437,4 +429,32 @@ void SanitizeStick(Common::Input::AnalogStatus& analog_x, Common::Input::AnalogS } } +Common::Input::MotionStatus GetVirtualMotion(Common::Input::MotionStatus input_data, + Common::Vec3f last_giro) { + Common::Input::MotionStatus motion_status = input_data; + + // Axis data is stored in the gyro value + float wx = input_data.gyro.x.raw_value; + float wy = input_data.gyro.y.raw_value; + + float rotX = (wy * 2 - 1.0f) * 135.0f; // up/down best + float rotY = (wx * 2 - 1.0f) * -180.0f; // left/right + float rotZ = input_data.gyro.y.raw_value * 14.0f + m_lastGyroRotation.z; + + Common::Vec3f rotation(rotX - m_lastGyroRotation.x, (rotY - m_lastGyroRotation.y) * 15.0f, + rotZ - m_lastGyroRotation.z); + + rotation.x = std::min(1.0f, std::max(-1.0f, rotation.x / 360.0f)); + rotation.y = std::min(1.0f, std::max(-1.0f, rotation.y / 360.0f)); + rotation.z = std::min(1.0f, std::max(-1.0f, rotation.z / 360.0f)); + + motion_status.gyro.x.raw_value = rotation.x; + motion_status.gyro.y.raw_value = rotation.y; + motion_status.gyro.z.raw_value = rotation.z; + + motion_status.accel.x.raw_value = 0.0f; + motion_status.accel.y.raw_value = 0.0f; + motion_status.accel.z.raw_value = -1.0f; +} + } // namespace Core::HID diff --git a/src/core/hid/input_converter.h b/src/core/hid/input_converter.h index c51c03e57..2a01b40d5 100644 --- a/src/core/hid/input_converter.h +++ b/src/core/hid/input_converter.h @@ -116,4 +116,21 @@ void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value); void SanitizeStick(Common::Input::AnalogStatus& analog_x, Common::Input::AnalogStatus& analog_y, bool clamp_value); +/** + * Converts raw stick data into a valid stick value + * @param analog_x raw analog data and properties for the x-axis + * @param analog_y raw analog data and properties for the y-axis + * @param clamp_value bool that determines if the value needs to be clamped into the unit circle. + */ +void SanitizeStick(Common::Input::AnalogStatus& analog_x, Common::Input::AnalogStatus& analog_y, + bool clamp_value); + +/** + * Calculates the accelerometer value needed to reach the axis position as if it was a pointer to a screen + * + * @param input_data Motion status containing the position of all 3 axis + * @return Motion status with accelerometer data + */ +Common::Input::MotionStatus GetVirtualMotion(Common::Input::MotionStatus input_data); + } // namespace Core::HID diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 380a01542..bb8d9bc90 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -674,7 +674,7 @@ public: void ForceUpdate() override { const Common::Input::CallbackStatus status{ - .type = Common::Input::InputType::Motion, + .type = Common::Input::InputType::VirtualMotion, .motion_status = GetStatus(), }; @@ -686,7 +686,7 @@ public: void OnChange() { const Common::Input::CallbackStatus status{ - .type = Common::Input::InputType::Motion, + .type = Common::Input::InputType::VirtualMotion, .motion_status = GetStatus(), }; @@ -1039,21 +1039,28 @@ std::unique_ptr InputFactory::CreateColorDevice( } std::unique_ptr InputFactory::CreateMotionDevice( - Common::ParamPackage params) { + const Common::ParamPackage& params) { const PadIdentifier identifier = { .guid = Common::UUID{params.Get("guid", "")}, .port = static_cast(params.Get("port", 0)), .pad = static_cast(params.Get("pad", 0)), }; - if (params.Has("motion")) { - const auto motion_sensor = params.Get("motion", 0); - const auto gyro_threshold = params.Get("threshold", 0.007f); - input_engine->PreSetController(identifier); - input_engine->PreSetMotion(identifier, motion_sensor); - return std::make_unique(identifier, motion_sensor, gyro_threshold, - input_engine.get()); - } + const auto motion_sensor = params.Get("motion", 0); + const auto gyro_threshold = params.Get("threshold", 0.007f); + input_engine->PreSetController(identifier); + input_engine->PreSetMotion(identifier, motion_sensor); + return std::make_unique(identifier, motion_sensor, gyro_threshold, + input_engine.get()); +} + +std::unique_ptr InputFactory::CreateVirtualMotionDevice( + const Common::ParamPackage& params) { + const PadIdentifier identifier = { + .guid = Common::UUID{params.Get("guid", "")}, + .port = static_cast(params.Get("port", 0)), + .pad = static_cast(params.Get("pad", 0)), + }; const auto deadzone = std::clamp(params.Get("deadzone", 0.15f), 0.0f, 1.0f); const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f); @@ -1147,7 +1154,7 @@ std::unique_ptr InputFactory::Create( return CreateHatButtonDevice(params); } if (params.Has("axis_x") && params.Has("axis_y") && params.Has("axis_z")) { - return CreateMotionDevice(params); + return CreateVirtualMotionDevice(params); } if (params.Has("motion")) { return CreateMotionDevice(params); diff --git a/src/input_common/input_poller.h b/src/input_common/input_poller.h index e097e254c..d07cc97c6 100644 --- a/src/input_common/input_poller.h +++ b/src/input_common/input_poller.h @@ -204,6 +204,19 @@ private: /** * Creates a motion device from the parameters given. * @param params contains parameters for creating the device: + * - "motion": index of the motion sensor + * - "threshold": gyro deadzone to avoid drifting + * - "guid": text string for identifying controllers + * - "port": port of the connected device + * - "pad": slot of the connected controller + * @returns a unique input device with the parameters specified + */ + std::unique_ptr CreateMotionDevice( + const Common::ParamPackage& params); + + /** + * Creates a virtual motion device from the parameters given. + * @param params contains parameters for creating the device: * - "axis_x": the controller horizontal axis id to bind with the input * - "axis_y": the controller vertical axis id to bind with the input * - "axis_z": the controller forward axis id to bind with the input @@ -220,7 +233,8 @@ private: * - "pad": slot of the connected controller * @returns a unique input device with the parameters specified */ - std::unique_ptr CreateMotionDevice(Common::ParamPackage params); + std::unique_ptr CreateVirtualMotionDevice( + const Common::ParamPackage& params); /** * Creates a camera device from the parameters given.