mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-10-05 01:16:26 +00:00
Added a hint SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE to control whether to use system mouse acceleration on raw relative motion.
This is currently only implemented on Windows, and "Enhanced pointer precision" mode is not quite correct.
This commit is contained in:
@@ -83,8 +83,10 @@ SDL_MouseNormalSpeedScaleChanged(void *userdata, const char *name, const char *o
|
||||
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
|
||||
|
||||
if (hint && *hint) {
|
||||
mouse->enable_normal_speed_scale = SDL_TRUE;
|
||||
mouse->normal_speed_scale = (float)SDL_atof(hint);
|
||||
} else {
|
||||
mouse->enable_normal_speed_scale = SDL_FALSE;
|
||||
mouse->normal_speed_scale = 1.0f;
|
||||
}
|
||||
}
|
||||
@@ -95,12 +97,22 @@ SDL_MouseRelativeSpeedScaleChanged(void *userdata, const char *name, const char
|
||||
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
|
||||
|
||||
if (hint && *hint) {
|
||||
mouse->enable_relative_speed_scale = SDL_TRUE;
|
||||
mouse->relative_speed_scale = (float)SDL_atof(hint);
|
||||
} else {
|
||||
mouse->enable_relative_speed_scale = SDL_FALSE;
|
||||
mouse->relative_speed_scale = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static void SDLCALL
|
||||
SDL_MouseRelativeSystemScaleChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
|
||||
{
|
||||
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
|
||||
|
||||
mouse->enable_relative_system_scale = SDL_GetStringBoolean(hint, SDL_FALSE);
|
||||
}
|
||||
|
||||
static void SDLCALL
|
||||
SDL_TouchMouseEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
|
||||
{
|
||||
@@ -189,6 +201,9 @@ SDL_MouseInit(void)
|
||||
SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE,
|
||||
SDL_MouseRelativeSpeedScaleChanged, mouse);
|
||||
|
||||
SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE,
|
||||
SDL_MouseRelativeSystemScaleChanged, mouse);
|
||||
|
||||
SDL_AddHintCallback(SDL_HINT_TOUCH_MOUSE_EVENTS,
|
||||
SDL_TouchMouseEventsChanged, mouse);
|
||||
|
||||
@@ -344,7 +359,10 @@ SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int
|
||||
static int
|
||||
GetScaledMouseDelta(float scale, int value, float *accum)
|
||||
{
|
||||
if (scale != 1.0f) {
|
||||
if (value && scale != 1.0f) {
|
||||
if ((value > 0) != (*accum > 0)) {
|
||||
*accum = 0.0f;
|
||||
}
|
||||
*accum += scale * value;
|
||||
if (*accum >= 0.0f) {
|
||||
value = (int)SDL_floor(*accum);
|
||||
@@ -356,6 +374,100 @@ GetScaledMouseDelta(float scale, int value, float *accum)
|
||||
return value;
|
||||
}
|
||||
|
||||
static float
|
||||
CalculateSystemScale(SDL_Mouse *mouse, int *x, int *y)
|
||||
{
|
||||
int i;
|
||||
int n = mouse->num_system_scale_values;
|
||||
float *v = mouse->system_scale_values;
|
||||
float speed, coef, scale;
|
||||
|
||||
/* If we're using a single scale value, return that */
|
||||
if (n == 1) {
|
||||
return v[0];
|
||||
}
|
||||
|
||||
speed = SDL_sqrtf((float)(*x * *x) + (*y * *y));
|
||||
for (i = 0; i < (n - 2); i += 2) {
|
||||
if (speed < v[i + 2]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == (n - 2)) {
|
||||
scale = v[n - 1];
|
||||
} else if (speed <= v[i]) {
|
||||
scale = v[i + 1];
|
||||
} else {
|
||||
coef = (speed - v[i]) / (v[i + 2] - v[i]);
|
||||
scale = v[i + 1] + (coef * (v[i + 3] - v[i + 1]));
|
||||
}
|
||||
SDL_Log("speed = %.2f, scale = %.2f\n", speed, scale);
|
||||
return scale;
|
||||
}
|
||||
|
||||
/* You can set either a single scale, or a set of {speed, scale} values in ascending order */
|
||||
int
|
||||
SDL_SetMouseSystemScale(int num_values, const float *values)
|
||||
{
|
||||
SDL_Mouse *mouse = SDL_GetMouse();
|
||||
float *v;
|
||||
|
||||
if (num_values == mouse->num_system_scale_values &&
|
||||
SDL_memcmp(values, mouse->system_scale_values, num_values * sizeof(*values)) == 0) {
|
||||
/* Nothing has changed */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (num_values < 1) {
|
||||
return SDL_SetError("You must have at least one scale value");
|
||||
}
|
||||
|
||||
if (num_values > 1) {
|
||||
/* Validate the values */
|
||||
int i;
|
||||
|
||||
if (num_values < 4 || (num_values % 2) != 0) {
|
||||
return SDL_SetError("You must pass a set of {speed, scale} values");
|
||||
}
|
||||
|
||||
for (i = 0; i < (num_values - 2); i += 2) {
|
||||
if (values[i] >= values[i + 2]) {
|
||||
return SDL_SetError("Speed values must be in ascending order");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
v = (float *)SDL_realloc(mouse->system_scale_values, num_values * sizeof(*values));
|
||||
if (!v) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
SDL_memcpy(v, values, num_values * sizeof(*values));
|
||||
|
||||
mouse->num_system_scale_values = num_values;
|
||||
mouse->system_scale_values = v;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
GetScaledMouseDeltas(SDL_Mouse *mouse, int *x, int *y)
|
||||
{
|
||||
if (mouse->relative_mode) {
|
||||
if (mouse->enable_relative_speed_scale) {
|
||||
*x = GetScaledMouseDelta(mouse->relative_speed_scale, *x, &mouse->scale_accum_x);
|
||||
*y = GetScaledMouseDelta(mouse->relative_speed_scale, *y, &mouse->scale_accum_y);
|
||||
} else if (mouse->enable_relative_system_scale && mouse->num_system_scale_values > 0) {
|
||||
float relative_system_scale = CalculateSystemScale(mouse, x, y);
|
||||
*x = GetScaledMouseDelta(relative_system_scale, *x, &mouse->scale_accum_x);
|
||||
*y = GetScaledMouseDelta(relative_system_scale, *y, &mouse->scale_accum_y);
|
||||
}
|
||||
} else {
|
||||
if (mouse->enable_normal_speed_scale) {
|
||||
*x = GetScaledMouseDelta(mouse->normal_speed_scale, *x, &mouse->scale_accum_x);
|
||||
*y = GetScaledMouseDelta(mouse->normal_speed_scale, *y, &mouse->scale_accum_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
|
||||
{
|
||||
@@ -405,13 +517,7 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ
|
||||
}
|
||||
|
||||
if (relative) {
|
||||
if (mouse->relative_mode) {
|
||||
x = GetScaledMouseDelta(mouse->relative_speed_scale, x, &mouse->scale_accum_x);
|
||||
y = GetScaledMouseDelta(mouse->relative_speed_scale, y, &mouse->scale_accum_y);
|
||||
} else {
|
||||
x = GetScaledMouseDelta(mouse->normal_speed_scale, x, &mouse->scale_accum_x);
|
||||
y = GetScaledMouseDelta(mouse->normal_speed_scale, y, &mouse->scale_accum_y);
|
||||
}
|
||||
GetScaledMouseDeltas(mouse, &x, &y);
|
||||
xrel = x;
|
||||
yrel = y;
|
||||
x = (mouse->last_x + xrel);
|
||||
@@ -818,6 +924,9 @@ SDL_MouseQuit(void)
|
||||
SDL_DelHintCallback(SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE,
|
||||
SDL_MouseRelativeSpeedScaleChanged, mouse);
|
||||
|
||||
SDL_DelHintCallback(SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE,
|
||||
SDL_MouseRelativeSystemScaleChanged, mouse);
|
||||
|
||||
SDL_DelHintCallback(SDL_HINT_TOUCH_MOUSE_EVENTS,
|
||||
SDL_TouchMouseEventsChanged, mouse);
|
||||
|
||||
|
Reference in New Issue
Block a user