add alternate raw mouse motion events with windows implementation (#10042)

This commit is contained in:
expikr
2024-12-19 09:29:27 +08:00
committed by GitHub
parent 345cab1e36
commit 5c0f8dc179
10 changed files with 221 additions and 75 deletions

View File

@@ -182,6 +182,9 @@ typedef enum SDL_EventType
SDL_EVENT_MOUSE_WHEEL, /**< Mouse wheel motion */ SDL_EVENT_MOUSE_WHEEL, /**< Mouse wheel motion */
SDL_EVENT_MOUSE_ADDED, /**< A new mouse has been inserted into the system */ SDL_EVENT_MOUSE_ADDED, /**< A new mouse has been inserted into the system */
SDL_EVENT_MOUSE_REMOVED, /**< A mouse has been removed */ SDL_EVENT_MOUSE_REMOVED, /**< A mouse has been removed */
SDL_EVENT_MOUSE_RAW_MOTION, /**< Mouse moved (raw motion deltas) */
SDL_EVENT_MOUSE_RAW_BUTTON, /**< Mouse click (raw button delta) */
SDL_EVENT_MOUSE_RAW_SCROLL, /**< Mouse wheel (raw scroll deltas) */
/* Joystick events */ /* Joystick events */
SDL_EVENT_JOYSTICK_AXIS_MOTION = 0x600, /**< Joystick axis motion */ SDL_EVENT_JOYSTICK_AXIS_MOTION = 0x600, /**< Joystick axis motion */
@@ -454,6 +457,23 @@ typedef struct SDL_MouseMotionEvent
float yrel; /**< The relative motion in the Y direction */ float yrel; /**< The relative motion in the Y direction */
} SDL_MouseMotionEvent; } SDL_MouseMotionEvent;
/**
* Mouse raw motion and wheel event structure (event.maxis.*)
*
* \since This struct is available since SDL 3.0.0.
*/
typedef struct SDL_MouseRawAxisEvent
{
SDL_EventType type; /**< SDL_EVENT_MOUSE_RAW_MOTION or SDL_EVENT_MOUSE_RAW_SCROLL */
Uint32 reserved;
Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */
SDL_MouseID which; /**< The mouse instance id, SDL_TOUCH_MOUSEID, or SDL_PEN_MOUSEID */
int dx; /**< The axis delta value in the X direction */
int dy; /**< The axis delta value in the Y direction */
float ux; /**< The denominator unit in the X direction */
float uy; /**< The denominator unit in the Y direction */
} SDL_MouseRawAxisEvent;
/** /**
* Mouse button event structure (event.button.*) * Mouse button event structure (event.button.*)
* *
@@ -474,6 +494,21 @@ typedef struct SDL_MouseButtonEvent
float y; /**< Y coordinate, relative to window */ float y; /**< Y coordinate, relative to window */
} SDL_MouseButtonEvent; } SDL_MouseButtonEvent;
/**
* Mouse raw button event structure (event.mbutton.*)
*
* \since This struct is available since SDL 3.0.0.
*/
typedef struct SDL_MouseRawButtonEvent
{
SDL_EventType type; /**< SDL_EVENT_MOUSE_RAW_BUTTON */
Uint32 reserved;
Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */
SDL_MouseID which; /**< The mouse instance id, SDL_TOUCH_MOUSEID, or SDL_PEN_MOUSEID */
Uint8 button; /**< The mouse button index */
Uint8 state; /**< SDL_PRESSED or SDL_RELEASED */
} SDL_MouseRawButtonEvent;
/** /**
* Mouse wheel event structure (event.wheel.*) * Mouse wheel event structure (event.wheel.*)
* *
@@ -997,6 +1032,8 @@ typedef union SDL_Event
SDL_MouseMotionEvent motion; /**< Mouse motion event data */ SDL_MouseMotionEvent motion; /**< Mouse motion event data */
SDL_MouseButtonEvent button; /**< Mouse button event data */ SDL_MouseButtonEvent button; /**< Mouse button event data */
SDL_MouseWheelEvent wheel; /**< Mouse wheel event data */ SDL_MouseWheelEvent wheel; /**< Mouse wheel event data */
SDL_MouseRawAxisEvent maxis; /**< Mouse raw axis event data (motion or wheel deltas) */
SDL_MouseRawButtonEvent mbutton; /**< Mouse raw button event data */
SDL_JoyDeviceEvent jdevice; /**< Joystick device change event data */ SDL_JoyDeviceEvent jdevice; /**< Joystick device change event data */
SDL_JoyAxisEvent jaxis; /**< Joystick axis event data */ SDL_JoyAxisEvent jaxis; /**< Joystick axis event data */
SDL_JoyBallEvent jball; /**< Joystick ball event data */ SDL_JoyBallEvent jball; /**< Joystick ball event data */

