diff --git a/src/common/settings.h b/src/common/settings.h index 402339443a..0fe716f6db 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -519,6 +519,9 @@ struct Values { BasicSetting mouse_panning{false, "mouse_panning"}; BasicRangedSetting mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"}; + BasicSetting mouse_as_joystick{false, "mouse_as_joystick"}; + BasicRangedSetting max_mouse_movement{500, 0, 65535, "max_mouse_movement"}; + BasicRangedSetting mouse_as_joystick_deadzone{20, 1, 100, "mouse_as_joystick_deadzone"}; BasicSetting mouse_enabled{false, "mouse_enabled"}; std::string mouse_device; MouseButtonsRaw mouse_buttons; diff --git a/src/input_common/mouse/mouse_input.cpp b/src/input_common/mouse/mouse_input.cpp index 3b052ffb22..1cf0ae4086 100644 --- a/src/input_common/mouse/mouse_input.cpp +++ b/src/input_common/mouse/mouse_input.cpp @@ -32,6 +32,30 @@ void Mouse::UpdateThread(std::stop_token stop_token) { info.tilt_speed = 0; info.data.motion = info.motion.GetMotion(); if (Settings::values.mouse_panning) { + if (Settings::values.mouse_as_joystick) { + float axis_x = 0.0f; + float axis_y = 0.0f; + float max_mouse_movement = + static_cast(Settings::values.max_mouse_movement.GetValue()); + float deadzone = Settings::values.mouse_as_joystick_deadzone.GetValue() / + 100.0f * max_mouse_movement; + if (fabs(info.last_mouse_change.x) > deadzone) { + axis_x = info.last_mouse_change.x - + (info.last_mouse_change.x > 0 ? deadzone : -deadzone); + axis_x /= max_mouse_movement; + axis_x *= 8; + } + + if (fabs(info.last_mouse_change.y) > deadzone) { + axis_y = info.last_mouse_change.y - + (info.last_mouse_change.y > 0 ? deadzone : -deadzone); + axis_y /= max_mouse_movement; + axis_y *= 8; + } + info.data.axis = {static_cast(16 * axis_x), + static_cast(16 * -axis_y)}; + continue; + } info.last_mouse_change *= 0.96f; info.data.axis = {static_cast(16 * info.last_mouse_change.x), static_cast(16 * -info.last_mouse_change.y)}; @@ -40,8 +64,10 @@ void Mouse::UpdateThread(std::stop_token stop_token) { if (configuring) { UpdateYuzuSettings(); } - if (mouse_panning_timout++ > 20) { - StopPanning(); + if (!Settings::values.mouse_as_joystick) { + if (mouse_panning_timout++ > 20) { + StopPanning(); + } } std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); } @@ -92,6 +118,19 @@ void Mouse::MouseMove(int x, int y, int center_x, int center_y) { if (mouse_change.y == 0 && mouse_change.x == 0) { continue; } + if (Settings::values.mouse_as_joystick) { + info.last_mouse_change += mouse_change; + + float max_movement = + static_cast(Settings::values.max_mouse_movement.GetValue()); + info.last_mouse_change = { + std::clamp(info.last_mouse_change.x, -max_movement, max_movement), + std::clamp(info.last_mouse_change.y, -max_movement, max_movement)}; + + info.tilt_direction = info.last_mouse_change; + info.tilt_speed = info.tilt_direction.Normalize() * info.sensitivity; + continue; + } const auto mouse_change_length = mouse_change.Length(); if (mouse_change_length < 3.0f) { mouse_change /= mouse_change_length / 3.0f; diff --git a/src/input_common/mouse/mouse_input.h b/src/input_common/mouse/mouse_input.h index c8bae99c14..a7ca2258c3 100644 --- a/src/input_common/mouse/mouse_input.h +++ b/src/input_common/mouse/mouse_input.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index eb941ce027..59b03088d6 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -570,6 +570,9 @@ void Config::ReadControlValues() { ReadBasicSetting(Settings::values.emulate_analog_keyboard); Settings::values.mouse_panning = false; ReadBasicSetting(Settings::values.mouse_panning_sensitivity); + ReadBasicSetting(Settings::values.mouse_as_joystick); + ReadBasicSetting(Settings::values.max_mouse_movement); + ReadBasicSetting(Settings::values.mouse_as_joystick_deadzone); ReadBasicSetting(Settings::values.tas_enable); ReadBasicSetting(Settings::values.tas_loop); @@ -1204,6 +1207,9 @@ void Config::SaveControlValues() { WriteBasicSetting(Settings::values.keyboard_enabled); WriteBasicSetting(Settings::values.emulate_analog_keyboard); WriteBasicSetting(Settings::values.mouse_panning_sensitivity); + WriteBasicSetting(Settings::values.mouse_as_joystick); + WriteBasicSetting(Settings::values.max_mouse_movement); + WriteBasicSetting(Settings::values.mouse_as_joystick_deadzone); WriteBasicSetting(Settings::values.tas_enable); WriteBasicSetting(Settings::values.tas_loop); diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index b30f09013c..298b933a34 100644 --- a/src/yuzu/configuration/configure_input_advanced.cpp +++ b/src/yuzu/configuration/configure_input_advanced.cpp @@ -129,6 +129,10 @@ void ConfigureInputAdvanced::ApplyConfiguration() { Settings::values.mouse_panning = ui->mouse_panning->isChecked(); Settings::values.mouse_panning_sensitivity = static_cast(ui->mouse_panning_sensitivity->value()); + Settings::values.mouse_as_joystick = ui->mouse_as_joystick->isChecked(); + Settings::values.max_mouse_movement = static_cast(ui->max_mouse_movement->value()); + Settings::values.mouse_as_joystick_deadzone = + static_cast(ui->mouse_as_joystick_deadzone->value()); Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked(); Settings::values.enable_raw_input = ui->enable_raw_input->isChecked(); } @@ -159,6 +163,10 @@ void ConfigureInputAdvanced::LoadConfiguration() { ui->emulate_analog_keyboard->setChecked(Settings::values.emulate_analog_keyboard.GetValue()); ui->mouse_panning->setChecked(Settings::values.mouse_panning.GetValue()); ui->mouse_panning_sensitivity->setValue(Settings::values.mouse_panning_sensitivity.GetValue()); + ui->mouse_as_joystick->setChecked(Settings::values.mouse_as_joystick.GetValue()); + ui->max_mouse_movement->setValue(Settings::values.max_mouse_movement.GetValue()); + ui->mouse_as_joystick_deadzone->setValue( + Settings::values.mouse_as_joystick_deadzone.GetValue()); ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled); ui->enable_raw_input->setChecked(Settings::values.enable_raw_input.GetValue()); diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui index 9095206a07..ac664e8279 100644 --- a/src/yuzu/configuration/configure_input_advanced.ui +++ b/src/yuzu/configuration/configure_input_advanced.ui @@ -2688,6 +2688,63 @@ + + + + + 0 + 23 + + + + Enable mouse-as-joystick (requires mouse panning) + + + + + + + Max mouse movement + + + Qt::AlignCenter + + + M + + + 1 + + + 65536 + + + 500 + + + + + + + Mouse joystick deadzone + + + Qt::AlignCenter + + + % + + + 1 + + + 100 + + + 20 + + + diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index 8119a50d8f..d7db67589f 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h @@ -122,6 +122,18 @@ mouse_panning = # Default: 1.0 mouse_panning_sensitivity = +# Mouse-controlled axis moves like a joystick (requires mouse_panning) +# 0 (default): Off, 1: On +mouse_as_joystick = + +# Maximum surface area mouse-as-joystick can move +# Default: 500.0 +max_mouse_movement = + +# Size of mouse center area where controlled axis is set to 0 +# Default: 0.2 +mouse_as_joystick_deadzone = + # Emulate an analog control stick from keyboard inputs. # 0 (default): Disabled, 1: Enabled emulate_analog_keyboard =