cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

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: */