View File

@@ -390,6 +390,7 @@ static void SDL_LogEvent(const SDL_Event *event)
// sensor/mouse/pen/finger motion are spammy, ignore these if they aren't demanded. // sensor/mouse/pen/finger motion are spammy, ignore these if they aren't demanded.
if ((SDL_EventLoggingVerbosity < 2) && if ((SDL_EventLoggingVerbosity < 2) &&
((event->type == SDL_EVENT_MOUSE_MOTION) || ((event->type == SDL_EVENT_MOUSE_MOTION) ||
(event->type == SDL_EVENT_MOUSE_RAW_MOTION) ||
(event->type == SDL_EVENT_FINGER_MOTION) || (event->type == SDL_EVENT_FINGER_MOTION) ||
(event->type == SDL_EVENT_PEN_AXIS) || (event->type == SDL_EVENT_PEN_AXIS) ||
(event->type == SDL_EVENT_PEN_MOTION) || (event->type == SDL_EVENT_PEN_MOTION) ||
@@ -1884,6 +1885,12 @@ void SDL_SetEventEnabled(Uint32 type, bool enabled)
if (type == SDL_EVENT_DROP_FILE || type == SDL_EVENT_DROP_TEXT) { if (type == SDL_EVENT_DROP_FILE || type == SDL_EVENT_DROP_TEXT) {
SDL_ToggleDragAndDropSupport(); SDL_ToggleDragAndDropSupport();
} }
if (type == SDL_EVENT_MOUSE_RAW_MOTION ||
type == SDL_EVENT_MOUSE_RAW_SCROLL ||
type == SDL_EVENT_MOUSE_RAW_BUTTON) {
SDL_UpdateRawMouseDataEnabled();
}
} }
} }
@@ -1972,6 +1979,9 @@ bool SDL_InitEvents(void)
return false; return false;
} }
SDL_SetEventEnabled(SDL_EVENT_MOUSE_RAW_MOTION, false);
SDL_SetEventEnabled(SDL_EVENT_MOUSE_RAW_SCROLL, false);
SDL_SetEventEnabled(SDL_EVENT_MOUSE_RAW_BUTTON, false);
SDL_InitQuit(); SDL_InitQuit();
return true; return true;

View File

