2015-06-21 10:33:46 -05:00
|
|
|
/*
|
|
|
|
Simple DirectMedia Layer
|
2022-01-03 11:40:00 -06:00
|
|
|
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
2015-06-21 10:33:46 -05:00
|
|
|
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
|
|
warranty. In no event will the authors be held liable for any damages
|
|
|
|
arising from the use of this software.
|
|
|
|
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
|
|
including commercial applications, and to alter it and redistribute it
|
|
|
|
freely, subject to the following restrictions:
|
|
|
|
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
|
|
claim that you wrote the original software. If you use this software
|
|
|
|
in a product, an acknowledgment in the product documentation would be
|
|
|
|
appreciated but is not required.
|
|
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
|
|
misrepresented as being the original software.
|
|
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
*/
|
|
|
|
#include "../SDL_internal.h"
|
|
|
|
|
|
|
|
/* General mouse handling code for SDL */
|
|
|
|
|
|
|
|
#include "SDL_hints.h"
|
|
|
|
#include "SDL_timer.h"
|
|
|
|
#include "SDL_events.h"
|
|
|
|
#include "SDL_events_c.h"
|
2019-11-13 23:53:01 -06:00
|
|
|
#include "../SDL_hints_c.h"
|
2015-06-21 10:33:46 -05:00
|
|
|
#include "../video/SDL_sysvideo.h"
|
2022-06-27 12:19:39 -05:00
|
|
|
#if defined(__WIN32__) || defined(__GDK__)
|
2019-03-16 21:07:34 -05:00
|
|
|
#include "../core/windows/SDL_windows.h" // For GetDoubleClickTime()
|
|
|
|
#endif
|
2020-10-14 15:01:06 -05:00
|
|
|
#if defined(__OS2__)
|
|
|
|
#define INCL_WIN
|
|
|
|
#include <os2.h>
|
|
|
|
#endif
|
2015-06-21 10:33:46 -05:00
|
|
|
|
|
|
|
/* #define DEBUG_MOUSE */
|
|
|
|
|
|
|
|
/* The mouse state */
|
|
|
|
static SDL_Mouse SDL_mouse;
|
|
|
|
|
2019-04-04 09:51:50 -05:00
|
|
|
/* for mapping mouse events to touch */
|
|
|
|
static SDL_bool track_mouse_down = SDL_FALSE;
|
|
|
|
|
2015-06-21 10:33:46 -05:00
|
|
|
static int
|
|
|
|
SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y);
|
|
|
|
|
2018-09-14 21:26:26 -05:00
|
|
|
static void SDLCALL
|
|
|
|
SDL_MouseDoubleClickTimeChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
|
|
|
|
|
|
|
|
if (hint && *hint) {
|
|
|
|
mouse->double_click_time = SDL_atoi(hint);
|
|
|
|
} else {
|
2022-07-01 15:59:14 -05:00
|
|
|
#if defined(__WIN32__) || defined(__WINGDK__)
|
2018-09-14 21:26:26 -05:00
|
|
|
mouse->double_click_time = GetDoubleClickTime();
|
2020-10-14 15:01:06 -05:00
|
|
|
#elif defined(__OS2__)
|
|
|
|
mouse->double_click_time = WinQuerySysValue(HWND_DESKTOP, SV_DBLCLKTIME);
|
2018-09-14 21:26:26 -05:00
|
|
|
#else
|
|
|
|
mouse->double_click_time = 500;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void SDLCALL
|
|
|
|
SDL_MouseDoubleClickRadiusChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
|
|
|
|
|
|
|
|
if (hint && *hint) {
|
|
|
|
mouse->double_click_radius = SDL_atoi(hint);
|
|
|
|
} else {
|
|
|
|
mouse->double_click_radius = 32; /* 32 pixels seems about right for touch interfaces */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-14 08:28:21 -05:00
|
|
|
static void SDLCALL
|
2016-12-02 23:01:13 -06:00
|
|
|
SDL_MouseNormalSpeedScaleChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
|
|
|
|
|
2016-12-03 11:59:43 -06:00
|
|
|
if (hint && *hint) {
|
|
|
|
mouse->normal_speed_scale = (float)SDL_atof(hint);
|
|
|
|
} else {
|
|
|
|
mouse->normal_speed_scale = 1.0f;
|
|
|
|
}
|
2016-12-02 23:01:13 -06:00
|
|
|
}
|
|
|
|
|
2017-08-14 08:28:21 -05:00
|
|
|
static void SDLCALL
|
2016-12-02 23:01:13 -06:00
|
|
|
SDL_MouseRelativeSpeedScaleChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
|
|
|
|
|
2016-12-03 11:59:43 -06:00
|
|
|
if (hint && *hint) {
|
|
|
|
mouse->relative_speed_scale = (float)SDL_atof(hint);
|
|
|
|
} else {
|
|
|
|
mouse->relative_speed_scale = 1.0f;
|
|
|
|
}
|
2016-12-02 23:01:13 -06:00
|
|
|
}
|
|
|
|
|
2017-08-14 08:28:21 -05:00
|
|
|
static void SDLCALL
|
2017-08-03 11:48:44 -05:00
|
|
|
SDL_TouchMouseEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
|
|
|
|
|
2019-11-13 23:53:01 -06:00
|
|
|
mouse->touch_mouse_events = SDL_GetStringBoolean(hint, SDL_TRUE);
|
2017-08-03 11:48:44 -05:00
|
|
|
}
|
|
|
|
|
2022-03-27 13:48:09 -05:00
|
|
|
#if defined(__vita__)
|
|
|
|
static void SDLCALL
|
|
|
|
SDL_VitaTouchMouseDeviceChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
|
|
|
|
if (hint) {
|
|
|
|
switch(*hint) {
|
|
|
|
default:
|
|
|
|
case '0':
|
|
|
|
mouse->vita_touch_mouse_device = 0;
|
|
|
|
break;
|
|
|
|
case '1':
|
|
|
|
mouse->vita_touch_mouse_device = 1;
|
|
|
|
break;
|
|
|
|
case '2':
|
|
|
|
mouse->vita_touch_mouse_device = 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-04-04 09:51:50 -05:00
|
|
|
static void SDLCALL
|
|
|
|
SDL_MouseTouchEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
|
2019-11-13 23:53:01 -06:00
|
|
|
SDL_bool default_value;
|
2019-04-04 09:51:50 -05:00
|
|
|
|
2019-04-05 10:10:12 -05:00
|
|
|
#if defined(__ANDROID__) || (defined(__IPHONEOS__) && !defined(__TVOS__))
|
2019-11-13 23:53:01 -06:00
|
|
|
default_value = SDL_TRUE;
|
2019-04-05 01:36:31 -05:00
|
|
|
#else
|
2019-11-13 23:53:01 -06:00
|
|
|
default_value = SDL_FALSE;
|
2019-04-05 01:36:31 -05:00
|
|
|
#endif
|
2019-11-13 23:53:01 -06:00
|
|
|
mouse->mouse_touch_events = SDL_GetStringBoolean(hint, default_value);
|
2019-04-05 01:36:31 -05:00
|
|
|
|
|
|
|
if (mouse->mouse_touch_events) {
|
|
|
|
SDL_AddTouch(SDL_MOUSE_TOUCHID, SDL_TOUCH_DEVICE_DIRECT, "mouse_input");
|
|
|
|
}
|
2019-04-04 09:51:50 -05:00
|
|
|
}
|
|
|
|
|
2022-03-17 19:39:46 -05:00
|
|
|
static void SDLCALL
|
|
|
|
SDL_MouseAutoCaptureChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
|
|
|
|
SDL_bool auto_capture = SDL_GetStringBoolean(hint, SDL_TRUE);
|
|
|
|
|
|
|
|
if (auto_capture != mouse->auto_capture) {
|
|
|
|
mouse->auto_capture = auto_capture;
|
2022-04-05 17:05:07 -05:00
|
|
|
SDL_UpdateMouseCapture(SDL_FALSE);
|
2022-03-17 19:39:46 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-21 10:33:46 -05:00
|
|
|
/* Public functions */
|
|
|
|
int
|
|
|
|
SDL_MouseInit(void)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
|
2017-10-12 15:28:48 -05:00
|
|
|
SDL_zerop(mouse);
|
|
|
|
|
2018-09-14 21:26:26 -05:00
|
|
|
SDL_AddHintCallback(SDL_HINT_MOUSE_DOUBLE_CLICK_TIME,
|
|
|
|
SDL_MouseDoubleClickTimeChanged, mouse);
|
|
|
|
|
|
|
|
SDL_AddHintCallback(SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS,
|
|
|
|
SDL_MouseDoubleClickRadiusChanged, mouse);
|
|
|
|
|
2016-12-02 23:01:13 -06:00
|
|
|
SDL_AddHintCallback(SDL_HINT_MOUSE_NORMAL_SPEED_SCALE,
|
|
|
|
SDL_MouseNormalSpeedScaleChanged, mouse);
|
|
|
|
|
|
|
|
SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE,
|
|
|
|
SDL_MouseRelativeSpeedScaleChanged, mouse);
|
|
|
|
|
2017-08-03 11:48:44 -05:00
|
|
|
SDL_AddHintCallback(SDL_HINT_TOUCH_MOUSE_EVENTS,
|
|
|
|
SDL_TouchMouseEventsChanged, mouse);
|
|
|
|
|
2022-03-27 13:48:09 -05:00
|
|
|
#if defined(__vita__)
|
|
|
|
SDL_AddHintCallback(SDL_HINT_VITA_TOUCH_MOUSE_DEVICE,
|
|
|
|
SDL_VitaTouchMouseDeviceChanged, mouse);
|
|
|
|
#endif
|
|
|
|
|
2019-04-04 09:51:50 -05:00
|
|
|
SDL_AddHintCallback(SDL_HINT_MOUSE_TOUCH_EVENTS,
|
|
|
|
SDL_MouseTouchEventsChanged, mouse);
|
|
|
|
|
2022-03-17 19:39:46 -05:00
|
|
|
SDL_AddHintCallback(SDL_HINT_MOUSE_AUTO_CAPTURE,
|
|
|
|
SDL_MouseAutoCaptureChanged, mouse);
|
|
|
|
|
2019-07-15 11:36:53 -05:00
|
|
|
mouse->was_touch_mouse_events = SDL_FALSE; /* no touch to mouse movement event pending */
|
|
|
|
|
2015-06-21 10:33:46 -05:00
|
|
|
mouse->cursor_shown = SDL_TRUE;
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SDL_SetDefaultCursor(SDL_Cursor * cursor)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
|
|
|
|
mouse->def_cursor = cursor;
|
|
|
|
if (!mouse->cur_cursor) {
|
|
|
|
SDL_SetCursor(cursor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_Mouse *
|
|
|
|
SDL_GetMouse(void)
|
|
|
|
{
|
|
|
|
return &SDL_mouse;
|
|
|
|
}
|
|
|
|
|
2021-11-10 15:41:44 -06:00
|
|
|
static Uint32 GetButtonState(SDL_Mouse *mouse)
|
2015-06-21 10:33:46 -05:00
|
|
|
{
|
2021-11-10 15:41:44 -06:00
|
|
|
int i;
|
|
|
|
Uint32 buttonstate = 0;
|
2015-06-21 10:33:46 -05:00
|
|
|
|
2021-11-10 15:41:44 -06:00
|
|
|
for (i = 0; i < mouse->num_sources; ++i) {
|
|
|
|
buttonstate |= mouse->sources[i].buttonstate;
|
|
|
|
}
|
|
|
|
return buttonstate;
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
|
2021-11-10 15:41:44 -06:00
|
|
|
SDL_Window *
|
|
|
|
SDL_GetMouseFocus(void)
|
2015-06-21 10:33:46 -05:00
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
|
2021-11-10 15:41:44 -06:00
|
|
|
return mouse->focus;
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SDL_SetMouseFocus(SDL_Window * window)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
|
|
|
|
if (mouse->focus == window) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Actually, this ends up being a bad idea, because most operating
|
|
|
|
systems have an implicit grab when you press the mouse button down
|
|
|
|
so you can drag things out of the window and then get the mouse up
|
|
|
|
when it happens. So, #if 0...
|
|
|
|
*/
|
|
|
|
#if 0
|
|
|
|
if (mouse->focus && !window) {
|
|
|
|
/* We won't get anymore mouse messages, so reset mouse state */
|
|
|
|
SDL_ResetMouse();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* See if the current window has lost focus */
|
|
|
|
if (mouse->focus) {
|
|
|
|
SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
mouse->focus = window;
|
2017-08-12 22:25:49 -05:00
|
|
|
mouse->has_position = SDL_FALSE;
|
2015-06-21 10:33:46 -05:00
|
|
|
|
|
|
|
if (mouse->focus) {
|
|
|
|
SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update cursor visibility */
|
|
|
|
SDL_SetCursor(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check to see if we need to synthesize focus events */
|
|
|
|
static SDL_bool
|
2019-07-15 11:36:53 -05:00
|
|
|
SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate, SDL_bool send_mouse_motion)
|
2015-06-21 10:33:46 -05:00
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
SDL_bool inWindow = SDL_TRUE;
|
|
|
|
|
|
|
|
if (window && ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0)) {
|
|
|
|
int w, h;
|
|
|
|
SDL_GetWindowSize(window, &w, &h);
|
|
|
|
if (x < 0 || y < 0 || x >= w || y >= h) {
|
|
|
|
inWindow = SDL_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!inWindow) {
|
|
|
|
if (window == mouse->focus) {
|
|
|
|
#ifdef DEBUG_MOUSE
|
2022-03-17 19:19:21 -05:00
|
|
|
SDL_Log("Mouse left window, synthesizing move & focus lost event\n");
|
2015-06-21 10:33:46 -05:00
|
|
|
#endif
|
2019-07-15 11:36:53 -05:00
|
|
|
if (send_mouse_motion) {
|
|
|
|
SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
|
|
|
|
}
|
2015-06-21 10:33:46 -05:00
|
|
|
SDL_SetMouseFocus(NULL);
|
|
|
|
}
|
|
|
|
return SDL_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (window != mouse->focus) {
|
|
|
|
#ifdef DEBUG_MOUSE
|
2022-03-17 19:19:21 -05:00
|
|
|
SDL_Log("Mouse entered window, synthesizing focus gain & move event\n");
|
2015-06-21 10:33:46 -05:00
|
|
|
#endif
|
2017-08-12 22:25:49 -05:00
|
|
|
SDL_SetMouseFocus(window);
|
2019-07-15 11:36:53 -05:00
|
|
|
if (send_mouse_motion) {
|
|
|
|
SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
|
|
|
|
}
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
return SDL_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
|
|
|
|
{
|
|
|
|
if (window && !relative) {
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
2021-11-10 15:41:44 -06:00
|
|
|
if (!SDL_UpdateMouseFocus(window, x, y, GetButtonState(mouse), (mouseID == SDL_TOUCH_MOUSEID) ? SDL_FALSE : SDL_TRUE)) {
|
2015-06-21 10:33:46 -05:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return SDL_PrivateSendMouseMotion(window, mouseID, relative, x, y);
|
|
|
|
}
|
|
|
|
|
2016-12-02 23:01:13 -06:00
|
|
|
static int
|
|
|
|
GetScaledMouseDelta(float scale, int value, float *accum)
|
|
|
|
{
|
|
|
|
if (scale != 1.0f) {
|
|
|
|
*accum += scale * value;
|
|
|
|
if (*accum >= 0.0f) {
|
|
|
|
value = (int)SDL_floor(*accum);
|
|
|
|
} else {
|
|
|
|
value = (int)SDL_ceil(*accum);
|
|
|
|
}
|
|
|
|
*accum -= value;
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2015-06-21 10:33:46 -05:00
|
|
|
static int
|
|
|
|
SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
int posted;
|
|
|
|
int xrel;
|
|
|
|
int yrel;
|
|
|
|
|
2019-04-04 09:51:50 -05:00
|
|
|
/* SDL_HINT_MOUSE_TOUCH_EVENTS: controlling whether mouse events should generate synthetic touch events */
|
|
|
|
if (mouse->mouse_touch_events) {
|
|
|
|
if (mouseID != SDL_TOUCH_MOUSEID && !relative && track_mouse_down) {
|
|
|
|
if (window) {
|
|
|
|
float fx = (float)x / (float)window->w;
|
|
|
|
float fy = (float)y / (float)window->h;
|
2019-08-01 16:22:12 -05:00
|
|
|
SDL_SendTouchMotion(SDL_MOUSE_TOUCHID, 0, window, fx, fy, 1.0f);
|
2019-04-04 09:51:50 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-09 04:46:42 -05:00
|
|
|
/* SDL_HINT_TOUCH_MOUSE_EVENTS: if not set, discard synthetic mouse events coming from platform layer */
|
|
|
|
if (mouse->touch_mouse_events == 0) {
|
|
|
|
if (mouseID == SDL_TOUCH_MOUSEID) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-12 22:25:49 -05:00
|
|
|
if (mouseID != SDL_TOUCH_MOUSEID && mouse->relative_mode_warp) {
|
2015-06-21 10:33:46 -05:00
|
|
|
int center_x = 0, center_y = 0;
|
|
|
|
SDL_GetWindowSize(window, ¢er_x, ¢er_y);
|
|
|
|
center_x /= 2;
|
|
|
|
center_y /= 2;
|
|
|
|
if (x == center_x && y == center_y) {
|
|
|
|
mouse->last_x = center_x;
|
|
|
|
mouse->last_y = center_y;
|
|
|
|
return 0;
|
|
|
|
}
|
2021-08-13 13:39:41 -05:00
|
|
|
if (window && (window->flags & SDL_WINDOW_INPUT_FOCUS) != 0) {
|
2021-10-14 20:37:27 -05:00
|
|
|
if (mouse->WarpMouse) {
|
|
|
|
mouse->WarpMouse(window, center_x, center_y);
|
|
|
|
} else {
|
|
|
|
SDL_PrivateSendMouseMotion(window, mouseID, 0, center_x, center_y);
|
|
|
|
}
|
2021-08-13 13:39:41 -05:00
|
|
|
}
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (relative) {
|
2016-12-02 23:01:13 -06:00
|
|
|
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);
|
|
|
|
}
|
2015-06-21 10:33:46 -05:00
|
|
|
xrel = x;
|
|
|
|
yrel = y;
|
|
|
|
x = (mouse->last_x + xrel);
|
|
|
|
y = (mouse->last_y + yrel);
|
|
|
|
} else {
|
|
|
|
xrel = x - mouse->last_x;
|
|
|
|
yrel = y - mouse->last_y;
|
|
|
|
}
|
|
|
|
|
2017-08-12 22:25:49 -05:00
|
|
|
/* Ignore relative motion when first positioning the mouse */
|
|
|
|
if (!mouse->has_position) {
|
2021-10-14 16:26:21 -05:00
|
|
|
mouse->x = x;
|
|
|
|
mouse->y = y;
|
2017-08-12 22:25:49 -05:00
|
|
|
mouse->has_position = SDL_TRUE;
|
2019-10-09 12:42:13 -05:00
|
|
|
} else if (!xrel && !yrel) { /* Drop events that don't change state */
|
|
|
|
#ifdef DEBUG_MOUSE
|
2022-03-17 19:19:21 -05:00
|
|
|
SDL_Log("Mouse event didn't change state - dropped!\n");
|
2019-10-09 12:42:13 -05:00
|
|
|
#endif
|
|
|
|
return 0;
|
2017-08-12 22:25:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Ignore relative motion positioning the first touch */
|
2021-11-10 15:41:44 -06:00
|
|
|
if (mouseID == SDL_TOUCH_MOUSEID && !GetButtonState(mouse)) {
|
2017-08-12 22:25:49 -05:00
|
|
|
xrel = 0;
|
|
|
|
yrel = 0;
|
|
|
|
}
|
|
|
|
|
2015-06-21 10:33:46 -05:00
|
|
|
/* Update internal mouse coordinates */
|
|
|
|
if (!mouse->relative_mode) {
|
|
|
|
mouse->x = x;
|
|
|
|
mouse->y = y;
|
|
|
|
} else {
|
|
|
|
mouse->x += xrel;
|
|
|
|
mouse->y += yrel;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* make sure that the pointers find themselves inside the windows,
|
|
|
|
unless we have the mouse captured. */
|
|
|
|
if (window && ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0)) {
|
2021-11-08 23:34:48 -06:00
|
|
|
int x_min = 0, x_max = 0;
|
|
|
|
int y_min = 0, y_max = 0;
|
|
|
|
const SDL_Rect *confine = SDL_GetWindowMouseRect(window);
|
2015-06-21 10:33:46 -05:00
|
|
|
|
2021-08-14 01:45:01 -05:00
|
|
|
SDL_GetWindowSize(window, &x_max, &y_max);
|
2015-06-21 10:33:46 -05:00
|
|
|
--x_max;
|
|
|
|
--y_max;
|
|
|
|
|
2021-11-08 23:34:48 -06:00
|
|
|
if (confine) {
|
|
|
|
SDL_Rect window_rect;
|
|
|
|
SDL_Rect mouse_rect;
|
|
|
|
|
|
|
|
window_rect.x = 0;
|
|
|
|
window_rect.y = 0;
|
|
|
|
window_rect.w = x_max + 1;
|
|
|
|
window_rect.h = y_max + 1;
|
|
|
|
if (SDL_IntersectRect(confine, &window_rect, &mouse_rect)) {
|
|
|
|
x_min = mouse_rect.x;
|
|
|
|
y_min = mouse_rect.y;
|
|
|
|
x_max = x_min + mouse_rect.w - 1;
|
2021-11-14 17:52:41 -06:00
|
|
|
y_max = y_min + mouse_rect.h - 1;
|
2021-11-08 23:34:48 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-21 10:33:46 -05:00
|
|
|
if (mouse->x > x_max) {
|
|
|
|
mouse->x = x_max;
|
|
|
|
}
|
2021-11-08 23:34:48 -06:00
|
|
|
if (mouse->x < x_min) {
|
|
|
|
mouse->x = x_min;
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mouse->y > y_max) {
|
|
|
|
mouse->y = y_max;
|
|
|
|
}
|
2021-11-08 23:34:48 -06:00
|
|
|
if (mouse->y < y_min) {
|
|
|
|
mouse->y = y_min;
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mouse->xdelta += xrel;
|
|
|
|
mouse->ydelta += yrel;
|
|
|
|
|
|
|
|
/* Move the mouse cursor, if needed */
|
|
|
|
if (mouse->cursor_shown && !mouse->relative_mode &&
|
|
|
|
mouse->MoveCursor && mouse->cur_cursor) {
|
|
|
|
mouse->MoveCursor(mouse->cur_cursor);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Post the event, if desired */
|
|
|
|
posted = 0;
|
|
|
|
if (SDL_GetEventState(SDL_MOUSEMOTION) == SDL_ENABLE) {
|
|
|
|
SDL_Event event;
|
|
|
|
event.motion.type = SDL_MOUSEMOTION;
|
|
|
|
event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
|
|
|
|
event.motion.which = mouseID;
|
2019-07-15 11:36:53 -05:00
|
|
|
/* Set us pending (or clear during a normal mouse movement event) as having triggered */
|
|
|
|
mouse->was_touch_mouse_events = (mouseID == SDL_TOUCH_MOUSEID)? SDL_TRUE : SDL_FALSE;
|
2021-11-10 15:41:44 -06:00
|
|
|
event.motion.state = GetButtonState(mouse);
|
2015-06-21 10:33:46 -05:00
|
|
|
event.motion.x = mouse->x;
|
|
|
|
event.motion.y = mouse->y;
|
|
|
|
event.motion.xrel = xrel;
|
|
|
|
event.motion.yrel = yrel;
|
|
|
|
posted = (SDL_PushEvent(&event) > 0);
|
|
|
|
}
|
|
|
|
if (relative) {
|
|
|
|
mouse->last_x = mouse->x;
|
|
|
|
mouse->last_y = mouse->y;
|
|
|
|
} else {
|
|
|
|
/* Use unclamped values if we're getting events outside the window */
|
|
|
|
mouse->last_x = x;
|
|
|
|
mouse->last_y = y;
|
|
|
|
}
|
|
|
|
return posted;
|
|
|
|
}
|
|
|
|
|
2021-11-10 15:41:44 -06:00
|
|
|
static SDL_MouseInputSource *GetMouseInputSource(SDL_Mouse *mouse, SDL_MouseID mouseID)
|
|
|
|
{
|
|
|
|
SDL_MouseInputSource *source, *sources;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < mouse->num_sources; ++i) {
|
|
|
|
source = &mouse->sources[i];
|
|
|
|
if (source->mouseID == mouseID) {
|
|
|
|
return source;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sources = (SDL_MouseInputSource *)SDL_realloc(mouse->sources, (mouse->num_sources + 1)*sizeof(*mouse->sources));
|
|
|
|
if (sources) {
|
|
|
|
mouse->sources = sources;
|
|
|
|
++mouse->num_sources;
|
|
|
|
source = &sources[mouse->num_sources - 1];
|
|
|
|
source->mouseID = mouseID;
|
|
|
|
source->buttonstate = 0;
|
|
|
|
return source;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-06-21 10:33:46 -05:00
|
|
|
static SDL_MouseClickState *GetMouseClickState(SDL_Mouse *mouse, Uint8 button)
|
|
|
|
{
|
|
|
|
if (button >= mouse->num_clickstates) {
|
|
|
|
int i, count = button + 1;
|
|
|
|
SDL_MouseClickState *clickstate = (SDL_MouseClickState *)SDL_realloc(mouse->clickstate, count * sizeof(*mouse->clickstate));
|
|
|
|
if (!clickstate) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
mouse->clickstate = clickstate;
|
|
|
|
|
|
|
|
for (i = mouse->num_clickstates; i < count; ++i) {
|
|
|
|
SDL_zero(mouse->clickstate[i]);
|
|
|
|
}
|
|
|
|
mouse->num_clickstates = count;
|
|
|
|
}
|
|
|
|
return &mouse->clickstate[button];
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:46:34 -05:00
|
|
|
static int
|
|
|
|
SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button, int clicks)
|
2015-06-21 10:33:46 -05:00
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
int posted;
|
|
|
|
Uint32 type;
|
2021-11-10 15:41:44 -06:00
|
|
|
Uint32 buttonstate;
|
|
|
|
SDL_MouseInputSource *source;
|
2022-03-17 19:39:46 -05:00
|
|
|
|
2021-11-10 15:41:44 -06:00
|
|
|
source = GetMouseInputSource(mouse, mouseID);
|
|
|
|
if (!source) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
buttonstate = source->buttonstate;
|
2015-06-21 10:33:46 -05:00
|
|
|
|
2019-04-04 09:51:50 -05:00
|
|
|
/* SDL_HINT_MOUSE_TOUCH_EVENTS: controlling whether mouse events should generate synthetic touch events */
|
|
|
|
if (mouse->mouse_touch_events) {
|
|
|
|
if (mouseID != SDL_TOUCH_MOUSEID && button == SDL_BUTTON_LEFT) {
|
2019-04-06 14:52:51 -05:00
|
|
|
if (state == SDL_PRESSED) {
|
|
|
|
track_mouse_down = SDL_TRUE;
|
|
|
|
} else {
|
|
|
|
track_mouse_down = SDL_FALSE;
|
|
|
|
}
|
2019-04-04 09:51:50 -05:00
|
|
|
if (window) {
|
|
|
|
float fx = (float)mouse->x / (float)window->w;
|
|
|
|
float fy = (float)mouse->y / (float)window->h;
|
2019-08-01 16:22:12 -05:00
|
|
|
SDL_SendTouch(SDL_MOUSE_TOUCHID, 0, window, track_mouse_down, fx, fy, 1.0f);
|
2019-04-04 09:51:50 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-09 04:46:42 -05:00
|
|
|
/* SDL_HINT_TOUCH_MOUSE_EVENTS: if not set, discard synthetic mouse events coming from platform layer */
|
|
|
|
if (mouse->touch_mouse_events == 0) {
|
|
|
|
if (mouseID == SDL_TOUCH_MOUSEID) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-21 10:33:46 -05:00
|
|
|
/* Figure out which event to perform */
|
|
|
|
switch (state) {
|
|
|
|
case SDL_PRESSED:
|
|
|
|
type = SDL_MOUSEBUTTONDOWN;
|
|
|
|
buttonstate |= SDL_BUTTON(button);
|
|
|
|
break;
|
|
|
|
case SDL_RELEASED:
|
|
|
|
type = SDL_MOUSEBUTTONUP;
|
|
|
|
buttonstate &= ~SDL_BUTTON(button);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Invalid state -- bail */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We do this after calculating buttonstate so button presses gain focus */
|
|
|
|
if (window && state == SDL_PRESSED) {
|
2019-07-15 11:36:53 -05:00
|
|
|
SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate, SDL_TRUE);
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
|
2021-11-10 15:41:44 -06:00
|
|
|
if (buttonstate == source->buttonstate) {
|
2015-06-21 10:33:46 -05:00
|
|
|
/* Ignore this event, no state change */
|
|
|
|
return 0;
|
|
|
|
}
|
2021-11-10 15:41:44 -06:00
|
|
|
source->buttonstate = buttonstate;
|
2015-06-21 10:33:46 -05:00
|
|
|
|
2016-09-24 16:46:34 -05:00
|
|
|
if (clicks < 0) {
|
|
|
|
SDL_MouseClickState *clickstate = GetMouseClickState(mouse, button);
|
2016-09-30 16:30:54 -05:00
|
|
|
if (clickstate) {
|
|
|
|
if (state == SDL_PRESSED) {
|
|
|
|
Uint32 now = SDL_GetTicks();
|
|
|
|
|
2018-09-14 21:26:26 -05:00
|
|
|
if (SDL_TICKS_PASSED(now, clickstate->last_timestamp + mouse->double_click_time) ||
|
|
|
|
SDL_abs(mouse->x - clickstate->last_x) > mouse->double_click_radius ||
|
|
|
|
SDL_abs(mouse->y - clickstate->last_y) > mouse->double_click_radius) {
|
2016-09-30 16:30:54 -05:00
|
|
|
clickstate->click_count = 0;
|
|
|
|
}
|
|
|
|
clickstate->last_timestamp = now;
|
|
|
|
clickstate->last_x = mouse->x;
|
|
|
|
clickstate->last_y = mouse->y;
|
|
|
|
if (clickstate->click_count < 255) {
|
|
|
|
++clickstate->click_count;
|
|
|
|
}
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
2016-09-30 16:30:54 -05:00
|
|
|
clicks = clickstate->click_count;
|
|
|
|
} else {
|
|
|
|
clicks = 1;
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Post the event, if desired */
|
|
|
|
posted = 0;
|
|
|
|
if (SDL_GetEventState(type) == SDL_ENABLE) {
|
|
|
|
SDL_Event event;
|
|
|
|
event.type = type;
|
|
|
|
event.button.windowID = mouse->focus ? mouse->focus->id : 0;
|
|
|
|
event.button.which = mouseID;
|
|
|
|
event.button.state = state;
|
|
|
|
event.button.button = button;
|
2016-09-24 16:46:34 -05:00
|
|
|
event.button.clicks = (Uint8) SDL_min(clicks, 255);
|
2015-06-21 10:33:46 -05:00
|
|
|
event.button.x = mouse->x;
|
|
|
|
event.button.y = mouse->y;
|
|
|
|
posted = (SDL_PushEvent(&event) > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We do this after dispatching event so button releases can lose focus */
|
|
|
|
if (window && state == SDL_RELEASED) {
|
2019-07-15 11:36:53 -05:00
|
|
|
SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate, SDL_TRUE);
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
2019-04-04 08:19:00 -05:00
|
|
|
|
2022-03-17 19:39:46 -05:00
|
|
|
/* Automatically capture the mouse while buttons are pressed */
|
|
|
|
if (mouse->auto_capture) {
|
2022-04-05 17:05:07 -05:00
|
|
|
SDL_UpdateMouseCapture(SDL_FALSE);
|
2022-03-17 19:39:46 -05:00
|
|
|
}
|
|
|
|
|
2015-06-21 10:33:46 -05:00
|
|
|
return posted;
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:46:34 -05:00
|
|
|
int
|
|
|
|
SDL_SendMouseButtonClicks(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button, int clicks)
|
|
|
|
{
|
|
|
|
clicks = SDL_max(clicks, 0);
|
|
|
|
return SDL_PrivateSendMouseButton(window, mouseID, state, button, clicks);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
|
|
|
|
{
|
|
|
|
return SDL_PrivateSendMouseButton(window, mouseID, state, button, -1);
|
|
|
|
}
|
|
|
|
|
2015-06-21 10:33:46 -05:00
|
|
|
int
|
Fixed bug 2293 - Precise scrolling events
Martijn Courteaux
I implemented precise scrolling events. I have been through all the folders in /src/video/[platform] to implement where possible. This works on OS X, but I can't speak for others. Build farm will figure that out, I guess. I think this patch should introduce precise scrolling on OS X, Wayland, Mir, Windows, Android, Nacl, Windows RT.
The way I provide precise scrolling events is by adding two float fields to the SDL_MouseWheelScrollEvent datastructure, called "preciseX" and "preciseY". The old integer fields "x" and "y" are still present. The idea is that every platform specific code normalises the scroll amounts and forwards them to the SDL_SendMouseWheel function. It is this function that will now accumulate these (using a static variable, as I have seen how it was implemented in the Windows specific code) and once we hit a unit size, set the traditional integer "x" and "y" fields.
I believe this is pretty solid way of doing it, although I'm not the expert here.
There is also a fix in the patch for a typo recently introduced, that might need to be taken away by the time anybody merges this in. There is also a file in Nacl which I have stripped a horrible amount of trailing whitespaces. (Leave that part out if you want).
2017-08-14 23:28:04 -05:00
|
|
|
SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, float x, float y, SDL_MouseWheelDirection direction)
|
2015-06-21 10:33:46 -05:00
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
int posted;
|
Fixed bug 2293 - Precise scrolling events
Martijn Courteaux
I implemented precise scrolling events. I have been through all the folders in /src/video/[platform] to implement where possible. This works on OS X, but I can't speak for others. Build farm will figure that out, I guess. I think this patch should introduce precise scrolling on OS X, Wayland, Mir, Windows, Android, Nacl, Windows RT.
The way I provide precise scrolling events is by adding two float fields to the SDL_MouseWheelScrollEvent datastructure, called "preciseX" and "preciseY". The old integer fields "x" and "y" are still present. The idea is that every platform specific code normalises the scroll amounts and forwards them to the SDL_SendMouseWheel function. It is this function that will now accumulate these (using a static variable, as I have seen how it was implemented in the Windows specific code) and once we hit a unit size, set the traditional integer "x" and "y" fields.
I believe this is pretty solid way of doing it, although I'm not the expert here.
There is also a fix in the patch for a typo recently introduced, that might need to be taken away by the time anybody merges this in. There is also a file in Nacl which I have stripped a horrible amount of trailing whitespaces. (Leave that part out if you want).
2017-08-14 23:28:04 -05:00
|
|
|
int integral_x, integral_y;
|
2015-06-21 10:33:46 -05:00
|
|
|
|
|
|
|
if (window) {
|
|
|
|
SDL_SetMouseFocus(window);
|
|
|
|
}
|
|
|
|
|
2018-12-06 11:09:05 -06:00
|
|
|
if (x == 0.0f && y == 0.0f) {
|
2015-06-21 10:33:46 -05:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-11-08 11:58:11 -06:00
|
|
|
if (x > 0.0f) {
|
|
|
|
if (mouse->accumulated_wheel_x < 0.0f) {
|
|
|
|
mouse->accumulated_wheel_x = 0.0f;
|
|
|
|
}
|
|
|
|
} else if (x < 0.0f) {
|
|
|
|
if (mouse->accumulated_wheel_x > 0.0f) {
|
|
|
|
mouse->accumulated_wheel_x = 0.0f;
|
|
|
|
}
|
|
|
|
}
|
Fixed bug 2293 - Precise scrolling events
Martijn Courteaux
I implemented precise scrolling events. I have been through all the folders in /src/video/[platform] to implement where possible. This works on OS X, but I can't speak for others. Build farm will figure that out, I guess. I think this patch should introduce precise scrolling on OS X, Wayland, Mir, Windows, Android, Nacl, Windows RT.
The way I provide precise scrolling events is by adding two float fields to the SDL_MouseWheelScrollEvent datastructure, called "preciseX" and "preciseY". The old integer fields "x" and "y" are still present. The idea is that every platform specific code normalises the scroll amounts and forwards them to the SDL_SendMouseWheel function. It is this function that will now accumulate these (using a static variable, as I have seen how it was implemented in the Windows specific code) and once we hit a unit size, set the traditional integer "x" and "y" fields.
I believe this is pretty solid way of doing it, although I'm not the expert here.
There is also a fix in the patch for a typo recently introduced, that might need to be taken away by the time anybody merges this in. There is also a file in Nacl which I have stripped a horrible amount of trailing whitespaces. (Leave that part out if you want).
2017-08-14 23:28:04 -05:00
|
|
|
mouse->accumulated_wheel_x += x;
|
2021-11-08 11:58:11 -06:00
|
|
|
if (mouse->accumulated_wheel_x > 0.0f) {
|
Fixed bug 2293 - Precise scrolling events
Martijn Courteaux
I implemented precise scrolling events. I have been through all the folders in /src/video/[platform] to implement where possible. This works on OS X, but I can't speak for others. Build farm will figure that out, I guess. I think this patch should introduce precise scrolling on OS X, Wayland, Mir, Windows, Android, Nacl, Windows RT.
The way I provide precise scrolling events is by adding two float fields to the SDL_MouseWheelScrollEvent datastructure, called "preciseX" and "preciseY". The old integer fields "x" and "y" are still present. The idea is that every platform specific code normalises the scroll amounts and forwards them to the SDL_SendMouseWheel function. It is this function that will now accumulate these (using a static variable, as I have seen how it was implemented in the Windows specific code) and once we hit a unit size, set the traditional integer "x" and "y" fields.
I believe this is pretty solid way of doing it, although I'm not the expert here.
There is also a fix in the patch for a typo recently introduced, that might need to be taken away by the time anybody merges this in. There is also a file in Nacl which I have stripped a horrible amount of trailing whitespaces. (Leave that part out if you want).
2017-08-14 23:28:04 -05:00
|
|
|
integral_x = (int)SDL_floor(mouse->accumulated_wheel_x);
|
2021-11-08 11:58:11 -06:00
|
|
|
} else if (mouse->accumulated_wheel_x < 0.0f) {
|
Fixed bug 2293 - Precise scrolling events
Martijn Courteaux
I implemented precise scrolling events. I have been through all the folders in /src/video/[platform] to implement where possible. This works on OS X, but I can't speak for others. Build farm will figure that out, I guess. I think this patch should introduce precise scrolling on OS X, Wayland, Mir, Windows, Android, Nacl, Windows RT.
The way I provide precise scrolling events is by adding two float fields to the SDL_MouseWheelScrollEvent datastructure, called "preciseX" and "preciseY". The old integer fields "x" and "y" are still present. The idea is that every platform specific code normalises the scroll amounts and forwards them to the SDL_SendMouseWheel function. It is this function that will now accumulate these (using a static variable, as I have seen how it was implemented in the Windows specific code) and once we hit a unit size, set the traditional integer "x" and "y" fields.
I believe this is pretty solid way of doing it, although I'm not the expert here.
There is also a fix in the patch for a typo recently introduced, that might need to be taken away by the time anybody merges this in. There is also a file in Nacl which I have stripped a horrible amount of trailing whitespaces. (Leave that part out if you want).
2017-08-14 23:28:04 -05:00
|
|
|
integral_x = (int)SDL_ceil(mouse->accumulated_wheel_x);
|
|
|
|
} else {
|
|
|
|
integral_x = 0;
|
|
|
|
}
|
|
|
|
mouse->accumulated_wheel_x -= integral_x;
|
|
|
|
|
2021-11-08 11:58:11 -06:00
|
|
|
if (y > 0.0f) {
|
|
|
|
if (mouse->accumulated_wheel_y < 0.0f) {
|
|
|
|
mouse->accumulated_wheel_y = 0.0f;
|
|
|
|
}
|
|
|
|
} else if (y < 0.0f) {
|
|
|
|
if (mouse->accumulated_wheel_y > 0.0f) {
|
|
|
|
mouse->accumulated_wheel_y = 0.0f;
|
|
|
|
}
|
|
|
|
}
|
Fixed bug 2293 - Precise scrolling events
Martijn Courteaux
I implemented precise scrolling events. I have been through all the folders in /src/video/[platform] to implement where possible. This works on OS X, but I can't speak for others. Build farm will figure that out, I guess. I think this patch should introduce precise scrolling on OS X, Wayland, Mir, Windows, Android, Nacl, Windows RT.
The way I provide precise scrolling events is by adding two float fields to the SDL_MouseWheelScrollEvent datastructure, called "preciseX" and "preciseY". The old integer fields "x" and "y" are still present. The idea is that every platform specific code normalises the scroll amounts and forwards them to the SDL_SendMouseWheel function. It is this function that will now accumulate these (using a static variable, as I have seen how it was implemented in the Windows specific code) and once we hit a unit size, set the traditional integer "x" and "y" fields.
I believe this is pretty solid way of doing it, although I'm not the expert here.
There is also a fix in the patch for a typo recently introduced, that might need to be taken away by the time anybody merges this in. There is also a file in Nacl which I have stripped a horrible amount of trailing whitespaces. (Leave that part out if you want).
2017-08-14 23:28:04 -05:00
|
|
|
mouse->accumulated_wheel_y += y;
|
2021-11-08 11:58:11 -06:00
|
|
|
if (mouse->accumulated_wheel_y > 0.0f) {
|
Fixed bug 2293 - Precise scrolling events
Martijn Courteaux
I implemented precise scrolling events. I have been through all the folders in /src/video/[platform] to implement where possible. This works on OS X, but I can't speak for others. Build farm will figure that out, I guess. I think this patch should introduce precise scrolling on OS X, Wayland, Mir, Windows, Android, Nacl, Windows RT.
The way I provide precise scrolling events is by adding two float fields to the SDL_MouseWheelScrollEvent datastructure, called "preciseX" and "preciseY". The old integer fields "x" and "y" are still present. The idea is that every platform specific code normalises the scroll amounts and forwards them to the SDL_SendMouseWheel function. It is this function that will now accumulate these (using a static variable, as I have seen how it was implemented in the Windows specific code) and once we hit a unit size, set the traditional integer "x" and "y" fields.
I believe this is pretty solid way of doing it, although I'm not the expert here.
There is also a fix in the patch for a typo recently introduced, that might need to be taken away by the time anybody merges this in. There is also a file in Nacl which I have stripped a horrible amount of trailing whitespaces. (Leave that part out if you want).
2017-08-14 23:28:04 -05:00
|
|
|
integral_y = (int)SDL_floor(mouse->accumulated_wheel_y);
|
2021-11-08 11:58:11 -06:00
|
|
|
} else if (mouse->accumulated_wheel_y < 0.0f) {
|
Fixed bug 2293 - Precise scrolling events
Martijn Courteaux
I implemented precise scrolling events. I have been through all the folders in /src/video/[platform] to implement where possible. This works on OS X, but I can't speak for others. Build farm will figure that out, I guess. I think this patch should introduce precise scrolling on OS X, Wayland, Mir, Windows, Android, Nacl, Windows RT.
The way I provide precise scrolling events is by adding two float fields to the SDL_MouseWheelScrollEvent datastructure, called "preciseX" and "preciseY". The old integer fields "x" and "y" are still present. The idea is that every platform specific code normalises the scroll amounts and forwards them to the SDL_SendMouseWheel function. It is this function that will now accumulate these (using a static variable, as I have seen how it was implemented in the Windows specific code) and once we hit a unit size, set the traditional integer "x" and "y" fields.
I believe this is pretty solid way of doing it, although I'm not the expert here.
There is also a fix in the patch for a typo recently introduced, that might need to be taken away by the time anybody merges this in. There is also a file in Nacl which I have stripped a horrible amount of trailing whitespaces. (Leave that part out if you want).
2017-08-14 23:28:04 -05:00
|
|
|
integral_y = (int)SDL_ceil(mouse->accumulated_wheel_y);
|
|
|
|
} else {
|
|
|
|
integral_y = 0;
|
|
|
|
}
|
|
|
|
mouse->accumulated_wheel_y -= integral_y;
|
|
|
|
|
2015-06-21 10:33:46 -05:00
|
|
|
/* Post the event, if desired */
|
|
|
|
posted = 0;
|
|
|
|
if (SDL_GetEventState(SDL_MOUSEWHEEL) == SDL_ENABLE) {
|
|
|
|
SDL_Event event;
|
|
|
|
event.type = SDL_MOUSEWHEEL;
|
|
|
|
event.wheel.windowID = mouse->focus ? mouse->focus->id : 0;
|
|
|
|
event.wheel.which = mouseID;
|
Fixed bug 2293 - Precise scrolling events
Martijn Courteaux
I implemented precise scrolling events. I have been through all the folders in /src/video/[platform] to implement where possible. This works on OS X, but I can't speak for others. Build farm will figure that out, I guess. I think this patch should introduce precise scrolling on OS X, Wayland, Mir, Windows, Android, Nacl, Windows RT.
The way I provide precise scrolling events is by adding two float fields to the SDL_MouseWheelScrollEvent datastructure, called "preciseX" and "preciseY". The old integer fields "x" and "y" are still present. The idea is that every platform specific code normalises the scroll amounts and forwards them to the SDL_SendMouseWheel function. It is this function that will now accumulate these (using a static variable, as I have seen how it was implemented in the Windows specific code) and once we hit a unit size, set the traditional integer "x" and "y" fields.
I believe this is pretty solid way of doing it, although I'm not the expert here.
There is also a fix in the patch for a typo recently introduced, that might need to be taken away by the time anybody merges this in. There is also a file in Nacl which I have stripped a horrible amount of trailing whitespaces. (Leave that part out if you want).
2017-08-14 23:28:04 -05:00
|
|
|
event.wheel.x = integral_x;
|
|
|
|
event.wheel.y = integral_y;
|
2021-11-08 11:44:31 -06:00
|
|
|
event.wheel.preciseX = x;
|
|
|
|
event.wheel.preciseY = y;
|
2015-06-21 10:33:46 -05:00
|
|
|
event.wheel.direction = (Uint32)direction;
|
|
|
|
posted = (SDL_PushEvent(&event) > 0);
|
|
|
|
}
|
|
|
|
return posted;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SDL_MouseQuit(void)
|
|
|
|
{
|
|
|
|
SDL_Cursor *cursor, *next;
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
|
|
|
|
if (mouse->CaptureMouse) {
|
|
|
|
SDL_CaptureMouse(SDL_FALSE);
|
2022-04-05 17:05:07 -05:00
|
|
|
SDL_UpdateMouseCapture(SDL_TRUE);
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
SDL_SetRelativeMouseMode(SDL_FALSE);
|
|
|
|
SDL_ShowCursor(1);
|
|
|
|
|
|
|
|
cursor = mouse->cursors;
|
|
|
|
while (cursor) {
|
|
|
|
next = cursor->next;
|
|
|
|
SDL_FreeCursor(cursor);
|
|
|
|
cursor = next;
|
|
|
|
}
|
2017-10-13 21:30:34 -05:00
|
|
|
mouse->cursors = NULL;
|
2019-03-11 09:31:46 -05:00
|
|
|
mouse->cur_cursor = NULL;
|
2015-06-21 10:33:46 -05:00
|
|
|
|
|
|
|
if (mouse->def_cursor && mouse->FreeCursor) {
|
|
|
|
mouse->FreeCursor(mouse->def_cursor);
|
2017-10-13 21:30:34 -05:00
|
|
|
mouse->def_cursor = NULL;
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
|
2021-11-10 15:41:44 -06:00
|
|
|
if (mouse->sources) {
|
|
|
|
SDL_free(mouse->sources);
|
|
|
|
mouse->sources = NULL;
|
|
|
|
}
|
|
|
|
mouse->num_sources = 0;
|
|
|
|
|
2015-06-21 10:33:46 -05:00
|
|
|
if (mouse->clickstate) {
|
|
|
|
SDL_free(mouse->clickstate);
|
2017-10-13 21:30:34 -05:00
|
|
|
mouse->clickstate = NULL;
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
2021-11-10 15:41:44 -06:00
|
|
|
mouse->num_clickstates = 0;
|
2015-06-21 10:33:46 -05:00
|
|
|
|
2022-03-17 19:39:46 -05:00
|
|
|
SDL_DelHintCallback(SDL_HINT_MOUSE_DOUBLE_CLICK_TIME,
|
|
|
|
SDL_MouseDoubleClickTimeChanged, mouse);
|
|
|
|
|
|
|
|
SDL_DelHintCallback(SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS,
|
|
|
|
SDL_MouseDoubleClickRadiusChanged, mouse);
|
|
|
|
|
2016-12-02 23:01:13 -06:00
|
|
|
SDL_DelHintCallback(SDL_HINT_MOUSE_NORMAL_SPEED_SCALE,
|
|
|
|
SDL_MouseNormalSpeedScaleChanged, mouse);
|
|
|
|
|
|
|
|
SDL_DelHintCallback(SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE,
|
|
|
|
SDL_MouseRelativeSpeedScaleChanged, mouse);
|
2022-03-17 19:39:46 -05:00
|
|
|
|
|
|
|
SDL_DelHintCallback(SDL_HINT_TOUCH_MOUSE_EVENTS,
|
|
|
|
SDL_TouchMouseEventsChanged, mouse);
|
|
|
|
|
|
|
|
SDL_DelHintCallback(SDL_HINT_MOUSE_TOUCH_EVENTS,
|
|
|
|
SDL_MouseTouchEventsChanged, mouse);
|
|
|
|
|
|
|
|
SDL_DelHintCallback(SDL_HINT_MOUSE_AUTO_CAPTURE,
|
|
|
|
SDL_MouseAutoCaptureChanged, mouse);
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
Uint32
|
|
|
|
SDL_GetMouseState(int *x, int *y)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
|
|
|
|
if (x) {
|
|
|
|
*x = mouse->x;
|
|
|
|
}
|
|
|
|
if (y) {
|
|
|
|
*y = mouse->y;
|
|
|
|
}
|
2021-11-10 15:41:44 -06:00
|
|
|
return GetButtonState(mouse);
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
Uint32
|
|
|
|
SDL_GetRelativeMouseState(int *x, int *y)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
|
|
|
|
if (x) {
|
|
|
|
*x = mouse->xdelta;
|
|
|
|
}
|
|
|
|
if (y) {
|
|
|
|
*y = mouse->ydelta;
|
|
|
|
}
|
|
|
|
mouse->xdelta = 0;
|
|
|
|
mouse->ydelta = 0;
|
2021-11-10 15:41:44 -06:00
|
|
|
return GetButtonState(mouse);
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
Uint32
|
|
|
|
SDL_GetGlobalMouseState(int *x, int *y)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
|
2020-05-26 18:34:50 -05:00
|
|
|
if (mouse->GetGlobalMouseState) {
|
|
|
|
int tmpx, tmpy;
|
|
|
|
|
|
|
|
/* make sure these are never NULL for the backend implementations... */
|
|
|
|
if (!x) {
|
|
|
|
x = &tmpx;
|
|
|
|
}
|
|
|
|
if (!y) {
|
|
|
|
y = &tmpy;
|
|
|
|
}
|
2015-06-21 10:33:46 -05:00
|
|
|
|
2020-05-26 18:34:50 -05:00
|
|
|
*x = *y = 0;
|
2015-06-21 10:33:46 -05:00
|
|
|
|
2020-05-26 18:34:50 -05:00
|
|
|
return mouse->GetGlobalMouseState(x, y);
|
|
|
|
} else {
|
|
|
|
return SDL_GetMouseState(x, y);
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-18 12:09:24 -05:00
|
|
|
void
|
2022-05-18 10:50:59 -05:00
|
|
|
SDL_PerformWarpMouseInWindow(SDL_Window *window, int x, int y, SDL_bool ignore_relative_mode)
|
2015-06-21 10:33:46 -05:00
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
|
|
|
|
if (window == NULL) {
|
|
|
|
window = mouse->focus;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (window == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-10-06 11:09:09 -05:00
|
|
|
if ((window->flags & SDL_WINDOW_MINIMIZED) == SDL_WINDOW_MINIMIZED) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-18 10:50:59 -05:00
|
|
|
if (mouse->relative_mode && !ignore_relative_mode) {
|
|
|
|
/* 2.0.22 made warping in relative mode actually functional, which
|
|
|
|
* surprised many applications that weren't expecting the additional
|
|
|
|
* mouse motion.
|
|
|
|
*
|
|
|
|
* So for now, warping in relative mode adjusts the absolution position
|
|
|
|
* but doesn't generate motion events.
|
|
|
|
*/
|
|
|
|
mouse->x = x;
|
|
|
|
mouse->y = y;
|
|
|
|
mouse->has_position = SDL_TRUE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-10-14 16:26:21 -05:00
|
|
|
/* Ignore the previous position when we warp */
|
|
|
|
mouse->has_position = SDL_FALSE;
|
|
|
|
|
|
|
|
if (mouse->WarpMouse &&
|
|
|
|
(!mouse->relative_mode || mouse->relative_mode_warp)) {
|
2015-06-21 10:33:46 -05:00
|
|
|
mouse->WarpMouse(window, x, y);
|
|
|
|
} else {
|
2021-10-14 16:26:21 -05:00
|
|
|
SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-18 10:50:59 -05:00
|
|
|
void
|
|
|
|
SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
|
|
|
|
{
|
|
|
|
SDL_PerformWarpMouseInWindow(window, x, y, SDL_FALSE);
|
|
|
|
}
|
|
|
|
|
2015-07-17 20:03:58 -05:00
|
|
|
int
|
2015-06-21 10:33:46 -05:00
|
|
|
SDL_WarpMouseGlobal(int x, int y)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
|
|
|
|
if (mouse->WarpMouseGlobal) {
|
2015-07-17 20:03:58 -05:00
|
|
|
return mouse->WarpMouseGlobal(x, y);
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
2015-07-17 20:03:58 -05:00
|
|
|
|
|
|
|
return SDL_Unsupported();
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static SDL_bool
|
|
|
|
ShouldUseRelativeModeWarp(SDL_Mouse *mouse)
|
|
|
|
{
|
2019-05-23 13:32:36 -05:00
|
|
|
if (!mouse->WarpMouse) {
|
|
|
|
/* Need this functionality for relative mode warp implementation */
|
|
|
|
return SDL_FALSE;
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
|
2016-10-08 01:40:44 -05:00
|
|
|
return SDL_GetHintBoolean(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, SDL_FALSE);
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
SDL_SetRelativeMouseMode(SDL_bool enabled)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
SDL_Window *focusWindow = SDL_GetKeyboardFocus();
|
|
|
|
|
|
|
|
if (enabled == mouse->relative_mode) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the relative mode */
|
|
|
|
if (!enabled && mouse->relative_mode_warp) {
|
|
|
|
mouse->relative_mode_warp = SDL_FALSE;
|
|
|
|
} else if (enabled && ShouldUseRelativeModeWarp(mouse)) {
|
|
|
|
mouse->relative_mode_warp = SDL_TRUE;
|
2019-05-23 13:32:36 -05:00
|
|
|
} else if (!mouse->SetRelativeMouseMode || mouse->SetRelativeMouseMode(enabled) < 0) {
|
2015-06-21 10:33:46 -05:00
|
|
|
if (enabled) {
|
|
|
|
/* Fall back to warp mode if native relative mode failed */
|
2018-06-18 15:14:02 -05:00
|
|
|
if (!mouse->WarpMouse) {
|
|
|
|
return SDL_SetError("No relative mode implementation available");
|
|
|
|
}
|
2015-06-21 10:33:46 -05:00
|
|
|
mouse->relative_mode_warp = SDL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mouse->relative_mode = enabled;
|
2016-12-02 23:01:13 -06:00
|
|
|
mouse->scale_accum_x = 0.0f;
|
|
|
|
mouse->scale_accum_y = 0.0f;
|
2015-06-21 10:33:46 -05:00
|
|
|
|
2021-08-14 01:36:13 -05:00
|
|
|
if (enabled) {
|
|
|
|
/* Update cursor visibility before we potentially warp the mouse */
|
|
|
|
SDL_SetCursor(NULL);
|
|
|
|
}
|
|
|
|
|
2019-06-18 16:24:26 -05:00
|
|
|
if (enabled && focusWindow) {
|
|
|
|
SDL_SetMouseFocus(focusWindow);
|
2021-04-01 22:52:21 -05:00
|
|
|
|
2022-05-18 10:50:59 -05:00
|
|
|
if (mouse->relative_mode_warp) {
|
|
|
|
SDL_PerformWarpMouseInWindow(focusWindow, focusWindow->w/2, focusWindow->h/2, SDL_TRUE);
|
|
|
|
}
|
2019-06-18 16:24:26 -05:00
|
|
|
}
|
|
|
|
|
2021-08-14 01:36:13 -05:00
|
|
|
if (focusWindow) {
|
|
|
|
SDL_UpdateWindowGrab(focusWindow);
|
2015-06-21 10:33:46 -05:00
|
|
|
|
|
|
|
/* Put the cursor back to where the application expects it */
|
|
|
|
if (!enabled) {
|
2022-05-18 10:50:59 -05:00
|
|
|
SDL_PerformWarpMouseInWindow(focusWindow, mouse->x, mouse->y, SDL_TRUE);
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
2022-04-05 17:05:07 -05:00
|
|
|
|
|
|
|
SDL_UpdateMouseCapture(SDL_FALSE);
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
|
2021-08-14 01:36:13 -05:00
|
|
|
if (!enabled) {
|
|
|
|
/* Update cursor visibility after we restore the mouse position */
|
|
|
|
SDL_SetCursor(NULL);
|
|
|
|
}
|
|
|
|
|
2015-06-21 10:33:46 -05:00
|
|
|
/* Flush pending mouse motion - ideally we would pump events, but that's not always safe */
|
|
|
|
SDL_FlushEvent(SDL_MOUSEMOTION);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_bool
|
|
|
|
SDL_GetRelativeMouseMode()
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
|
|
|
|
return mouse->relative_mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2022-04-05 17:05:07 -05:00
|
|
|
SDL_UpdateMouseCapture(SDL_bool force_release)
|
2015-06-21 10:33:46 -05:00
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
2022-04-05 17:05:07 -05:00
|
|
|
SDL_Window *capture_window = NULL;
|
2015-06-21 10:33:46 -05:00
|
|
|
|
|
|
|
if (!mouse->CaptureMouse) {
|
2022-04-05 17:05:07 -05:00
|
|
|
return 0;
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
|
2022-04-05 17:05:07 -05:00
|
|
|
if (!force_release) {
|
2022-05-18 17:29:59 -05:00
|
|
|
if (SDL_GetMessageBoxCount() == 0 &&
|
|
|
|
(mouse->capture_desired || (mouse->auto_capture && SDL_GetMouseState(NULL, NULL) != 0))) {
|
2022-04-05 17:05:07 -05:00
|
|
|
if (!mouse->relative_mode) {
|
|
|
|
capture_window = SDL_GetKeyboardFocus();
|
|
|
|
}
|
|
|
|
}
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
|
2022-04-05 17:05:07 -05:00
|
|
|
if (capture_window != mouse->capture_window) {
|
2022-05-18 19:15:10 -05:00
|
|
|
/* We can get here recursively on Windows, so make sure we complete
|
|
|
|
* all of the window state operations before we change the capture state
|
|
|
|
* (e.g. https://github.com/libsdl-org/SDL/pull/5608)
|
|
|
|
*/
|
|
|
|
SDL_Window *previous_capture = mouse->capture_window;
|
|
|
|
|
|
|
|
if (previous_capture) {
|
|
|
|
previous_capture->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
2022-04-05 17:05:07 -05:00
|
|
|
|
|
|
|
if (capture_window) {
|
|
|
|
capture_window->flags |= SDL_WINDOW_MOUSE_CAPTURE;
|
2015-06-21 10:33:46 -05:00
|
|
|
}
|
|
|
|
|
2022-04-05 17:05:07 -05:00
|
|
|
mouse->capture_window = capture_window;
|
2022-05-18 19:15:10 -05:00
|
|
|
|
|
|
|
if (mouse->CaptureMouse(capture_window) < 0) {
|
|
|
|
/* CaptureMouse() will have set an error, just restore the state */
|
|
|
|
if (previous_capture) {
|
|
|
|
previous_capture->flags |= SDL_WINDOW_MOUSE_CAPTURE;
|
|
|
|
}
|
|
|
|
if (capture_window) {
|
|
|
|
capture_window->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
|
|
|
|
}
|
2022-05-18 19:23:49 -05:00
|
|
|
mouse->capture_window = previous_capture;
|
|
|
|
|
2022-05-18 19:15:10 -05:00
|
|
|
return -1;
|
|
|
|
}
|
2022-04-05 17:05:07 -05:00
|
|
|
}
|
2015-06-21 10:33:46 -05:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-04-05 17:05:07 -05:00
|
|
|
int
|
|
|
|
SDL_CaptureMouse(SDL_bool enabled)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
|
|
|
|
if (!mouse->CaptureMouse) {
|
|
|
|
return SDL_Unsupported();
|
|
|
|
}
|
|
|
|
|
2022-06-27 12:19:39 -05:00
|
|
|
#if defined(__WIN32__) || defined(__WINGDK__)
|
2022-05-19 11:45:57 -05:00
|
|
|
/* Windows mouse capture is tied to the current thread, and must be called
|
|
|
|
* from the thread that created the window being captured. Since we update
|
|
|
|
* the mouse capture state from the event processing, any application state
|
|
|
|
* changes must be processed on that thread as well.
|
|
|
|
*/
|
|
|
|
if (!SDL_OnVideoThread()) {
|
|
|
|
return SDL_SetError("SDL_CaptureMouse() must be called on the main thread");
|
|
|
|
}
|
2022-06-27 12:19:39 -05:00
|
|
|
#endif /* defined(__WIN32__) || defined(__WINGDK__) */
|
2022-05-19 11:45:57 -05:00
|
|
|
|
2022-04-05 17:11:49 -05:00
|
|
|
if (enabled && SDL_GetKeyboardFocus() == NULL) {
|
2022-04-05 17:05:07 -05:00
|
|
|
return SDL_SetError("No window has focus");
|
|
|
|
}
|
|
|
|
mouse->capture_desired = enabled;
|
|
|
|
|
|
|
|
return SDL_UpdateMouseCapture(SDL_FALSE);
|
|
|
|
}
|
|
|
|
|
2015-06-21 10:33:46 -05:00
|
|
|
SDL_Cursor *
|
|
|
|
SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
|
|
|
|
int w, int h, int hot_x, int hot_y)
|
|
|
|
{
|
|
|
|
SDL_Surface *surface;
|
|
|
|
SDL_Cursor *cursor;
|
|
|
|
int x, y;
|
|
|
|
Uint32 *pixel;
|
|
|
|
Uint8 datab = 0, maskb = 0;
|
|
|
|
const Uint32 black = 0xFF000000;
|
|
|
|
const Uint32 white = 0xFFFFFFFF;
|
|
|
|
const Uint32 transparent = 0x00000000;
|
|
|
|
|
|
|
|
/* Make sure the width is a multiple of 8 */
|
|
|
|
w = ((w + 7) & ~7);
|
|
|
|
|
|
|
|
/* Create the surface from a bitmap */
|
|
|
|
surface = SDL_CreateRGBSurface(0, w, h, 32,
|
|
|
|
0x00FF0000,
|
|
|
|
0x0000FF00,
|
|
|
|
0x000000FF,
|
|
|
|
0xFF000000);
|
|
|
|
if (!surface) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
for (y = 0; y < h; ++y) {
|
|
|
|
pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
|
|
|
|
for (x = 0; x < w; ++x) {
|
|
|
|
if ((x % 8) == 0) {
|
|
|
|
datab = *data++;
|
|
|
|
maskb = *mask++;
|
|
|
|
}
|
|
|
|
if (maskb & 0x80) {
|
|
|
|
*pixel++ = (datab & 0x80) ? black : white;
|
|
|
|
} else {
|
|
|
|
*pixel++ = (datab & 0x80) ? black : transparent;
|
|
|
|
}
|
|
|
|
datab <<= 1;
|
|
|
|
maskb <<= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cursor = SDL_CreateColorCursor(surface, hot_x, hot_y);
|
|
|
|
|
|
|
|
SDL_FreeSurface(surface);
|
|
|
|
|
|
|
|
return cursor;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_Cursor *
|
|
|
|
SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
SDL_Surface *temp = NULL;
|
|
|
|
SDL_Cursor *cursor;
|
|
|
|
|
|
|
|
if (!surface) {
|
2022-01-17 09:26:02 -06:00
|
|
|
SDL_InvalidParamError("surface");
|
2015-06-21 10:33:46 -05:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mouse->CreateCursor) {
|
|
|
|
SDL_SetError("Cursors are not currently supported");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sanity check the hot spot */
|
|
|
|
if ((hot_x < 0) || (hot_y < 0) ||
|
|
|
|
(hot_x >= surface->w) || (hot_y >= surface->h)) {
|
|
|
|
SDL_SetError("Cursor hot spot doesn't lie within cursor");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (surface->format->format != SDL_PIXELFORMAT_ARGB8888) {
|
|
|
|
temp = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0);
|
|
|
|
if (!temp) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
surface = temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
cursor = mouse->CreateCursor(surface, hot_x, hot_y);
|
|
|
|
if (cursor) {
|
|
|
|
cursor->next = mouse->cursors;
|
|
|
|
mouse->cursors = cursor;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_FreeSurface(temp);
|
|
|
|
|
|
|
|
return cursor;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_Cursor *
|
|
|
|
SDL_CreateSystemCursor(SDL_SystemCursor id)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
SDL_Cursor *cursor;
|
|
|
|
|
|
|
|
if (!mouse->CreateSystemCursor) {
|
|
|
|
SDL_SetError("CreateSystemCursor is not currently supported");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
cursor = mouse->CreateSystemCursor(id);
|
|
|
|
if (cursor) {
|
|
|
|
cursor->next = mouse->cursors;
|
|
|
|
mouse->cursors = cursor;
|
|
|
|
}
|
|
|
|
|
|
|
|
return cursor;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* SDL_SetCursor(NULL) can be used to force the cursor redraw,
|
|
|
|
if this is desired for any reason. This is used when setting
|
|
|
|
the video mode and when the SDL window gains the mouse focus.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
SDL_SetCursor(SDL_Cursor * cursor)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
|
|
|
|
/* Set the new cursor */
|
|
|
|
if (cursor) {
|
|
|
|
/* Make sure the cursor is still valid for this mouse */
|
|
|
|
if (cursor != mouse->def_cursor) {
|
|
|
|
SDL_Cursor *found;
|
|
|
|
for (found = mouse->cursors; found; found = found->next) {
|
|
|
|
if (found == cursor) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!found) {
|
|
|
|
SDL_SetError("Cursor not associated with the current mouse");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mouse->cur_cursor = cursor;
|
|
|
|
} else {
|
|
|
|
if (mouse->focus) {
|
|
|
|
cursor = mouse->cur_cursor;
|
|
|
|
} else {
|
|
|
|
cursor = mouse->def_cursor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
|
|
|
|
if (mouse->ShowCursor) {
|
|
|
|
mouse->ShowCursor(cursor);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (mouse->ShowCursor) {
|
|
|
|
mouse->ShowCursor(NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_Cursor *
|
|
|
|
SDL_GetCursor(void)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
|
|
|
|
if (!mouse) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return mouse->cur_cursor;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_Cursor *
|
|
|
|
SDL_GetDefaultCursor(void)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
|
|
|
|
if (!mouse) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return mouse->def_cursor;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SDL_FreeCursor(SDL_Cursor * cursor)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
SDL_Cursor *curr, *prev;
|
|
|
|
|
|
|
|
if (!cursor) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cursor == mouse->def_cursor) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (cursor == mouse->cur_cursor) {
|
|
|
|
SDL_SetCursor(mouse->def_cursor);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (prev = NULL, curr = mouse->cursors; curr;
|
|
|
|
prev = curr, curr = curr->next) {
|
|
|
|
if (curr == cursor) {
|
|
|
|
if (prev) {
|
|
|
|
prev->next = curr->next;
|
|
|
|
} else {
|
|
|
|
mouse->cursors = curr->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mouse->FreeCursor) {
|
|
|
|
mouse->FreeCursor(curr);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
SDL_ShowCursor(int toggle)
|
|
|
|
{
|
|
|
|
SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
SDL_bool shown;
|
|
|
|
|
|
|
|
if (!mouse) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
shown = mouse->cursor_shown;
|
|
|
|
if (toggle >= 0) {
|
|
|
|
if (toggle) {
|
|
|
|
mouse->cursor_shown = SDL_TRUE;
|
|
|
|
} else {
|
|
|
|
mouse->cursor_shown = SDL_FALSE;
|
|
|
|
}
|
|
|
|
if (mouse->cursor_shown != shown) {
|
|
|
|
SDL_SetCursor(NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return shown;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* vi: set ts=4 sw=4 expandtab: */
|