backend/libinput: Support libinput backend 73/278073/1
authorduna.oh <duna.oh@samsung.com>
Thu, 12 May 2022 06:52:31 +0000 (15:52 +0900)
committerSooChan Lim <sc1.lim@samsung.com>
Mon, 18 Jul 2022 05:08:27 +0000 (14:08 +0900)
add struct ds_libinput_backend, ds_libinput_input_device, etc.
add an executable 'libinput-backend' to test libinput events

Change-Id: Ifbc5ab8e587fbbc0767a3070da6b7b548d990cac

13 files changed:
include/libds/backend/libinput.h [new file with mode: 0644]
include/libds/pointer.h
packaging/libds.spec
src/examples/libinput-backend.c [new file with mode: 0644]
src/examples/meson.build
src/libds/backend/libinput/backend.c [new file with mode: 0644]
src/libds/backend/libinput/backend.h [new file with mode: 0644]
src/libds/backend/libinput/input.c [new file with mode: 0644]
src/libds/backend/libinput/keyboard.c [new file with mode: 0644]
src/libds/backend/libinput/meson.build [new file with mode: 0644]
src/libds/backend/libinput/pointer.c [new file with mode: 0644]
src/libds/backend/libinput/touch.c [new file with mode: 0644]
src/libds/backend/meson.build

diff --git a/include/libds/backend/libinput.h b/include/libds/backend/libinput.h
new file mode 100644 (file)
index 0000000..29efb0c
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef LIBDS_BACKEND_LIBINPUT_H
+#define LIBDS_BACKEND_LIBINPUT_H
+
+#include <libds/backend.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ds_backend *
+ds_libinput_backend_create(struct wl_display *display);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index 30bfaca..99545df 100644 (file)
@@ -15,6 +15,13 @@ struct ds_event_pointer_motion_absolute
     double x, y;
 };
 
