mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 03:25:16 +00:00
Input: Add config lerp factor for buttons and triggers
Adds new lerp factors to the keyboard pad handler In order to simulate triggers and analog buttons. See "Analog Button Lerp Factor" and "Trigger Lerp Factor" in the yml in InputConfigs/Keyboard/. Values Range from 0-100 as before, where 100 is instant press and 0 is never. Currently I'm not planning any GUI element for this.
This commit is contained in:
parent
64ed2f1151
commit
7b49249f5f
4 changed files with 144 additions and 45 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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 };
|
||||
|
||||
|
|
|
@ -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<int>(pad->m_sticks.size()); i++)
|
||||
|
@ -576,6 +593,8 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr<Pad> 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> 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<std::chrono::microseconds>(now - m_last_mouse_move_left).count() / 1000.0;
|
||||
const double elapsed_right = std::chrono::duration_cast<std::chrono::microseconds>(now - m_last_mouse_move_right).count() / 1000.0;
|
||||
const double elapsed_up = std::chrono::duration_cast<std::chrono::microseconds>(now - m_last_mouse_move_up).count() / 1000.0;
|
||||
const double elapsed_down = std::chrono::duration_cast<std::chrono::microseconds>(now - m_last_mouse_move_down).count() / 1000.0;
|
||||
const double elapsed_stick = std::chrono::duration_cast<std::chrono::microseconds>(now - m_stick_time).count() / 1000.0;
|
||||
const double elapsed_button = std::chrono::duration_cast<std::chrono::microseconds>(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<std::chrono::microseconds>(now - m_last_mouse_move_left).count() / 1000.0;
|
||||
const double elapsed_right = std::chrono::duration_cast<std::chrono::microseconds>(now - m_last_mouse_move_right).count() / 1000.0;
|
||||
const double elapsed_up = std::chrono::duration_cast<std::chrono::microseconds>(now - m_last_mouse_move_up).count() / 1000.0;
|
||||
const double elapsed_down = std::chrono::duration_cast<std::chrono::microseconds>(now - m_last_mouse_move_down).count() / 1000.0;
|
||||
const double elapsed_stick = std::chrono::duration_cast<std::chrono::microseconds>(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<int>(bindings[i]->m_sticks.size()); j++)
|
||||
{
|
||||
|
@ -691,25 +733,50 @@ void keyboard_pad_handler::ThreadProc()
|
|||
{
|
||||
const f32 v0 = static_cast<f32>(bindings[i]->m_sticks[j].m_value);
|
||||
const f32 v1 = static_cast<f32>(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<u16>(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<f32>(button.m_value);
|
||||
const f32 v1 = static_cast<f32>(button.m_actual_value);
|
||||
const f32 res = get_lerped(v0, v1, m_analog_lerp_factor);
|
||||
|
||||
button.m_value = static_cast<u16>(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<f32>(button.m_value);
|
||||
const f32 v1 = static_cast<f32>(button.m_actual_value);
|
||||
const f32 res = get_lerped(v0, v1, m_trigger_lerp_factor);
|
||||
|
||||
button.m_value = static_cast<u16>(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)
|
||||
|
|
|
@ -101,6 +101,11 @@ private:
|
|||
QWindow* m_target = nullptr;
|
||||
std::vector<std::shared_ptr<Pad>> 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;
|
||||
|
|
Loading…
Add table
Reference in a new issue