@@ -597,6 +597,34 @@ void SDL_SendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouse
SDL_PrivateSendMouseMotion(timestamp, window, mouseID, relative, x, y); SDL_PrivateSendMouseMotion(timestamp, window, mouseID, relative, x, y);
} }
void SDL_SendRawMouseAxis(Uint64 timestamp, SDL_MouseID mouseID, int dx, int dy, float ux, float uy, SDL_EventType type)
{
if (SDL_EventEnabled(type)) {
SDL_Event event;
event.type = type;
event.common.timestamp = timestamp;
event.maxis.which = mouseID;
event.maxis.dx = dx;
event.maxis.dy = dy;
event.maxis.ux = ux;
event.maxis.uy = uy;
SDL_PushEvent(&event);
}
}
void SDL_SendRawMouseButton(Uint64 timestamp, SDL_MouseID mouseID, Uint8 state, Uint8 button)
{
if (SDL_EventEnabled(SDL_EVENT_MOUSE_RAW_BUTTON)) {
SDL_Event event;
event.type = SDL_EVENT_MOUSE_RAW_BUTTON;
event.common.timestamp = timestamp;
event.mbutton.which = mouseID;
event.mbutton.button = button;
event.mbutton.state = state;
SDL_PushEvent(&event);
}
}
static void ConstrainMousePosition(SDL_Mouse *mouse, SDL_Window *window, float *x, float *y) static void ConstrainMousePosition(SDL_Mouse *mouse, SDL_Window *window, float *x, float *y)
{ {
/* make sure that the pointers find themselves inside the windows, /* make sure that the pointers find themselves inside the windows,

View File

@@ -170,6 +170,12 @@ extern bool SDL_UpdateMouseCapture(bool force_release);
// Send a mouse motion event // Send a mouse motion event
extern void SDL_SendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, bool relative, float x, float y); extern void SDL_SendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, bool relative, float x, float y);
/* Send a raw mouse motion or scroll event */
extern void SDL_SendRawMouseAxis(Uint64 timestamp, SDL_MouseID mouseID, int dx, int dy, float ux, float uy, SDL_EventType type);
/* Send a raw mouse button event */
extern void SDL_SendRawMouseButton(Uint64 timestamp, SDL_MouseID mouseID, Uint8 state, Uint8 button);
// Send a mouse button event // Send a mouse button event
extern void SDL_SendMouseButton(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, Uint8 button, bool down); extern void SDL_SendMouseButton(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, Uint8 button, bool down);

View File

@@ -385,6 +385,9 @@ struct SDL_VideoDevice
// Display the system-level window menu // Display the system-level window menu
void (*ShowWindowSystemMenu)(SDL_Window *window, int x, int y); void (*ShowWindowSystemMenu)(SDL_Window *window, int x, int y);
/* Re-synchronize platform raw input subscription */
bool (*RefreshRawInput)(SDL_VideoDevice *_this);
/* * * */ /* * * */
// Data common to all drivers // Data common to all drivers
SDL_ThreadID thread; SDL_ThreadID thread;
@@ -583,6 +586,7 @@ extern SDL_Window *SDL_GetToplevelForKeyboardFocus(void);
extern bool SDL_ShouldAllowTopmost(void); extern bool SDL_ShouldAllowTopmost(void);
extern void SDL_ToggleDragAndDropSupport(void); extern void SDL_ToggleDragAndDropSupport(void);
extern void SDL_UpdateRawMouseDataEnabled(void);
extern SDL_TextInputType SDL_GetTextInputType(SDL_PropertiesID props); extern SDL_TextInputType SDL_GetTextInputType(SDL_PropertiesID props);
extern SDL_Capitalization SDL_GetTextInputCapitalization(SDL_PropertiesID props); extern SDL_Capitalization SDL_GetTextInputCapitalization(SDL_PropertiesID props);

View File

@@ -2109,6 +2109,13 @@ void SDL_ToggleDragAndDropSupport(void)
} }
} }
void SDL_UpdateRawMouseDataEnabled(void)
{
if (_this && _this->RefreshRawInput) {
_this->RefreshRawInput(_this);
}
}
SDL_Window **SDLCALL SDL_GetWindows(int *count) SDL_Window **SDLCALL SDL_GetWindows(int *count)
{ {
if (count) { if (count) {

View File

@@ -521,6 +521,46 @@ static bool WIN_SwapButtons(HANDLE hDevice)
static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_VideoData *data, HANDLE hDevice, RAWMOUSE *rawmouse) static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_VideoData *data, HANDLE hDevice, RAWMOUSE *rawmouse)
{ {
int xraw = (int)rawmouse->lLastX;
int yraw = (int)rawmouse->lLastY;
bool haveMotion = (xraw || yraw) ? true : false;
bool haveButton = (rawmouse->usButtonFlags) ? true : false;
bool isAbsolute = (rawmouse->usFlags & MOUSE_MOVE_ABSOLUTE) ? true : false;
SDL_MouseID mouseID = (SDL_MouseID)(uintptr_t)hDevice;
if (SDL_EventEnabled(SDL_EVENT_MOUSE_RAW_MOTION)) {
if (haveMotion && !isAbsolute) {
SDL_SendRawMouseAxis(timestamp, mouseID, xraw, yraw, 1.0f, 1.0f, SDL_EVENT_MOUSE_RAW_MOTION);
}
}
if (SDL_EventEnabled(SDL_EVENT_MOUSE_RAW_BUTTON)) {
if (haveButton) {
USHORT flagBits = rawmouse->usButtonFlags;
for (Uint8 i = 0; i < 10; ++i) {
if (flagBits & 1) {
Uint8 state = (i & 1) ^ 1;
Uint8 button = (i >> 1) + 1;
SDL_SendRawMouseButton(timestamp, mouseID, state, button);
}
flagBits = flagBits >> 1;
}
}
}
if (SDL_EventEnabled(SDL_EVENT_MOUSE_RAW_SCROLL)) {
if (haveButton) {
short amount = (short)rawmouse->usButtonData;
if (rawmouse->usButtonFlags & RI_MOUSE_WHEEL) {
SDL_SendRawMouseAxis(timestamp, mouseID, 0, (int)amount, 120.0f, 120.0f, SDL_EVENT_MOUSE_RAW_SCROLL);
} else if (rawmouse->usButtonFlags & RI_MOUSE_HWHEEL) {
SDL_SendRawMouseAxis(timestamp, mouseID, (int)amount, 0, 120.0f, 120.0f, SDL_EVENT_MOUSE_RAW_SCROLL);
}
}
}
// this check is for whether relative mode should also receive events from the rawinput stream,
// separate from whether or not the optional rawaxis/rawbutton events should be generated.
if (!data->raw_mouse_enabled) { if (!data->raw_mouse_enabled) {
return; return;
} }
@@ -535,14 +575,12 @@ static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_VideoData *data, HANDL
return; return;
} }
SDL_MouseID mouseID = (SDL_MouseID)(uintptr_t)hDevice;
SDL_WindowData *windowdata = window->internal; SDL_WindowData *windowdata = window->internal;
if ((rawmouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) { if (haveMotion) {
if (rawmouse->lLastX || rawmouse->lLastY) { if (!isAbsolute) {
SDL_SendMouseMotion(timestamp, window, mouseID, true, (float)rawmouse->lLastX, (float)rawmouse->lLastY); SDL_SendMouseMotion(timestamp, window, mouseID, true, (float)xraw, (float)yraw);
} } else {
} else if (rawmouse->lLastX || rawmouse->lLastY) {
/* This is absolute motion, either using a tablet or mouse over RDP /* This is absolute motion, either using a tablet or mouse over RDP
Notes on how RDP appears to work, as of Windows 10 2004: Notes on how RDP appears to work, as of Windows 10 2004:
@@ -555,14 +593,14 @@ static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_VideoData *data, HANDL
*/ */
bool remote_desktop = GetSystemMetrics(SM_REMOTESESSION) ? true : false; bool remote_desktop = GetSystemMetrics(SM_REMOTESESSION) ? true : false;
bool virtual_desktop = (rawmouse->usFlags & MOUSE_VIRTUAL_DESKTOP) ? true : false; bool virtual_desktop = (rawmouse->usFlags & MOUSE_VIRTUAL_DESKTOP) ? true : false;
bool normalized_coordinates = !(rawmouse->usFlags & 0x40) ? true : false; bool raw_coordinates = (rawmouse->usFlags & 0x40) ? true : false;
int w = GetSystemMetrics(virtual_desktop ? SM_CXVIRTUALSCREEN : SM_CXSCREEN); int w = GetSystemMetrics(virtual_desktop ? SM_CXVIRTUALSCREEN : SM_CXSCREEN);
int h = GetSystemMetrics(virtual_desktop ? SM_CYVIRTUALSCREEN : SM_CYSCREEN); int h = GetSystemMetrics(virtual_desktop ? SM_CYVIRTUALSCREEN : SM_CYSCREEN);
int x = normalized_coordinates ? (int)(((float)rawmouse->lLastX / 65535.0f) * w) : (int)rawmouse->lLastX; int x = raw_coordinates ? (int)xraw : (int)(((float)xraw / 65535.0f) * w);
int y = normalized_coordinates ? (int)(((float)rawmouse->lLastY / 65535.0f) * h) : (int)rawmouse->lLastY; int y = raw_coordinates ? (int)yraw : (int)(((float)yraw / 65535.0f) * h);
int relX, relY; int relX, relY;
// Calculate relative motion /* Calculate relative motion */
if (data->last_raw_mouse_position.x == 0 && data->last_raw_mouse_position.y == 0) { if (data->last_raw_mouse_position.x == 0 && data->last_raw_mouse_position.y == 0) {
data->last_raw_mouse_position.x = x; data->last_raw_mouse_position.x = x;
data->last_raw_mouse_position.y = y; data->last_raw_mouse_position.y = y;
@@ -576,9 +614,9 @@ static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_VideoData *data, HANDL
float floatX = (float)x / w; float floatX = (float)x / w;
float floatY = (float)y / h; float floatY = (float)y / h;
// See if the mouse is at the edge of the screen, or in the RDP title bar area /* See if the mouse is at the edge of the screen, or in the RDP title bar area */
if (floatX <= 0.01f || floatX >= 0.99f || floatY <= 0.01f || floatY >= 0.99f || y < 32) { if (floatX <= 0.01f || floatX >= 0.99f || floatY <= 0.01f || floatY >= 0.99f || y < 32) {
// Wobble the cursor position so it's not ignored if the last warp didn't have any effect /* Wobble the cursor position so it's not ignored if the last warp didn't have any effect */
RECT rect = windowdata->cursor_clipped_rect; RECT rect = windowdata->cursor_clipped_rect;
int warpX = rect.left + ((rect.right - rect.left) / 2) + wobble; int warpX = rect.left + ((rect.right - rect.left) / 2) + wobble;
int warpY = rect.top + ((rect.bottom - rect.top) / 2); int warpY = rect.top + ((rect.bottom - rect.top) / 2);
@@ -605,7 +643,7 @@ static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_VideoData *data, HANDL
const int MAXIMUM_TABLET_RELATIVE_MOTION = 32; const int MAXIMUM_TABLET_RELATIVE_MOTION = 32;
if (SDL_abs(relX) > MAXIMUM_TABLET_RELATIVE_MOTION || if (SDL_abs(relX) > MAXIMUM_TABLET_RELATIVE_MOTION ||
SDL_abs(relY) > MAXIMUM_TABLET_RELATIVE_MOTION) { SDL_abs(relY) > MAXIMUM_TABLET_RELATIVE_MOTION) {
// Ignore this motion, probably a pen lift and drop /* Ignore this motion, probably a pen lift and drop */
} else { } else {
SDL_SendMouseMotion(timestamp, window, mouseID, true, (float)relX, (float)relY); SDL_SendMouseMotion(timestamp, window, mouseID, true, (float)relX, (float)relY);
} }
@@ -614,8 +652,9 @@ static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_VideoData *data, HANDL
data->last_raw_mouse_position.x = x; data->last_raw_mouse_position.x = x;
data->last_raw_mouse_position.y = y; data->last_raw_mouse_position.y = y;
} }
}
if (rawmouse->usButtonFlags) { if (haveButton) {
static struct { static struct {
USHORT usButtonFlags; USHORT usButtonFlags;
Uint8 button; Uint8 button;

View File

@@ -29,6 +29,7 @@
#include "SDL_windowsevents.h" #include "SDL_windowsevents.h"
#include "../../joystick/usb_ids.h" #include "../../joystick/usb_ids.h"
#include "../../events/SDL_events_c.h"
#define ENABLE_RAW_MOUSE_INPUT 0x01 #define ENABLE_RAW_MOUSE_INPUT 0x01
#define ENABLE_RAW_KEYBOARD_INPUT 0x02 #define ENABLE_RAW_KEYBOARD_INPUT 0x02
@@ -192,7 +193,10 @@ static bool WIN_UpdateRawInputEnabled(SDL_VideoDevice *_this)
{ {
SDL_VideoData *data = _this->internal; SDL_VideoData *data = _this->internal;
Uint32 flags = 0; Uint32 flags = 0;
if (data->raw_mouse_enabled) { if (SDL_EventEnabled(SDL_EVENT_MOUSE_RAW_MOTION) ||
SDL_EventEnabled(SDL_EVENT_MOUSE_RAW_SCROLL) ||
SDL_EventEnabled(SDL_EVENT_MOUSE_RAW_BUTTON) ||
data->raw_mouse_enabled) {
flags |= ENABLE_RAW_MOUSE_INPUT; flags |= ENABLE_RAW_MOUSE_INPUT;
} }
if (data->raw_keyboard_enabled) { if (data->raw_keyboard_enabled) {
@@ -244,6 +248,11 @@ bool WIN_SetRawKeyboardEnabled(SDL_VideoDevice *_this, bool enabled)
return true; return true;
} }
bool WIN_RefreshRawInputEnabled(SDL_VideoDevice *_this)
{
return WIN_UpdateRawInputEnabled(_this);
}
#else #else
bool WIN_SetRawMouseEnabled(SDL_VideoDevice *_this, bool enabled) bool WIN_SetRawMouseEnabled(SDL_VideoDevice *_this, bool enabled)
@@ -256,6 +265,10 @@ bool WIN_SetRawKeyboardEnabled(SDL_VideoDevice *_this, bool enabled)
return SDL_Unsupported(); return SDL_Unsupported();
} }
bool WIN_RefreshRawInputEnabled(SDL_VideoDevice *_this)
{
return SDL_Unsupported();
}
#endif // !SDL_PLATFORM_XBOXONE && !SDL_PLATFORM_XBOXSERIES #endif // !SDL_PLATFORM_XBOXONE && !SDL_PLATFORM_XBOXSERIES
#endif // SDL_VIDEO_DRIVER_WINDOWS #endif // SDL_VIDEO_DRIVER_WINDOWS

View File

@@ -25,5 +25,6 @@
extern bool WIN_SetRawMouseEnabled(SDL_VideoDevice *_this, bool enabled); extern bool WIN_SetRawMouseEnabled(SDL_VideoDevice *_this, bool enabled);
extern bool WIN_SetRawKeyboardEnabled(SDL_VideoDevice *_this, bool enabled); extern bool WIN_SetRawKeyboardEnabled(SDL_VideoDevice *_this, bool enabled);
extern bool WIN_RefreshRawInputEnabled(SDL_VideoDevice *_this);
#endif // SDL_windowsrawinput_h_ #endif // SDL_windowsrawinput_h_

View File

@@ -246,6 +246,7 @@ static SDL_VideoDevice *WIN_CreateDevice(void)
device->OnWindowEnter = WIN_OnWindowEnter; device->OnWindowEnter = WIN_OnWindowEnter;
device->SetWindowHitTest = WIN_SetWindowHitTest; device->SetWindowHitTest = WIN_SetWindowHitTest;
device->AcceptDragAndDrop = WIN_AcceptDragAndDrop; device->AcceptDragAndDrop = WIN_AcceptDragAndDrop;
device->RefreshRawInput = WIN_RefreshRawInputEnabled;
device->FlashWindow = WIN_FlashWindow; device->FlashWindow = WIN_FlashWindow;
device->ShowWindowSystemMenu = WIN_ShowWindowSystemMenu; device->ShowWindowSystemMenu = WIN_ShowWindowSystemMenu;
device->SetWindowFocusable = WIN_SetWindowFocusable; device->SetWindowFocusable = WIN_SetWindowFocusable;