From 2706486559cb71be01a9691d08bc166e778ae72e Mon Sep 17 00:00:00 2001 From: Megamouse Date: Thu, 5 May 2022 16:23:30 +0200 Subject: [PATCH] input: add absolute mouse movement mode --- rpcs3/Emu/Io/pad_config.h | 1 + rpcs3/Emu/Io/pad_config_types.cpp | 15 +++++++++ rpcs3/Emu/Io/pad_config_types.h | 6 ++++ rpcs3/Input/keyboard_pad_handler.cpp | 44 ++++++++++++++++++++++++--- rpcs3/Input/keyboard_pad_handler.h | 1 + rpcs3/rpcs3qt/pad_settings_dialog.cpp | 12 ++++++++ rpcs3/rpcs3qt/pad_settings_dialog.ui | 24 +++++++++++++++ rpcs3/rpcs3qt/tooltips.h | 1 + 8 files changed, 100 insertions(+), 4 deletions(-) diff --git a/rpcs3/Emu/Io/pad_config.h b/rpcs3/Emu/Io/pad_config.h index a024d03dcd..cec5e11e77 100644 --- a/rpcs3/Emu/Io/pad_config.h +++ b/rpcs3/Emu/Io/pad_config.h @@ -66,6 +66,7 @@ struct cfg_pad final : cfg::node cfg::_bool enable_vibration_motor_small{ this, "Enable Small Vibration Motor", true }; cfg::_bool switch_vibration_motors{ this, "Switch Vibration Motors", false }; + cfg::_enum mouse_move_mode{ this, "Mouse Movement Mode", mouse_movement_mode::relative }; cfg::uint<0, 255> mouse_deadzone_x{ this, "Mouse Deadzone X Axis", 60 }; cfg::uint<0, 255> mouse_deadzone_y{ this, "Mouse Deadzone Y Axis", 60 }; cfg::uint<0, 999999> mouse_acceleration_x{ this, "Mouse Acceleration X Axis", 200 }; diff --git a/rpcs3/Emu/Io/pad_config_types.cpp b/rpcs3/Emu/Io/pad_config_types.cpp index 733bf6b393..7facfa0aae 100644 --- a/rpcs3/Emu/Io/pad_config_types.cpp +++ b/rpcs3/Emu/Io/pad_config_types.cpp @@ -25,3 +25,18 @@ void fmt_class_string::format(std::string& out, u64 arg) return unknown; }); } + +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](mouse_movement_mode value) + { + switch (value) + { + case mouse_movement_mode::relative: return "Relative"; + case mouse_movement_mode::absolute: return "Absolute"; + } + + return unknown; + }); +} diff --git a/rpcs3/Emu/Io/pad_config_types.h b/rpcs3/Emu/Io/pad_config_types.h index 94e6d31186..500bfc873a 100644 --- a/rpcs3/Emu/Io/pad_config_types.h +++ b/rpcs3/Emu/Io/pad_config_types.h @@ -18,6 +18,12 @@ enum class pad_handler #endif }; +enum class mouse_movement_mode : s32 +{ + relative = 0, + absolute = 1 +}; + struct PadInfo { u32 now_connect; diff --git a/rpcs3/Input/keyboard_pad_handler.cpp b/rpcs3/Input/keyboard_pad_handler.cpp index c751f5d706..b48f61cea0 100644 --- a/rpcs3/Input/keyboard_pad_handler.cpp +++ b/rpcs3/Input/keyboard_pad_handler.cpp @@ -415,10 +415,28 @@ void keyboard_pad_handler::mouseMoveEvent(QMouseEvent* event) // get the delta of the mouse position to the screen center const QPoint p_delta = event->pos() - p_center; - movement_x = p_delta.x(); - movement_y = p_delta.y(); + if (m_mouse_movement_mode == mouse_movement_mode::relative) + { + movement_x = p_delta.x(); + movement_y = p_delta.y(); + } + else + { + // current mouse position, starting at the center + static QPoint p_real(p_center); + + // update the current position without leaving the screen borders + p_real.setX(std::clamp(p_real.x() + p_delta.x(), 0, screen.width())); + p_real.setY(std::clamp(p_real.y() + p_delta.y(), 0, screen.height())); + + // get the delta of the real mouse position to the screen center + const QPoint p_real_delta = p_real - p_center; + + movement_x = p_real_delta.x(); + movement_y = p_real_delta.y(); + } } - else + else if (m_mouse_movement_mode == mouse_movement_mode::relative) { static int last_pos_x = 0; static int last_pos_y = 0; @@ -429,6 +447,23 @@ void keyboard_pad_handler::mouseMoveEvent(QMouseEvent* event) last_pos_x = event->x(); last_pos_y = event->y(); } + else if (m_target && m_target->isActive()) + { + // get the screen dimensions + const QSize screen = m_target->size(); + + // get the center of the screen in global coordinates + QPoint p_center = m_target->geometry().topLeft() + QPoint(screen.width() / 2, screen.height() / 2); + + // convert the center into screen coordinates + p_center = m_target->mapFromGlobal(p_center); + + // get the delta of the mouse position to the screen center + const QPoint p_delta = event->pos() - p_center; + + movement_x = p_delta.x(); + movement_y = p_delta.y(); + } movement_x *= m_multi_x; movement_y *= m_multi_y; @@ -759,6 +794,7 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr pad, const std:: if (cfg == nullptr) return false; + m_mouse_movement_mode = cfg->mouse_move_mode; m_mouse_move_used = false; m_mouse_wheel_used = false; m_deadzone_x = cfg->mouse_deadzone_x; @@ -872,7 +908,7 @@ void keyboard_pad_handler::ThreadProc() m_button_time = now; } - if (m_mouse_move_used) + if (m_mouse_move_used && m_mouse_movement_mode == mouse_movement_mode::relative) { static const double mouse_interval = 30.0; diff --git a/rpcs3/Input/keyboard_pad_handler.h b/rpcs3/Input/keyboard_pad_handler.h index 10c81db41b..692a5c0ddb 100644 --- a/rpcs3/Input/keyboard_pad_handler.h +++ b/rpcs3/Input/keyboard_pad_handler.h @@ -104,6 +104,7 @@ protected: private: QWindow* m_target = nullptr; + mouse_movement_mode m_mouse_movement_mode = mouse_movement_mode::relative; bool m_mouse_move_used = false; bool m_mouse_wheel_used = false; bool get_mouse_lock_state() const; diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.cpp b/rpcs3/rpcs3qt/pad_settings_dialog.cpp index fd9624c54a..3981e8f832 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/pad_settings_dialog.cpp @@ -177,6 +177,9 @@ pad_settings_dialog::pad_settings_dialog(std::shared_ptr gui_setti RepaintPreviewLabel(ui->preview_stick_right, ui->slider_stick_right->value(), ui->slider_stick_right->size().width(), m_rx, m_ry, cfg.rpadsquircling, cfg.rstickmultiplier / 100.0); }); + ui->mouse_movement->addItem(tr("Relative"), static_cast(mouse_movement_mode::relative)); + ui->mouse_movement->addItem(tr("Absolute"), static_cast(mouse_movement_mode::absolute)); + // Initialize configurable buttons InitButtons(); @@ -947,6 +950,11 @@ void pad_settings_dialog::UpdateLabels(bool is_reset) std::vector range; + // Update Mouse Movement Mode + const int mouse_movement_index = ui->mouse_movement->findData(static_cast(cfg.mouse_move_mode.get())); + ensure(mouse_movement_index >= 0); + ui->mouse_movement->setCurrentIndex(mouse_movement_index); + // Update Mouse Deadzones range = cfg.mouse_deadzone_x.to_list(); ui->mouse_dz_x->setRange(std::stoi(range.front()), std::stoi(range.back())); @@ -1608,6 +1616,9 @@ void pad_settings_dialog::ApplyCurrentPlayerConfig(int new_player_id) if (m_handler->m_type == pad_handler::keyboard) { + const int mouse_move_mode = ui->mouse_movement->currentData().toInt(); + ensure(mouse_move_mode >= 0 && mouse_move_mode <= 1); + cfg.mouse_move_mode.set(static_cast(mouse_move_mode)); cfg.mouse_acceleration_x.set(ui->mouse_accel_x->value() * 100); cfg.mouse_acceleration_y.set(ui->mouse_accel_y->value() * 100); cfg.mouse_deadzone_x.set(ui->mouse_dz_x->value()); @@ -1757,4 +1768,5 @@ void pad_settings_dialog::SubscribeTooltips() SubscribeTooltip(ui->gb_stick_lerp, tooltips.gamepad_settings.stick_lerp); SubscribeTooltip(ui->gb_mouse_accel, tooltips.gamepad_settings.mouse_acceleration); SubscribeTooltip(ui->gb_mouse_dz, tooltips.gamepad_settings.mouse_deadzones); + SubscribeTooltip(ui->gb_mouse_movement, tooltips.gamepad_settings.mouse_movement); } diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.ui b/rpcs3/rpcs3qt/pad_settings_dialog.ui index 175cdd73e9..a3789803f7 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.ui +++ b/rpcs3/rpcs3qt/pad_settings_dialog.ui @@ -1026,6 +1026,30 @@ + + + + Mouse Movement Mode + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + + + diff --git a/rpcs3/rpcs3qt/tooltips.h b/rpcs3/rpcs3qt/tooltips.h index c6bd7d08c4..46dd845e6f 100644 --- a/rpcs3/rpcs3qt/tooltips.h +++ b/rpcs3/rpcs3qt/tooltips.h @@ -257,6 +257,7 @@ public: const QString stick_lerp = tr("With keyboards, you are inevitably restricted to 8 stick directions (4 straight + 4 diagonal). Furthermore, the stick will jump to the maximum value of the chosen direction immediately when a key is pressed. The stick interpolation can be used to work-around both of these issues by smoothening out these directional changes. The lower the value, the longer you have to press or release a key until the maximum amplitude is reached."); const QString mouse_deadzones = tr("The mouse deadzones represent the games' own deadzones on the x and y axes. Games usually enforce their own deadzones to filter out small unwanted stick movements. In consequence, mouse input feels unintuitive since it relies on immediate responsiveness. You can change these values temporarily during gameplay in order to find out the optimal values for your game (Alt+T and Alt+Y for x, Alt+U and Alt+I for y)."); const QString mouse_acceleration = tr("The mouse acceleration can be used to amplify your mouse movements on the x and y axes. Increase these values if your mouse movements feel too slow while playing a game. You can change these values temporarily during gameplay in order to find out the optimal values (Alt+G and Alt+H for x, Alt+J and Alt+K for y). Keep in mind that modern mice usually provide different modes and settings that can be used to change mouse movement speeds as well."); + const QString mouse_movement = tr("The mouse movement mode determines how the mouse movement is translated to pad input.
Use the relative mode for traditional mouse movement.
Use the absolute mode to use the mouse's distance to the center of the screen as input value."); } gamepad_settings; };