+struct ds_event_pointer_motion
+{
+    struct ds_input_device *device;
+    uint32_t time_msec;
+    double delta_x, delta_y;
+};
+
 struct ds_event_pointer_button
 {
     struct ds_input_device *device;
index bee3972..5656382 100644 (file)
@@ -15,6 +15,8 @@ BuildRequires:  pkgconfig(tizen-extension-server)
 BuildRequires:  pkgconfig(pixman-1)
 BuildRequires:  pkgconfig(libdrm)
 BuildRequires:  pkgconfig(xkbcommon)
+BuildRequires:  pkgconfig(libinput)
+BuildRequires:  pkgconfig(libudev)
 
 BuildRequires:  pkgconfig(libtdm)
 BuildRequires:  pkgconfig(libtbm)
@@ -87,6 +89,7 @@ ninja -C builddir install
 %{_bindir}/wl-backend
 %{_bindir}/tinyds
 %{_bindir}/input-device-test
+%{_bindir}/libinput-backend
 
 %files tizen-devel
 %manifest %{name}.manifest
diff --git a/src/examples/libinput-backend.c b/src/examples/libinput-backend.c
new file mode 100644 (file)
index 0000000..592fbc3
--- /dev/null
@@ -0,0 +1,340 @@
+#include <assert.h>
+ #include <stdlib.h>
+
+#include <wayland-server.h>
+#include <libds/log.h>
+#include <libds/backend/libinput.h>
+#include <libds/input_device.h>
+#include <libds/pointer.h>
+#include <libds/keyboard.h>
+#include <libds/touch.h>
+
+#define UNUSED   __attribute__((unused))
+
+struct keyboard_device
+{
+    struct server *server;
+    struct ds_keyboard *ds_keyboard;
+
+    struct wl_listener destroy;
+    struct wl_listener key;
+};
+
+struct pointer_device
+{
+    struct ds_pointer *ds_pointer;
+
+    struct wl_listener destroy;
+    struct wl_listener motion;
+    struct wl_listener button;
+};
+
+struct touch_device
+{
+    struct ds_touch *ds_touch;
+
+    struct wl_listener destroy;
+    struct wl_listener down;
+    struct wl_listener up;
+    struct wl_listener motion;
+};
+
+struct server
+{
+    struct wl_display *display;
+
+    struct ds_backend *backend;
+
+    struct wl_listener backend_destroy;
+    struct wl_listener new_input;
+};
+
+struct server _server;
+
+static struct ds_backend *create_backend_auto(struct wl_display *display);
+static void handle_backend_destroy(struct wl_listener *listener, void *data);
+static void handle_new_input(struct wl_listener *listener, void *data);
+
+int
+main(void)
+{
+    struct server *server = &_server;
+
+    ds_log_init(DS_DBG, NULL);
+
+    server->display = wl_display_create();
+    assert(server->display);
+
+    server->backend = create_backend_auto(server->display);
+    assert(server->backend);
+
+    server->backend_destroy.notify = handle_backend_destroy;
+    ds_backend_add_destroy_listener(server->backend, &server->backend_destroy);
+
+    server->new_input.notify = handle_new_input;
+    ds_backend_add_new_input_listener(server->backend, &server->new_input);
+
+    ds_backend_start(server->backend);
+
+    wl_display_run(server->display);
+
+    wl_display_destroy(server->display);
+
+    return 0;
+}
+
+static struct ds_backend *
+create_backend_auto(struct wl_display *display)
+{
+    struct ds_backend *backend = NULL;
+    backend = ds_libinput_backend_create(display);
+    if (!backend)
+        ds_err("Failed to create libinput backend");
+
+    return backend;
+}
+
+static void
+handle_backend_destroy(struct wl_listener *listener, void *data)
+{
+    struct server *server;
+
+    server = wl_container_of(listener, server, backend_destroy);
+
+    wl_list_remove(&server->backend_destroy.link);
+    wl_list_remove(&server->new_input.link);
+}
+
+static char *
+device_type_to_string(enum ds_input_device_type type)
+{
+    switch (type) {
+        case DS_INPUT_DEVICE_POINTER:
+            return "pointer";
+            break;
+        case DS_INPUT_DEVICE_KEYBOARD:
+            return "keyboard";
+            break;
+        case DS_INPUT_DEVICE_TOUCH:
+            return "touch";
+            break;
+        default:
+            return "Unknown";
+    }
+}
+
+static void
+keyboard_handle_device_destroy(struct wl_listener *listener, void *data)
+{
+    struct keyboard_device *keyboard;
+
+    keyboard = wl_container_of(listener, keyboard, destroy);
+
+    wl_list_remove(&keyboard->destroy.link);
+    wl_list_remove(&keyboard->key.link);
+
+    free(keyboard);
+}
+
+static void
+keyboard_handle_key(struct wl_listener *listener, void *data)
+{
+    struct ds_event_keyboard_key *event = data;
+    struct keyboard_device *keyboard;
+
+    keyboard = wl_container_of(listener, keyboard, key);
+
+    ds_inf("Keyboard(%p) event key: keycode(%d), state(%d), time_msec(%d), "
+            "update_state(%d)", keyboard->ds_keyboard,
+            event->keycode, event->state, event->time_msec,
+            event->update_state);
+}
+
+static void
+add_keyboard(struct server *server, struct ds_input_device *dev)
+{
+    struct keyboard_device *keyboard;
+
+    keyboard = calloc(1, sizeof *keyboard);
+    if (!keyboard)
+        return;
+
+    keyboard->server = server;
+    keyboard->ds_keyboard = ds_input_device_get_keyboard(dev);
+
+    ds_inf("Keyboard(%p) added", keyboard->ds_keyboard);
+
+    keyboard->destroy.notify = keyboard_handle_device_destroy;
+    ds_input_device_add_destroy_listener(dev, &keyboard->destroy);
+
+    keyboard->key.notify = keyboard_handle_key;
+    ds_keyboard_add_key_listener(keyboard->ds_keyboard,
+            &keyboard->key);
+}
+
+static void
+pointer_handle_device_destroy(struct wl_listener *listener, void *data)
+{
+    struct pointer_device *pointer;
+
+    pointer = wl_container_of(listener, pointer, destroy);
+
+    wl_list_remove(&pointer->destroy.link);
+    wl_list_remove(&pointer->button.link);
+    wl_list_remove(&pointer->motion.link);
+
+    free(pointer);
+}
+
+static void
+pointer_handle_motion(struct wl_listener *listener, void *data)
+{
+    struct ds_event_pointer_motion *event = data;
+    struct pointer_device *pointer;
+
+    pointer = wl_container_of(listener, pointer, motion);
+
+    ds_inf("Pointer Device(%p): motion delta_x,y(%f, %f) time(%d ms)",
+            pointer->ds_pointer, event->delta_x, event->delta_y,
+            event->time_msec);
+}
+
+static void
+pointer_handle_button(struct wl_listener *listener, void *data)
+{
+    struct ds_event_pointer_button *event = data;
+    struct pointer_device *pointer;
+
+    pointer = wl_container_of(listener, pointer, button);
+    ds_inf("Pointer Device(%p): button(%d) state(%d) time(%d ms)",
+            pointer->ds_pointer, event->button, event->state,
+            event->time_msec);
+}
+
+static void
+add_pointer(struct ds_input_device *dev)
+{
+    struct pointer_device *pointer;
+
+    pointer = calloc(1, sizeof *pointer);
+    if (!pointer)
+        return;
+
+    pointer->ds_pointer = ds_input_device_get_pointer(dev);
+
+    ds_inf("Pointer(%p) added", pointer->ds_pointer);
+
+    pointer->destroy.notify = pointer_handle_device_destroy;
+    ds_input_device_add_destroy_listener(dev, &pointer->destroy);
+
+    pointer->motion.notify = pointer_handle_motion;
+    ds_pointer_add_motion_listener(pointer->ds_pointer,
+            &pointer->motion);
+
+    pointer->button.notify = pointer_handle_button;
+    ds_pointer_add_button_listener(pointer->ds_pointer,
+            &pointer->button);
+}
+
+static void
+touch_handle_device_destroy(struct wl_listener *listener, void *data)
+{
+    struct touch_device *touch;
+
+    touch = wl_container_of(listener, touch, destroy);
+
+    wl_list_remove(&touch->destroy.link);
+    wl_list_remove(&touch->down.link);
+    wl_list_remove(&touch->up.link);
+    wl_list_remove(&touch->motion.link);
+
+    free(touch);
+}
+
+static void
+touch_handle_down(struct wl_listener *listener, void *data)
+{
+    struct ds_event_touch_down *event = data;
+    struct touch_device *touch;
+
+    touch = wl_container_of(listener, touch, down);
+
+    ds_inf("Touch(%p) event down: id(%d) x(%f) y(%f) time_msec(%d)",
+            touch->ds_touch, event->id, event->x, event->y, event->time_msec);
+}
+
+static void
+touch_handle_up(struct wl_listener *listener, void *data)
+{
+    struct ds_event_touch_up *event = data;
+    struct touch_device *touch;
+
+    touch = wl_container_of(listener, touch, up);
+
+    ds_inf("Touch(%p) event up: id(%d) time_msec(%d)",
+            touch->ds_touch, event->id, event->time_msec);
+}
+
+static void
+touch_handle_motion(struct wl_listener *listener, void *data)
+{
+    struct ds_event_touch_motion *event = data;
+    struct touch_device *touch;
+
+    touch = wl_container_of(listener, touch, motion);
+
+    ds_inf("Touch(%p) event motion: id(%d) x(%f) y(%f) time_msec(%d)",
+            touch->ds_touch, event->id, event->x, event->y, event->time_msec);
+}
+
+static void
+add_touch(struct server *server, struct ds_input_device *dev)
+{
+    struct touch_device *touch;
+
+    touch = calloc(1, sizeof *touch);
+    if (!touch)
+        return;
+
+    touch->ds_touch = ds_input_device_get_touch(dev);
+
+    ds_inf("Touch(%p) added", touch->ds_touch);
+
+    touch->destroy.notify = touch_handle_device_destroy;
+    ds_input_device_add_destroy_listener(dev, &touch->destroy);
+
+    touch->down.notify = touch_handle_down;
+    ds_touch_add_down_listener(touch->ds_touch,
+            &touch->down);
+
+    touch->up.notify = touch_handle_up;
+    ds_touch_add_up_listener(touch->ds_touch,
+            &touch->up);
+
+    touch->motion.notify = touch_handle_motion;
+    ds_touch_add_motion_listener(touch->ds_touch,
+            &touch->motion);
+}
+
+static void
+handle_new_input(struct wl_listener *listener, void *data)
+{
+    struct server *server;
+    struct ds_input_device *dev = data;
+    enum ds_input_device_type type;
+
+    type = ds_input_device_get_type(dev);
+
+    ds_inf("New device(%p) type(%s)", dev, device_type_to_string(type));
+
+    if (type == DS_INPUT_DEVICE_POINTER)
+        add_pointer(dev);
+    else if (type == DS_INPUT_DEVICE_KEYBOARD) {
+        server = wl_container_of(listener, server, new_input);
+        add_keyboard(server, dev);
+    }
+    else if (type == DS_INPUT_DEVICE_TOUCH) {
+        server = wl_container_of(listener, server, new_input);
+        add_touch(server, dev);
+    }
+}
index c568eb6..9f2d976 100644 (file)
@@ -58,4 +58,11 @@ if get_option('tizen')
     install_dir: libds_bindir,
     install : true
   )
