summaryrefslogtreecommitdiff
path: root/src/input_common/sdl
diff options
context:
space:
mode:
Diffstat (limited to 'src/input_common/sdl')
-rw-r--r--src/input_common/sdl/sdl_impl.cpp117
1 files changed, 88 insertions, 29 deletions
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 70a0ba09c..ecb00d428 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -21,7 +21,7 @@
#include "common/logging/log.h"
#include "common/math_util.h"
#include "common/param_package.h"
-#include "common/settings_input.h"
+#include "common/settings.h"
#include "common/threadsafe_queue.h"
#include "core/frontend/input.h"
#include "input_common/motion_input.h"
@@ -82,6 +82,12 @@ public:
state.buttons.insert_or_assign(button, value);
}
+ void PreSetButton(int button) {
+ if (!state.buttons.contains(button)) {
+ SetButton(button, false);
+ }
+ }
+
void SetMotion(SDL_ControllerSensorEvent event) {
constexpr float gravity_constant = 9.80665f;
std::lock_guard lock{mutex};
@@ -155,9 +161,17 @@ public:
state.axes.insert_or_assign(axis, value);
}
- float GetAxis(int axis, float range) const {
+ void PreSetAxis(int axis) {
+ if (!state.axes.contains(axis)) {
+ SetAxis(axis, 0);
+ }
+ }
+
+ float GetAxis(int axis, float range, float offset) const {
std::lock_guard lock{mutex};
- return static_cast<float>(state.axes.at(axis)) / (32767.0f * range);
+ const float value = static_cast<float>(state.axes.at(axis)) / 32767.0f;
+ const float offset_scale = (value + offset) > 0.0f ? 1.0f + offset : 1.0f - offset;
+ return (value + offset) / range / offset_scale;
}
bool RumblePlay(u16 amp_low, u16 amp_high) {
@@ -174,9 +188,10 @@ public:
return false;
}
- std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range) const {
- float x = GetAxis(axis_x, range);
- float y = GetAxis(axis_y, range);
+ std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range, float offset_x,
+ float offset_y) const {
+ float x = GetAxis(axis_x, range, offset_x);
+ float y = GetAxis(axis_y, range, offset_y);
y = -y; // 3DS uses an y-axis inverse from SDL
// Make sure the coordinates are in the unit circle,
@@ -240,11 +255,25 @@ public:
}
bool IsJoyconLeft() const {
- return std::strstr(GetControllerName().c_str(), "Joy-Con Left") != nullptr;
+ const std::string controller_name = GetControllerName();
+ if (std::strstr(controller_name.c_str(), "Joy-Con Left") != nullptr) {
+ return true;
+ }
+ if (std::strstr(controller_name.c_str(), "Joy-Con (L)") != nullptr) {
+ return true;
+ }
+ return false;
}
bool IsJoyconRight() const {
- return std::strstr(GetControllerName().c_str(), "Joy-Con Right") != nullptr;
+ const std::string controller_name = GetControllerName();
+ if (std::strstr(controller_name.c_str(), "Joy-Con Right") != nullptr) {
+ return true;
+ }
+ if (std::strstr(controller_name.c_str(), "Joy-Con (R)") != nullptr) {
+ return true;
+ }
+ return false;
}
std::string GetControllerName() const {
@@ -483,7 +512,7 @@ public:
trigger_if_greater(trigger_if_greater_) {}
bool GetStatus() const override {
- const float axis_value = joystick->GetAxis(axis, 1.0f);
+ const float axis_value = joystick->GetAxis(axis, 1.0f, 0.0f);
if (trigger_if_greater) {
return axis_value > threshold;
}
@@ -500,12 +529,14 @@ private:
class SDLAnalog final : public Input::AnalogDevice {
public:
explicit SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_,
- bool invert_x_, bool invert_y_, float deadzone_, float range_)
+ bool invert_x_, bool invert_y_, float deadzone_, float range_,
+ float offset_x_, float offset_y_)
: joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_),
- invert_y(invert_y_), deadzone(deadzone_), range(range_) {}
+ invert_y(invert_y_), deadzone(deadzone_), range(range_), offset_x(offset_x_),
+ offset_y(offset_y_) {}
std::tuple<float, float> GetStatus() const override {
- auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range);
+ auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range, offset_x, offset_y);
const float r = std::sqrt((x * x) + (y * y));
if (invert_x) {
x = -x;
@@ -522,8 +553,8 @@ public:
}
std::tuple<float, float> GetRawStatus() const override {
- const float x = joystick->GetAxis(axis_x, range);
- const float y = joystick->GetAxis(axis_y, range);
+ const float x = joystick->GetAxis(axis_x, range, offset_x);
+ const float y = joystick->GetAxis(axis_y, range, offset_y);
return {x, -y};
}
@@ -555,6 +586,8 @@ private:
const bool invert_y;
const float deadzone;
const float range;
+ const float offset_x;
+ const float offset_y;
};
class SDLVibration final : public Input::VibrationDevice {
@@ -621,7 +654,7 @@ public:
trigger_if_greater(trigger_if_greater_) {}
Input::MotionStatus GetStatus() const override {
- const float axis_value = joystick->GetAxis(axis, 1.0f);
+ const float axis_value = joystick->GetAxis(axis, 1.0f, 0.0f);
bool trigger = axis_value < threshold;
if (trigger_if_greater) {
trigger = axis_value > threshold;
@@ -720,13 +753,13 @@ public:
LOG_ERROR(Input, "Unknown direction {}", direction_name);
}
// This is necessary so accessing GetAxis with axis won't crash
- joystick->SetAxis(axis, 0);
+ joystick->PreSetAxis(axis);
return std::make_unique<SDLAxisButton>(joystick, axis, threshold, trigger_if_greater);
}
const int button = params.Get("button", 0);
// This is necessary so accessing GetButton with button won't crash
- joystick->SetButton(button, false);
+ joystick->PreSetButton(button);
return std::make_unique<SDLButton>(joystick, button, toggle);
}
@@ -757,13 +790,15 @@ public:
const std::string invert_y_value = params.Get("invert_y", "+");
const bool invert_x = invert_x_value == "-";
const bool invert_y = invert_y_value == "-";
+ const float offset_x = std::clamp(params.Get("offset_x", 0.0f), -0.99f, 0.99f);
+ const float offset_y = std::clamp(params.Get("offset_y", 0.0f), -0.99f, 0.99f);
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);
+ joystick->PreSetAxis(axis_x);
+ joystick->PreSetAxis(axis_y);
return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, invert_x, invert_y, deadzone,
- range);
+ range, offset_x, offset_y);
}
private:
@@ -844,13 +879,13 @@ public:
LOG_ERROR(Input, "Unknown direction {}", direction_name);
}
// This is necessary so accessing GetAxis with axis won't crash
- joystick->SetAxis(axis, 0);
+ joystick->PreSetAxis(axis);
return std::make_unique<SDLAxisMotion>(joystick, axis, threshold, trigger_if_greater);
}
const int button = params.Get("button", 0);
// This is necessary so accessing GetButton with button won't crash
- joystick->SetButton(button, false);
+ joystick->PreSetButton(button);
return std::make_unique<SDLButtonMotion>(joystick, button);
}
@@ -869,16 +904,21 @@ SDLState::SDLState() {
RegisterFactory<VibrationDevice>("sdl", vibration_factory);
RegisterFactory<MotionDevice>("sdl", motion_factory);
+ if (!Settings::values.enable_raw_input) {
+ // Disable raw input. When enabled this setting causes SDL to die when a web applet opens
+ SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0");
+ }
+
// Enable HIDAPI rumble. This prevents SDL from disabling motion on PS4 and PS5 controllers
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
// Tell SDL2 to use the hidapi driver. This will allow joycons to be detected as a
// GameController and not a generic one
- SDL_SetHint("SDL_JOYSTICK_HIDAPI_JOY_CONS", "1");
+ SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1");
// Turn off Pro controller home led
- SDL_SetHint("SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED", "0");
+ SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0");
// If the frontend is going to manage the event loop, then we don't start one here
start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0;
@@ -995,6 +1035,7 @@ Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid
params.Set("port", port);
params.Set("guid", std::move(guid));
params.Set("button", button);
+ params.Set("toggle", false);
return params;
}
@@ -1134,13 +1175,15 @@ Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& gu
}
Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x,
- int axis_y) {
+ int axis_y, float offset_x, float offset_y) {
Common::ParamPackage params;
params.Set("engine", "sdl");
params.Set("port", port);
params.Set("guid", guid);
params.Set("axis_x", axis_x);
params.Set("axis_y", axis_y);
+ params.Set("offset_x", offset_x);
+ params.Set("offset_y", offset_y);
params.Set("invert_x", "+");
params.Set("invert_y", "+");
return params;
@@ -1342,24 +1385,39 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa
const auto& binding_left_y =
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
if (params.Has("guid2")) {
+ joystick2->PreSetAxis(binding_left_x.value.axis);
+ joystick2->PreSetAxis(binding_left_y.value.axis);
+ const auto left_offset_x = -joystick2->GetAxis(binding_left_x.value.axis, 1.0f, 0);
+ const auto left_offset_y = -joystick2->GetAxis(binding_left_y.value.axis, 1.0f, 0);
mapping.insert_or_assign(
Settings::NativeAnalog::LStick,
BuildParamPackageForAnalog(joystick2->GetPort(), joystick2->GetGUID(),
- binding_left_x.value.axis, binding_left_y.value.axis));
+ binding_left_x.value.axis, binding_left_y.value.axis,
+ left_offset_x, left_offset_y));
} else {
+ joystick->PreSetAxis(binding_left_x.value.axis);
+ joystick->PreSetAxis(binding_left_y.value.axis);
+ const auto left_offset_x = -joystick->GetAxis(binding_left_x.value.axis, 1.0f, 0);
+ const auto left_offset_y = -joystick->GetAxis(binding_left_y.value.axis, 1.0f, 0);
mapping.insert_or_assign(
Settings::NativeAnalog::LStick,
BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
- binding_left_x.value.axis, binding_left_y.value.axis));
+ binding_left_x.value.axis, binding_left_y.value.axis,
+ left_offset_x, left_offset_y));
}
const auto& binding_right_x =
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
const auto& binding_right_y =
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
+ joystick->PreSetAxis(binding_right_x.value.axis);
+ joystick->PreSetAxis(binding_right_y.value.axis);
+ const auto right_offset_x = -joystick->GetAxis(binding_right_x.value.axis, 1.0f, 0);
+ const auto right_offset_y = -joystick->GetAxis(binding_right_y.value.axis, 1.0f, 0);
mapping.insert_or_assign(Settings::NativeAnalog::RStick,
BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
binding_right_x.value.axis,
- binding_right_y.value.axis));
+ binding_right_y.value.axis, right_offset_x,
+ right_offset_y));
return mapping;
}
@@ -1563,8 +1621,9 @@ public:
}
if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) {
+ // Set offset to zero since the joystick is not on center
auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
- first_axis, axis);
+ first_axis, axis, 0, 0);
first_axis = -1;
return params;
}