diff --git a/lang/system/en-gb.xml b/lang/system/en-gb.xml
index 0b40c2f83..7a553c2bf 100644
--- a/lang/system/en-gb.xml
+++ b/lang/system/en-gb.xml
@@ -323,7 +323,7 @@ Connect a controller that is compatible with SDL3.
PS button
L1 button
R1 button
- Only in PS TV mode.
+ Only in PS TV mode
L2 button
R2 button
L3 button
diff --git a/lang/system/en.xml b/lang/system/en.xml
index 77545ea23..1e64208a1 100644
--- a/lang/system/en.xml
+++ b/lang/system/en.xml
@@ -323,7 +323,7 @@ Connect a controller that is compatible with SDL3.
PS button
L1 button
R1 button
- Only in PS TV mode.
+ Only in PS TV mode
L2 button
R2 button
L3 button
diff --git a/vita3k/config/include/config/config.h b/vita3k/config/include/config/config.h
index 2ae5775b7..8970acdc9 100644
--- a/vita3k/config/include/config/config.h
+++ b/vita3k/config/include/config/config.h
@@ -111,6 +111,7 @@ enum ScreenshotFormat {
code(int, "performance-overlay-position", static_cast(TOP_LEFT), performance_overlay_position) \
code(int, "screenshot-format", static_cast(JPEG), screenshot_format) \
code(bool, "disable-motion", false, disable_motion) \
+ code(float, "controller-analog-multiplier", 1.0f, controller_analog_multiplier) \
code(int, "keyboard-button-select", 229, keyboard_button_select) \
code(int, "keyboard-button-start", 40, keyboard_button_start) \
code(int, "keyboard-button-up", 82, keyboard_button_up) \
diff --git a/vita3k/ctrl/include/ctrl/state.h b/vita3k/ctrl/include/ctrl/state.h
index 642a88e32..43678203c 100644
--- a/vita3k/ctrl/include/ctrl/state.h
+++ b/vita3k/ctrl/include/ctrl/state.h
@@ -56,6 +56,7 @@ struct CtrlState {
std::mutex mutex;
ControllerList controllers;
int controllers_num = 0;
+ float analog_multiplier = 1.0f;
bool has_motion_support = false;
bool free_ports[SCE_CTRL_MAX_WIRELESS_NUM] = { true, true, true, true };
SceCtrlPadInputMode input_mode = SCE_CTRL_MODE_DIGITAL;
diff --git a/vita3k/ctrl/src/ctrl.cpp b/vita3k/ctrl/src/ctrl.cpp
index 010408ab0..489e624e6 100644
--- a/vita3k/ctrl/src/ctrl.cpp
+++ b/vita3k/ctrl/src/ctrl.cpp
@@ -179,29 +179,6 @@ static void apply_keyboard(uint32_t *buttons, float axes[4], bool ext, EmuEnvSta
axes[3] += keys_to_axis(keys, static_cast(emuenv.cfg.keyboard_rightstick_up), static_cast(emuenv.cfg.keyboard_rightstick_down));
}
-static float axis_to_axis(int16_t axis) {
- const auto unsigned_axis = static_cast(axis - INT16_MIN);
- assert(unsigned_axis >= 0);
- assert(unsigned_axis <= UINT16_MAX);
-
- const float f = unsigned_axis / UINT16_MAX;
-
- const float output = (f * 2) - 1;
- assert(output >= -1);
- assert(output <= 1);
-
- return output;
-}
-
-static uint8_t float_to_byte(float f) {
- const float mapped = (f * 0.5f) + 0.5f;
- const float clamped = std::max(0.0f, std::min(mapped, 1.0f));
- assert(clamped >= 0);
- assert(clamped <= 1);
-
- return static_cast(clamped * 255);
-}
-
static std::array get_controller_bindings(EmuEnvState &emuenv) {
return { {
{ static_cast(emuenv.cfg.controller_binds[SDL_GAMEPAD_BUTTON_BACK]), SCE_CTRL_SELECT },
@@ -240,6 +217,25 @@ std::array get_controller_bindings_ext(EmuEnvState &emuen
} };
}
+static float axis_to_axis(int16_t axis, const auto &mult) {
+ const auto unsigned_axis = static_cast(axis - INT16_MIN);
+ assert(unsigned_axis >= 0);
+ assert(unsigned_axis <= UINT16_MAX);
+
+ const auto f = unsigned_axis / UINT16_MAX;
+
+ const auto output = std::clamp(((f * 2) - 1) * mult, -1.0f, 1.f);
+
+ return output;
+}
+
+static uint8_t float_to_byte(float f) {
+ const auto clamped_f = std::clamp(f, -1.0f, 1.0f);
+ const auto mapped = (clamped_f * 0.5f) + 0.5f;
+
+ return static_cast(mapped * 255);
+}
+
static void apply_controller(EmuEnvState &emuenv, uint32_t *buttons, float axes[4], SDL_Gamepad *controller, bool ext) {
if (ext) {
for (const auto &binding : get_controller_bindings_ext(emuenv)) {
@@ -262,10 +258,11 @@ static void apply_controller(EmuEnvState &emuenv, uint32_t *buttons, float axes[
}
}
- axes[0] += axis_to_axis(SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_LEFTX));
- axes[1] += axis_to_axis(SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_LEFTY));
- axes[2] += axis_to_axis(SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_RIGHTX));
- axes[3] += axis_to_axis(SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_RIGHTY));
+ auto &analog_multiplier = emuenv.cfg.controller_analog_multiplier;
+ axes[0] += axis_to_axis(SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_LEFTX), analog_multiplier);
+ axes[1] += axis_to_axis(SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_LEFTY), analog_multiplier);
+ axes[2] += axis_to_axis(SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_RIGHTX), analog_multiplier);
+ axes[3] += axis_to_axis(SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_RIGHTY), analog_multiplier);
}
static void retrieve_ctrl_data(EmuEnvState &emuenv, int port, bool is_v2, bool negative, bool from_ext_function, SceUInt32 &buttons, SceUInt8 &lx, SceUInt8 &ly, SceUInt8 &rx, SceUInt8 &ry) {
@@ -276,7 +273,7 @@ static void retrieve_ctrl_data(EmuEnvState &emuenv, int port, bool is_v2, bool n
}
CtrlState &state = emuenv.ctrl;
- std::array axes;
+ std::array axes{};
axes.fill(0);
const auto reset_axes = [&]() {
diff --git a/vita3k/gui/src/controllers_dialog.cpp b/vita3k/gui/src/controllers_dialog.cpp
index fe1ac7820..85573e5e2 100644
--- a/vita3k/gui/src/controllers_dialog.cpp
+++ b/vita3k/gui/src/controllers_dialog.cpp
@@ -334,7 +334,7 @@ void draw_controllers_dialog(GuiState &gui, EmuEnvState &emuenv) {
ImGui::Separator();
ImGui::Spacing();
- ImGui::TextColored(GUI_COLOR_TEXT_TITLE, "%s", controls["ps_tv_mode"].c_str());
+ TextColoredCentered(GUI_COLOR_TEXT_TITLE, controls["ps_tv_mode"].c_str());
if (ImGui::BeginTable("rebindExt", 2, ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_BordersInnerV)) {
ImGui::TableSetupColumn("leftButtons");
ImGui::TableSetupColumn("rightButtons");
@@ -355,7 +355,18 @@ void draw_controllers_dialog(GuiState &gui, EmuEnvState &emuenv) {
}
ImGui::EndTable();
}
-
+ ImGui::Spacing();
+ ImGui::Separator();
+ ImGui::Spacing();
+ TextColoredCentered(GUI_COLOR_TEXT_TITLE, "Analog Stick Multiplier");
+ ImGui::Spacing();
+ auto &mult = emuenv.cfg.controller_analog_multiplier;
+ if (ImGui::SliderFloat("##analog_multiplier", &mult, 0.1f, 2.f, "%.1fx", ImGuiSliderFlags_AlwaysClamp))
+ config::serialize_config(emuenv.cfg, emuenv.cfg.config_path);
+ SetTooltipEx("Analog multipiler can be used to change the sensitivity of your stick movements.");
+ ImGui::Spacing();
+ ImGui::Separator();
+ ImGui::Spacing();
if (ctrl.controllers[guid].has_led) {
const auto set_led_color = [&](const std::vector &led) {
SDL_SetGamepadLED(ctrl.controllers[guid].controller.get(), led[0], led[1], led[2]);
diff --git a/vita3k/lang/include/lang/state.h b/vita3k/lang/include/lang/state.h
index c130e82b0..6492691df 100644
--- a/vita3k/lang/include/lang/state.h
+++ b/vita3k/lang/include/lang/state.h
@@ -294,7 +294,7 @@ struct LangState {
{ "ps_button", "PS button" },
{ "l1_button", "L1 button" },
{ "r1_button", "R1 button" },
- { "ps_tv_mode", "Only in PS TV mode." },
+ { "ps_tv_mode", "Only in PS TV mode" },
{ "l2_button", "L2 button" },
{ "r2_button", "R2 button" },
{ "l3_button", "L3 button" },