src/video/wayland/SDL_waylandevents.c
author Ryan C. Gordon
Mon, 20 Jan 2014 12:53:44 -0500
changeset 8116 f7c2f71251e5
parent 8104 2e4f1bd21196
child 8135 dd4729596096
permissions -rw-r--r--
Patched to compile if Wayland is disabled via SDL_config.h (thanks, Martin!).

Fixes Bugzilla #2351.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 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 
    47 struct 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 
    61 void
    62 Wayland_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 
    77 static void
    78 pointer_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     input->pointer_focus = wl_surface_get_user_data(surface);
    91     window = input->pointer_focus;
    92     SDL_SetMouseFocus(window->sdlwindow);
    93 }
    94 
    95 static void
    96 pointer_handle_leave(void *data, struct wl_pointer *pointer,
    97                      uint32_t serial, struct wl_surface *surface)
    98 {
    99     struct SDL_WaylandInput *input = data;
   100 
   101     SDL_SetMouseFocus(NULL);
   102     input->pointer_focus = NULL;
   103 }
   104 
   105 static void
   106 pointer_handle_motion(void *data, struct wl_pointer *pointer,
   107                       uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
   108 {
   109     struct SDL_WaylandInput *input = data;
   110     SDL_WindowData *window = input->pointer_focus;
   111     int sx = wl_fixed_to_int(sx_w);
   112     int sy = wl_fixed_to_int(sy_w);
   113 
   114     SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
   115 }
   116 
   117 static void
   118 pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
   119                       uint32_t time, uint32_t button, uint32_t state_w)
   120 {
   121     struct SDL_WaylandInput *input = data;
   122     SDL_WindowData *window = input->pointer_focus;
   123     enum wl_pointer_button_state state = state_w;
   124     uint32_t sdl_button;
   125 
   126     switch (button) {
   127     case BTN_LEFT:
   128         sdl_button = SDL_BUTTON_LEFT;
   129         break;
   130     case BTN_MIDDLE:
   131         sdl_button = SDL_BUTTON_MIDDLE;
   132         break;
   133     case BTN_RIGHT:
   134         sdl_button = SDL_BUTTON_RIGHT;
   135         break;
   136     case BTN_SIDE:
   137         sdl_button = SDL_BUTTON_X1;
   138         break;
   139     case BTN_EXTRA:
   140         sdl_button = SDL_BUTTON_X2;
   141         break;
   142     default:
   143         return;
   144     }
   145 
   146     SDL_SendMouseButton(window->sdlwindow, 0,
   147                         state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
   148 }
   149 
   150 static void
   151 pointer_handle_axis(void *data, struct wl_pointer *pointer,
   152                     uint32_t time, uint32_t axis, wl_fixed_t value)
   153 {
   154     struct SDL_WaylandInput *input = data;
   155     SDL_WindowData *window = input->pointer_focus;
   156     enum wl_pointer_axis a = axis;
   157     int x, y;
   158 
   159     switch (a) {
   160     case WL_POINTER_AXIS_VERTICAL_SCROLL:
   161         x = 0;
   162         y = wl_fixed_to_int(value);
   163         break;
   164     case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
   165         x = wl_fixed_to_int(value);
   166         y = 0;
   167         break;
   168     default:
   169         return;
   170     }
   171 
   172     SDL_SendMouseWheel(window->sdlwindow, 0, x, y);
   173 }
   174 
   175 static const struct wl_pointer_listener pointer_listener = {
   176     pointer_handle_enter,
   177     pointer_handle_leave,
   178     pointer_handle_motion,
   179     pointer_handle_button,
   180     pointer_handle_axis,
   181 };
   182 
   183 static void
   184 keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
   185                        uint32_t format, int fd, uint32_t size)
   186 {
   187     struct SDL_WaylandInput *input = data;
   188     char *map_str;
   189 
   190     if (!data) {
   191         close(fd);
   192         return;
   193     }
   194 
   195     if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
   196         close(fd);
   197         return;
   198     }
   199 
   200     map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
   201     if (map_str == MAP_FAILED) {
   202         close(fd);
   203         return;
   204     }
   205 
   206     input->xkb.keymap = WAYLAND_xkb_keymap_new_from_string(input->display->xkb_context,
   207                                                 map_str,
   208                                                 XKB_KEYMAP_FORMAT_TEXT_V1,
   209                                                 0);
   210     munmap(map_str, size);
   211     close(fd);
   212 
   213     if (!input->xkb.keymap) {
   214         fprintf(stderr, "failed to compile keymap\n");
   215         return;
   216     }
   217 
   218     input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap);
   219     if (!input->xkb.state) {
   220         fprintf(stderr, "failed to create XKB state\n");
   221         WAYLAND_xkb_keymap_unref(input->xkb.keymap);
   222         input->xkb.keymap = NULL;
   223         return;
   224     }
   225 }
   226 
   227 static void
   228 keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
   229                       uint32_t serial, struct wl_surface *surface,
   230                       struct wl_array *keys)
   231 {
   232     struct SDL_WaylandInput *input = data;
   233     SDL_WindowData *window = wl_surface_get_user_data(surface);
   234 
   235     input->keyboard_focus = window;
   236     window->keyboard_device = input;
   237     SDL_SetKeyboardFocus(window->sdlwindow);
   238 }
   239 
   240 static void
   241 keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
   242                       uint32_t serial, struct wl_surface *surface)
   243 {
   244     SDL_SetKeyboardFocus(NULL);
   245 }
   246 
   247 static void
   248 keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
   249                     uint32_t serial, uint32_t time, uint32_t key,
   250                     uint32_t state_w)
   251 {
   252     struct SDL_WaylandInput *input = data;
   253     SDL_WindowData *window = input->keyboard_focus;
   254     enum wl_keyboard_key_state state = state_w;
   255     const xkb_keysym_t *syms;
   256     uint32_t scancode;
   257     char text[8];
   258     int size;
   259 
   260     if (key < SDL_arraysize(xfree86_scancode_table2)) {
   261         scancode = xfree86_scancode_table2[key];
   262 
   263         // TODO when do we get WL_KEYBOARD_KEY_STATE_REPEAT?
   264         if (scancode != SDL_SCANCODE_UNKNOWN)
   265             SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ?
   266                                 SDL_PRESSED : SDL_RELEASED, scancode);
   267     }
   268 
   269     if (!window || window->keyboard_device != input || !input->xkb.state)
   270         return;
   271 
   272     // TODO can this happen?
   273     if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1)
   274         return;
   275 
   276     if (state) {
   277         size = WAYLAND_xkb_keysym_to_utf8(syms[0], text, sizeof text);
   278 
   279         if (size > 0) {
   280             text[size] = 0;
   281             SDL_SendKeyboardText(text);
   282         }
   283     }
   284 }
   285 
   286 static void
   287 keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
   288                           uint32_t serial, uint32_t mods_depressed,
   289                           uint32_t mods_latched, uint32_t mods_locked,
   290                           uint32_t group)
   291 {
   292     struct SDL_WaylandInput *input = data;
   293 
   294     WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
   295                           mods_locked, 0, 0, group);
   296 }
   297 
   298 static const struct wl_keyboard_listener keyboard_listener = {
   299     keyboard_handle_keymap,
   300     keyboard_handle_enter,
   301     keyboard_handle_leave,
   302     keyboard_handle_key,
   303     keyboard_handle_modifiers,
   304 };
   305 
   306 static void
   307 seat_handle_capabilities(void *data, struct wl_seat *seat,
   308                          enum wl_seat_capability caps)
   309 {
   310     struct SDL_WaylandInput *input = data;
   311 
   312     if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
   313         input->pointer = wl_seat_get_pointer(seat);
   314         input->display->pointer = input->pointer;
   315         wl_pointer_set_user_data(input->pointer, input);
   316         wl_pointer_add_listener(input->pointer, &pointer_listener,
   317                                 input);
   318     } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
   319         wl_pointer_destroy(input->pointer);
   320         input->pointer = NULL;
   321     }
   322 
   323     if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
   324         input->keyboard = wl_seat_get_keyboard(seat);
   325         wl_keyboard_set_user_data(input->keyboard, input);
   326         wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
   327                                  input);
   328     } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
   329         wl_keyboard_destroy(input->keyboard);
   330         input->keyboard = NULL;
   331     }
   332 }
   333 
   334 static const struct wl_seat_listener seat_listener = {
   335     seat_handle_capabilities,
   336 };
   337 
   338 void
   339 Wayland_display_add_input(SDL_VideoData *d, uint32_t id)
   340 {
   341     struct SDL_WaylandInput *input;
   342 
   343     input = malloc(sizeof *input);
   344     if (input == NULL)
   345         return;
   346 
   347     memset(input, 0, sizeof *input);
   348     input->display = d;
   349     input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 1);
   350 
   351     d->input = input;
   352 
   353     wl_seat_add_listener(input->seat, &seat_listener, input);
   354     wl_seat_set_user_data(input->seat, input);
   355 
   356     WAYLAND_wl_display_flush(d->display);
   357 }
   358 
   359 void Wayland_display_destroy_input(SDL_VideoData *d)
   360 {
   361     struct SDL_WaylandInput *input = d->input;
   362 
   363     if (!input)
   364         return;
   365 
   366     if (input->keyboard)
   367         wl_keyboard_destroy(input->keyboard);
   368 
   369     if (input->pointer)
   370         wl_pointer_destroy(input->pointer);
   371 
   372     if (input->seat)
   373         wl_seat_destroy(input->seat);
   374 
   375     if (input->xkb.state)
   376         WAYLAND_xkb_state_unref(input->xkb.state);
   377 
   378     if (input->xkb.keymap)
   379         WAYLAND_xkb_keymap_unref(input->xkb.keymap);
   380 
   381     free(input);
   382     d->input = NULL;
   383 }
   384 
   385 #endif /* SDL_VIDEO_DRIVER_WAYLAND */
   386 
   387 /* vi: set ts=4 sw=4 expandtab: */