2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
22 #include "../../SDL_internal.h"
24 #if SDL_VIDEO_DRIVER_WAYLAND
26 #include "SDL_stdinc.h"
27 #include "SDL_assert.h"
29 #include "../../events/SDL_sysevents.h"
30 #include "../../events/SDL_events_c.h"
31 #include "../../events/scancodes_xfree86.h"
33 #include "SDL_waylandvideo.h"
34 #include "SDL_waylandevents_c.h"
35 #include "SDL_waylandwindow.h"
37 #include "SDL_waylanddyn.h"
39 #include <linux/input.h>
40 #include <sys/select.h>
45 #include <xkbcommon/xkbcommon.h>
47 struct SDL_WaylandInput {
48 SDL_VideoData *display;
50 struct wl_pointer *pointer;
51 struct wl_keyboard *keyboard;
52 SDL_WindowData *pointer_focus;
53 SDL_WindowData *keyboard_focus;
55 /* Last motion location */
60 struct xkb_keymap *keymap;
61 struct xkb_state *state;
66 Wayland_PumpEvents(_THIS)
68 SDL_VideoData *d = _this->driverdata;
71 pfd[0].fd = WAYLAND_wl_display_get_fd(d->display);
72 pfd[0].events = POLLIN;
75 if (pfd[0].revents & POLLIN)
76 WAYLAND_wl_display_dispatch(d->display);
78 WAYLAND_wl_display_dispatch_pending(d->display);
82 pointer_handle_enter(void *data, struct wl_pointer *pointer,
83 uint32_t serial, struct wl_surface *surface,
84 wl_fixed_t sx_w, wl_fixed_t sy_w)
86 struct SDL_WaylandInput *input = data;
87 SDL_WindowData *window;
90 /* enter event for a window we've just destroyed */
94 /* This handler will be called twice in Wayland 1.4
95 * Once for the window surface which has valid user data
96 * and again for the mouse cursor surface which does not have valid user data
100 window = (SDL_WindowData *)wl_surface_get_user_data(surface);
103 input->pointer_focus = window;
104 SDL_SetMouseFocus(window->sdlwindow);
109 pointer_handle_leave(void *data, struct wl_pointer *pointer,
110 uint32_t serial, struct wl_surface *surface)
112 struct SDL_WaylandInput *input = data;
114 if (input->pointer_focus) {
115 SDL_SetMouseFocus(NULL);
116 input->pointer_focus = NULL;
121 pointer_handle_motion(void *data, struct wl_pointer *pointer,
122 uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
124 struct SDL_WaylandInput *input = data;
125 SDL_WindowData *window = input->pointer_focus;
128 if (input->pointer_focus) {
129 const int sx = wl_fixed_to_int(sx_w);
130 const int sy = wl_fixed_to_int(sy_w);
131 SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
136 ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial)
138 SDL_WindowData *window_data = input->pointer_focus;
139 SDL_Window *window = window_data->sdlwindow;
141 if (window->hit_test) {
142 const SDL_Point point = { wl_fixed_to_int(input->sx_w), wl_fixed_to_int(input->sy_w) };
143 const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
144 static const uint32_t directions[] = {
145 WL_SHELL_SURFACE_RESIZE_TOP_LEFT, WL_SHELL_SURFACE_RESIZE_TOP,
146 WL_SHELL_SURFACE_RESIZE_TOP_RIGHT, WL_SHELL_SURFACE_RESIZE_RIGHT,
147 WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT, WL_SHELL_SURFACE_RESIZE_BOTTOM,
148 WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT, WL_SHELL_SURFACE_RESIZE_LEFT
151 case SDL_HITTEST_DRAGGABLE:
152 wl_shell_surface_move(window_data->shell_surface, input->seat, serial);
155 case SDL_HITTEST_RESIZE_TOPLEFT:
156 case SDL_HITTEST_RESIZE_TOP:
157 case SDL_HITTEST_RESIZE_TOPRIGHT:
158 case SDL_HITTEST_RESIZE_RIGHT:
159 case SDL_HITTEST_RESIZE_BOTTOMRIGHT:
160 case SDL_HITTEST_RESIZE_BOTTOM:
161 case SDL_HITTEST_RESIZE_BOTTOMLEFT:
162 case SDL_HITTEST_RESIZE_LEFT:
163 wl_shell_surface_resize(window_data->shell_surface, input->seat, serial, directions[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
166 default: return SDL_FALSE;
174 pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
175 uint32_t time, uint32_t button, uint32_t state_w)
177 struct SDL_WaylandInput *input = data;
178 SDL_WindowData *window = input->pointer_focus;
179 enum wl_pointer_button_state state = state_w;
182 if (input->pointer_focus) {
185 sdl_button = SDL_BUTTON_LEFT;
186 if (ProcessHitTest(data, serial)) {
187 return; /* don't pass this event on to app. */
191 sdl_button = SDL_BUTTON_MIDDLE;
194 sdl_button = SDL_BUTTON_RIGHT;
197 sdl_button = SDL_BUTTON_X1;
200 sdl_button = SDL_BUTTON_X2;
206 SDL_SendMouseButton(window->sdlwindow, 0,
207 state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
212 pointer_handle_axis(void *data, struct wl_pointer *pointer,
213 uint32_t time, uint32_t axis, wl_fixed_t value)
215 struct SDL_WaylandInput *input = data;
216 SDL_WindowData *window = input->pointer_focus;
217 enum wl_pointer_axis a = axis;
220 if (input->pointer_focus) {
222 case WL_POINTER_AXIS_VERTICAL_SCROLL:
224 y = wl_fixed_to_int(value);
226 case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
227 x = wl_fixed_to_int(value);
234 SDL_SendMouseWheel(window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL);
238 static const struct wl_pointer_listener pointer_listener = {
239 pointer_handle_enter,
240 pointer_handle_leave,
241 pointer_handle_motion,
242 pointer_handle_button,
247 keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
248 uint32_t format, int fd, uint32_t size)
250 struct SDL_WaylandInput *input = data;
258 if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
263 map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
264 if (map_str == MAP_FAILED) {
269 input->xkb.keymap = WAYLAND_xkb_keymap_new_from_string(input->display->xkb_context,
271 XKB_KEYMAP_FORMAT_TEXT_V1,
273 munmap(map_str, size);
276 if (!input->xkb.keymap) {
277 fprintf(stderr, "failed to compile keymap\n");
281 input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap);
282 if (!input->xkb.state) {
283 fprintf(stderr, "failed to create XKB state\n");
284 WAYLAND_xkb_keymap_unref(input->xkb.keymap);
285 input->xkb.keymap = NULL;
291 keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
292 uint32_t serial, struct wl_surface *surface,
293 struct wl_array *keys)
295 struct SDL_WaylandInput *input = data;
296 SDL_WindowData *window;
299 /* enter event for a window we've just destroyed */
303 window = wl_surface_get_user_data(surface);
305 input->keyboard_focus = window;
306 window->keyboard_device = input;
308 SDL_SetKeyboardFocus(window->sdlwindow);
313 keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
314 uint32_t serial, struct wl_surface *surface)
316 SDL_SetKeyboardFocus(NULL);
320 keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
321 uint32_t serial, uint32_t time, uint32_t key,
324 struct SDL_WaylandInput *input = data;
325 SDL_WindowData *window = input->keyboard_focus;
326 enum wl_keyboard_key_state state = state_w;
327 const xkb_keysym_t *syms;
332 if (key < SDL_arraysize(xfree86_scancode_table2)) {
333 scancode = xfree86_scancode_table2[key];
335 // TODO when do we get WL_KEYBOARD_KEY_STATE_REPEAT?
336 if (scancode != SDL_SCANCODE_UNKNOWN)
337 SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ?
338 SDL_PRESSED : SDL_RELEASED, scancode);
341 if (!window || window->keyboard_device != input || !input->xkb.state)
344 // TODO can this happen?
345 if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1)
349 size = WAYLAND_xkb_keysym_to_utf8(syms[0], text, sizeof text);
353 SDL_SendKeyboardText(text);
359 keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
360 uint32_t serial, uint32_t mods_depressed,
361 uint32_t mods_latched, uint32_t mods_locked,
364 struct SDL_WaylandInput *input = data;
366 WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
367 mods_locked, 0, 0, group);
370 static const struct wl_keyboard_listener keyboard_listener = {
371 keyboard_handle_keymap,
372 keyboard_handle_enter,
373 keyboard_handle_leave,
375 keyboard_handle_modifiers,
379 seat_handle_capabilities(void *data, struct wl_seat *seat,
380 enum wl_seat_capability caps)
382 struct SDL_WaylandInput *input = data;
384 if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
385 input->pointer = wl_seat_get_pointer(seat);
386 input->display->pointer = input->pointer;
387 wl_pointer_set_user_data(input->pointer, input);
388 wl_pointer_add_listener(input->pointer, &pointer_listener,
390 } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
391 wl_pointer_destroy(input->pointer);
392 input->pointer = NULL;
395 if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
396 input->keyboard = wl_seat_get_keyboard(seat);
397 wl_keyboard_set_user_data(input->keyboard, input);
398 wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
400 } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
401 wl_keyboard_destroy(input->keyboard);
402 input->keyboard = NULL;
406 static const struct wl_seat_listener seat_listener = {
407 seat_handle_capabilities,
411 Wayland_display_add_input(SDL_VideoData *d, uint32_t id)
413 struct SDL_WaylandInput *input;
415 input = SDL_calloc(1, sizeof *input);
420 input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 1);
421 input->sx_w = wl_fixed_from_int(0);
422 input->sy_w = wl_fixed_from_int(0);
425 wl_seat_add_listener(input->seat, &seat_listener, input);
426 wl_seat_set_user_data(input->seat, input);
428 WAYLAND_wl_display_flush(d->display);
431 void Wayland_display_destroy_input(SDL_VideoData *d)
433 struct SDL_WaylandInput *input = d->input;
439 wl_keyboard_destroy(input->keyboard);
442 wl_pointer_destroy(input->pointer);
445 wl_seat_destroy(input->seat);
447 if (input->xkb.state)
448 WAYLAND_xkb_state_unref(input->xkb.state);
450 if (input->xkb.keymap)
451 WAYLAND_xkb_keymap_unref(input->xkb.keymap);
457 #endif /* SDL_VIDEO_DRIVER_WAYLAND */
459 /* vi: set ts=4 sw=4 expandtab: */