diff options
Diffstat (limited to 'src/input_common')
| -rw-r--r-- | src/input_common/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/input_common/gcadapter/gc_adapter.cpp | 2 | ||||
| -rw-r--r-- | src/input_common/gcadapter/gc_adapter.h | 2 | ||||
| -rw-r--r-- | src/input_common/gcadapter/gc_poller.cpp | 22 | ||||
| -rw-r--r-- | src/input_common/main.cpp | 11 | ||||
| -rw-r--r-- | src/input_common/main.h | 3 | ||||
| -rw-r--r-- | src/input_common/motion_input.cpp | 181 | ||||
| -rw-r--r-- | src/input_common/motion_input.h | 68 | ||||
| -rw-r--r-- | src/input_common/sdl/sdl_impl.cpp | 114 | ||||
| -rw-r--r-- | src/input_common/touch_from_button.cpp | 50 | ||||
| -rw-r--r-- | src/input_common/touch_from_button.h | 23 |
11 files changed, 416 insertions, 64 deletions
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 56267c8a8..09361e37e 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt | |||
| @@ -7,8 +7,12 @@ add_library(input_common STATIC | |||
| 7 | main.h | 7 | main.h |
| 8 | motion_emu.cpp | 8 | motion_emu.cpp |
| 9 | motion_emu.h | 9 | motion_emu.h |
| 10 | motion_input.cpp | ||
| 11 | motion_input.h | ||
| 10 | settings.cpp | 12 | settings.cpp |
| 11 | settings.h | 13 | settings.h |
| 14 | touch_from_button.cpp | ||
| 15 | touch_from_button.h | ||
| 12 | gcadapter/gc_adapter.cpp | 16 | gcadapter/gc_adapter.cpp |
| 13 | gcadapter/gc_adapter.h | 17 | gcadapter/gc_adapter.h |
| 14 | gcadapter/gc_poller.cpp | 18 | gcadapter/gc_poller.cpp |
diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp index 74759ea7d..c6c423c4b 100644 --- a/src/input_common/gcadapter/gc_adapter.cpp +++ b/src/input_common/gcadapter/gc_adapter.cpp | |||
| @@ -283,7 +283,7 @@ void Adapter::Reset() { | |||
| 283 | } | 283 | } |
| 284 | } | 284 | } |
| 285 | 285 | ||
| 286 | bool Adapter::DeviceConnected(std::size_t port) { | 286 | bool Adapter::DeviceConnected(std::size_t port) const { |
| 287 | return adapter_controllers_status[port] != ControllerTypes::None; | 287 | return adapter_controllers_status[port] != ControllerTypes::None; |
| 288 | } | 288 | } |
| 289 | 289 | ||
diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h index bed81915c..20e97d283 100644 --- a/src/input_common/gcadapter/gc_adapter.h +++ b/src/input_common/gcadapter/gc_adapter.h | |||
| @@ -76,7 +76,7 @@ public: | |||
| 76 | void EndConfiguration(); | 76 | void EndConfiguration(); |
| 77 | 77 | ||
| 78 | /// Returns true if there is a device connected to port | 78 | /// Returns true if there is a device connected to port |
| 79 | bool DeviceConnected(std::size_t port); | 79 | bool DeviceConnected(std::size_t port) const; |
| 80 | 80 | ||
| 81 | std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue(); | 81 | std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue(); |
| 82 | const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const; | 82 | const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const; |
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp index 71cd85eeb..92e9e8e89 100644 --- a/src/input_common/gcadapter/gc_poller.cpp +++ b/src/input_common/gcadapter/gc_poller.cpp | |||
| @@ -15,7 +15,7 @@ namespace InputCommon { | |||
| 15 | 15 | ||
| 16 | class GCButton final : public Input::ButtonDevice { | 16 | class GCButton final : public Input::ButtonDevice { |
| 17 | public: | 17 | public: |
| 18 | explicit GCButton(int port_, int button_, GCAdapter::Adapter* adapter) | 18 | explicit GCButton(int port_, int button_, const GCAdapter::Adapter* adapter) |
| 19 | : port(port_), button(button_), gcadapter(adapter) {} | 19 | : port(port_), button(button_), gcadapter(adapter) {} |
| 20 | 20 | ||
| 21 | ~GCButton() override; | 21 | ~GCButton() override; |
| @@ -30,15 +30,16 @@ public: | |||
| 30 | private: | 30 | private: |
| 31 | const int port; | 31 | const int port; |
| 32 | const int button; | 32 | const int button; |
| 33 | GCAdapter::Adapter* gcadapter; | 33 | const GCAdapter::Adapter* gcadapter; |
| 34 | }; | 34 | }; |
| 35 | 35 | ||
| 36 | class GCAxisButton final : public Input::ButtonDevice { | 36 | class GCAxisButton final : public Input::ButtonDevice { |
| 37 | public: | 37 | public: |
| 38 | explicit GCAxisButton(int port_, int axis_, float threshold_, bool trigger_if_greater_, | 38 | explicit GCAxisButton(int port_, int axis_, float threshold_, bool trigger_if_greater_, |
| 39 | GCAdapter::Adapter* adapter) | 39 | const GCAdapter::Adapter* adapter) |
| 40 | : port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_), | 40 | : port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_), |
| 41 | gcadapter(adapter), origin_value(adapter->GetOriginValue(port_, axis_)) {} | 41 | gcadapter(adapter), |
| 42 | origin_value(static_cast<float>(adapter->GetOriginValue(port_, axis_))) {} | ||
| 42 | 43 | ||
| 43 | bool GetStatus() const override { | 44 | bool GetStatus() const override { |
| 44 | if (gcadapter->DeviceConnected(port)) { | 45 | if (gcadapter->DeviceConnected(port)) { |
| @@ -59,7 +60,7 @@ private: | |||
| 59 | const int axis; | 60 | const int axis; |
| 60 | float threshold; | 61 | float threshold; |
| 61 | bool trigger_if_greater; | 62 | bool trigger_if_greater; |
| 62 | GCAdapter::Adapter* gcadapter; | 63 | const GCAdapter::Adapter* gcadapter; |
| 63 | const float origin_value; | 64 | const float origin_value; |
| 64 | }; | 65 | }; |
| 65 | 66 | ||
| @@ -148,11 +149,12 @@ void GCButtonFactory::EndConfiguration() { | |||
| 148 | 149 | ||
| 149 | class GCAnalog final : public Input::AnalogDevice { | 150 | class GCAnalog final : public Input::AnalogDevice { |
| 150 | public: | 151 | public: |
| 151 | GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter, | 152 | GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, |
| 152 | float range_) | 153 | const GCAdapter::Adapter* adapter, float range_) |
| 153 | : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter), | 154 | : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter), |
| 154 | origin_value_x(adapter->GetOriginValue(port_, axis_x_)), | 155 | origin_value_x(static_cast<float>(adapter->GetOriginValue(port_, axis_x_))), |
| 155 | origin_value_y(adapter->GetOriginValue(port_, axis_y_)), range(range_) {} | 156 | origin_value_y(static_cast<float>(adapter->GetOriginValue(port_, axis_y_))), |
| 157 | range(range_) {} | ||
| 156 | 158 | ||
| 157 | float GetAxis(int axis) const { | 159 | float GetAxis(int axis) const { |
| 158 | if (gcadapter->DeviceConnected(port)) { | 160 | if (gcadapter->DeviceConnected(port)) { |
| @@ -210,7 +212,7 @@ private: | |||
| 210 | const int axis_x; | 212 | const int axis_x; |
| 211 | const int axis_y; | 213 | const int axis_y; |
| 212 | const float deadzone; | 214 | const float deadzone; |
| 213 | GCAdapter::Adapter* gcadapter; | 215 | const GCAdapter::Adapter* gcadapter; |
| 214 | const float origin_value_x; | 216 | const float origin_value_x; |
| 215 | const float origin_value_y; | 217 | const float origin_value_y; |
| 216 | const float range; | 218 | const float range; |
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 57e7a25fe..ea1a1cee6 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include "input_common/keyboard.h" | 11 | #include "input_common/keyboard.h" |
| 12 | #include "input_common/main.h" | 12 | #include "input_common/main.h" |
| 13 | #include "input_common/motion_emu.h" | 13 | #include "input_common/motion_emu.h" |
| 14 | #include "input_common/touch_from_button.h" | ||
| 14 | #include "input_common/udp/udp.h" | 15 | #include "input_common/udp/udp.h" |
| 15 | #ifdef HAVE_SDL2 | 16 | #ifdef HAVE_SDL2 |
| 16 | #include "input_common/sdl/sdl.h" | 17 | #include "input_common/sdl/sdl.h" |
| @@ -32,6 +33,8 @@ struct InputSubsystem::Impl { | |||
| 32 | std::make_shared<AnalogFromButton>()); | 33 | std::make_shared<AnalogFromButton>()); |
| 33 | motion_emu = std::make_shared<MotionEmu>(); | 34 | motion_emu = std::make_shared<MotionEmu>(); |
| 34 | Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu); | 35 | Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu); |
| 36 | Input::RegisterFactory<Input::TouchDevice>("touch_from_button", | ||
| 37 | std::make_shared<TouchFromButtonFactory>()); | ||
| 35 | 38 | ||
| 36 | #ifdef HAVE_SDL2 | 39 | #ifdef HAVE_SDL2 |
| 37 | sdl = SDL::Init(); | 40 | sdl = SDL::Init(); |
| @@ -46,6 +49,7 @@ struct InputSubsystem::Impl { | |||
| 46 | Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button"); | 49 | Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button"); |
| 47 | Input::UnregisterFactory<Input::MotionDevice>("motion_emu"); | 50 | Input::UnregisterFactory<Input::MotionDevice>("motion_emu"); |
| 48 | motion_emu.reset(); | 51 | motion_emu.reset(); |
| 52 | Input::UnregisterFactory<Input::TouchDevice>("touch_from_button"); | ||
| 49 | #ifdef HAVE_SDL2 | 53 | #ifdef HAVE_SDL2 |
| 50 | sdl.reset(); | 54 | sdl.reset(); |
| 51 | #endif | 55 | #endif |
| @@ -171,6 +175,13 @@ const GCButtonFactory* InputSubsystem::GetGCButtons() const { | |||
| 171 | return impl->gcbuttons.get(); | 175 | return impl->gcbuttons.get(); |
| 172 | } | 176 | } |
| 173 | 177 | ||
| 178 | void InputSubsystem::ReloadInputDevices() { | ||
| 179 | if (!impl->udp) { | ||
| 180 | return; | ||
| 181 | } | ||
| 182 | impl->udp->ReloadUDPClient(); | ||
| 183 | } | ||
| 184 | |||
| 174 | std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers( | 185 | std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers( |
| 175 | Polling::DeviceType type) const { | 186 | Polling::DeviceType type) const { |
| 176 | #ifdef HAVE_SDL2 | 187 | #ifdef HAVE_SDL2 |
diff --git a/src/input_common/main.h b/src/input_common/main.h index 58e5dc250..f3fbf696e 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h | |||
| @@ -115,6 +115,9 @@ public: | |||
| 115 | /// Retrieves the underlying GameCube button handler. | 115 | /// Retrieves the underlying GameCube button handler. |
| 116 | [[nodiscard]] const GCButtonFactory* GetGCButtons() const; | 116 | [[nodiscard]] const GCButtonFactory* GetGCButtons() const; |
| 117 | 117 | ||
| 118 | /// Reloads the input devices | ||
| 119 | void ReloadInputDevices(); | ||
| 120 | |||
| 118 | /// Get all DevicePoller from all backends for a specific device type | 121 | /// Get all DevicePoller from all backends for a specific device type |
| 119 | [[nodiscard]] std::vector<std::unique_ptr<Polling::DevicePoller>> GetPollers( | 122 | [[nodiscard]] std::vector<std::unique_ptr<Polling::DevicePoller>> GetPollers( |
| 120 | Polling::DeviceType type) const; | 123 | Polling::DeviceType type) const; |
diff --git a/src/input_common/motion_input.cpp b/src/input_common/motion_input.cpp new file mode 100644 index 000000000..22a849866 --- /dev/null +++ b/src/input_common/motion_input.cpp | |||
| @@ -0,0 +1,181 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included | ||
| 4 | |||
| 5 | #include "common/math_util.h" | ||
| 6 | #include "input_common/motion_input.h" | ||
| 7 | |||
| 8 | namespace InputCommon { | ||
| 9 | |||
| 10 | MotionInput::MotionInput(f32 new_kp, f32 new_ki, f32 new_kd) | ||
| 11 | : kp(new_kp), ki(new_ki), kd(new_kd), quat{{0, 0, -1}, 0} {} | ||
| 12 | |||
| 13 | void MotionInput::SetAcceleration(const Common::Vec3f& acceleration) { | ||
| 14 | accel = acceleration; | ||
| 15 | } | ||
| 16 | |||
| 17 | void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) { | ||
| 18 | gyro = gyroscope - gyro_drift; | ||
| 19 | if (gyro.Length2() < gyro_threshold) { | ||
| 20 | gyro = {}; | ||
| 21 | } | ||
| 22 | } | ||
| 23 | |||
| 24 | void MotionInput::SetQuaternion(const Common::Quaternion<f32>& quaternion) { | ||
| 25 | quat = quaternion; | ||
| 26 | } | ||
| 27 | |||
| 28 | void MotionInput::SetGyroDrift(const Common::Vec3f& drift) { | ||
| 29 | gyro_drift = drift; | ||
| 30 | } | ||
| 31 | |||
| 32 | void MotionInput::SetGyroThreshold(f32 threshold) { | ||
| 33 | gyro_threshold = threshold; | ||
| 34 | } | ||
| 35 | |||
| 36 | void MotionInput::EnableReset(bool reset) { | ||
| 37 | reset_enabled = reset; | ||
| 38 | } | ||
| 39 | |||
| 40 | void MotionInput::ResetRotations() { | ||
| 41 | rotations = {}; | ||
| 42 | } | ||
| 43 | |||
| 44 | bool MotionInput::IsMoving(f32 sensitivity) const { | ||
| 45 | return gyro.Length() >= sensitivity || accel.Length() <= 0.9f || accel.Length() >= 1.1f; | ||
| 46 | } | ||
| 47 | |||
| 48 | bool MotionInput::IsCalibrated(f32 sensitivity) const { | ||
| 49 | return real_error.Length() < sensitivity; | ||
| 50 | } | ||
| 51 | |||
| 52 | void MotionInput::UpdateRotation(u64 elapsed_time) { | ||
| 53 | const f32 sample_period = elapsed_time / 1000000.0f; | ||
| 54 | if (sample_period > 0.1f) { | ||
| 55 | return; | ||
| 56 | } | ||
| 57 | rotations += gyro * sample_period; | ||
| 58 | } | ||
| 59 | |||
| 60 | void MotionInput::UpdateOrientation(u64 elapsed_time) { | ||
| 61 | if (!IsCalibrated(0.1f)) { | ||
| 62 | ResetOrientation(); | ||
| 63 | } | ||
| 64 | // Short name local variable for readability | ||
| 65 | f32 q1 = quat.w; | ||
| 66 | f32 q2 = quat.xyz[0]; | ||
| 67 | f32 q3 = quat.xyz[1]; | ||
| 68 | f32 q4 = quat.xyz[2]; | ||
| 69 | const f32 sample_period = elapsed_time / 1000000.0f; | ||
| 70 | |||
| 71 | // ignore invalid elapsed time | ||
| 72 | if (sample_period > 0.1f) { | ||
| 73 | return; | ||
| 74 | } | ||
| 75 | |||
| 76 | const auto normal_accel = accel.Normalized(); | ||
| 77 | auto rad_gyro = gyro * Common::PI * 2; | ||
| 78 | const f32 swap = rad_gyro.x; | ||
| 79 | rad_gyro.x = rad_gyro.y; | ||
| 80 | rad_gyro.y = -swap; | ||
| 81 | rad_gyro.z = -rad_gyro.z; | ||
| 82 | |||
| 83 | // Ignore drift correction if acceleration is not reliable | ||
| 84 | if (accel.Length() >= 0.75f && accel.Length() <= 1.25f) { | ||
| 85 | const f32 ax = -normal_accel.x; | ||
| 86 | const f32 ay = normal_accel.y; | ||
| 87 | const f32 az = -normal_accel.z; | ||
| 88 | |||
| 89 | // Estimated direction of gravity | ||
| 90 | const f32 vx = 2.0f * (q2 * q4 - q1 * q3); | ||
| 91 | const f32 vy = 2.0f * (q1 * q2 + q3 * q4); | ||
| 92 | const f32 vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4; | ||
| 93 | |||
| 94 | // Error is cross product between estimated direction and measured direction of gravity | ||
| 95 | const Common::Vec3f new_real_error = {az * vx - ax * vz, ay * vz - az * vy, | ||
| 96 | ax * vy - ay * vx}; | ||
| 97 | |||
| 98 | derivative_error = new_real_error - real_error; | ||
| 99 | real_error = new_real_error; | ||
| 100 | |||
| 101 | // Prevent integral windup | ||
| 102 | if (ki != 0.0f && !IsCalibrated(0.05f)) { | ||
| 103 | integral_error += real_error; | ||
| 104 | } else { | ||
| 105 | integral_error = {}; | ||
| 106 | } | ||
| 107 | |||
| 108 | // Apply feedback terms | ||
| 109 | rad_gyro += kp * real_error; | ||
| 110 | rad_gyro += ki * integral_error; | ||
| 111 | rad_gyro += kd * derivative_error; | ||
| 112 | } | ||
| 113 | |||
| 114 | const f32 gx = rad_gyro.y; | ||
| 115 | const f32 gy = rad_gyro.x; | ||
| 116 | const f32 gz = rad_gyro.z; | ||
| 117 | |||
| 118 | // Integrate rate of change of quaternion | ||
| 119 | const f32 pa = q2; | ||
| 120 | const f32 pb = q3; | ||
| 121 | const f32 pc = q4; | ||
| 122 | q1 = q1 + (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * sample_period); | ||
| 123 | q2 = pa + (q1 * gx + pb * gz - pc * gy) * (0.5f * sample_period); | ||
| 124 | q3 = pb + (q1 * gy - pa * gz + pc * gx) * (0.5f * sample_period); | ||
| 125 | q4 = pc + (q1 * gz + pa * gy - pb * gx) * (0.5f * sample_period); | ||
| 126 | |||
| 127 | quat.w = q1; | ||
| 128 | quat.xyz[0] = q2; | ||
| 129 | quat.xyz[1] = q3; | ||
| 130 | quat.xyz[2] = q4; | ||
| 131 | quat = quat.Normalized(); | ||
| 132 | } | ||
| 133 | |||
| 134 | std::array<Common::Vec3f, 3> MotionInput::GetOrientation() const { | ||
| 135 | const Common::Quaternion<float> quad{ | ||
| 136 | .xyz = {-quat.xyz[1], -quat.xyz[0], -quat.w}, | ||
| 137 | .w = -quat.xyz[2], | ||
| 138 | }; | ||
| 139 | const std::array<float, 16> matrix4x4 = quad.ToMatrix(); | ||
| 140 | |||
| 141 | return {Common::Vec3f(matrix4x4[0], matrix4x4[1], -matrix4x4[2]), | ||
| 142 | Common::Vec3f(matrix4x4[4], matrix4x4[5], -matrix4x4[6]), | ||
| 143 | Common::Vec3f(-matrix4x4[8], -matrix4x4[9], matrix4x4[10])}; | ||
| 144 | } | ||
| 145 | |||
| 146 | Common::Vec3f MotionInput::GetAcceleration() const { | ||
| 147 | return accel; | ||
| 148 | } | ||
| 149 | |||
| 150 | Common::Vec3f MotionInput::GetGyroscope() const { | ||
| 151 | return gyro; | ||
| 152 | } | ||
| 153 | |||
| 154 | Common::Quaternion<f32> MotionInput::GetQuaternion() const { | ||
| 155 | return quat; | ||
| 156 | } | ||
| 157 | |||
| 158 | Common::Vec3f MotionInput::GetRotations() const { | ||
| 159 | return rotations; | ||
| 160 | } | ||
| 161 | |||
| 162 | void MotionInput::ResetOrientation() { | ||
| 163 | if (!reset_enabled) { | ||
| 164 | return; | ||
| 165 | } | ||
| 166 | if (!IsMoving(0.5f) && accel.z <= -0.9f) { | ||
| 167 | ++reset_counter; | ||
| 168 | if (reset_counter > 900) { | ||
| 169 | // TODO: calculate quaternion from gravity vector | ||
| 170 | quat.w = 0; | ||
| 171 | quat.xyz[0] = 0; | ||
| 172 | quat.xyz[1] = 0; | ||
| 173 | quat.xyz[2] = -1; | ||
| 174 | integral_error = {}; | ||
| 175 | reset_counter = 0; | ||
| 176 | } | ||
| 177 | } else { | ||
| 178 | reset_counter = 0; | ||
| 179 | } | ||
| 180 | } | ||
| 181 | } // namespace InputCommon | ||
diff --git a/src/input_common/motion_input.h b/src/input_common/motion_input.h new file mode 100644 index 000000000..54b4439d9 --- /dev/null +++ b/src/input_common/motion_input.h | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/quaternion.h" | ||
| 9 | #include "common/vector_math.h" | ||
| 10 | |||
| 11 | namespace InputCommon { | ||
| 12 | |||
| 13 | class MotionInput { | ||
| 14 | public: | ||
| 15 | MotionInput(f32 new_kp, f32 new_ki, f32 new_kd); | ||
| 16 | |||
| 17 | MotionInput(const MotionInput&) = default; | ||
| 18 | MotionInput& operator=(const MotionInput&) = default; | ||
| 19 | |||
| 20 | MotionInput(MotionInput&&) = default; | ||
| 21 | MotionInput& operator=(MotionInput&&) = default; | ||
| 22 | |||
| 23 | void SetAcceleration(const Common::Vec3f& acceleration); | ||
| 24 | void SetGyroscope(const Common::Vec3f& acceleration); | ||
| 25 | void SetQuaternion(const Common::Quaternion<f32>& quaternion); | ||
| 26 | void SetGyroDrift(const Common::Vec3f& drift); | ||
| 27 | void SetGyroThreshold(f32 threshold); | ||
| 28 | |||
| 29 | void EnableReset(bool reset); | ||
| 30 | void ResetRotations(); | ||
| 31 | |||
| 32 | void UpdateRotation(u64 elapsed_time); | ||
| 33 | void UpdateOrientation(u64 elapsed_time); | ||
| 34 | |||
| 35 | std::array<Common::Vec3f, 3> GetOrientation() const; | ||
| 36 | Common::Vec3f GetAcceleration() const; | ||
| 37 | Common::Vec3f GetGyroscope() const; | ||
| 38 | Common::Vec3f GetRotations() const; | ||
| 39 | Common::Quaternion<f32> GetQuaternion() const; | ||
| 40 | |||
| 41 | bool IsMoving(f32 sensitivity) const; | ||
| 42 | bool IsCalibrated(f32 sensitivity) const; | ||
| 43 | |||
| 44 | private: | ||
| 45 | void ResetOrientation(); | ||
| 46 | |||
| 47 | // PID constants | ||
| 48 | const f32 kp; | ||
| 49 | const f32 ki; | ||
| 50 | const f32 kd; | ||
| 51 | |||
| 52 | // PID errors | ||
| 53 | Common::Vec3f real_error; | ||
| 54 | Common::Vec3f integral_error; | ||
| 55 | Common::Vec3f derivative_error; | ||
| 56 | |||
| 57 | Common::Quaternion<f32> quat; | ||
| 58 | Common::Vec3f rotations; | ||
| 59 | Common::Vec3f accel; | ||
| 60 | Common::Vec3f gyro; | ||
| 61 | Common::Vec3f gyro_drift; | ||
| 62 | |||
| 63 | f32 gyro_threshold = 0.0f; | ||
| 64 | u32 reset_counter = 0; | ||
| 65 | bool reset_enabled = true; | ||
| 66 | }; | ||
| 67 | |||
| 68 | } // namespace InputCommon | ||
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index c8d9eb2bc..a9e676f4b 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <array> | ||
| 6 | #include <atomic> | 7 | #include <atomic> |
| 7 | #include <cmath> | 8 | #include <cmath> |
| 8 | #include <functional> | 9 | #include <functional> |
| @@ -358,7 +359,7 @@ public: | |||
| 358 | return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone), | 359 | return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone), |
| 359 | y / r * (r - deadzone) / (1 - deadzone)); | 360 | y / r * (r - deadzone) / (1 - deadzone)); |
| 360 | } | 361 | } |
| 361 | return std::make_tuple<float, float>(0.0f, 0.0f); | 362 | return {}; |
| 362 | } | 363 | } |
| 363 | 364 | ||
| 364 | bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { | 365 | bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { |
| @@ -574,10 +575,10 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() { | |||
| 574 | 575 | ||
| 575 | namespace { | 576 | namespace { |
| 576 | Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, u8 axis, | 577 | Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, u8 axis, |
| 577 | float value = 0.1) { | 578 | float value = 0.1f) { |
| 578 | Common::ParamPackage params({{"engine", "sdl"}}); | 579 | Common::ParamPackage params({{"engine", "sdl"}}); |
| 579 | params.Set("port", port); | 580 | params.Set("port", port); |
| 580 | params.Set("guid", guid); | 581 | params.Set("guid", std::move(guid)); |
| 581 | params.Set("axis", axis); | 582 | params.Set("axis", axis); |
| 582 | if (value > 0) { | 583 | if (value > 0) { |
| 583 | params.Set("direction", "+"); | 584 | params.Set("direction", "+"); |
| @@ -592,7 +593,7 @@ Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid | |||
| 592 | Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, u8 button) { | 593 | Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, u8 button) { |
| 593 | Common::ParamPackage params({{"engine", "sdl"}}); | 594 | Common::ParamPackage params({{"engine", "sdl"}}); |
| 594 | params.Set("port", port); | 595 | params.Set("port", port); |
| 595 | params.Set("guid", guid); | 596 | params.Set("guid", std::move(guid)); |
| 596 | params.Set("button", button); | 597 | params.Set("button", button); |
| 597 | return params; | 598 | return params; |
| 598 | } | 599 | } |
| @@ -601,7 +602,7 @@ Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, u | |||
| 601 | Common::ParamPackage params({{"engine", "sdl"}}); | 602 | Common::ParamPackage params({{"engine", "sdl"}}); |
| 602 | 603 | ||
| 603 | params.Set("port", port); | 604 | params.Set("port", port); |
| 604 | params.Set("guid", guid); | 605 | params.Set("guid", std::move(guid)); |
| 605 | params.Set("hat", hat); | 606 | params.Set("hat", hat); |
| 606 | switch (value) { | 607 | switch (value) { |
| 607 | case SDL_HAT_UP: | 608 | case SDL_HAT_UP: |
| @@ -670,55 +671,62 @@ Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& gui | |||
| 670 | } // Anonymous namespace | 671 | } // Anonymous namespace |
| 671 | 672 | ||
| 672 | ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& params) { | 673 | ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& params) { |
| 673 | // This list is missing ZL/ZR since those are not considered buttons in SDL GameController. | ||
| 674 | // We will add those afterwards | ||
| 675 | // This list also excludes Screenshot since theres not really a mapping for that | ||
| 676 | std::unordered_map<Settings::NativeButton::Values, SDL_GameControllerButton> | ||
| 677 | switch_to_sdl_button = { | ||
| 678 | {Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B}, | ||
| 679 | {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A}, | ||
| 680 | {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y}, | ||
| 681 | {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X}, | ||
| 682 | {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK}, | ||
| 683 | {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK}, | ||
| 684 | {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, | ||
| 685 | {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, | ||
| 686 | {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START}, | ||
| 687 | {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK}, | ||
| 688 | {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT}, | ||
| 689 | {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP}, | ||
| 690 | {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT}, | ||
| 691 | {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN}, | ||
| 692 | {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, | ||
| 693 | {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, | ||
| 694 | {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE}, | ||
| 695 | }; | ||
| 696 | if (!params.Has("guid") || !params.Has("port")) { | 674 | if (!params.Has("guid") || !params.Has("port")) { |
| 697 | return {}; | 675 | return {}; |
| 698 | } | 676 | } |
| 699 | const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); | 677 | const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); |
| 700 | auto controller = joystick->GetSDLGameController(); | 678 | auto* controller = joystick->GetSDLGameController(); |
| 701 | if (!controller) { | 679 | if (controller == nullptr) { |
| 702 | return {}; | 680 | return {}; |
| 703 | } | 681 | } |
| 704 | 682 | ||
| 705 | ButtonMapping mapping{}; | 683 | // This list is missing ZL/ZR since those are not considered buttons in SDL GameController. |
| 684 | // We will add those afterwards | ||
| 685 | // This list also excludes Screenshot since theres not really a mapping for that | ||
| 686 | using ButtonBindings = | ||
| 687 | std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>; | ||
| 688 | static constexpr ButtonBindings switch_to_sdl_button{{ | ||
| 689 | {Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B}, | ||
| 690 | {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A}, | ||
| 691 | {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y}, | ||
| 692 | {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X}, | ||
| 693 | {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK}, | ||
| 694 | {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK}, | ||
| 695 | {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, | ||
| 696 | {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, | ||
| 697 | {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START}, | ||
| 698 | {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK}, | ||
| 699 | {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT}, | ||
| 700 | {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP}, | ||
| 701 | {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT}, | ||
| 702 | {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN}, | ||
| 703 | {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, | ||
| 704 | {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, | ||
| 705 | {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE}, | ||
| 706 | }}; | ||
| 707 | |||
| 708 | // Add the missing bindings for ZL/ZR | ||
| 709 | using ZBindings = | ||
| 710 | std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>; | ||
| 711 | static constexpr ZBindings switch_to_sdl_axis{{ | ||
| 712 | {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT}, | ||
| 713 | {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT}, | ||
| 714 | }}; | ||
| 715 | |||
| 716 | ButtonMapping mapping; | ||
| 717 | mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size()); | ||
| 718 | |||
| 706 | for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) { | 719 | for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) { |
| 707 | const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button); | 720 | const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button); |
| 708 | mapping[switch_button] = | 721 | mapping.insert_or_assign( |
| 709 | BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding); | 722 | switch_button, |
| 723 | BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); | ||
| 710 | } | 724 | } |
| 711 | |||
| 712 | // Add the missing bindings for ZL/ZR | ||
| 713 | std::unordered_map<Settings::NativeButton::Values, SDL_GameControllerAxis> switch_to_sdl_axis = | ||
| 714 | { | ||
| 715 | {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT}, | ||
| 716 | {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT}, | ||
| 717 | }; | ||
| 718 | for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) { | 725 | for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) { |
| 719 | const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis); | 726 | const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis); |
| 720 | mapping[switch_button] = | 727 | mapping.insert_or_assign( |
| 721 | BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding); | 728 | switch_button, |
| 729 | BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); | ||
| 722 | } | 730 | } |
| 723 | 731 | ||
| 724 | return mapping; | 732 | return mapping; |
| @@ -729,8 +737,8 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa | |||
| 729 | return {}; | 737 | return {}; |
| 730 | } | 738 | } |
| 731 | const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); | 739 | const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); |
| 732 | auto controller = joystick->GetSDLGameController(); | 740 | auto* controller = joystick->GetSDLGameController(); |
| 733 | if (!controller) { | 741 | if (controller == nullptr) { |
| 734 | return {}; | 742 | return {}; |
| 735 | } | 743 | } |
| 736 | 744 | ||
| @@ -739,16 +747,18 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa | |||
| 739 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX); | 747 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX); |
| 740 | const auto& binding_left_y = | 748 | const auto& binding_left_y = |
| 741 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); | 749 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); |
| 742 | mapping[Settings::NativeAnalog::LStick] = | 750 | mapping.insert_or_assign(Settings::NativeAnalog::LStick, |
| 743 | BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), | 751 | BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), |
| 744 | binding_left_x.value.axis, binding_left_y.value.axis); | 752 | binding_left_x.value.axis, |
| 753 | binding_left_y.value.axis)); | ||
| 745 | const auto& binding_right_x = | 754 | const auto& binding_right_x = |
| 746 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX); | 755 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX); |
| 747 | const auto& binding_right_y = | 756 | const auto& binding_right_y = |
| 748 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY); | 757 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY); |
| 749 | mapping[Settings::NativeAnalog::RStick] = | 758 | mapping.insert_or_assign(Settings::NativeAnalog::RStick, |
| 750 | BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), | 759 | BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), |
| 751 | binding_right_x.value.axis, binding_right_y.value.axis); | 760 | binding_right_x.value.axis, |
| 761 | binding_right_y.value.axis)); | ||
| 752 | return mapping; | 762 | return mapping; |
| 753 | } | 763 | } |
| 754 | 764 | ||
| @@ -784,7 +794,7 @@ public: | |||
| 784 | } | 794 | } |
| 785 | return {}; | 795 | return {}; |
| 786 | } | 796 | } |
| 787 | std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) { | 797 | [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const { |
| 788 | switch (event.type) { | 798 | switch (event.type) { |
| 789 | case SDL_JOYAXISMOTION: | 799 | case SDL_JOYAXISMOTION: |
| 790 | if (std::abs(event.jaxis.value / 32767.0) < 0.5) { | 800 | if (std::abs(event.jaxis.value / 32767.0) < 0.5) { |
| @@ -795,7 +805,7 @@ public: | |||
| 795 | case SDL_JOYHATMOTION: | 805 | case SDL_JOYHATMOTION: |
| 796 | return {SDLEventToButtonParamPackage(state, event)}; | 806 | return {SDLEventToButtonParamPackage(state, event)}; |
| 797 | } | 807 | } |
| 798 | return {}; | 808 | return std::nullopt; |
| 799 | } | 809 | } |
| 800 | }; | 810 | }; |
| 801 | 811 | ||
diff --git a/src/input_common/touch_from_button.cpp b/src/input_common/touch_from_button.cpp new file mode 100644 index 000000000..98da0ef1a --- /dev/null +++ b/src/input_common/touch_from_button.cpp | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | // Copyright 2020 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/frontend/framebuffer_layout.h" | ||
| 6 | #include "core/settings.h" | ||
| 7 | #include "input_common/touch_from_button.h" | ||
| 8 | |||
| 9 | namespace InputCommon { | ||
| 10 | |||
| 11 | class TouchFromButtonDevice final : public Input::TouchDevice { | ||
| 12 | public: | ||
| 13 | TouchFromButtonDevice() { | ||
| 14 | for (const auto& config_entry : | ||
| 15 | Settings::values.touch_from_button_maps[Settings::values.touch_from_button_map_index] | ||
| 16 | .buttons) { | ||
| 17 | const Common::ParamPackage package{config_entry}; | ||
| 18 | map.emplace_back( | ||
| 19 | Input::CreateDevice<Input::ButtonDevice>(config_entry), | ||
| 20 | std::clamp(package.Get("x", 0), 0, static_cast<int>(Layout::ScreenUndocked::Width)), | ||
| 21 | std::clamp(package.Get("y", 0), 0, | ||
| 22 | static_cast<int>(Layout::ScreenUndocked::Height))); | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | std::tuple<float, float, bool> GetStatus() const override { | ||
| 27 | for (const auto& m : map) { | ||
| 28 | const bool state = std::get<0>(m)->GetStatus(); | ||
| 29 | if (state) { | ||
| 30 | const float x = static_cast<float>(std::get<1>(m)) / | ||
| 31 | static_cast<int>(Layout::ScreenUndocked::Width); | ||
| 32 | const float y = static_cast<float>(std::get<2>(m)) / | ||
| 33 | static_cast<int>(Layout::ScreenUndocked::Height); | ||
| 34 | return {x, y, true}; | ||
| 35 | } | ||
| 36 | } | ||
| 37 | return {}; | ||
| 38 | } | ||
| 39 | |||
| 40 | private: | ||
| 41 | // A vector of the mapped button, its x and its y-coordinate | ||
| 42 | std::vector<std::tuple<std::unique_ptr<Input::ButtonDevice>, int, int>> map; | ||
| 43 | }; | ||
| 44 | |||
| 45 | std::unique_ptr<Input::TouchDevice> TouchFromButtonFactory::Create( | ||
| 46 | const Common::ParamPackage& params) { | ||
| 47 | return std::make_unique<TouchFromButtonDevice>(); | ||
| 48 | } | ||
| 49 | |||
| 50 | } // namespace InputCommon | ||
diff --git a/src/input_common/touch_from_button.h b/src/input_common/touch_from_button.h new file mode 100644 index 000000000..8b4d1aa96 --- /dev/null +++ b/src/input_common/touch_from_button.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | // Copyright 2020 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include "core/frontend/input.h" | ||
| 9 | |||
| 10 | namespace InputCommon { | ||
| 11 | |||
| 12 | /** | ||
| 13 | * A touch device factory that takes a list of button devices and combines them into a touch device. | ||
| 14 | */ | ||
| 15 | class TouchFromButtonFactory final : public Input::Factory<Input::TouchDevice> { | ||
| 16 | public: | ||
| 17 | /** | ||
| 18 | * Creates a touch device from a list of button devices | ||
| 19 | */ | ||
| 20 | std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage& params) override; | ||
| 21 | }; | ||
| 22 | |||
| 23 | } // namespace InputCommon | ||