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