diff --git a/rpcs3/Emu/Io/PadHandler.h b/rpcs3/Emu/Io/PadHandler.h index 68f07c3574..2cdcce6491 100644 --- a/rpcs3/Emu/Io/PadHandler.h +++ b/rpcs3/Emu/Io/PadHandler.h @@ -112,11 +112,36 @@ struct Button u16 m_value = 0; bool m_pressed = false; + u16 m_actual_value = 0; // only used in keyboard_pad_handler + bool m_analog = false; // only used in keyboard_pad_handler + bool m_trigger = false; // only used in keyboard_pad_handler + Button(u32 offset, u32 keyCode, u32 outKeyCode) : m_offset(offset) , m_keyCode(keyCode) , m_outKeyCode(outKeyCode) { + if (offset == CELL_PAD_BTN_OFFSET_DIGITAL1) + { + if (outKeyCode == CELL_PAD_CTRL_LEFT || outKeyCode == CELL_PAD_CTRL_RIGHT || + outKeyCode == CELL_PAD_CTRL_UP || outKeyCode == CELL_PAD_CTRL_DOWN) + { + m_analog = true; + } + } + else if (offset == CELL_PAD_BTN_OFFSET_DIGITAL2) + { + if (outKeyCode == CELL_PAD_CTRL_CROSS || outKeyCode == CELL_PAD_CTRL_CIRCLE || + outKeyCode == CELL_PAD_CTRL_SQUARE || outKeyCode == CELL_PAD_CTRL_TRIANGLE || + outKeyCode == CELL_PAD_CTRL_L1 || outKeyCode == CELL_PAD_CTRL_R1) + { + m_analog = true; + } + else if (outKeyCode == CELL_PAD_CTRL_L2 || outKeyCode == CELL_PAD_CTRL_R2) + { + m_trigger = true; + } + } } }; diff --git a/rpcs3/Emu/Io/pad_config.h b/rpcs3/Emu/Io/pad_config.h index 96434a18a7..23dcab66ce 100644 --- a/rpcs3/Emu/Io/pad_config.h +++ b/rpcs3/Emu/Io/pad_config.h @@ -99,6 +99,8 @@ struct pad_config final : cfg::node cfg::_int<0, 100> l_stick_lerp_factor{ this, "Left Stick Lerp Factor", 100 }; cfg::_int<0, 100> r_stick_lerp_factor{ this, "Right Stick Lerp Factor", 100 }; + cfg::_int<0, 100> analog_lerp_factor{ this, "Analog Button Lerp Factor", 100 }; + cfg::_int<0, 100> trigger_lerp_factor{ this, "Trigger Lerp Factor", 100 }; cfg::_int<0, 5> device_class_type{ this, "Device Class Type", 0 }; diff --git a/rpcs3/Input/keyboard_pad_handler.cpp b/rpcs3/Input/keyboard_pad_handler.cpp index 9dcfa91c1b..0c4bb70c41 100644 --- a/rpcs3/Input/keyboard_pad_handler.cpp +++ b/rpcs3/Input/keyboard_pad_handler.cpp @@ -75,8 +75,25 @@ void keyboard_pad_handler::Key(const u32 code, bool pressed, u16 value) if (button.m_keyCode != code) continue; - button.m_pressed = pressed; - button.m_value = pressed ? value : 0; + button.m_actual_value = pressed ? value : 0; + + bool update_button = true; + + // to get the fastest response time possible we don't wanna use any lerp with factor 1 + if (button.m_analog) + { + update_button = m_analog_lerp_factor >= 1.0f; + } + else if (button.m_trigger) + { + update_button = m_trigger_lerp_factor >= 1.0f; + } + + if (update_button) + { + button.m_value = pressed ? value : 0; + button.m_pressed = pressed; + } } for (int i = 0; i < static_cast(pad->m_sticks.size()); i++) @@ -576,6 +593,8 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr pad, const std:: m_multi_y = p_profile->mouse_acceleration_y / 100.0; m_l_stick_lerp_factor = p_profile->l_stick_lerp_factor / 100.0f; m_r_stick_lerp_factor = p_profile->r_stick_lerp_factor / 100.0f; + m_analog_lerp_factor = p_profile->analog_lerp_factor / 100.0f; + m_trigger_lerp_factor = p_profile->trigger_lerp_factor / 100.0f; auto find_key = [&](const cfg::string& name) { @@ -635,6 +654,63 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr pad, const std:: void keyboard_pad_handler::ThreadProc() { + static const double mouse_interval = 30.0; + static const double stick_interval = 10.0; + static const double button_interval = 10.0; + + const auto now = std::chrono::steady_clock::now(); + + const double elapsed_left = std::chrono::duration_cast(now - m_last_mouse_move_left).count() / 1000.0; + const double elapsed_right = std::chrono::duration_cast(now - m_last_mouse_move_right).count() / 1000.0; + const double elapsed_up = std::chrono::duration_cast(now - m_last_mouse_move_up).count() / 1000.0; + const double elapsed_down = std::chrono::duration_cast(now - m_last_mouse_move_down).count() / 1000.0; + const double elapsed_stick = std::chrono::duration_cast(now - m_stick_time).count() / 1000.0; + const double elapsed_button = std::chrono::duration_cast(now - m_button_time).count() / 1000.0; + + const bool update_sticks = elapsed_stick > stick_interval; + const bool update_buttons = elapsed_button > button_interval; + + if (update_sticks) + { + m_stick_time = now; + } + + if (update_buttons) + { + m_button_time = now; + } + + // roughly 1-2 frames to process the next mouse move + if (elapsed_left > mouse_interval) + { + Key(mouse::move_left, false); + m_last_mouse_move_left = now; + } + if (elapsed_right > mouse_interval) + { + Key(mouse::move_right, false); + m_last_mouse_move_right = now; + } + if (elapsed_up > mouse_interval) + { + Key(mouse::move_up, false); + m_last_mouse_move_up = now; + } + if (elapsed_down > mouse_interval) + { + Key(mouse::move_down, false); + m_last_mouse_move_down = now; + } + + const auto get_lerped = [](f32 v0, f32 v1, f32 lerp_factor) + { + // linear interpolation from the current value v0 to the desired value v1 + const f32 res = std::lerp(v0, v1, lerp_factor); + + // round to the correct direction to prevent sticky values on small factors + return (v0 <= v1) ? std::ceil(res) : std::floor(res); + }; + for (uint i = 0; i < bindings.size(); i++) { if (last_connection_status[i] == false) @@ -646,41 +722,7 @@ void keyboard_pad_handler::ThreadProc() } else { - static std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); - now = std::chrono::steady_clock::now(); - - const double elapsed_left = std::chrono::duration_cast(now - m_last_mouse_move_left).count() / 1000.0; - const double elapsed_right = std::chrono::duration_cast(now - m_last_mouse_move_right).count() / 1000.0; - const double elapsed_up = std::chrono::duration_cast(now - m_last_mouse_move_up).count() / 1000.0; - const double elapsed_down = std::chrono::duration_cast(now - m_last_mouse_move_down).count() / 1000.0; - const double elapsed_stick = std::chrono::duration_cast(now - m_stick_time).count() / 1000.0; - - const double mouse_interval = 30.0; - const double stick_interval = 10.0; - - // roughly 1-2 frames to process the next mouse move - if (elapsed_left > mouse_interval) - { - Key(mouse::move_left, false); - m_last_mouse_move_left = now; - } - if (elapsed_right > mouse_interval) - { - Key(mouse::move_right, false); - m_last_mouse_move_right = now; - } - if (elapsed_up > mouse_interval) - { - Key(mouse::move_up, false); - m_last_mouse_move_up = now; - } - if (elapsed_down > mouse_interval) - { - Key(mouse::move_down, false); - m_last_mouse_move_down = now; - } - - if (elapsed_stick > stick_interval) + if (update_sticks) { for (int j = 0; j < static_cast(bindings[i]->m_sticks.size()); j++) { @@ -691,25 +733,50 @@ void keyboard_pad_handler::ThreadProc() { const f32 v0 = static_cast(bindings[i]->m_sticks[j].m_value); const f32 v1 = static_cast(m_stick_val[j]); - - // linear interpolation from the current stick value v0 to the desired stick value v1 - f32 res = std::lerp(v0, v1, stick_lerp_factor); - - // round to the correct direction to prevent sticky sticks on small factors - res = (v0 <= v1) ? std::ceil(res) : std::floor(res); + const f32 res = get_lerped(v0, v1, stick_lerp_factor); bindings[i]->m_sticks[j].m_value = static_cast(res); } } + } - m_stick_time = now; + if (update_buttons) + { + for (auto& button : bindings[i]->m_buttons) + { + if (button.m_analog) + { + // we already applied the following values on keypress if we used factor 1 + if (m_analog_lerp_factor < 1.0f) + { + const f32 v0 = static_cast(button.m_value); + const f32 v1 = static_cast(button.m_actual_value); + const f32 res = get_lerped(v0, v1, m_analog_lerp_factor); + + button.m_value = static_cast(res); + button.m_pressed = button.m_value > 0; + } + } + else if (button.m_trigger) + { + // we already applied the following values on keypress if we used factor 1 + if (m_trigger_lerp_factor < 1.0f) + { + const f32 v0 = static_cast(button.m_value); + const f32 v1 = static_cast(button.m_actual_value); + const f32 res = get_lerped(v0, v1, m_trigger_lerp_factor); + + button.m_value = static_cast(res); + button.m_pressed = button.m_value > 0; + } + } + } } } } // Releases the wheel buttons 0,1 sec after they've been triggered // Next activation is set to distant future to avoid activating this on every proc - const auto now = std::chrono::steady_clock::now(); const auto update_threshold = now - std::chrono::milliseconds(100); const auto distant_future = now + std::chrono::hours(24); if (update_threshold >= m_last_wheel_move_up) diff --git a/rpcs3/Input/keyboard_pad_handler.h b/rpcs3/Input/keyboard_pad_handler.h index 870bc1c099..21ad893a46 100644 --- a/rpcs3/Input/keyboard_pad_handler.h +++ b/rpcs3/Input/keyboard_pad_handler.h @@ -101,6 +101,11 @@ private: QWindow* m_target = nullptr; std::vector> bindings; + // Button Movements + std::chrono::steady_clock::time_point m_button_time; + f32 m_analog_lerp_factor = 1.0f; + f32 m_trigger_lerp_factor = 1.0f; + // Stick Movements std::chrono::steady_clock::time_point m_stick_time; f32 m_l_stick_lerp_factor = 1.0f;