SDL_waylandevents.c (11578B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> 4 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. 8 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: 12 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. 20*/ 21 22#include "../../SDL_internal.h" 23 24#if SDL_VIDEO_DRIVER_WAYLAND 25 26#include "SDL_stdinc.h" 27#include "SDL_assert.h" 28 29#include "../../events/SDL_sysevents.h" 30#include "../../events/SDL_events_c.h" 31#include "../../events/scancodes_xfree86.h" 32 33#include "SDL_waylandvideo.h" 34#include "SDL_waylandevents_c.h" 35#include "SDL_waylandwindow.h" 36 37#include "SDL_waylanddyn.h" 38 39#include <linux/input.h> 40#include <sys/select.h> 41#include <sys/mman.h> 42#include <poll.h> 43#include <errno.h> 44#include <unistd.h> 45#include <xkbcommon/xkbcommon.h> 46 47struct SDL_WaylandInput { 48 SDL_VideoData *display; 49 struct wl_seat *seat; 50 struct wl_pointer *pointer; 51 struct wl_keyboard *keyboard; 52 SDL_WindowData *pointer_focus; 53 SDL_WindowData *keyboard_focus; 54 55 struct { 56 struct xkb_keymap *keymap; 57 struct xkb_state *state; 58 } xkb; 59}; 60 61void 62Wayland_PumpEvents(_THIS) 63{ 64 SDL_VideoData *d = _this->driverdata; 65 struct pollfd pfd[1]; 66 67 pfd[0].fd = WAYLAND_wl_display_get_fd(d->display); 68 pfd[0].events = POLLIN; 69 poll(pfd, 1, 0); 70 71 if (pfd[0].revents & POLLIN) 72 WAYLAND_wl_display_dispatch(d->display); 73 else 74 WAYLAND_wl_display_dispatch_pending(d->display); 75} 76 77static void 78pointer_handle_enter(void *data, struct wl_pointer *pointer, 79 uint32_t serial, struct wl_surface *surface, 80 wl_fixed_t sx_w, wl_fixed_t sy_w) 81{ 82 struct SDL_WaylandInput *input = data; 83 SDL_WindowData *window; 84 85 if (!surface) { 86 /* enter event for a window we've just destroyed */ 87 return; 88 } 89 90 /* This handler will be called twice in Wayland 1.4 91 * Once for the window surface which has valid user data 92 * and again for the mouse cursor surface which does not have valid user data 93 * We ignore the later 94 */ 95 96 window = (SDL_WindowData *)wl_surface_get_user_data(surface); 97 98 if (window) { 99 input->pointer_focus = window; 100 SDL_SetMouseFocus(window->sdlwindow); 101 } 102} 103 104static void 105pointer_handle_leave(void *data, struct wl_pointer *pointer, 106 uint32_t serial, struct wl_surface *surface) 107{ 108 struct SDL_WaylandInput *input = data; 109 110 if (input->pointer_focus) { 111 SDL_SetMouseFocus(NULL); 112 input->pointer_focus = NULL; 113 } 114} 115 116static void 117pointer_handle_motion(void *data, struct wl_pointer *pointer, 118 uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w) 119{ 120 struct SDL_WaylandInput *input = data; 121 SDL_WindowData *window = input->pointer_focus; 122 int sx = wl_fixed_to_int(sx_w); 123 int sy = wl_fixed_to_int(sy_w); 124 if (input->pointer_focus) { 125 SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy); 126 } 127} 128 129static void 130pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial, 131 uint32_t time, uint32_t button, uint32_t state_w) 132{ 133 struct SDL_WaylandInput *input = data; 134 SDL_WindowData *window = input->pointer_focus; 135 enum wl_pointer_button_state state = state_w; 136 uint32_t sdl_button; 137 138 if (input->pointer_focus) { 139 switch (button) { 140 case BTN_LEFT: 141 sdl_button = SDL_BUTTON_LEFT; 142 break; 143 case BTN_MIDDLE: 144 sdl_button = SDL_BUTTON_MIDDLE; 145 break; 146 case BTN_RIGHT: 147 sdl_button = SDL_BUTTON_RIGHT; 148 break; 149 case BTN_SIDE: 150 sdl_button = SDL_BUTTON_X1; 151 break; 152 case BTN_EXTRA: 153 sdl_button = SDL_BUTTON_X2; 154 break; 155 default: 156 return; 157 } 158 159 SDL_SendMouseButton(window->sdlwindow, 0, 160 state ? SDL_PRESSED : SDL_RELEASED, sdl_button); 161 } 162} 163 164static void 165pointer_handle_axis(void *data, struct wl_pointer *pointer, 166 uint32_t time, uint32_t axis, wl_fixed_t value) 167{ 168 struct SDL_WaylandInput *input = data; 169 SDL_WindowData *window = input->pointer_focus; 170 enum wl_pointer_axis a = axis; 171 int x, y; 172 173 if (input->pointer_focus) { 174 switch (a) { 175 case WL_POINTER_AXIS_VERTICAL_SCROLL: 176 x = 0; 177 y = wl_fixed_to_int(value); 178 break; 179 case WL_POINTER_AXIS_HORIZONTAL_SCROLL: 180 x = wl_fixed_to_int(value); 181 y = 0; 182 break; 183 default: 184 return; 185 } 186 187 SDL_SendMouseWheel(window->sdlwindow, 0, x, y); 188 } 189} 190 191static const struct wl_pointer_listener pointer_listener = { 192 pointer_handle_enter, 193 pointer_handle_leave, 194 pointer_handle_motion, 195 pointer_handle_button, 196 pointer_handle_axis, 197}; 198 199static void 200keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, 201 uint32_t format, int fd, uint32_t size) 202{ 203 struct SDL_WaylandInput *input = data; 204 char *map_str; 205 206 if (!data) { 207 close(fd); 208 return; 209 } 210 211 if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { 212 close(fd); 213 return; 214 } 215 216 map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); 217 if (map_str == MAP_FAILED) { 218 close(fd); 219 return; 220 } 221 222 input->xkb.keymap = WAYLAND_xkb_keymap_new_from_string(input->display->xkb_context, 223 map_str, 224 XKB_KEYMAP_FORMAT_TEXT_V1, 225 0); 226 munmap(map_str, size); 227 close(fd); 228 229 if (!input->xkb.keymap) { 230 fprintf(stderr, "failed to compile keymap\n"); 231 return; 232 } 233 234 input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap); 235 if (!input->xkb.state) { 236 fprintf(stderr, "failed to create XKB state\n"); 237 WAYLAND_xkb_keymap_unref(input->xkb.keymap); 238 input->xkb.keymap = NULL; 239 return; 240 } 241} 242 243static void 244keyboard_handle_enter(void *data, struct wl_keyboard *keyboard, 245 uint32_t serial, struct wl_surface *surface, 246 struct wl_array *keys) 247{ 248 struct SDL_WaylandInput *input = data; 249 SDL_WindowData *window = wl_surface_get_user_data(surface); 250 251 input->keyboard_focus = window; 252 window->keyboard_device = input; 253 if (window) { 254 SDL_SetKeyboardFocus(window->sdlwindow); 255 } 256} 257 258static void 259keyboard_handle_leave(void *data, struct wl_keyboard *keyboard, 260 uint32_t serial, struct wl_surface *surface) 261{ 262 SDL_SetKeyboardFocus(NULL); 263} 264 265static void 266keyboard_handle_key(void *data, struct wl_keyboard *keyboard, 267 uint32_t serial, uint32_t time, uint32_t key, 268 uint32_t state_w) 269{ 270 struct SDL_WaylandInput *input = data; 271 SDL_WindowData *window = input->keyboard_focus; 272 enum wl_keyboard_key_state state = state_w; 273 const xkb_keysym_t *syms; 274 uint32_t scancode; 275 char text[8]; 276 int size; 277 278 if (key < SDL_arraysize(xfree86_scancode_table2)) { 279 scancode = xfree86_scancode_table2[key]; 280 281 // TODO when do we get WL_KEYBOARD_KEY_STATE_REPEAT? 282 if (scancode != SDL_SCANCODE_UNKNOWN) 283 SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ? 284 SDL_PRESSED : SDL_RELEASED, scancode); 285 } 286 287 if (!window || window->keyboard_device != input || !input->xkb.state) 288 return; 289 290 // TODO can this happen? 291 if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1) 292 return; 293 294 if (state) { 295 size = WAYLAND_xkb_keysym_to_utf8(syms[0], text, sizeof text); 296 297 if (size > 0) { 298 text[size] = 0; 299 SDL_SendKeyboardText(text); 300 } 301 } 302} 303 304static void 305keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard, 306 uint32_t serial, uint32_t mods_depressed, 307 uint32_t mods_latched, uint32_t mods_locked, 308 uint32_t group) 309{ 310 struct SDL_WaylandInput *input = data; 311 312 WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched, 313 mods_locked, 0, 0, group); 314} 315 316static const struct wl_keyboard_listener keyboard_listener = { 317 keyboard_handle_keymap, 318 keyboard_handle_enter, 319 keyboard_handle_leave, 320 keyboard_handle_key, 321 keyboard_handle_modifiers, 322}; 323 324static void 325seat_handle_capabilities(void *data, struct wl_seat *seat, 326 enum wl_seat_capability caps) 327{ 328 struct SDL_WaylandInput *input = data; 329 330 if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) { 331 input->pointer = wl_seat_get_pointer(seat); 332 input->display->pointer = input->pointer; 333 wl_pointer_set_user_data(input->pointer, input); 334 wl_pointer_add_listener(input->pointer, &pointer_listener, 335 input); 336 } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) { 337 wl_pointer_destroy(input->pointer); 338 input->pointer = NULL; 339 } 340 341 if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) { 342 input->keyboard = wl_seat_get_keyboard(seat); 343 wl_keyboard_set_user_data(input->keyboard, input); 344 wl_keyboard_add_listener(input->keyboard, &keyboard_listener, 345 input); 346 } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) { 347 wl_keyboard_destroy(input->keyboard); 348 input->keyboard = NULL; 349 } 350} 351 352static const struct wl_seat_listener seat_listener = { 353 seat_handle_capabilities, 354}; 355 356void 357Wayland_display_add_input(SDL_VideoData *d, uint32_t id) 358{ 359 struct SDL_WaylandInput *input; 360 361 input = SDL_calloc(1, sizeof *input); 362 if (input == NULL) 363 return; 364 365 input->display = d; 366 input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 1); 367 368 d->input = input; 369 370 wl_seat_add_listener(input->seat, &seat_listener, input); 371 wl_seat_set_user_data(input->seat, input); 372 373 WAYLAND_wl_display_flush(d->display); 374} 375 376void Wayland_display_destroy_input(SDL_VideoData *d) 377{ 378 struct SDL_WaylandInput *input = d->input; 379 380 if (!input) 381 return; 382 383 if (input->keyboard) 384 wl_keyboard_destroy(input->keyboard); 385 386 if (input->pointer) 387 wl_pointer_destroy(input->pointer); 388 389 if (input->seat) 390 wl_seat_destroy(input->seat); 391 392 if (input->xkb.state) 393 WAYLAND_xkb_state_unref(input->xkb.state); 394 395 if (input->xkb.keymap) 396 WAYLAND_xkb_keymap_unref(input->xkb.keymap); 397 398 SDL_free(input); 399 d->input = NULL; 400} 401 402#endif /* SDL_VIDEO_DRIVER_WAYLAND */ 403 404/* vi: set ts=4 sw=4 expandtab: */