input_common: Redesign mouse->stick panning for better responsiveness
Previously, the mouse processing code had some issues that reduced mouse | control quality. No matter how you configured it or how you used the mouse, it was impossible to be able to make both fine inputs and maximum inputs to the control stick with the same configuration, as inputs were clamped to the range, and *outputs* were multiplied by the sensitivity setting. It was also impossible to make brief inputs, as two built-in exponential moving average filters in the mouse driver caused any mouse inputs, no matter how brief, to continue to produce stick outputs for several hundred milliseconds before dissipating. This commit is an attempt to address those issues. With this commit, an entirely different model of processing inputs is used. Instead of applying the sesnsitivity to the stick output, this commit applies the sensitivity at the beginning of processing to the mouse input. Next, inputs from the mouse are accumulated into a buffer variable. When the stick is updated, stick output is clamped to the range of the stick, and that value is subtracted from the input buffer. Any *excess* motion still remaining in the buffer gets decayed exponentially (similar to one of the exponential moving averages before). This gives a good compromise between responsiveness (brief mouse movement causes a brief stick response) and inertia (large mouse movement which exceeds the stick's instantaneous dynamic range causes stick movement that persists for a short time afterwards, mimicking inertia). Finally, to improve the linearity of the response, the stick motion is square-rooted to amplify small movements. This commit changes the semantics of the sensitivity option. It's no longer a percent, and "100(%)" no longer means anything special, so the input configuration UI has been changed to allow values up to 10,000 instead of being limited to 100. The changes to the filtration also affect the sensitivity. There are some magic constants in the code to try to keep the sensitivity about the same with a given value, but it's not exact, and users are encouraged to play around with it again on the new code.
This commit is contained in:
parent
e8a025b4f8
commit
88c8042932
2 changed files with 22 additions and 40 deletions
|
@ -88,13 +88,26 @@ void Mouse::UpdateStickInput() {
|
|||
return;
|
||||
}
|
||||
|
||||
const float sensitivity =
|
||||
Settings::values.mouse_panning_sensitivity.GetValue() * default_stick_sensitivity;
|
||||
auto mouse_change = last_mouse_change;
|
||||
auto move_distance = mouse_change.Length();
|
||||
|
||||
// Slow movement by 4%
|
||||
last_mouse_change *= 0.96f;
|
||||
SetAxis(identifier, mouse_axis_x, last_mouse_change.x * sensitivity);
|
||||
SetAxis(identifier, mouse_axis_y, -last_mouse_change.y * sensitivity);
|
||||
// Perform at most 1 unit of buffered mouse movement
|
||||
if (move_distance > 1.0f) {
|
||||
mouse_change *= 1.0f / move_distance;
|
||||
move_distance = mouse_change.Length();
|
||||
}
|
||||
|
||||
last_mouse_change -= mouse_change;
|
||||
|
||||
// Decay remaining buffered movement by 5%
|
||||
last_mouse_change *= 0.95f;
|
||||
|
||||
// Stick response is nonlinear, and is not sensitive enough to fine changes
|
||||
const auto sqrt_distance = sqrt(move_distance);
|
||||
mouse_change *= sqrt_distance / move_distance;
|
||||
|
||||
SetAxis(identifier, mouse_axis_x, mouse_change.x);
|
||||
SetAxis(identifier, mouse_axis_y, -mouse_change.y);
|
||||
}
|
||||
|
||||
void Mouse::UpdateMotionInput() {
|
||||
|
@ -130,48 +143,20 @@ void Mouse::UpdateMotionInput() {
|
|||
}
|
||||
|
||||
void Mouse::Move(int x, int y, int center_x, int center_y) {
|
||||
const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.0012f;
|
||||
if (Settings::values.mouse_panning) {
|
||||
mouse_panning_timeout = 0;
|
||||
|
||||
auto mouse_change =
|
||||
(Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast<float>();
|
||||
last_motion_change += {-mouse_change.y, -mouse_change.x, 0};
|
||||
|
||||
const auto move_distance = mouse_change.Length();
|
||||
if (move_distance == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make slow movements at least 3 units on length
|
||||
if (move_distance < 3.0f) {
|
||||
// Normalize value
|
||||
mouse_change /= move_distance;
|
||||
mouse_change *= 3.0f;
|
||||
}
|
||||
|
||||
// Average mouse movements
|
||||
last_mouse_change = (last_mouse_change * 0.91f) + (mouse_change * 0.09f);
|
||||
|
||||
const auto last_move_distance = last_mouse_change.Length();
|
||||
|
||||
// Make fast movements clamp to 8 units on length
|
||||
if (last_move_distance > 8.0f) {
|
||||
// Normalize value
|
||||
last_mouse_change /= last_move_distance;
|
||||
last_mouse_change *= 8.0f;
|
||||
}
|
||||
|
||||
// Ignore average if it's less than 1 unit and use current movement value
|
||||
if (last_move_distance < 1.0f) {
|
||||
last_mouse_change = mouse_change / mouse_change.Length();
|
||||
}
|
||||
last_mouse_change += mouse_change * sensitivity * 0.1f;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (button_pressed) {
|
||||
const auto mouse_move = Common::MakeVec<int>(x, y) - mouse_origin;
|
||||
const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.0012f;
|
||||
SetAxis(identifier, mouse_axis_x, static_cast<float>(mouse_move.x) * sensitivity);
|
||||
SetAxis(identifier, mouse_axis_y, static_cast<float>(-mouse_move.y) * sensitivity);
|
||||
|
||||
|
|
|
@ -2764,14 +2764,11 @@
|
|||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string>%</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
<number>10000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>100</number>
|
||||
|
|
Loading…
Add table
Reference in a new issue