+
+  executable('libinput-backend',
+    'libinput-backend.c',
+    dependencies: common_deps,
+    install_dir: libds_bindir,
+    install : true
+  )
 endif
diff --git a/src/libds/backend/libinput/backend.c b/src/libds/backend/libinput/backend.c
new file mode 100644 (file)
index 0000000..f3ee044
--- /dev/null
@@ -0,0 +1,227 @@
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "libds/log.h"
+
+#include "backend.h"
+
+static const struct ds_backend_interface libinput_backend_interface;
+static void libinput_backend_handle_display_destroy(
+        struct wl_listener *listener, void *data);
+
+WL_EXPORT struct ds_backend *
+ds_libinput_backend_create(struct wl_display *display)
+{
+    struct ds_libinput_backend *libinput_backend;
+
+    libinput_backend = calloc(1, sizeof *libinput_backend);
+    if (!libinput_backend) {
+        ds_log_errno(DS_ERR, "Could not allocate memory");
+        return NULL;
+    }
+
+    ds_backend_init(&libinput_backend->base, &libinput_backend_interface);
+
+    libinput_backend->display = display;
+    wl_list_init(&libinput_backend->devices);
+
+    libinput_backend->display_destroy.notify =
+            libinput_backend_handle_display_destroy;
+    wl_display_add_destroy_listener(display,
+            &libinput_backend->display_destroy);
+
+    ds_inf("Libinput backend(%p) created",
+            libinput_backend);
+
+    return &libinput_backend->base;
+}
+
+WL_EXPORT struct ds_libinput_backend *
+libinput_backend_from_backend(struct ds_backend *backend)
+{
+    assert(backend->iface == &libinput_backend_interface);
+    return (struct ds_libinput_backend *)backend;
+}
+
+void
+destroy_libinput_input_device(struct ds_libinput_input_device *dev)
+{
+    ds_input_device_destroy(&dev->base);
+    libinput_device_unref(dev->handle);
+    wl_list_remove(&dev->link);
+    free(dev);
+}
+
+static void
+libinput_backend_destroy(struct ds_libinput_backend *backend)
+{
+    struct ds_libinput_input_device *dev, *tmp_dev;
+
+    wl_list_for_each_safe(dev, tmp_dev, &backend->devices, link)
+        destroy_libinput_input_device(dev);
+
+    ds_backend_finish(&backend->base);
+    wl_list_remove(&backend->display_destroy.link);
+    wl_event_source_remove(backend->server_event_source);
+    udev_unref(backend->udev);
+    libinput_unref(backend->libinput_context);
+
+    free(backend);
+}
+
+static int
+libinput_open_restricted(const char *path, int flags, void *_backend)
+{
+    int fd = -1;
+    struct stat s;
+
+    fd = open(path, flags | O_CLOEXEC);
+
+    if (fd < 0 || (fstat(fd, &s) == -1)) {
+        ds_log(DS_ERR, "Could not open device");
+        close(fd);
+        return -1;
+    }
+    return fd;
+}
+
+static void
+libinput_close_restricted(int fd, void *_backend)
+{
+    if (fd >= 0) close(fd);
+}
+
+static const struct libinput_interface libinput_impl = {
+    .open_restricted = libinput_open_restricted,
+    .close_restricted = libinput_close_restricted
+};
+
+static int
+handle_libinput_readable(int fd, uint32_t mask, void *_backend)
+{
+    struct ds_libinput_backend *backend = _backend;
+    struct libinput_event *event;
+    int ret;
+
+    ret = libinput_dispatch(backend->libinput_context);
+    if (ret != 0) {
+        ds_log(DS_ERR, "Failed to dispatch libinput: %s", strerror(-ret));
+        wl_display_terminate(backend->display);
+        return 0;
+    }
+
+    while ((event = libinput_get_event(backend->libinput_context))) {
+        handle_libinput_event(backend, event);
+        libinput_event_destroy(event);
+    }
+    return 0;
+}
+
+static void
+log_libinput(struct libinput *libinput_context,
+        enum libinput_log_priority priority, const char *fmt, va_list args)
+{
+    char buf[1024] = {0,};
+
+    vsnprintf(buf, 1024, fmt, args);
+    switch (priority) {
+        case LIBINPUT_LOG_PRIORITY_DEBUG:
+           ds_log(DS_DBG,"%s", buf);
+           break;
+        case LIBINPUT_LOG_PRIORITY_INFO:
+           ds_log(DS_INF, "%s", buf);
+           break;
+        case LIBINPUT_LOG_PRIORITY_ERROR:
+           ds_log(DS_ERR, "%s", buf);
+           break;
+        default:
+           break;
+     }
+}
+
+static bool
+libinput_backend_iface_start(struct ds_backend *ds_backend)
+{
+    struct ds_libinput_backend *backend;
+    struct wl_event_loop *event_loop;
+    int libinput_fd;
+
+    backend = libinput_backend_from_backend(ds_backend);
+    ds_log(DS_DBG, "Starting libinput backend");
+
+    backend->udev = udev_new();
+    backend->libinput_context = libinput_udev_create_context(&libinput_impl,
+            backend, backend->udev);
+    if (!backend->libinput_context) {
+        ds_log(DS_ERR, "Failed to create libinput context");
+        return false;
+    }
+
+    if (libinput_udev_assign_seat(backend->libinput_context, "seat0") != 0) {
+        ds_log(DS_ERR, "Failed to assign libinput seat");
+        return false;
+    }
+
+    libinput_log_set_handler(backend->libinput_context, log_libinput);
+    libinput_log_set_priority(backend->libinput_context,
+            LIBINPUT_LOG_PRIORITY_DEBUG);
+
+    libinput_fd = libinput_get_fd(backend->libinput_context);
+    if (wl_list_empty(&backend->devices)) {
+        handle_libinput_readable(libinput_fd, WL_EVENT_READABLE, backend);
+        if (wl_list_empty(&backend->devices)) {
+            ds_log(DS_ERR, "libinput initialization failed, no input devices");
+            return false;
+        }
+    }
+
+    event_loop = wl_display_get_event_loop(backend->display);
+    if (backend->server_event_source) {
+        wl_event_source_remove(backend->server_event_source);
+    }
+    backend->server_event_source =
+            wl_event_loop_add_fd(event_loop, libinput_fd, WL_EVENT_READABLE,
+            handle_libinput_readable, backend);
+    if (!backend->server_event_source) {
+        ds_log(DS_ERR, "Failed to create input event on event loop");
+        return false;
+    }
+    ds_log(DS_DBG, "libinput successfully initialized");
+
+    return true;
+}
+
+static void
+libinput_backend_iface_destroy(struct ds_backend *backend)
+{
+    struct ds_libinput_backend *libinput_backend;
+
+    if (!backend)
+        return;
+
+    libinput_backend = libinput_backend_from_backend(backend);
+    libinput_backend_destroy(libinput_backend);
+}
+
+static const struct ds_backend_interface libinput_backend_interface =
+{
+    .start = libinput_backend_iface_start,
+    .destroy = libinput_backend_iface_destroy,
+    .get_drm_fd = NULL,
+};
+
+static void
+libinput_backend_handle_display_destroy(struct wl_listener *listener,
+        void *data)
+{
+    struct ds_libinput_backend *libinput_backend;
+
+    libinput_backend =
+            wl_container_of(listener, libinput_backend, display_destroy);
+    libinput_backend_destroy(libinput_backend);
+}
diff --git a/src/libds/backend/libinput/backend.h b/src/libds/backend/libinput/backend.h
new file mode 100644 (file)
index 0000000..6fa2122
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef DS_BACKEND_LIBINPUT_H
+#define DS_BACKEND_LIBINPUT_H
+
+#include <libinput.h>
+#include <libudev.h>
+
+#include "libds/interfaces/backend.h"
+#include "libds/interfaces/input_device.h"
+#include "libds/interfaces/pointer.h"
+#include "libds/interfaces/keyboard.h"
+#include "libds/interfaces/touch.h"
+
+struct ds_libinput_backend
+{
+    struct ds_backend base;
+
+    struct wl_display *display;
+    struct wl_listener display_destroy;
+
+    struct udev *udev;
+    struct libinput *libinput_context;
+    struct wl_list devices; // ds_libinput_input_device::link
+
+    struct wl_event_source *server_event_source;
+};
+
+struct ds_libinput_input_device
+{
+    struct ds_input_device base;
+
+    struct ds_libinput_backend *backend;
+    struct libinput_device *handle;
+
+    struct wl_list link; //ds_libinput_backend.devices
+};
+
+struct ds_libinput_backend *
+        libinput_backend_from_backend(struct ds_backend *backend);
+
+void handle_libinput_event(struct ds_libinput_backend *state,
+        struct libinput_event *event);
+
+void destroy_libinput_input_device(struct ds_libinput_input_device *dev);
+
+//keyboard
+void handle_keyboard_key(struct libinput_event *event,
+        struct ds_keyboard *kbd);
+
+//pointer
+void handle_pointer_motion(struct libinput_event *event,
+        struct ds_pointer *pointer);
+void handle_pointer_motion_abs(struct libinput_event *event,
+        struct ds_pointer *pointer);
+void handle_pointer_button(struct libinput_event *event,
+        struct ds_pointer *pointer);
+void handle_pointer_axis(struct libinput_event *event,
+        struct ds_pointer *pointer);
+
+//touch
+void handle_touch_down(struct libinput_event *event,
+        struct ds_touch *touch);
+void handle_touch_up(struct libinput_event *event,
+        struct ds_touch *touch);
+void handle_touch_motion(struct libinput_event *event,
+        struct ds_touch *touch);
+void handle_touch_cancel(struct libinput_event *event,
+        struct ds_touch *touch);
+void handle_touch_frame(struct libinput_event *event,
+        struct ds_touch *touch);
+
+#endif
diff --git a/src/libds/backend/libinput/input.c b/src/libds/backend/libinput/input.c
new file mode 100644 (file)
index 0000000..2457a06
--- /dev/null
@@ -0,0 +1,210 @@
+#include <assert.h>
+
+#include "libds/log.h"
+#include "backend.h"
+
+static const struct ds_input_device_interface input_device_iface;
+
+static bool
+ds_input_device_is_libinput(struct ds_input_device *ds_dev)
+{
+    return ds_dev->iface == &input_device_iface;
+}
+
+static struct ds_libinput_input_device *
+get_libinput_input_device_from_input_device(struct ds_input_device *ds_dev)
+{
+    assert(ds_input_device_is_libinput(ds_dev));
+    return (struct ds_libinput_input_device *)ds_dev;
+}
+
+static void
+input_device_iface_destroy(struct ds_input_device *ds_dev)
+{
+    struct ds_libinput_input_device *dev;
+
+    dev = get_libinput_input_device_from_input_device(ds_dev);
+
+    free(dev);
+}
+
+static const struct ds_input_device_interface input_device_iface =
+{
+    .destroy = input_device_iface_destroy,
+};
+
+static struct ds_keyboard *
+create_ds_keyboard()
+{
+    struct ds_keyboard *kbd;
+    kbd = calloc(1, sizeof *kbd);
+    if (!kbd) {
+        ds_err("Could not allocate memory");
+        return NULL;
+    }
+    ds_keyboard_init(kbd, NULL);
+
+    return kbd;
+}
+
+static struct ds_pointer *
+create_ds_pointer()
+{
+    struct ds_pointer *pointer;
+    pointer = calloc(1, sizeof *pointer);
+    if (!pointer) {
+        ds_err("Could not allocate memory");
+        return NULL;
+    }
+    ds_pointer_init(pointer, NULL);
+
+    return pointer;
+}
+
+static struct ds_touch *
+create_ds_touch()
+{
+    struct ds_touch *touch;
+    touch = calloc(1, sizeof *touch);
+    if (!touch) {
+        ds_err("Could not allocate memory");
+        return NULL;
+    }
+    ds_touch_init(touch, NULL);
+
+    return touch;
+}
+
+static void
+handle_device_added(struct ds_libinput_backend *backend,
+       struct libinput_device *libinput_dev)
+{
+    int vendor, product;
+    const char *name;
+    struct ds_libinput_input_device *dev;
+
+    vendor = libinput_device_get_id_vendor(libinput_dev);
+    product = libinput_device_get_id_product(libinput_dev);
+    name = libinput_device_get_name(libinput_dev);
+    ds_log(DS_DBG, "Adding %s [%d:%d]", name, vendor, product);
+
+    dev = calloc(1, sizeof(struct ds_libinput_input_device));
+    if (dev == NULL) {
+        ds_log(DS_ERR, "failed to allocate ds_libinput_input_device");
+        return;
+    }
+
+    dev->handle = libinput_dev;
+    dev->backend = backend;
+    libinput_device_ref(libinput_dev);
+    libinput_device_set_user_data(libinput_dev, dev);
+
+    wl_list_insert(&backend->devices, &dev->link);
+
+    if (libinput_device_has_capability(
+                libinput_dev, LIBINPUT_DEVICE_CAP_KEYBOARD)) {
+        ds_input_device_init(&dev->base, DS_INPUT_DEVICE_KEYBOARD,
+                &input_device_iface, name, vendor, product);
+        dev->base.keyboard = create_ds_keyboard();
+
+        wl_signal_emit(&backend->base.events.new_input,
+                &dev->base);
+    }
+
+    if (libinput_device_has_capability(
+                libinput_dev, LIBINPUT_DEVICE_CAP_POINTER)) {
+        ds_input_device_init(&dev->base, DS_INPUT_DEVICE_POINTER,
+                &input_device_iface, name, vendor, product);
+        dev->base.pointer = create_ds_pointer();
+
+        wl_signal_emit(&backend->base.events.new_input,
+                &dev->base);
+    }
+
+    if (libinput_device_has_capability(
+                libinput_dev, LIBINPUT_DEVICE_CAP_TOUCH)) {
+        ds_input_device_init(&dev->base, DS_INPUT_DEVICE_TOUCH,
+                &input_device_iface, name, vendor, product);
+        dev->base.touch = create_ds_touch();
+
+        wl_signal_emit(&backend->base.events.new_input,
+                &dev->base);
+    }
+}
+
+static void
+handle_device_removed(struct ds_libinput_backend *backend,
+        struct libinput_device *libinput_dev)
+{
+    int vendor, product;
+    const char *name;
+    struct ds_libinput_input_device *dev;
+
+    vendor = libinput_device_get_id_vendor(libinput_dev);
+    product = libinput_device_get_id_product(libinput_dev);
+    name = libinput_device_get_name(libinput_dev);
+    ds_log(DS_DBG, "Removing %s [%d:%d]", name, vendor, product);
+
+    dev = libinput_device_get_user_data(libinput_dev);
+    if (dev == NULL) {
+        ds_log(DS_ERR, "libinput_device has no ds_libinput_input_device");
+        return;
+    }
+
+    destroy_libinput_input_device(dev);
+}
+
+void
+handle_libinput_event(struct ds_libinput_backend *backend,
+        struct libinput_event *event)
+{
+    struct libinput_device *libinput_dev;
+    struct ds_libinput_input_device *dev;
+    enum libinput_event_type event_type;
+
+    libinput_dev = libinput_event_get_device(event);
+    event_type = libinput_event_get_type(event);
+    dev = libinput_device_get_user_data(libinput_dev);
+
+    switch (event_type) {
+        case LIBINPUT_EVENT_DEVICE_ADDED:
+            handle_device_added(backend, libinput_dev);
+            break;
+        case LIBINPUT_EVENT_DEVICE_REMOVED:
+            handle_device_removed(backend, libinput_dev);
+            break;
+        case LIBINPUT_EVENT_KEYBOARD_KEY:
+            handle_keyboard_key(event, dev->base.keyboard);
+            break;
+        case LIBINPUT_EVENT_POINTER_MOTION:
+            handle_pointer_motion(event, dev->base.pointer);
+            break;
+        case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
+            handle_pointer_motion_abs(event, dev->base.pointer);
+            break;
+        case LIBINPUT_EVENT_POINTER_BUTTON:
+            handle_pointer_button(event, dev->base.pointer);
+            break;
+        case LIBINPUT_EVENT_POINTER_AXIS:
+            handle_pointer_axis(event, dev->base.pointer);
+            break;
+        case LIBINPUT_EVENT_TOUCH_DOWN:
+            handle_touch_down(event, dev->base.touch);
+            break;
+        case LIBINPUT_EVENT_TOUCH_UP:
+            handle_touch_up(event, dev->base.touch);
+            break;
+        case LIBINPUT_EVENT_TOUCH_MOTION:
+            handle_touch_motion(event, dev->base.touch);
+            break;
+        case LIBINPUT_EVENT_TOUCH_CANCEL:
+            handle_touch_cancel(event, dev->base.touch);
+            break;
+        case LIBINPUT_EVENT_TOUCH_FRAME:
+            handle_touch_frame(event, dev->base.touch);
+            break;
+        default:
+            ds_log(DS_DBG, "Unknown libinput event %d", event_type);
+            break;
+    }
+}
diff --git a/src/libds/backend/libinput/keyboard.c b/src/libds/backend/libinput/keyboard.c
new file mode 100644 (file)
index 0000000..53db0c9
--- /dev/null
@@ -0,0 +1,35 @@
+#include "libds/log.h"
+#include "backend.h"
+
+void
+handle_keyboard_key(struct libinput_event *event,
+        struct ds_keyboard *kbd)
+{
+    struct libinput_event_keyboard *kbevent;
+    uint32_t key;
+    enum libinput_key_state li_state;
+    enum wl_keyboard_key_state state = WL_KEYBOARD_KEY_STATE_PRESSED;
+
+    kbevent = libinput_event_get_keyboard_event(event);
+
+    key = libinput_event_keyboard_get_key(kbevent);
+    li_state = libinput_event_keyboard_get_key_state(kbevent);
+    if (li_state == LIBINPUT_KEY_STATE_PRESSED) {
+        state = WL_KEYBOARD_KEY_STATE_PRESSED;
+    }
+    else {
+        state = WL_KEYBOARD_KEY_STATE_RELEASED;
+    }
+
+    ds_log(DS_DBG, "Keyboard(%p) key event key:%d, state:%s", kbd, key,
+            (state == WL_KEYBOARD_KEY_STATE_PRESSED) ? "PRESSED":"RELEASED");
+
+    struct ds_event_keyboard_key ds_event = {
+        .keycode = key,
+        .state = state,
+        .time_msec = -1,
+        .update_state = false,
+    };
+
+    ds_keyboard_notify_key(kbd, &ds_event);
+}
diff --git a/src/libds/backend/libinput/meson.build b/src/libds/backend/libinput/meson.build
new file mode 100644 (file)
index 0000000..be85808
--- /dev/null
@@ -0,0 +1,15 @@
+libds_files += files(
+  'backend.c',
+  'input.c',
+  'keyboard.c',
+  'pointer.c',
+  'touch.c',
+)
+
+libinput = dependency('libinput', required: true)
+libudev = dependency('libudev', required: true)
+
+libds_deps += [
+  libinput,
+  libudev,
+]
diff --git a/src/libds/backend/libinput/pointer.c b/src/libds/backend/libinput/pointer.c
new file mode 100644 (file)
index 0000000..c118d06
--- /dev/null
@@ -0,0 +1,91 @@
+#include "libds/log.h"
+#include "backend.h"
+
+void
+handle_pointer_motion(struct libinput_event *event,
+        struct ds_pointer *pointer)
+{
+    struct libinput_event_pointer *pevent;
+    double delta_x, delta_y;
+    struct ds_event_pointer_motion ds_event = { 0 };
+
+    pevent = libinput_event_get_pointer_event(event);
+
+    delta_x = libinput_event_pointer_get_dx(pevent);
+    delta_y = libinput_event_pointer_get_dy(pevent);
+
+    ds_log(DS_DBG, "pointer motion event delta_x:%f, delta_y:%f", delta_x, delta_y);
+
+    ds_event.device = NULL;
+    ds_event.time_msec = -1;
+    ds_event.delta_x = delta_x;
+    ds_event.delta_y = delta_y;
+
+    wl_signal_emit(&pointer->events.motion, &ds_event);
+}
+
+void
+handle_pointer_motion_abs(struct libinput_event *event,
+        struct ds_pointer *pointer)
+{
+    struct libinput_event_pointer *pevent;
+    double x, y;
+    struct ds_event_pointer_motion_absolute ds_event = { 0 };
+
+    pevent = libinput_event_get_pointer_event(event);
+
+    x = libinput_event_pointer_get_absolute_x_transformed(pevent, 1);
+    y = libinput_event_pointer_get_absolute_y_transformed(pevent, 1);
+
+    ds_log(DS_DBG, "Pointer(%p) motion abs event x:%f, y:%f", pointer, x, y);
+
+    ds_event.device = NULL;
+    ds_event.time_msec = -1;
+    ds_event.x = x;
+    ds_event.y = y;
+
+    wl_signal_emit(&pointer->events.motion_absolute, &ds_event);
+}
+void
+handle_pointer_button(struct libinput_event *event,
+        struct ds_pointer *pointer)
+{
+    struct libinput_event_pointer *pevent;
+    uint32_t button;
+    enum libinput_button_state li_state = LIBINPUT_BUTTON_STATE_PRESSED;
+    enum ds_button_state state = DS_BUTTON_PRESSED;
+    struct ds_event_pointer_button ds_event = { 0 };
+
+    pevent = libinput_event_get_pointer_event(event);
+
+    button = libinput_event_pointer_get_button(pevent);
+    button = ((button & 0x00F) + 1);
+    if (button == 3) button = 2;
+    else if (button == 2) button = 3;
+
+    li_state = libinput_event_pointer_get_button_state(pevent);
+    if (li_state == LIBINPUT_BUTTON_STATE_PRESSED) {
+        state = DS_BUTTON_PRESSED;
+    }
+    else {
+        state = DS_BUTTON_RELEASED;
+    }
+    ds_log(DS_DBG, "Pointer(%p) button event button:%d state:%s",
+            pointer, button,
+            (state == DS_BUTTON_PRESSED) ? "PRESSED" : "RELEASED");
+
+    ds_event.device = NULL;
+    ds_event.time_msec = -1;
+    ds_event.button = button;
+    ds_event.state = state;
+
+    wl_signal_emit(&pointer->events.button, &ds_event);
+}
+
+void
+handle_pointer_axis(struct libinput_event *event,
+        struct ds_pointer *pointer)
+{
+    ds_log(DS_DBG, "pointer(%p) axis event", pointer);
+    /* TODO: wl_signal_emit() */
+}
diff --git a/src/libds/backend/libinput/touch.c b/src/libds/backend/libinput/touch.c
new file mode 100644 (file)
index 0000000..08b7b80
--- /dev/null
@@ -0,0 +1,98 @@
+#include "libds/log.h"
+#include "backend.h"
+
+void
+handle_touch_down(struct libinput_event *event,
+        struct ds_touch *touch)
+{
+    struct libinput_event_touch *tevent;
+    uint32_t touch_id;
+    double x, y;
+    struct ds_event_touch_down ds_event = { 0 };
+
+    tevent = libinput_event_get_touch_event(event);
+
+    touch_id = libinput_event_touch_get_seat_slot(tevent);
+    x = libinput_event_touch_get_x_transformed(tevent, 1);
+    y = libinput_event_touch_get_y_transformed(tevent, 1);
+
+    ds_log(DS_DBG, "touch down event id:%d, x:%f, y:%f", touch_id, x, y);
+
+    ds_event.device = NULL;
+    ds_event.time_msec = -1;
+    ds_event.id = touch_id;
+    ds_event.x = x;
+    ds_event.y = y;
+
+    wl_signal_emit(&touch->events.down, &ds_event);
+}
+
+void
+handle_touch_up(struct libinput_event *event,
+        struct ds_touch *touch)
+{
+    struct libinput_event_touch *tevent;
+    uint32_t touch_id;
+    struct ds_event_touch_up ds_event = { 0 };
+
+    tevent = libinput_event_get_touch_event(event);
+
+    touch_id = libinput_event_touch_get_seat_slot(tevent);
+
+    ds_log(DS_DBG, "touch up event id:%d", touch_id);
+
+    ds_event.device = NULL;
+    ds_event.time_msec = -1;
+    ds_event.id = touch_id;
+
+    wl_signal_emit(&touch->events.up, &ds_event);
+}
+
+void
+handle_touch_motion(struct libinput_event *event,
+        struct ds_touch *touch)
+{
+    struct libinput_event_touch *tevent;
+    uint32_t touch_id;
+    double x, y;
+    struct ds_event_touch_motion ds_event = { 0 };
+
+    tevent = libinput_event_get_touch_event(event);
+
+    touch_id = libinput_event_touch_get_seat_slot(tevent);
+    x = libinput_event_touch_get_x_transformed(tevent, 1);
+    y = libinput_event_touch_get_y_transformed(tevent, 1);
+
+    ds_log(DS_DBG, "touch motion event id:%d, x:%f, y:%f", touch_id, x, y);
+
+    ds_event.device = NULL;
+    ds_event.time_msec = -1;
+    ds_event.id = touch_id;
+    ds_event.x = x;
+    ds_event.y = y;
+
+    wl_signal_emit(&touch->events.motion, &ds_event);
+}
+
+void
+handle_touch_cancel(struct libinput_event *event,
+        struct ds_touch *touch)
+{
+    struct libinput_event_touch *tevent;
+    uint32_t touch_id;
+
+    tevent = libinput_event_get_touch_event(event);
+
+    touch_id = libinput_event_touch_get_seat_slot(tevent);
+
+    ds_log(DS_DBG, "touch cancel event id:%d", touch_id);
+    /* TODO: wl_signal_emit() */
+}
+
+void
+handle_touch_frame(struct libinput_event *event,
+        struct ds_touch *touch)
+{
+    ds_log(DS_DBG, "touch frame event");
+    /* TODO: wl_signal_emit() */
+}
index 895ffca..97e8087 100644 (file)
@@ -1 +1,2 @@
 subdir('wayland')
+subdir('libinput')