diff options
Diffstat (limited to 'src/input_common')
-rw-r--r-- | src/input_common/gcadapter/gc_poller.cpp | 28 | ||||
-rw-r--r-- | src/input_common/mouse/mouse_poller.cpp | 25 | ||||
-rw-r--r-- | src/input_common/sdl/sdl_impl.cpp | 73 | ||||
-rw-r--r-- | src/input_common/udp/client.cpp | 5 |
4 files changed, 112 insertions, 19 deletions
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp index 4d1052414..9670bdeb2 100644 --- a/src/input_common/gcadapter/gc_poller.cpp +++ b/src/input_common/gcadapter/gc_poller.cpp @@ -139,10 +139,10 @@ void GCButtonFactory::EndConfiguration() { class GCAnalog final : public Input::AnalogDevice { public: - explicit GCAnalog(u32 port_, u32 axis_x_, u32 axis_y_, float deadzone_, - const GCAdapter::Adapter* adapter, float range_) - : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter), - range(range_) {} + explicit GCAnalog(u32 port_, u32 axis_x_, u32 axis_y_, bool invert_x_, bool invert_y_, + float deadzone_, float range_, const GCAdapter::Adapter* adapter) + : port(port_), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_), invert_y(invert_y_), + deadzone(deadzone_), range(range_), gcadapter(adapter) {} float GetAxis(u32 axis) const { if (gcadapter->DeviceConnected(port)) { @@ -157,7 +157,12 @@ public: std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const { float x = GetAxis(analog_axis_x); float y = GetAxis(analog_axis_y); - + if (invert_x) { + x = -x; + } + if (invert_y) { + y = -y; + } // Make sure the coordinates are in the unit circle, // otherwise normalize it. float r = x * x + y * y; @@ -200,9 +205,11 @@ private: const u32 port; const u32 axis_x; const u32 axis_y; + const bool invert_x; + const bool invert_y; const float deadzone; - const GCAdapter::Adapter* gcadapter; const float range; + const GCAdapter::Adapter* gcadapter; mutable std::mutex mutex; }; @@ -223,8 +230,13 @@ std::unique_ptr<Input::AnalogDevice> GCAnalogFactory::Create(const Common::Param const auto axis_y = static_cast<u32>(params.Get("axis_y", 1)); const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f); const auto range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f); + const std::string invert_x_value = params.Get("invert_x", "+"); + const std::string invert_y_value = params.Get("invert_y", "+"); + const bool invert_x = invert_x_value == "-"; + const bool invert_y = invert_y_value == "-"; - return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone, adapter.get(), range); + return std::make_unique<GCAnalog>(port, axis_x, axis_y, invert_x, invert_y, deadzone, range, + adapter.get()); } void GCAnalogFactory::BeginConfiguration() { @@ -282,6 +294,8 @@ Common::ParamPackage GCAnalogFactory::GetNextInput() { params.Set("port", controller_number); params.Set("axis_x", analog_x_axis); params.Set("axis_y", analog_y_axis); + params.Set("invert_x", "+"); + params.Set("invert_y", "+"); analog_x_axis = -1; analog_y_axis = -1; controller_number = -1; diff --git a/src/input_common/mouse/mouse_poller.cpp b/src/input_common/mouse/mouse_poller.cpp index 7445ad3ad..508eb0c7d 100644 --- a/src/input_common/mouse/mouse_poller.cpp +++ b/src/input_common/mouse/mouse_poller.cpp @@ -62,10 +62,10 @@ void MouseButtonFactory::EndConfiguration() { class MouseAnalog final : public Input::AnalogDevice { public: - explicit MouseAnalog(u32 port_, u32 axis_x_, u32 axis_y_, float deadzone_, float range_, - const MouseInput::Mouse* mouse_input_) - : button(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), range(range_), - mouse_input(mouse_input_) {} + explicit MouseAnalog(u32 port_, u32 axis_x_, u32 axis_y_, bool invert_x_, bool invert_y_, + float deadzone_, float range_, const MouseInput::Mouse* mouse_input_) + : button(port_), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_), invert_y(invert_y_), + deadzone(deadzone_), range(range_), mouse_input(mouse_input_) {} float GetAxis(u32 axis) const { std::lock_guard lock{mutex}; @@ -77,6 +77,12 @@ public: std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const { float x = GetAxis(analog_axis_x); float y = GetAxis(analog_axis_y); + if (invert_x) { + x = -x; + } + if (invert_y) { + y = -y; + } // Make sure the coordinates are in the unit circle, // otherwise normalize it. @@ -104,6 +110,8 @@ private: const u32 button; const u32 axis_x; const u32 axis_y; + const bool invert_x; + const bool invert_y; const float deadzone; const float range; const MouseInput::Mouse* mouse_input; @@ -128,8 +136,13 @@ std::unique_ptr<Input::AnalogDevice> MouseAnalogFactory::Create( const auto axis_y = static_cast<u32>(params.Get("axis_y", 1)); const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f); const auto range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f); + const std::string invert_x_value = params.Get("invert_x", "+"); + const std::string invert_y_value = params.Get("invert_y", "+"); + const bool invert_x = invert_x_value == "-"; + const bool invert_y = invert_y_value == "-"; - return std::make_unique<MouseAnalog>(port, axis_x, axis_y, deadzone, range, mouse_input.get()); + return std::make_unique<MouseAnalog>(port, axis_x, axis_y, invert_x, invert_y, deadzone, range, + mouse_input.get()); } void MouseAnalogFactory::BeginConfiguration() { @@ -153,6 +166,8 @@ Common::ParamPackage MouseAnalogFactory::GetNextInput() const { params.Set("port", static_cast<u16>(pad.button)); params.Set("axis_x", 0); params.Set("axis_y", 1); + params.Set("invert_x", "+"); + params.Set("invert_y", "+"); return params; } } diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index 7827e324c..d32eb732a 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp @@ -352,13 +352,20 @@ private: class SDLAnalog final : public Input::AnalogDevice { public: explicit SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, - float deadzone_, float range_) - : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), - range(range_) {} + bool invert_x_, bool invert_y_, float deadzone_, float range_) + : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_), + invert_y(invert_y_), deadzone(deadzone_), range(range_) {} std::tuple<float, float> GetStatus() const override { - const auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range); + auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range); const float r = std::sqrt((x * x) + (y * y)); + if (invert_x) { + x = -x; + } + if (invert_y) { + y = -y; + } + if (r > deadzone) { return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone), y / r * (r - deadzone) / (1 - deadzone)); @@ -386,6 +393,8 @@ private: std::shared_ptr<SDLJoystick> joystick; const int axis_x; const int axis_y; + const bool invert_x; + const bool invert_y; const float deadzone; const float range; }; @@ -572,12 +581,17 @@ public: const int axis_y = params.Get("axis_y", 1); const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f); const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f); + const std::string invert_x_value = params.Get("invert_x", "+"); + const std::string invert_y_value = params.Get("invert_y", "+"); + const bool invert_x = invert_x_value == "-"; + const bool invert_y = invert_y_value == "-"; auto joystick = state.GetSDLJoystickByGUID(guid, port); // This is necessary so accessing GetAxis with axis_x and axis_y won't crash joystick->SetAxis(axis_x, 0); joystick->SetAxis(axis_y, 0); - return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, deadzone, range); + return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, invert_x, invert_y, deadzone, + range); } private: @@ -886,6 +900,8 @@ Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& gui params.Set("guid", guid); params.Set("axis_x", axis_x); params.Set("axis_y", axis_y); + params.Set("invert_x", "+"); + params.Set("invert_y", "+"); return params; } } // Anonymous namespace @@ -1014,11 +1030,44 @@ public: } return {}; } - [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const { + [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(SDL_Event& event) { switch (event.type) { case SDL_JOYAXISMOTION: - if (std::abs(event.jaxis.value / 32767.0) < 0.5) { + if (!axis_memory.count(event.jaxis.which) || + !axis_memory[event.jaxis.which].count(event.jaxis.axis)) { + axis_memory[event.jaxis.which][event.jaxis.axis] = event.jaxis.value; + axis_event_count[event.jaxis.which][event.jaxis.axis] = 1; break; + } else { + axis_event_count[event.jaxis.which][event.jaxis.axis]++; + // The joystick and axis exist in our map if we take this branch, so no checks + // needed + if (std::abs( + (event.jaxis.value - axis_memory[event.jaxis.which][event.jaxis.axis]) / + 32767.0) < 0.5) { + break; + } else { + if (axis_event_count[event.jaxis.which][event.jaxis.axis] == 2 && + IsAxisAtPole(event.jaxis.value) && + IsAxisAtPole(axis_memory[event.jaxis.which][event.jaxis.axis])) { + // If we have exactly two events and both are near a pole, this is + // likely a digital input masquerading as an analog axis; Instead of + // trying to look at the direction the axis travelled, assume the first + // event was press and the second was release; This should handle most + // digital axes while deferring to the direction of travel for analog + // axes + event.jaxis.value = static_cast<Sint16>( + std::copysign(32767, axis_memory[event.jaxis.which][event.jaxis.axis])); + } else { + // There are more than two events, so this is likely a true analog axis, + // check the direction it travelled + event.jaxis.value = static_cast<Sint16>(std::copysign( + 32767, + event.jaxis.value - axis_memory[event.jaxis.which][event.jaxis.axis])); + } + axis_memory.clear(); + axis_event_count.clear(); + } } [[fallthrough]]; case SDL_JOYBUTTONUP: @@ -1027,6 +1076,16 @@ public: } return std::nullopt; } + +private: + // Determine whether an axis value is close to an extreme or center + // Some controllers have a digital D-Pad as a pair of analog sticks, with 3 possible values per + // axis, which is why the center must be considered a pole + bool IsAxisAtPole(int16_t value) const { + return std::abs(value) >= 32767 || std::abs(value) < 327; + } + std::unordered_map<SDL_JoystickID, std::unordered_map<uint8_t, int16_t>> axis_memory; + std::unordered_map<SDL_JoystickID, std::unordered_map<uint8_t, uint32_t>> axis_event_count; }; class SDLMotionPoller final : public SDLPoller { diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp index 17a9225d7..412d57896 100644 --- a/src/input_common/udp/client.cpp +++ b/src/input_common/udp/client.cpp @@ -225,6 +225,11 @@ void Client::OnPortInfo([[maybe_unused]] Response::PortInfo data) { } void Client::OnPadData(Response::PadData data, std::size_t client) { + // Accept packets only for the correct pad + if (static_cast<u8>(clients[client].pad_index) != data.info.id) { + return; + } + LOG_TRACE(Input, "PadData packet received"); if (data.packet_counter == clients[client].packet_sequence) { LOG_WARNING( |