Skip to content
Permalink
Browse files

Fixed bug 3644 - Wayland touch event support

Moritz Bitsch

Attached is a small patch which enables multitouch events on Wayland.
  • Loading branch information
slouken committed Aug 21, 2017
1 parent a78c20a commit 834ab350e5cd1fed9b023587875e5be1aec2a64b
Showing with 180 additions and 0 deletions.
  1. +180 −0 src/video/wayland/SDL_waylandevents.c
@@ -52,6 +52,7 @@ struct SDL_WaylandInput {
SDL_VideoData *display;
struct wl_seat *seat;
struct wl_pointer *pointer;
struct wl_touch *touch;
struct wl_keyboard *keyboard;
SDL_WaylandDataDevice *data_device;
struct zwp_relative_pointer_v1 *relative_pointer;
@@ -71,6 +72,105 @@ struct SDL_WaylandInput {
} xkb;
};

struct SDL_WaylandTouchPoint {
SDL_TouchID id;
float x;
float y;
struct wl_surface* surface;

struct SDL_WaylandTouchPoint* prev;
struct SDL_WaylandTouchPoint* next;
};

struct SDL_WaylandTouchPointList {
struct SDL_WaylandTouchPoint* head;
struct SDL_WaylandTouchPoint* tail;
};

static struct SDL_WaylandTouchPointList touch_points = {NULL, NULL};

static void
touch_add(SDL_TouchID id, float x, float y, struct wl_surface *surface)
{
struct SDL_WaylandTouchPoint* tp = SDL_malloc(sizeof(struct SDL_WaylandTouchPoint));

tp->id = id;
tp->x = x;
tp->y = y;
tp->surface = surface;

if (touch_points.tail) {
touch_points.tail->next = tp;
tp->prev = touch_points.tail;
} else {
touch_points.head = tp;
tp->prev = NULL;
}

touch_points.tail = tp;
tp->next = NULL;
}

static void
touch_update(SDL_TouchID id, float x, float y)
{
struct SDL_WaylandTouchPoint* tp = touch_points.head;

while (tp) {
if (tp->id == id) {
tp->x = x;
tp->y = y;
}

tp = tp->next;
}
}

static void
touch_del(SDL_TouchID id, float* x, float* y)
{
struct SDL_WaylandTouchPoint* tp = touch_points.head;

while (tp) {
if (tp->id == id) {
*x = tp->x;
*y = tp->y;

if (tp->prev) {
tp->prev->next = tp->next;
} else {
touch_points.head = tp->next;
}

if (tp->next) {
tp->next->prev = tp->prev;
} else {
touch_points.tail = tp->prev;
}

SDL_free(tp);
}

tp = tp->next;
}
}

static struct wl_surface*
touch_surface(SDL_TouchID id)
{
struct SDL_WaylandTouchPoint* tp = touch_points.head;

while (tp) {
if (tp->id == id) {
return tp->surface;
}

tp = tp->next;
}

return NULL;
}

void
Wayland_PumpEvents(_THIS)
{
@@ -268,6 +368,69 @@ static const struct wl_pointer_listener pointer_listener = {
pointer_handle_axis,
};

static void
touch_handler_down(void *data, struct wl_touch *touch, unsigned int serial,
unsigned int timestamp, struct wl_surface *surface,
int id, wl_fixed_t fx, wl_fixed_t fy)
{
float x, y;
SDL_WindowData* window;

window = (SDL_WindowData *)wl_surface_get_user_data(surface);

x = wl_fixed_to_double(fx) / window->sdlwindow->w;
y = wl_fixed_to_double(fy) / window->sdlwindow->h;

touch_add(id, x, y, surface);
SDL_SendTouch(1, (SDL_FingerID)id, SDL_TRUE, x, y, 1.0f);
}

static void
touch_handler_up(void *data, struct wl_touch *touch, unsigned int serial,
unsigned int timestamp, int id)
{
float x = 0, y = 0;

touch_del(id, &x, &y);
SDL_SendTouch(1, (SDL_FingerID)id, SDL_FALSE, x, y, 0.0f);
}

static void
touch_handler_motion(void *data, struct wl_touch *touch, unsigned int timestamp,
int id, wl_fixed_t fx, wl_fixed_t fy)
{
float x, y;
SDL_WindowData* window;

window = (SDL_WindowData *)wl_surface_get_user_data(touch_surface(id));

x = wl_fixed_to_double(fx) / window->sdlwindow->w;
y = wl_fixed_to_double(fy) / window->sdlwindow->h;

touch_update(id, x, y);
SDL_SendTouchMotion(1, (SDL_FingerID)id, x, y, 1.0f);
}

static void
touch_handler_frame(void *data, struct wl_touch *touch)
{

}

static void
touch_handler_cancel(void *data, struct wl_touch *touch)
{

}

static const struct wl_touch_listener touch_listener = {
touch_handler_down,
touch_handler_up,
touch_handler_motion,
touch_handler_frame,
touch_handler_cancel
};

static void
keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
uint32_t format, int fd, uint32_t size)
@@ -420,6 +583,18 @@ seat_handle_capabilities(void *data, struct wl_seat *seat,
input->pointer = NULL;
}

if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) {
SDL_AddTouch(1, "wayland_touch");
input->touch = wl_seat_get_touch(seat);
wl_touch_set_user_data(input->touch, input);
wl_touch_add_listener(input->touch, &touch_listener,
input);
} else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) {
SDL_DelTouch(1);
wl_touch_destroy(input->touch);
input->touch = NULL;
}

if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
input->keyboard = wl_seat_get_keyboard(seat);
wl_keyboard_set_user_data(input->keyboard, input);
@@ -739,6 +914,11 @@ void Wayland_display_destroy_input(SDL_VideoData *d)
if (input->pointer)
wl_pointer_destroy(input->pointer);

if (input->touch) {
SDL_DelTouch(1);
wl_touch_destroy(input->touch);
}

if (input->seat)
wl_seat_destroy(input->seat);

0 comments on commit 834ab35

Please sign in to comment.