Mouse coordinates are floating point

You can get sub-pixel mouse coordinates and motion depending on the platform and display scaling.

Fixes https://github.com/libsdl-org/SDL/issues/2999
This commit is contained in:
Sam Lantinga
2022-12-29 19:31:12 -08:00
parent 8c3239dee5
commit cefbeb582f
52 changed files with 564 additions and 654 deletions

View File

@@ -44,8 +44,6 @@ static SDL_Cursor *RPI_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y);
static int RPI_ShowCursor(SDL_Cursor *cursor);
static void RPI_MoveCursor(SDL_Cursor *cursor);
static void RPI_FreeCursor(SDL_Cursor *cursor);
static void RPI_WarpMouse(SDL_Window *window, int x, int y);
static int RPI_WarpMouseGlobal(int x, int y);
static SDL_Cursor *global_cursor;
@@ -223,14 +221,61 @@ static void RPI_FreeCursor(SDL_Cursor *cursor)
}
}
/* Warp the mouse to (x,y) */
static void RPI_WarpMouse(SDL_Window *window, int x, int y)
static int RPI_WarpMouseGlobalGraphically(float x, float y)
{
RPI_WarpMouseGlobal(x, y);
RPI_CursorData *curdata;
DISPMANX_UPDATE_HANDLE_T update;
int ret;
VC_RECT_T dst_rect;
VC_RECT_T src_rect;
SDL_Mouse *mouse = SDL_GetMouse();
if (mouse == NULL || mouse->cur_cursor == NULL || mouse->cur_cursor->driverdata == NULL) {
return 0;
}
curdata = (RPI_CursorData *)mouse->cur_cursor->driverdata;
if (curdata->element == DISPMANX_NO_HANDLE) {
return 0;
}
update = vc_dispmanx_update_start(0);
if (!update) {
return 0;
}
src_rect.x = 0;
src_rect.y = 0;
src_rect.width = curdata->w << 16;
src_rect.height = curdata->h << 16;
dst_rect.x = (int)x - curdata->hot_x;
dst_rect.y = (int)y - curdata->hot_y;
dst_rect.width = curdata->w;
dst_rect.height = curdata->h;
ret = vc_dispmanx_element_change_attributes(
update,
curdata->element,
0,
0,
0,
&dst_rect,
&src_rect,
DISPMANX_NO_HANDLE,
DISPMANX_NO_ROTATE);
if (ret != DISPMANX_SUCCESS) {
return SDL_SetError("vc_dispmanx_element_change_attributes() failed");
}
/* Submit asynchronously, otherwise the peformance suffers a lot */
ret = vc_dispmanx_update_submit(update, 0, NULL);
if (ret != DISPMANX_SUCCESS) {
return SDL_SetError("vc_dispmanx_update_submit() failed");
}
return 0;
}
/* Warp the mouse to (x,y) */
static int RPI_WarpMouseGlobal(int x, int y)
static int RPI_WarpMouseGlobal(float x, float y)
{
RPI_CursorData *curdata;
DISPMANX_UPDATE_HANDLE_T update;
@@ -246,100 +291,12 @@ static int RPI_WarpMouseGlobal(int x, int y)
/* Update internal mouse position. */
SDL_SendMouseMotion(0, mouse->focus, mouse->mouseID, 0, x, y);
curdata = (RPI_CursorData *)mouse->cur_cursor->driverdata;
if (curdata->element == DISPMANX_NO_HANDLE) {
return 0;
}
update = vc_dispmanx_update_start(0);
if (!update) {
return 0;
}
src_rect.x = 0;
src_rect.y = 0;
src_rect.width = curdata->w << 16;
src_rect.height = curdata->h << 16;
dst_rect.x = x - curdata->hot_x;
dst_rect.y = y - curdata->hot_y;
dst_rect.width = curdata->w;
dst_rect.height = curdata->h;
ret = vc_dispmanx_element_change_attributes(
update,
curdata->element,
0,
0,
0,
&dst_rect,
&src_rect,
DISPMANX_NO_HANDLE,
DISPMANX_NO_ROTATE);
if (ret != DISPMANX_SUCCESS) {
return SDL_SetError("vc_dispmanx_element_change_attributes() failed");
}
/* Submit asynchronously, otherwise the peformance suffers a lot */
ret = vc_dispmanx_update_submit(update, 0, NULL);
if (ret != DISPMANX_SUCCESS) {
return SDL_SetError("vc_dispmanx_update_submit() failed");
}
return 0;
return RPI_WarpMouseGlobalGraphically(x, y);
}
/* Warp the mouse to (x,y) */
static int RPI_WarpMouseGlobalGraphicOnly(int x, int y)
static void RPI_WarpMouse(SDL_Window *window, float x, float y)
{
RPI_CursorData *curdata;
DISPMANX_UPDATE_HANDLE_T update;
int ret;
VC_RECT_T dst_rect;
VC_RECT_T src_rect;
SDL_Mouse *mouse = SDL_GetMouse();
if (mouse == NULL || mouse->cur_cursor == NULL || mouse->cur_cursor->driverdata == NULL) {
return 0;
}
curdata = (RPI_CursorData *)mouse->cur_cursor->driverdata;
if (curdata->element == DISPMANX_NO_HANDLE) {
return 0;
}
update = vc_dispmanx_update_start(0);
if (!update) {
return 0;
}
src_rect.x = 0;
src_rect.y = 0;
src_rect.width = curdata->w << 16;
src_rect.height = curdata->h << 16;
dst_rect.x = x - curdata->hot_x;
dst_rect.y = y - curdata->hot_y;
dst_rect.width = curdata->w;
dst_rect.height = curdata->h;
ret = vc_dispmanx_element_change_attributes(
update,
curdata->element,
0,
0,
0,
&dst_rect,
&src_rect,
DISPMANX_NO_HANDLE,
DISPMANX_NO_ROTATE);
if (ret != DISPMANX_SUCCESS) {
return SDL_SetError("vc_dispmanx_element_change_attributes() failed");
}
/* Submit asynchronously, otherwise the peformance suffers a lot */
ret = vc_dispmanx_update_submit(update, 0, NULL);
if (ret != DISPMANX_SUCCESS) {
return SDL_SetError("vc_dispmanx_update_submit() failed");
}
return 0;
RPI_WarpMouseGlobal(x, y);
}
void RPI_InitMouse(_THIS)
@@ -369,7 +326,7 @@ static void RPI_MoveCursor(SDL_Cursor *cursor)
SDL_Mouse *mouse = SDL_GetMouse();
/* We must NOT call SDL_SendMouseMotion() on the next call or we will enter recursivity,
* so we create a version of WarpMouseGlobal without it. */
RPI_WarpMouseGlobalGraphicOnly(mouse->x, mouse->y);
RPI_WarpMouseGlobalGraphically(mouse->x, mouse->y);
}
#endif /* SDL_VIDEO_DRIVER_RPI */