Fixed bug 3644 - Wayland touch event support
authorSam Lantinga <slouken@libsdl.org>
Mon, 21 Aug 2017 11:19:38 -0700
changeset 113365893a480c519
parent 11335 a9f4f63b5add
child 11337 d9f24e95e8ba
Fixed bug 3644 - Wayland touch event support

Moritz Bitsch

Attached is a small patch which enables multitouch events on Wayland.
src/video/wayland/SDL_waylandevents.c
     1.1 --- a/src/video/wayland/SDL_waylandevents.c	Mon Aug 21 11:17:38 2017 -0700
     1.2 +++ b/src/video/wayland/SDL_waylandevents.c	Mon Aug 21 11:19:38 2017 -0700
     1.3 @@ -52,6 +52,7 @@
     1.4      SDL_VideoData *display;
     1.5      struct wl_seat *seat;
     1.6      struct wl_pointer *pointer;
     1.7 +    struct wl_touch *touch;
     1.8      struct wl_keyboard *keyboard;
     1.9      SDL_WaylandDataDevice *data_device;
    1.10      struct zwp_relative_pointer_v1 *relative_pointer;
    1.11 @@ -71,6 +72,105 @@
    1.12      } xkb;
    1.13  };
    1.14  
    1.15 +struct SDL_WaylandTouchPoint {
    1.16 +    SDL_TouchID id;
    1.17 +    float x;
    1.18 +    float y;
    1.19 +    struct wl_surface* surface;
    1.20 +
    1.21 +    struct SDL_WaylandTouchPoint* prev;
    1.22 +    struct SDL_WaylandTouchPoint* next;
    1.23 +};
    1.24 +
    1.25 +struct SDL_WaylandTouchPointList {
    1.26 +    struct SDL_WaylandTouchPoint* head;
    1.27 +    struct SDL_WaylandTouchPoint* tail;
    1.28 +};
    1.29 +
    1.30 +static struct SDL_WaylandTouchPointList touch_points = {NULL, NULL};
    1.31 +
    1.32 +static void
    1.33 +touch_add(SDL_TouchID id, float x, float y, struct wl_surface *surface)
    1.34 +{
    1.35 +    struct SDL_WaylandTouchPoint* tp = SDL_malloc(sizeof(struct SDL_WaylandTouchPoint));
    1.36 +
    1.37 +    tp->id = id;
    1.38 +    tp->x = x;
    1.39 +    tp->y = y;
    1.40 +    tp->surface = surface;
    1.41 +
    1.42 +    if (touch_points.tail) {
    1.43 +        touch_points.tail->next = tp;
    1.44 +        tp->prev = touch_points.tail;
    1.45 +    } else {
    1.46 +        touch_points.head = tp;
    1.47 +        tp->prev = NULL;
    1.48 +    }
    1.49 +
    1.50 +    touch_points.tail = tp;
    1.51 +    tp->next = NULL;
    1.52 +}
    1.53 +
    1.54 +static void
    1.55 +touch_update(SDL_TouchID id, float x, float y)
    1.56 +{
    1.57 +    struct SDL_WaylandTouchPoint* tp = touch_points.head;
    1.58 +
    1.59 +    while (tp) {
    1.60 +        if (tp->id == id) {
    1.61 +            tp->x = x;
    1.62 +            tp->y = y;
    1.63 +        }
    1.64 +
    1.65 +        tp = tp->next;
    1.66 +    }
    1.67 +}
    1.68 +
    1.69 +static void
    1.70 +touch_del(SDL_TouchID id, float* x, float* y)
    1.71 +{
    1.72 +    struct SDL_WaylandTouchPoint* tp = touch_points.head;
    1.73 +
    1.74 +    while (tp) {
    1.75 +        if (tp->id == id) {
    1.76 +            *x = tp->x;
    1.77 +            *y = tp->y;
    1.78 +
    1.79 +            if (tp->prev) {
    1.80 +                tp->prev->next = tp->next;
    1.81 +            } else {
    1.82 +                touch_points.head = tp->next;
    1.83 +            }
    1.84 +
    1.85 +            if (tp->next) {
    1.86 +                tp->next->prev = tp->prev;
    1.87 +            } else {
    1.88 +                touch_points.tail = tp->prev;
    1.89 +            }
    1.90 +
    1.91 +            SDL_free(tp);
    1.92 +        }
    1.93 +
    1.94 +        tp = tp->next;
    1.95 +    }
    1.96 +}
    1.97 +
    1.98 +static struct wl_surface*
    1.99 +touch_surface(SDL_TouchID id)
   1.100 +{
   1.101 +    struct SDL_WaylandTouchPoint* tp = touch_points.head;
   1.102 +
   1.103 +    while (tp) {
   1.104 +        if (tp->id == id) {
   1.105 +            return tp->surface;
   1.106 +        }
   1.107 +
   1.108 +        tp = tp->next;
   1.109 +    }
   1.110 +
   1.111 +    return NULL;
   1.112 +}
   1.113 +
   1.114  void
   1.115  Wayland_PumpEvents(_THIS)
   1.116  {
   1.117 @@ -269,6 +369,69 @@
   1.118  };
   1.119  
   1.120  static void
   1.121 +touch_handler_down(void *data, struct wl_touch *touch, unsigned int serial,
   1.122 +                   unsigned int timestamp, struct wl_surface *surface,
   1.123 +                   int id, wl_fixed_t fx, wl_fixed_t fy)
   1.124 +{
   1.125 +    float x, y;
   1.126 +    SDL_WindowData* window;
   1.127 +
   1.128 +    window = (SDL_WindowData *)wl_surface_get_user_data(surface);
   1.129 +
   1.130 +    x = wl_fixed_to_double(fx) / window->sdlwindow->w;
   1.131 +    y = wl_fixed_to_double(fy) / window->sdlwindow->h;
   1.132 +
   1.133 +    touch_add(id, x, y, surface);
   1.134 +    SDL_SendTouch(1, (SDL_FingerID)id, SDL_TRUE, x, y, 1.0f);
   1.135 +}
   1.136 +
   1.137 +static void
   1.138 +touch_handler_up(void *data, struct wl_touch *touch, unsigned int serial,
   1.139 +                 unsigned int timestamp, int id)
   1.140 +{
   1.141 +    float x = 0, y = 0;
   1.142 +
   1.143 +    touch_del(id, &x, &y);
   1.144 +    SDL_SendTouch(1, (SDL_FingerID)id, SDL_FALSE, x, y, 0.0f);
   1.145 +}
   1.146 +
   1.147 +static void
   1.148 +touch_handler_motion(void *data, struct wl_touch *touch, unsigned int timestamp,
   1.149 +                     int id, wl_fixed_t fx, wl_fixed_t fy)
   1.150 +{
   1.151 +    float x, y;
   1.152 +    SDL_WindowData* window;
   1.153 +
   1.154 +    window = (SDL_WindowData *)wl_surface_get_user_data(touch_surface(id));
   1.155 +
   1.156 +    x = wl_fixed_to_double(fx) / window->sdlwindow->w;
   1.157 +    y = wl_fixed_to_double(fy) / window->sdlwindow->h;
   1.158 +
   1.159 +    touch_update(id, x, y);
   1.160 +    SDL_SendTouchMotion(1, (SDL_FingerID)id, x, y, 1.0f);
   1.161 +}
   1.162 +
   1.163 +static void
   1.164 +touch_handler_frame(void *data, struct wl_touch *touch)
   1.165 +{
   1.166 +
   1.167 +}
   1.168 +
   1.169 +static void
   1.170 +touch_handler_cancel(void *data, struct wl_touch *touch)
   1.171 +{
   1.172 +
   1.173 +}
   1.174 +
   1.175 +static const struct wl_touch_listener touch_listener = {
   1.176 +    touch_handler_down,
   1.177 +    touch_handler_up,
   1.178 +    touch_handler_motion,
   1.179 +    touch_handler_frame,
   1.180 +    touch_handler_cancel
   1.181 +};
   1.182 +
   1.183 +static void
   1.184  keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
   1.185                         uint32_t format, int fd, uint32_t size)
   1.186  {
   1.187 @@ -420,6 +583,18 @@
   1.188          input->pointer = NULL;
   1.189      }
   1.190  
   1.191 +    if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) {
   1.192 +        SDL_AddTouch(1, "wayland_touch");
   1.193 +        input->touch = wl_seat_get_touch(seat);
   1.194 +        wl_touch_set_user_data(input->touch, input);
   1.195 +        wl_touch_add_listener(input->touch, &touch_listener,
   1.196 +                                 input);
   1.197 +    } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) {
   1.198 +        SDL_DelTouch(1);
   1.199 +        wl_touch_destroy(input->touch);
   1.200 +        input->touch = NULL;
   1.201 +    }
   1.202 +
   1.203      if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
   1.204          input->keyboard = wl_seat_get_keyboard(seat);
   1.205          wl_keyboard_set_user_data(input->keyboard, input);
   1.206 @@ -739,6 +914,11 @@
   1.207      if (input->pointer)
   1.208          wl_pointer_destroy(input->pointer);
   1.209  
   1.210 +    if (input->touch) {
   1.211 +        SDL_DelTouch(1);
   1.212 +        wl_touch_destroy(input->touch);
   1.213 +    }
   1.214 +
   1.215      if (input->seat)
   1.216          wl_seat_destroy(input->seat);
   1.217