mirror of
https://github.com/Ryujinx/SDL.git
synced 2024-12-22 21:35:30 +00:00
wayland: Handle mouse focus when receiving touch events
Compositors may switch from mouse to touch mode when a touch event is received, causing a pointer leave event and subsequent loss of mouse focus. Don't relinquish mouse focus on surfaces with active touch events. If there are active touch events when pointer focus is lost, the keyboard focus is used as a fallback for relinquishing mouse focus: if, in this case, the keyboard focus is then lost and there are no active touches, mouse focus is lost, and if all touches are raised and there is no keyboard or pointer focus, then the window loses mouse focus. (cherry picked from commit 21879faf4815a6acdb29e290d51a15bbe4dae03e)
This commit is contained in:
parent
239b5278bf
commit
867d8643d7
|
@ -163,6 +163,21 @@ static void touch_del(SDL_TouchID id, wl_fixed_t *x, wl_fixed_t *y, struct wl_su
|
|||
}
|
||||
}
|
||||
|
||||
static SDL_bool Wayland_SurfaceHasActiveTouches(struct wl_surface *surface)
|
||||
{
|
||||
struct SDL_WaylandTouchPoint *tp = touch_points.head;
|
||||
|
||||
while (tp) {
|
||||
if (tp->surface == surface) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
tp = tp->next;
|
||||
}
|
||||
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/* Returns SDL_TRUE if a key repeat event was due */
|
||||
static SDL_bool keyboard_repeat_handle(SDL_WaylandKeyboardRepeat *repeat_info, uint32_t elapsed)
|
||||
{
|
||||
|
@ -453,7 +468,12 @@ static void pointer_handle_leave(void *data, struct wl_pointer *pointer,
|
|||
}
|
||||
|
||||
if (input->pointer_focus) {
|
||||
SDL_SetMouseFocus(NULL);
|
||||
/* A pointer leave event may be emitted if the compositor hides the pointer in response to receiving a touch event.
|
||||
* Don't relinquish focus if the surface has active touches, as the compositor is just transitioning from mouse to touch mode.
|
||||
*/
|
||||
if (!Wayland_SurfaceHasActiveTouches(surface)) {
|
||||
SDL_SetMouseFocus(NULL);
|
||||
}
|
||||
input->pointer_focus = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -820,6 +840,8 @@ static void touch_handler_down(void *data, struct wl_touch *touch, uint32_t seri
|
|||
const float x = dblx / window_data->sdlwindow->w;
|
||||
const float y = dbly / window_data->sdlwindow->h;
|
||||
|
||||
SDL_SetMouseFocus(window_data->sdlwindow);
|
||||
|
||||
SDL_SendTouch((SDL_TouchID)(intptr_t)touch, (SDL_FingerID)id,
|
||||
window_data->sdlwindow, SDL_TRUE, x, y, 1.0f);
|
||||
}
|
||||
|
@ -829,6 +851,7 @@ static void touch_handler_up(void *data, struct wl_touch *touch, uint32_t serial
|
|||
uint32_t timestamp, int id)
|
||||
{
|
||||
wl_fixed_t fx = 0, fy = 0;
|
||||
struct SDL_WaylandInput *input = (struct SDL_WaylandInput *)data;
|
||||
struct wl_surface *surface = NULL;
|
||||
|
||||
touch_del(id, &fx, &fy, &surface);
|
||||
|
@ -844,6 +867,14 @@ static void touch_handler_up(void *data, struct wl_touch *touch, uint32_t serial
|
|||
|
||||
SDL_SendTouch((SDL_TouchID)(intptr_t)touch, (SDL_FingerID)id,
|
||||
window_data->sdlwindow, SDL_FALSE, x, y, 1.0f);
|
||||
|
||||
/* If the seat lacks pointer focus, the seat's keyboard focus is another window or NULL, this window curently
|
||||
* has mouse focus, and the surface has no active touch events, consider mouse focus to be lost.
|
||||
*/
|
||||
if (!input->pointer_focus && input->keyboard_focus != window_data &&
|
||||
SDL_GetMouseFocus() == window_data->sdlwindow && !Wayland_SurfaceHasActiveTouches(surface)) {
|
||||
SDL_SetMouseFocus(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1127,15 +1158,18 @@ static void keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
|
|||
uint32_t serial, struct wl_surface *surface)
|
||||
{
|
||||
struct SDL_WaylandInput *input = data;
|
||||
SDL_WindowData *window;
|
||||
SDL_WindowData *wind;
|
||||
SDL_Window *window = NULL;
|
||||
|
||||
if (!surface || !SDL_WAYLAND_own_surface(surface)) {
|
||||
return;
|
||||
}
|
||||
|
||||
window = wl_surface_get_user_data(surface);
|
||||
if (window) {
|
||||
window->sdlwindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
|
||||
wind = wl_surface_get_user_data(surface);
|
||||
if (wind) {
|
||||
wind->keyboard_device = NULL;
|
||||
window = wind->sdlwindow;
|
||||
window->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
|
||||
}
|
||||
|
||||
/* Stop key repeat before clearing keyboard focus */
|
||||
|
@ -1143,12 +1177,20 @@ static void keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
|
|||
|
||||
/* This will release any keys still pressed */
|
||||
SDL_SetKeyboardFocus(NULL);
|
||||
input->keyboard_focus = NULL;
|
||||
|
||||
#ifdef SDL_USE_IME
|
||||
if (!input->text_input) {
|
||||
SDL_IME_SetFocus(SDL_FALSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If the surface had a pointer leave event while still having active touch events, it retained mouse focus.
|
||||
* Clear it now if all touch events are raised.
|
||||
*/
|
||||
if (!input->pointer_focus && SDL_GetMouseFocus() == window && !Wayland_SurfaceHasActiveTouches(surface)) {
|
||||
SDL_SetMouseFocus(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_bool keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint32_t key, Uint8 state, SDL_bool *handled_by_ime)
|
||||
|
|
Loading…
Reference in a new issue