diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 5bbcbf7b1d..bde2a53bde 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -1334,12 +1334,33 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara SDL_SendPenTouch(timestamp, pen, window, (pen_info.penFlags & PEN_FLAG_INVERTED) != 0, false); } - POINT position; - position.x = (LONG) GET_X_LPARAM(lParam); - position.y = (LONG) GET_Y_LPARAM(lParam); - ScreenToClient(data->hwnd, &position); + const POINTER_INFO *pointer_info = &pen_info.pointerInfo; + RECT tablet_bounds, tablet_mapping; + float fx, fy; - SDL_SendPenMotion(timestamp, pen, window, (float) position.x, (float) position.y); + // try to get a more-precise position than is stored in lParam...GetPointerDeviceRects is available starting in Windows 8. + // we might need to cache this somewhere (and if we cache it, we will need to update it if the display changes)...for now we'll see if GetPointerDeviceRect is fast enough. + if (!data->videodata->GetPointerDeviceRects || !data->videodata->GetPointerDeviceRects(pointer_info->sourceDevice, &tablet_bounds, &tablet_mapping)) { + POINT position = { (LONG) GET_X_LPARAM(lParam), (LONG) GET_Y_LPARAM(lParam) }; + ScreenToClient(data->hwnd, &position); + fx = (float) position.x; + fy = (float) position.y; + } else { + int ix, iy; + SDL_GetWindowPosition(window, &ix, &iy); + const SDL_FPoint window_pos = { (float) ix, (float) iy }; + + const float facX = pointer_info->ptHimetricLocationRaw.x / (float) (tablet_bounds.right ); + const float facY = pointer_info->ptHimetricLocationRaw.y / (float) (tablet_bounds.bottom); + + const float w = tablet_mapping.right - tablet_mapping.left; + const float h = tablet_mapping.bottom - tablet_mapping.top; + + fx = (tablet_mapping.left + (facX * w)) - window_pos.x; + fy = (tablet_mapping.top + (facY * h)) - window_pos.y; + } + + SDL_SendPenMotion(timestamp, pen, window, fx, fy); SDL_SendPenButton(timestamp, pen, window, 1, (pen_info.penFlags & PEN_FLAG_BARREL) != 0); SDL_SendPenButton(timestamp, pen, window, 2, (pen_info.penFlags & PEN_FLAG_ERASER) != 0); diff --git a/src/video/windows/SDL_windowsvideo.c b/src/video/windows/SDL_windowsvideo.c index 6b459138f7..3db7614b46 100644 --- a/src/video/windows/SDL_windowsvideo.c +++ b/src/video/windows/SDL_windowsvideo.c @@ -267,6 +267,7 @@ static SDL_VideoDevice *WIN_CreateDevice(void) data->DisplayConfigGetDeviceInfo = (LONG (WINAPI *)(DISPLAYCONFIG_DEVICE_INFO_HEADER*))SDL_LoadFunction(data->userDLL, "DisplayConfigGetDeviceInfo"); data->GetPointerType = (BOOL (WINAPI *)(UINT32, POINTER_INPUT_TYPE *))SDL_LoadFunction(data->userDLL, "GetPointerType"); data->GetPointerPenInfo = (BOOL (WINAPI *)(UINT32, POINTER_PEN_INFO *))SDL_LoadFunction(data->userDLL, "GetPointerPenInfo"); + data->GetPointerDeviceRects = (BOOL (WINAPI *)(HANDLE, RECT *, RECT *))SDL_LoadFunction(data->userDLL, "GetPointerDeviceRects"); /* *INDENT-ON* */ // clang-format on } else { SDL_ClearError(); diff --git a/src/video/windows/SDL_windowsvideo.h b/src/video/windows/SDL_windowsvideo.h index 4ed1a42b58..a1a5bc608a 100644 --- a/src/video/windows/SDL_windowsvideo.h +++ b/src/video/windows/SDL_windowsvideo.h @@ -552,6 +552,7 @@ struct SDL_VideoData /* *INDENT-OFF* */ // clang-format off BOOL (WINAPI *GetPointerType)(UINT32 pointerId, POINTER_INPUT_TYPE *pointerType); BOOL (WINAPI *GetPointerPenInfo)(UINT32 pointerId, POINTER_PEN_INFO *penInfo); + BOOL (WINAPI *GetPointerDeviceRects)(HANDLE device, RECT *pointerDeviceRect, RECT *displayRect); /* *INDENT-ON* */ // clang-format on // DPI functions