devicemgr: implement libds-tizen-input-devicemgr 09/278209/1
authorduna.oh <duna.oh@samsung.com>
Tue, 7 Jun 2022 10:38:39 +0000 (19:38 +0900)
committerSooChan Lim <sc1.lim@samsung.com>
Mon, 18 Jul 2022 05:58:51 +0000 (14:58 +0900)
Change-Id: I3e0451c47fea0c5dac467d45143d594f36161907

20 files changed:
include/libds-tizen/input-devicemgr.h [new file with mode: 0644]
include/libds/input_device.h
include/libds/interfaces/backend.h
packaging/libds.spec
src/clients/input-generator.c [new file with mode: 0644]
src/clients/meson.build
src/clients/simple-tbm.c
src/examples/meson.build
src/examples/tinyds-tdm-libinput.c
src/libds-tizen/backend/tdm/backend.c
src/libds-tizen/input-devicemgr/input-devicemgr.c [new file with mode: 0644]
src/libds-tizen/input-devicemgr/input-devicemgr.h [new file with mode: 0644]
src/libds-tizen/input-devicemgr/meson.build [new file with mode: 0644]
src/libds-tizen/meson.build
src/libds/backend.c
src/libds/backend/libinput/backend.c
src/libds/backend/libinput/input.c
src/libds/backend/wayland/backend.c
src/libds/input_device.c
src/libds/seat/seat_keyboard.c

diff --git a/include/libds-tizen/input-devicemgr.h b/include/libds-tizen/input-devicemgr.h
new file mode 100644 (file)
index 0000000..a9ed808
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef LIBDS_TIZEN_INPUT_DEVICEMGR_H
+#define LIBDS_TIZEN_INPUT_DEVICEMGR_H
+
+#include <wayland-server.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ds_tizen_input_devicemgr;
+struct ds_backend;
+struct ds_seat;
+
+struct ds_tizen_input_devicemgr_keymap_data
+{
+    char *name;
+    int keycode;
+
+    struct wl_list link;
+};
+
+struct ds_tizen_input_devicemgr *
+ds_tizen_input_devicemgr_create(struct ds_backend *backend,
+        struct ds_seat *seat);
+
+void
+ds_tizen_input_devicemgr_add_destroy_listener(
+        struct ds_tizen_input_devicemgr *devicemgr,
+        struct wl_listener *listener);
+
+bool
+ds_tizen_input_devicemgr_set_keymap_list(
+        struct ds_tizen_input_devicemgr *devicemgr,
+        struct wl_list *list);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index 1a3652b..55aabbd 100644 (file)
@@ -25,6 +25,9 @@ enum ds_input_device_type
 enum ds_input_device_type
 ds_input_device_get_type(struct ds_input_device *dev);
 
+const char *
+ds_input_device_get_name(struct ds_input_device *dev);
+
 struct ds_pointer *
 ds_input_device_get_pointer(struct ds_input_device *dev);
 
index bad37a0..55a2475 100644 (file)
@@ -29,7 +29,8 @@ struct ds_backend
 };
 
 void
-ds_backend_init(struct ds_backend *backend, const struct ds_backend_interface *iface);
+ds_backend_init(struct ds_backend *backend, struct wl_display *display,
+        const struct ds_backend_interface *iface);
 
 void
 ds_backend_finish(struct ds_backend *backend);
index 6260ed2..f53efa9 100644 (file)
@@ -12,6 +12,7 @@ BuildRequires:  pkgconfig(wayland-server)
 BuildRequires:  pkgconfig(wayland-client)
 BuildRequires:  pkgconfig(wayland-protocols)
 BuildRequires:  pkgconfig(tizen-extension-server)
+BuildRequires:  pkgconfig(tizen-extension-client)
 BuildRequires:  pkgconfig(pixman-1)
 BuildRequires:  pkgconfig(libdrm)
 BuildRequires:  pkgconfig(xkbcommon)
@@ -59,6 +60,20 @@ Group:   Development/Libraries
 %description tizen-keyrouter-devel
 Keyrouter Development package for Wayland Compositor Library
 
+%package tizen-input-devicemgr
+Summary: Library for tizen input devicemgr
+Group:   Development/Libraries
+
+%description tizen-input-devicemgr
+Library for tizen input devicemgr
+
+%package tizen-input-devicemgr-devel
+Summary: Development package for tizen input devicemgr
+Group:   Development/Libraries
+
+%description tizen-input-devicemgr-devel
+Development package for tizen input devicemgr
+
 %prep
 %setup -q
 cp %{SOURCE1001} .
@@ -110,6 +125,7 @@ ninja -C builddir install
 %{_bindir}/ds-simple-shm-shell
 %{_bindir}/tinyds-tdm-dpms
 %{_bindir}/ds-simple-dpms
+%{_bindir}/input-generator
 
 %files tizen-keyrouter
 %manifest %{name}.manifest
@@ -124,3 +140,17 @@ ninja -C builddir install
 %{_includedir}/libds-tizen/keyrouter.h
 %{_libdir}/pkgconfig/libds-tizen-keyrouter.pc
 %{_libdir}/libds-tizen-keyrouter.so
+
+%files tizen-input-devicemgr
+%manifest %{name}.manifest
+%defattr(-,root,root,-)
+%license LICENSE
+%{_libdir}/libds-tizen-input-devicemgr.so.*
+
+%files tizen-input-devicemgr-devel
+%manifest %{name}.manifest
+%defattr(-,root,root,-)
+%license LICENSE
+%{_includedir}/libds-tizen/input-devicemgr.h
+%{_libdir}/pkgconfig/libds-tizen-input-devicemgr.pc
+%{_libdir}/libds-tizen-input-devicemgr.so
diff --git a/src/clients/input-generator.c b/src/clients/input-generator.c
new file mode 100644 (file)
index 0000000..f61e84b
--- /dev/null
@@ -0,0 +1,540 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+
+#include <wayland-client.h>
+#include <tizen-extension-client-protocol.h>
+
+#define MAX_STR 1024
+#define SIZE_EPOLL 16
+
+enum enum_key_type
+{
+    KEY_UP = 0,
+    KEY_DOWN,
+    KEY_ALL
+};
+
+enum enum_touch_type
+{
+    TOUCH_BEGIN = 0,
+    TOUCH_UPDATE,
+    TOUCH_END,
+    TOUCH_ALL
+};
+
+struct display
+{
+    struct wl_display *display;
+    struct wl_registry *registry;
+    struct wl_compositor *compositor;
+
+    struct tizen_input_device_manager *devicemgr;
+    enum tizen_input_device_manager_clas clas;
+    struct wl_event_queue *queue;
+
+    int run;
+    int fd_epoll;
+    int fd_display;
+
+    int request_notified;
+    int init;
+
+    int enable_log;
+};
+
+struct display data_wl;
+
+static void
+usage(void)
+{
+    printf("  Supported commands:  init  (Initialize input generator)\n");
+    printf("                    :  deinit  (Deinitialize input generator)\n");
+    printf("                    :  key  (Generate key events)\n");
+    printf("                    :  touch  (Generate touch events)\n");
+    printf("                    :  help  (Print this help text)\n");
+    printf("                    :  q/quit  (Quit program)\n");
+    printf("                    :  log  (Print detailed logs)\n");
+    printf("init {device type}\n");
+    printf("  : device type:\n");
+    printf("    - default: all\n");
+    printf("    - key/keyboard: keyboard\n");
+    printf("    - touch: touch screen\n");
+    printf("    - all: all of devices\n");
+    printf("  : ex> init keyboard / init\n");
+    printf("\n");
+    printf("deinit\n");
+    printf("  : ex> deinit\n");
+    printf("\n");
+    printf("key [keyname] {pressed}\n");
+    printf("  : pressed:\n");
+    printf("    - default: down&up pair\n");
+    printf("    - key down: 1\n");
+    printf("    - key up: 0\n");
+    printf("  : ex> key XF86Back 1\n");
+    printf("\n");
+    printf("touch {index} {type} {x} {y}\n");
+    printf("  : index:\n");
+    printf("    - default: first finger(0)\n");
+    printf("    - first finger is 0\n");
+    printf("  : type:\n");
+    printf("    - default: generate sample touch events\n");
+    printf("    - touch begin: 1\n");
+    printf("    - touch update: 2\n");
+    printf("    - touch end: 3\n");
+    printf("  : x/y:\n");
+    printf("    - default: 0\n");
+    printf("  : ex> touch / touch 0 1 100 100\n");
+    printf("\n");
+}
+
+static void
+init_input_generator(enum tizen_input_device_manager_clas clas)
+{
+    if (data_wl.init) {
+        printf("Already init input generator\n");
+        return;
+    }
+
+    tizen_input_device_manager_init_generator(data_wl.devicemgr, clas);
+
+    while (data_wl.request_notified == -1)
+        wl_display_dispatch_queue(data_wl.display, data_wl.queue);
+
+    if (data_wl.request_notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) {
+        data_wl.init = 1;
+        printf("Success to init input generator\n");
+    } else {
+        printf("Failed to init input generator: %d\n", data_wl.request_notified);
+    }
+
+    data_wl.clas = clas;
+    data_wl.request_notified = -1;
+}
+
+static void
+deinit_input_generator(void)
+{
+    if (!data_wl.init) {
+        printf("input generator is not initialized\n");
+        return;
+    }
+
+    tizen_input_device_manager_deinit_generator(data_wl.devicemgr, data_wl.clas);
+
+    while (data_wl.request_notified == -1)
+        wl_display_dispatch_queue(data_wl.display, data_wl.queue);
+
+    if (data_wl.request_notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) {
+        data_wl.init = 0;
+        printf("Success to deinit input generator\n");
+    } else {
+        printf("Failed to deinit input generator: %d\n", data_wl.request_notified);
+    }
+
+    data_wl.request_notified = -1;
+}
+
+static void
+input_generator_key(char *name, int type)
+{
+    tizen_input_device_manager_generate_key(data_wl.devicemgr, name, !!type);
+
+    while (data_wl.request_notified == -1)
+        wl_display_dispatch_queue(data_wl.display, data_wl.queue);
+
+    if (data_wl.request_notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) {
+        if (data_wl.enable_log) {
+            printf("Success to generate key: %s key %s\n", name, type?"down":"up");
+        }
+    } else {
+        printf("Failed to generate %s key %s: %d\n", name, type?"down":"up", data_wl.request_notified);
+    }
+
+    data_wl.request_notified = -1;
+}
+
+static void
+key_generate(char *name, int type)
+{
+    printf("name: %s, type: %d\n", name, type);
+
+    if (!data_wl.init) {
+        printf("Input genrator is not initialized\n");
+        return;
+    }
+
+    if (!name) {
+        printf("Type which key is generated\n");
+        return;
+    }
+
+    if (type == KEY_ALL) {
+        input_generator_key(name, 1);
+        input_generator_key(name, 0);
+    } else {
+        input_generator_key(name, !!type);
+    }
+}
+
+static char *
+touch_type_string_get(int type)
+{
+    switch (type) {
+        case TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_BEGIN:
+            return "begin";
+        case TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE:
+            return "update";
+        case TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_END:
+            return "end";
+        default:
+            return "Unknown";
+    }
+}
+
+static void
+input_generator_touch(int idx, int type, int x, int y)
+{
+    tizen_input_device_manager_generate_touch(data_wl.devicemgr, type, x, y, idx);
+
+    while (data_wl.request_notified == -1)
+        wl_display_dispatch_queue(data_wl.display, data_wl.queue);
+
+    if (data_wl.request_notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) {
+        if (data_wl.enable_log) {
+            printf("Success to generate touch: %d finger %s on (%d, %d)\n", idx, touch_type_string_get(type), x, y);
+        }
+    } else {
+        printf("Failed to generate touch(%d finger %s on (%d, %d)): %d\n", idx, touch_type_string_get(type), x, y, data_wl.request_notified);
+    }
+
+    data_wl.request_notified = -1;
+}
+
+static void
+touch_generate(int idx, int type, int x, int y)
+{
+    if (!data_wl.init) {
+        printf("Input genrator is not initialized\n");
+        return;
+    }
+
+    if (type == TOUCH_ALL) {
+        input_generator_touch(0, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_BEGIN, 100, 100);
+        input_generator_touch(1, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_BEGIN, 200, 200);
+        input_generator_touch(2, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_BEGIN, 300, 300);
+
+        input_generator_touch(0, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 110, 110);
+        input_generator_touch(1, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 210, 210);
+        input_generator_touch(2, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 310, 310);
+
+        input_generator_touch(0, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 120, 120);
+        input_generator_touch(1, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 220, 220);
+        input_generator_touch(2, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_UPDATE, 320, 320);
+
+        input_generator_touch(0, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_END, 120, 120);
+        input_generator_touch(1, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_END, 220, 220);
+        input_generator_touch(2, TIZEN_INPUT_DEVICE_MANAGER_POINTER_EVENT_TYPE_END, 320, 320);
+    } else {
+        input_generator_touch(idx, type, x, y);
+    }
+}
+
+static void
+stdin_read(void)
+{
+    int c;
+    char buf[MAX_STR] = {0, }, *tmp, *buf_ptr, key_name[MAX_STR] = {0, };
+    int count = 0;
+    int key_type = KEY_ALL, touch_idx = 0, touch_type = TOUCH_ALL, touch_x = 0, touch_y = 0;
+
+    while ((c = getchar()) != EOF) {
+        if (c == '\n') break;
+        if (count >= MAX_STR) break;
+
+        buf[count] = c;
+        count++;
+    }
+
+    count = 0;
+    tmp = strtok_r(buf, " ", &buf_ptr);
+    if (!tmp) return;
+
+    if (!strncmp(tmp, "init", sizeof("init"))) {
+        while (tmp) {
+            tmp = strtok_r(NULL, " ", &buf_ptr);
+            if (tmp) {
+                switch (count) {
+                    case 0:
+                        if (!strncmp("keyboard", tmp, MAX_STR-1))
+                            init_input_generator(TIZEN_INPUT_DEVICE_MANAGER_CLAS_KEYBOARD);
+                        else if (!strncmp("touch", tmp, MAX_STR-1))
+                            init_input_generator(TIZEN_INPUT_DEVICE_MANAGER_CLAS_TOUCHSCREEN);
+                        break;
+                    default:
+                        break;
+                }
+            }
+            count++;
+        }
+    } else if (!strncmp(tmp, "deinit", sizeof("deinit"))) {
+        deinit_input_generator();
+    } else if (!strncmp(tmp, "key", sizeof("key"))) {
+        while (tmp) {
+            tmp = strtok_r(NULL, " ", &buf_ptr);
+            if (tmp) {
+                switch (count) {
+                    case 0:
+                        strncpy(key_name, tmp, MAX_STR-1);
+                        break;
+                    case 1:
+                        key_type = atoi(tmp);
+                        break;
+                    default:
+                        break;
+                }
+            }
+            count++;
+        }
+        key_generate(key_name, key_type);
+    } else if (!strncmp(tmp, "touch", sizeof("touch"))) {
+        while (tmp) {
+            tmp = strtok_r(NULL, " ", &buf_ptr);
+            if (tmp) {
+                switch (count) {
+                    case 0:
+                        touch_idx = atoi(tmp);
+                        break;
+                    case 1:
+                        touch_type = atoi(tmp);
+                        break;
+                    case 2:
+                        touch_x = atoi(tmp);
+                        break;
+                    case 3:
+                        touch_y = atoi(tmp);
+                        break;
+                    default:
+                        break;
+                }
+            }
+            count++;
+        }
+        touch_generate(touch_idx, touch_type, touch_x, touch_y);
+    } else if (!strncmp(buf, "q", MAX_STR) || !strncmp(buf, "quit", MAX_STR)) {
+        data_wl.run = 0;
+    } else if (!strncmp(buf, "help", MAX_STR)) {
+        usage();
+    } else if (!strncmp(buf, "log", MAX_STR)) {
+        if (data_wl.enable_log)
+            printf("Disable detailed logs\n");
+        else
+            printf("Enable detailed logs\n");
+
+        data_wl.enable_log = !data_wl.enable_log;
+    } else {
+        printf("Invalid arguments\n");
+        usage();
+    }
+}
+
+static void
+input_device_manager_handle_error(void *data,
+        struct tizen_input_device_manager *tizen_input_device_manager,
+        uint32_t errorcode)
+{
+    if (data_wl.enable_log)
+        printf("errorcode: %d\n", errorcode);
+    data_wl.request_notified = errorcode;
+}
+
+static const struct tizen_input_device_manager_listener _input_device_manager_listener =
+{
+    .device_add = NULL,
+    .device_remove = NULL,
+    .error = input_device_manager_handle_error,
+    .block_expired = NULL,
+};
+
+static void
+registry_handle_global(void * data, struct wl_registry * registry, uint32_t id,
+        const char * interface, uint32_t version)
+{
+    if (strcmp(interface, "wl_compositor") == 0) {
+        data_wl.compositor = wl_registry_bind(registry, id,
+                &wl_compositor_interface, version);
+        if (!data_wl.compositor) {
+            printf("Failed to bind compositor.");
+            return;
+        }
+        if (data_wl.enable_log)
+            printf("Success to bind compositor.");
+    } else if (strcmp(interface, "tizen_input_device_manager") == 0) {
+        data_wl.devicemgr = wl_registry_bind(registry, id,
+                &tizen_input_device_manager_interface, version);
+        if (!data_wl.devicemgr) {
+            printf("Failed to bind input device manager");
+            return;
+        }
+        if (data_wl.enable_log)
+            printf("Success to bind tizen input device manager.");
+        tizen_input_device_manager_add_listener(data_wl.devicemgr,
+            &_input_device_manager_listener, data_wl.display);
+    }
+}
+
+static void
+registry_handle_global_remove(void * data, struct wl_registry * registry, uint32_t id)
+{
+    if (data_wl.enable_log)
+        printf("registry is removed. id: %d !\n", id);
+}
+
+static const struct wl_registry_listener _registry_listener = {
+    registry_handle_global,
+    registry_handle_global_remove
+};
+
+static int
+wayland_init(void)
+{
+    memset(&data_wl, 0, sizeof(struct display));
+    data_wl.request_notified = -1;
+
+    data_wl.display = wl_display_connect(NULL);
+    if (!data_wl.display) {
+        printf("Failed to connect wayland display\n");
+        return 0;
+    }
+
+    data_wl.queue = wl_display_create_queue(data_wl.display);
+    if (!data_wl.queue) {
+        printf("Failed to create queue\n");
+        return 0;
+    }
+
+    data_wl.registry = wl_display_get_registry(data_wl.display);
+    if (!data_wl.registry) {
+        printf("Failed to get registry\n");
+        return 0;
+    }
+
+    wl_proxy_set_queue((struct wl_proxy*)data_wl.registry, data_wl.queue);
+    wl_registry_add_listener(data_wl.registry, &_registry_listener, NULL);
+
+    if (wl_display_dispatch_queue(data_wl.display, data_wl.queue) == -1) {
+        printf("Failed to dispatch display\n");
+        return 0;
+    }
+    if (wl_display_roundtrip_queue(data_wl.display, data_wl.queue) == -1) {
+        printf("Failed to roundtrip display\n");
+        return 0;
+    }
+
+    return 1;
+}
+
+static void
+wayland_deinit(void)
+{
+    if (data_wl.enable_log)
+        printf("Shutdown wayland system\n");
+
+    if (data_wl.init) deinit_input_generator();
+
+    if (data_wl.queue) wl_event_queue_destroy(data_wl.queue);
+    if (data_wl.devicemgr) tizen_input_device_manager_destroy(data_wl.devicemgr);
+    if (data_wl.display) {
+        wl_registry_destroy(data_wl.registry);
+        wl_display_flush(data_wl.display);
+        wl_display_disconnect(data_wl.display);
+    }
+}
+
+static int
+epoll_init(void)
+{
+    struct epoll_event ep[2];
+
+    data_wl.fd_epoll = epoll_create(SIZE_EPOLL);
+    if (data_wl.fd_epoll <= 0) {
+        printf("Failed to epoll create: %d\n", SIZE_EPOLL);
+        return 0;
+    }
+
+    data_wl.fd_display = wl_display_get_fd(data_wl.display);
+
+    memset(ep, 0, sizeof(struct epoll_event)*2);
+
+    ep[0].events = EPOLLIN | EPOLLERR | EPOLLHUP;
+    ep[0].data.fd = data_wl.fd_display;
+    epoll_ctl(data_wl.fd_epoll, EPOLL_CTL_ADD, data_wl.fd_display, &ep[0]);
+    ep[1].events = EPOLLIN | EPOLLERR | EPOLLHUP;
+    ep[1].data.fd = STDIN_FILENO;
+    epoll_ctl(data_wl.fd_epoll, EPOLL_CTL_ADD, 0, &ep[1]);
+
+    return 1;
+}
+
+static void
+mainloop(void)
+{
+    struct epoll_event ep[SIZE_EPOLL];
+    int res, count, i;
+
+    res = epoll_init();
+    if (!res) {
+        printf("Failed to init epoll\n");
+        return;
+    }
+
+    data_wl.run = 1;
+    while (data_wl.run) {
+        res = wl_display_dispatch_queue_pending(data_wl.display, data_wl.queue);
+        if (res < 0) {
+            printf("Failed to dispatch pending. result: %d\n", res);
+            data_wl.run = 0;
+            break;
+        }
+        res = wl_display_flush(data_wl.display);
+        if (res < 0) {
+            printf("Failed to flush display. result: %d\n", res);
+            data_wl.run = 0;
+            break;
+        }
+
+        count = epoll_wait(data_wl.fd_epoll, ep, SIZE_EPOLL, -1);
+        for (i = 0; i < count; i++) {
+            if (ep[i].events & EPOLLIN) {
+                if (ep[i].data.fd == data_wl.fd_display) {
+                    wl_display_dispatch_queue(data_wl.display, data_wl.queue);
+                } else {
+                    stdin_read();
+                }
+            }
+            if (ep[i].events & EPOLLERR) {
+                data_wl.run = 0;
+            }
+            if (ep[i].events & EPOLLHUP) {
+                data_wl.run = 0;
+            }
+        }
+    }
+}
+
+int
+main(int argc, char **argv)
+{
+    int res;
+
+    res = wayland_init();
+    if (!res) return 0;
+
+    mainloop();
+
+    wayland_deinit();
+
+    return 0;
+}
index 6fcd3f8..ba09b32 100644 (file)
@@ -12,6 +12,7 @@ executable('ds-simple-shm-shell',
 
 wayland_tbm_client = dependency('wayland-tbm-client', required: false)
 libtbm = dependency('libtbm', required: false)
+tizen_extension_client = dependency('tizen-extension-client', required: true)
 
 if not wayland_tbm_client.found() or not libtbm.found()
   subdir_done()
@@ -22,6 +23,7 @@ simple_tbm_deps = [
   dependency('wayland-client', required: true),
   wayland_tbm_client,
   libtbm,
+  tizen_extension_client,
 ]
 
 protocols = {
@@ -65,3 +67,16 @@ executable('ds-simple-dpms',
   install_dir: libds_bindir,
   install: true,
 )
+
+input_generator_files = ['input-generator.c']
+input_generator_deps = [
+  dependency('wayland-client', required: true),
+  tizen_extension_client,
+]
+
+executable('input-generator',
+  input_generator_files,
+  dependencies: input_generator_deps,
+  install_dir: libds_bindir,
+  install: true,
+)
index 4fd9847..c82349f 100644 (file)
@@ -38,6 +38,7 @@
 #include <tbm_surface.h>
 #include <tbm_surface_internal.h>
 #include "xdg-shell-client-protocol.h"
+#include <tizen-extension-client-protocol.h>
 
 static uint64_t buffer_info_key;
 #define BUFFER_INFO_KEY (unsigned long)(&buffer_info_key)
@@ -51,6 +52,10 @@ struct display {
        struct wl_seat *seat;
     struct wayland_tbm_client *wl_tbm;
        bool has_xrgb;
+
+       struct tizen_input_device_manager *devicemgr;
+       int notified;
+       bool blocked;
 };
 
 struct window {
@@ -385,12 +390,43 @@ static void touch_handle_down(void *data, struct wl_touch *wl_touch,
 {
     fprintf(stderr, "touch_handle_down id:%d, x:%d, y:%d\n",
             id, wl_fixed_to_int(x), wl_fixed_to_int(y));
+
+    struct display *d = data;
+
+    tizen_input_device_manager_block_events(d->devicemgr, 0, TIZEN_INPUT_DEVICE_MANAGER_CLAS_KEYBOARD, 50000);
+
+    while (d->notified == -1)
+        wl_display_roundtrip(d->display);
+
+    if (d->notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) {
+        printf("Success to block keyboard events\n");
+    } else {
+        printf("Failed to block keyboard events: %d\n", d->notified);
+    }
+    d->notified = -1;
+    d->blocked = true;
 }
 
 static void touch_handle_up(void *data, struct wl_touch *wl_touch,
         uint32_t serial, uint32_t time, int32_t id)
 {
     fprintf(stderr, "touch_handle_up id:%d\n", id);
+
+    struct display *d = data;
+
+    if (!d->blocked) return;
+    tizen_input_device_manager_unblock_events(d->devicemgr, 0);
+
+    while (d->notified == -1)
+        wl_display_roundtrip(d->display);
+
+    if (d->notified == TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) {
+        printf("Success to unblock keyboard events\n");
+    } else {
+        printf("Failed to unblock keyboard events: %d\n", d->notified);
+    }
+    d->notified = -1;
+    d->blocked = false;
 }
 
 static void touch_handle_motion(void *data, struct wl_touch *wl_touch,
@@ -446,9 +482,9 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard,
         uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
 {
     if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
-        fprintf(stderr, "keyboard_handle_key: PRESSED\n");
+        fprintf(stderr, "keyboard_handle_key: key:%d, PRESSED\n", key);
     } else {
-        fprintf(stderr, "keyboard_handle_key: RELEASED\n");
+        fprintf(stderr, "keyboard_handle_key: key:%d, RELEASED\n", key);
     }
 }
 
@@ -464,6 +500,7 @@ static struct wl_keyboard_listener keyboard_listener = {
 static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
         enum wl_seat_capability caps)
 {
+       struct display *d = data;
     if ((caps & WL_SEAT_CAPABILITY_KEYBOARD)) {
         struct wl_keyboard *keyboard = wl_seat_get_keyboard(wl_seat);
         wl_keyboard_add_listener(keyboard, &keyboard_listener, NULL);
@@ -476,7 +513,7 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
     }
     if ((caps & WL_SEAT_CAPABILITY_TOUCH)) {
         struct wl_touch *touch = wl_seat_get_touch(wl_seat);
-        wl_touch_add_listener(touch, &touch_listener, NULL);
+        wl_touch_add_listener(touch, &touch_listener, d);
         fprintf(stderr, "seat_handle_capabilities: touch\n");
     }
 }
@@ -493,6 +530,31 @@ const struct wl_seat_listener seat_listener = {
 };
 
 static void
+input_device_manager_handle_error(void *data,
+        struct tizen_input_device_manager *tizen_input_device_manager,
+        uint32_t errorcode)
+{
+    struct display *d = data;
+    fprintf(stderr, "errorcode: %d\n", errorcode);
+    d->notified = errorcode;
+}
+
+static void
+input_device_manager_handle_block_expired(void *data,
+        struct tizen_input_device_manager *tizen_input_device_manager)
+{
+    fprintf(stderr, "block expired\n");
+}
+
+static const struct tizen_input_device_manager_listener _input_device_manager_listener =
+{
+    .device_add = NULL,
+    .device_remove = NULL,
+    .error = input_device_manager_handle_error,
+    .block_expired = input_device_manager_handle_block_expired,
+};
+
+static void
 registry_handle_global(void *data, struct wl_registry *registry,
                       uint32_t id, const char *interface, uint32_t version)
 {
@@ -515,7 +577,13 @@ registry_handle_global(void *data, struct wl_registry *registry,
                                          id, &wl_seat_interface, 7);
                wl_seat_add_listener(d->seat, &seat_listener, d);
                fprintf(stderr, "wl_seat bound!\n");
-       }
+       } else if (strcmp(interface, "tizen_input_device_manager") == 0) {
+               d->devicemgr = wl_registry_bind(registry,
+                                         id, &tizen_input_device_manager_interface, version);
+               tizen_input_device_manager_add_listener(d->devicemgr,
+                                &_input_device_manager_listener, d);
+               fprintf(stderr, "tizen input device manager bound!\n");
+    }
 }
 
 static void
@@ -605,12 +673,20 @@ create_display(void)
         exit(1);
     }
 
+       display->notified = -1;
+
        return display;
 }
 
 static void
 destroy_display(struct display *display)
 {
+       if (display->seat)
+           wl_seat_destroy(display->seat);
+
+       if (display->devicemgr)
+           tizen_input_device_manager_destroy(display->devicemgr);
+
        if (display->shm)
                wl_shm_destroy(display->shm);
 
index aad893e..eb9ae29 100644 (file)
@@ -76,6 +76,7 @@ if get_option('tizen')
     tinyds_tdm_libinput_files,
     dependencies: [
       common_deps,
+      dep_libds_tizen_input_devicemgr,
       dependency('pixman-1', required: true),
       dependency('threads', required: true),
     ],
index f4e9319..5634707 100644 (file)
@@ -23,6 +23,9 @@
 #include <libds/touch.h>
 #include <libds/pointer.h>
 #include <libds/seat.h>
+#include <libds-tizen/input-devicemgr.h>
+#include <xkbcommon/xkbcommon.h>
+#include <libds/interfaces/keyboard.h>
 
 #define USE_TDM_BUFFER_QUEUE
 
@@ -36,6 +39,7 @@
 #include "pixman-helper.h"
 
 #define TINYDS_UNUSED   __attribute__((unused))
+struct tinyds_keyboard;
 
 struct tinyds_output
 {
@@ -73,6 +77,7 @@ struct tinyds_server
     struct ds_seat *seat;
     uint32_t seat_caps;
     double output_x, output_y;
+    struct ds_tizen_input_devicemgr *devicemgr;
 
     struct tinyds_output *output;
     struct wl_event_source *stdin_source;
@@ -82,6 +87,8 @@ struct tinyds_server
     struct wl_listener new_output;
     struct wl_listener new_input;
     struct wl_listener new_xdg_surface;
+
+    struct tinyds_keyboard *keyboard;
 };
 
 struct tinyds_view
@@ -206,9 +213,18 @@ view_handle_xdg_surface_map(struct wl_listener *listener,
         void *data TINYDS_UNUSED)
 {
     struct tinyds_view *view;
-
+    struct ds_keyboard *keyboard;
     view = wl_container_of(listener, view, xdg_surface_map);
     view->mapped = true;
+
+    if (!view->server->keyboard) return;
+    keyboard = ds_input_device_get_keyboard(view->server->keyboard->dev);
+    if (keyboard != NULL) {
+        ds_seat_keyboard_notify_enter(view->server->seat,
+                ds_xdg_surface_get_surface(view->xdg_surface),
+                keyboard->keycodes, keyboard->num_keycodes,
+                &keyboard->modifiers);
+    }
 }
 
 static void
@@ -373,6 +389,59 @@ backend_handle_new_input(struct wl_listener *listener, void *data)
     ds_seat_set_capabilities(server->seat, server->seat_caps);
 }
 
+static void
+devicemgr_add_keymap_data(struct wl_list *list, const char *name, int keycode)
+{
+    struct ds_tizen_input_devicemgr_keymap_data *data;
+
+    data = calloc(1, sizeof *data);
+    if (!data) {
+        ds_err("Failed to alloc memory\n");
+        return;
+    }
+
+    data->name = strdup(name);
+    data->keycode = keycode;
+
+    wl_list_insert(list, &data->link);
+}
+
+static void
+devicemgr_remove_keymap_data(struct wl_list *list, int keycode)
+{
+    struct ds_tizen_input_devicemgr_keymap_data *data, *tmp;
+
+    wl_list_for_each_safe(data, tmp, list, link) {
+        if (data->keycode == keycode) {
+            wl_list_remove(&data->link);
+            free(data);
+        }
+    }
+}
+
+static void
+devicemgr_set_keymap(struct ds_tizen_input_devicemgr *devicemgr)
+{
+    struct wl_list keymap_list;
+    bool res;
+
+    wl_list_init(&keymap_list);
+
+    devicemgr_add_keymap_data(&keymap_list, "XF86VolumeRaise", 455);
+    devicemgr_add_keymap_data(&keymap_list, "XF86VolumeLower", 456);
+    devicemgr_add_keymap_data(&keymap_list, "XF86LightOn", 457);
+    devicemgr_add_keymap_data(&keymap_list, "XF86LightOff", 458);
+
+    res = ds_tizen_input_devicemgr_set_keymap_list(devicemgr, &keymap_list);
+    if (!res)
+        ds_inf("Failed to set keymap");
+
+    devicemgr_remove_keymap_data(&keymap_list, 455);
+    devicemgr_remove_keymap_data(&keymap_list, 456);
+    devicemgr_remove_keymap_data(&keymap_list, 457);
+    devicemgr_remove_keymap_data(&keymap_list, 458);
+}
+
 static bool
 init_server(struct tinyds_server *server, struct wl_display *display)
 {
@@ -388,8 +457,10 @@ init_server(struct tinyds_server *server, struct wl_display *display)
         return false;
 
     server->input_backend = ds_libinput_backend_create(display);
-    if (!server->input_backend)
+    if (!server->input_backend) {
+        ds_backend_destroy(server->backend);
         return false;
+    }
 
     server->new_output.notify = backend_handle_new_output;
     ds_backend_add_new_output_listener(server->backend,
@@ -419,6 +490,13 @@ init_server(struct tinyds_server *server, struct wl_display *display)
         goto err;
     server->seat_caps = 0;
 
+    server->devicemgr = ds_tizen_input_devicemgr_create(
+            server->input_backend, server->seat);
+    if (!server->devicemgr) {
+        goto err;
+    }
+
+    devicemgr_set_keymap(server->devicemgr);
     return true;
 
 err:
@@ -683,14 +761,35 @@ keyboard_handle_device_destroy(struct wl_listener *listener, void *data)
     wl_list_remove(&kbd->destroy.link);
     wl_list_remove(&kbd->key.link);
 
+    kbd->server->keyboard = NULL;
+
     free(kbd);
 }
 
+static bool
+server_handle_keybinding(struct tinyds_server *server, xkb_keysym_t sym)
+{
+    switch (sym) {
+        case XKB_KEY_BackSpace:
+            wl_display_terminate(server->display);
+            break;
+        default:
+            return false;
+    }
+
+    return true;
+}
+
 static void
 keyboard_handle_key(struct wl_listener *listener, void *data)
 {
     struct tinyds_keyboard *kbd;
     struct ds_event_keyboard_key *event = data;
+    struct ds_keyboard *ds_keyboard;
+    struct xkb_state *xkb_state;
+    const xkb_keysym_t *syms;
+    int nsyms;
+    bool handled = false;
 
     kbd = wl_container_of(listener, kbd, key);
 
@@ -698,14 +797,32 @@ keyboard_handle_key(struct wl_listener *listener, void *data)
             "update_state(%d)", kbd->dev,
             event->keycode, event->state, event->time_msec,
             event->update_state);
-    //TODO:
-    //ds_seat_keyboard_notify_key()
+
+    ds_keyboard = ds_input_device_get_keyboard(kbd->dev);
+
+    if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+        xkb_state = ds_keyboard_get_xkb_state(ds_keyboard);
+        if (xkb_state) {
+            nsyms = xkb_state_key_get_syms(xkb_state, event->keycode + 8,
+                    &syms);
+            for (int i = 0; i < nsyms; i++) {
+                handled = server_handle_keybinding(kbd->server, syms[i]);
+            }
+        }
+    }
+
+    if (!handled) {
+        ds_seat_keyboard_notify_key(kbd->server->seat, event->time_msec,
+                event->keycode, event->state);
+    }
 }
 
 static void
 server_add_keyboard(struct tinyds_server *server, struct ds_input_device *dev)
 {
     struct tinyds_keyboard *kbd;
+    struct xkb_context *context;
+    struct xkb_keymap *keymap;
 
     kbd = calloc(1, sizeof *kbd);
     assert(kbd);
@@ -713,12 +830,28 @@ server_add_keyboard(struct tinyds_server *server, struct ds_input_device *dev)
     kbd->dev = dev;
     kbd->server = server;
 
+    context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+    keymap = xkb_keymap_new_from_names(context, NULL,
+            XKB_KEYMAP_COMPILE_NO_FLAGS);
+
+    if (!keymap) {
+        ds_err("Failed to compile keymap");
+        xkb_context_unref(context);
+    }
+
+    ds_keyboard_set_keymap(ds_input_device_get_keyboard(dev), keymap);
+
+    xkb_keymap_unref(keymap);
+    xkb_context_unref(context);
+
     kbd->destroy.notify = keyboard_handle_device_destroy;
     ds_input_device_add_destroy_listener(dev, &kbd->destroy);
 
     kbd->key.notify = keyboard_handle_key;
     ds_keyboard_add_key_listener(ds_input_device_get_keyboard(dev), &kbd->key);
 
+    server->keyboard = kbd;
+
     ds_inf("Keyboard(%p) added", kbd);
 }
 
index e756ac1..21fb025 100644 (file)
@@ -25,7 +25,7 @@ ds_tdm_backend_create(struct wl_display *display)
     if (!tdm)
         return NULL;
 
-    ds_backend_init(&tdm->base, &tdm_backend_iface);
+    ds_backend_init(&tdm->base, display, &tdm_backend_iface);
 
     tdm->wl_display = display;
     tdm->clock = CLOCK_MONOTONIC;   // FIXME
diff --git a/src/libds-tizen/input-devicemgr/input-devicemgr.c b/src/libds-tizen/input-devicemgr/input-devicemgr.c
new file mode 100644 (file)
index 0000000..84700d7
--- /dev/null
@@ -0,0 +1,1063 @@
+#include <stdlib.h>
+#include <time.h> // gettimeofday()
+#include <libds/backend.h>
+#include <libds/log.h>
+#include <libds-tizen/input-devicemgr.h>
+#include <libds/interfaces/backend.h>
+#include <libds/interfaces/keyboard.h>
+#include <libds/seat.h>
+
+#include "util.h"
+#include "input-devicemgr.h"
+#include "src/libds/seat.h"
+
+#define TIZEN_INPUT_DEVICEMGR_VERSION 4
+#define TIZEN_PRIV_INPUT_GENERATOR "http://tizen.org/privilege/inputgenerator"
+#define TIZEN_PRIV_INPUT_BLOCK "http://tizen.org/privilege/internal/inputdevice.block"
+
+static const struct ds_keyboard_grab_interface devicemgr_keyboard_grab_iface;
+
+//listeners
+static void
+backend_handle_destroy(struct wl_listener *listener, void *data);
+static void
+backend_handle_input_device_add(struct wl_listener *listener, void *data);
+static void
+seat_handle_destroy(struct wl_listener *listener, void *data);
+
+//tizen_input_device_manager bind/unbind
+static void
+device_manager_handle_bind(struct wl_client *client, void *data,
+        uint32_t version, uint32_t id);
+static void
+device_manager_client_handle_resource_destroy(struct wl_resource *resource);
+
+//tizen_input_device_manager's handlers for requests
+static void
+device_manager_handle_block_events(struct wl_client *client,
+        struct wl_resource *resource, uint32_t serial,
+        uint32_t clas, uint32_t duration);
+static void
+device_manager_handle_unblock_events(struct wl_client *client,
+        struct wl_resource *resource, uint32_t serial);
+static void
+device_manager_handle_init_generator(struct wl_client *client,
+        struct wl_resource *resource, uint32_t clas);
+static void
+device_manager_handle_init_generator_with_name(struct wl_client *client,
+        struct wl_resource *resource, uint32_t clas, const char *name);
+static void
+device_manager_handle_deinit_generator(struct wl_client *client,
+        struct wl_resource *resource, uint32_t clas);
+static void
+device_manager_handle_generate_key(struct wl_client *client,
+        struct wl_resource *resource,
+        const char *keyname, uint32_t pressed);
+static void
+device_manager_handle_destroy(struct wl_client *client,
+        struct wl_resource *resource);
+
+//
+static void tz_devicemgr_destroy(struct ds_tizen_input_devicemgr *tz_devicemgr);
+static int
+tz_devicemgr_init_generator(struct ds_tizen_input_devicemgr *tz_devicemgr,
+        struct wl_resource *resource, const char *name);
+static int
+tz_devicemgr_deinit_generator(struct ds_tizen_input_devicemgr *tz_devicemgr,
+        struct wl_resource *resource);
+static bool
+tz_devicemgr_generate_key(struct ds_input_device *device, int keycode,
+        int pressed);
+static bool
+tz_devicemgr_pressed_keys_update(struct ds_tizen_input_devicemgr *tz_devicemgr,
+        int keycode, bool pressed);
+static void
+tz_devicemgr_pressed_keys_cleanup(struct ds_tizen_input_devicemgr *tz_devicemgr);
+static void
+tz_devicemgr_keymap_list_cleanup(struct ds_tizen_input_devicemgr *tz_devicemgr);
+static int
+tz_devicemgr_keyname_to_keycode(struct wl_list *list, const char *name);
+
+static bool
+tz_devicemgr_check_privilege(struct ds_tizen_input_devicemgr *tz_devicemgr,
+        struct wl_client *client, const char *rule);
+
+static void
+tz_devicemgr_grab_keyboard(struct ds_tizen_input_devicemgr *tz_devicemgr);
+static void
+tz_devicemgr_ungrab_keyboard(struct ds_tizen_input_devicemgr *tz_devicemgr);
+static void
+tz_devicemgr_ungrab_keyboard_check(struct ds_tizen_input_devicemgr *tz_devicemgr);
+static void
+tz_devicemgr_blocked_keys_cleanup(struct ds_tizen_input_devicemgr *tz_devicemgr);
+
+WL_EXPORT struct ds_tizen_input_devicemgr *
+ds_tizen_input_devicemgr_create(struct ds_backend *backend,
+        struct ds_seat *seat)
+{
+    struct ds_tizen_input_devicemgr *tz_devicemgr;
+
+    tz_devicemgr = calloc(1, sizeof *tz_devicemgr);
+    if (!tz_devicemgr) {
+        ds_err("Fail to allocate ds_tizen_input_devicemgr");
+        return NULL;
+    }
+
+    tz_devicemgr->backend = backend;
+    tz_devicemgr->backend_destroy.notify = backend_handle_destroy;
+    ds_backend_add_destroy_listener(backend, &tz_devicemgr->backend_destroy);
+
+    tz_devicemgr->seat = seat;
+    tz_devicemgr->seat_destroy.notify = seat_handle_destroy;
+    ds_seat_add_destroy_listener(seat, &tz_devicemgr->seat_destroy);
+
+    tz_devicemgr->new_input.notify = backend_handle_input_device_add;
+    ds_backend_add_new_input_listener(backend, &tz_devicemgr->new_input);
+
+    tz_devicemgr->global = wl_global_create(backend->display,
+            &tizen_input_device_manager_interface,
+            TIZEN_INPUT_DEVICEMGR_VERSION,
+            tz_devicemgr, device_manager_handle_bind);
+    if (!tz_devicemgr->global) {
+        goto err_global;
+    }
+
+    tz_devicemgr->devices.kbd = calloc(1,
+            sizeof(struct ds_tizen_input_devicemgr_device));
+    if (!tz_devicemgr->devices.kbd) {
+        goto err_kbd;
+    }
+
+    tz_devicemgr->grab = calloc(1, sizeof(struct ds_seat_keyboard_grab));
+    if (!tz_devicemgr->grab)
+    {
+        goto err_grab;
+    }
+
+    tz_devicemgr->grab->iface = &devicemgr_keyboard_grab_iface;
+    tz_devicemgr->grab->seat = tz_devicemgr->seat;
+    tz_devicemgr->grab->data = tz_devicemgr;
+
+    wl_signal_init(&tz_devicemgr->events.destroy);
+    wl_list_init(&tz_devicemgr->clients);
+    wl_list_init(&tz_devicemgr->pressed_keys);
+    wl_list_init(&tz_devicemgr->keymap_list);
+    wl_list_init(&tz_devicemgr->blocked_keys);
+
+    if (!tizen_security_init()) {
+        ds_inf("tizen_security_init() is failed. go on without security");
+    }
+
+    ds_inf("Global created: ds_tizen_input_devicemgr(%p) ", tz_devicemgr);
+    return tz_devicemgr;
+err_grab:
+    free(tz_devicemgr->devices.kbd);
+err_kbd:
+    wl_global_destroy(tz_devicemgr->global);
+err_global:
+    wl_list_remove(&tz_devicemgr->backend_destroy.link);
+    wl_list_remove(&tz_devicemgr->seat_destroy.link);
+    wl_list_remove(&tz_devicemgr->new_input.link);
+    free(tz_devicemgr);
+    return NULL;
+}
+
+WL_EXPORT void
+ds_tizen_input_devicemgr_add_destroy_listener(
+        struct ds_tizen_input_devicemgr *tz_devicemgr,
+        struct wl_listener *listener)
+{
+    wl_signal_add(&tz_devicemgr->events.destroy, listener);
+}
+
+WL_EXPORT bool
+ds_tizen_input_devicemgr_set_keymap_list(
+        struct ds_tizen_input_devicemgr *tz_devicemgr, struct wl_list *list)
+{
+    struct ds_tizen_input_devicemgr_keymap_data *data, *new_data;
+
+    if (!tz_devicemgr || !list) {
+        ds_err("Please insert correct data\n");
+        return false;
+    }
+
+    wl_list_for_each(data, list, link) {
+        new_data = calloc(1, sizeof *data);
+        if (!new_data) {
+            ds_err("Failed to alloc memory");
+            return false;
+        }
+        new_data->name = strdup(data->name);
+        new_data->keycode = data->keycode;
+        wl_list_insert(&tz_devicemgr->keymap_list, &new_data->link);
+    }
+    ds_inf("keymap set. length:%d",
+            wl_list_length(&tz_devicemgr->keymap_list));
+
+    return true;
+}
+
+static void
+tz_devicemgr_destroy(struct ds_tizen_input_devicemgr *tz_devicemgr)
+{
+    struct ds_tizen_input_devicemgr_client *client_data, *tmp;
+
+    tizen_security_finish();
+
+    tz_devicemgr_keymap_list_cleanup(tz_devicemgr);
+    tz_devicemgr_blocked_keys_cleanup(tz_devicemgr);
+    tz_devicemgr_ungrab_keyboard(tz_devicemgr);
+
+    wl_signal_emit(&tz_devicemgr->events.destroy, tz_devicemgr);
+    wl_list_remove(&tz_devicemgr->backend_destroy.link);
+    wl_list_remove(&tz_devicemgr->seat_destroy.link);
+    wl_list_remove(&tz_devicemgr->new_input.link);
+
+    wl_global_destroy(tz_devicemgr->global);
+
+    wl_list_for_each_safe(client_data, tmp, &tz_devicemgr->clients, link) {
+        wl_list_remove(&client_data->link);
+        tz_devicemgr_deinit_generator(tz_devicemgr, client_data->resource);
+
+        wl_resource_set_user_data(client_data->resource, NULL);
+        free(client_data);
+    }
+
+    free(tz_devicemgr->devices.kbd);
+    free(tz_devicemgr->grab);
+    free(tz_devicemgr);
+}
+
+static void
+backend_handle_destroy(struct wl_listener *listener, void *data)
+{
+    struct ds_tizen_input_devicemgr *tz_devicemgr;
+
+    tz_devicemgr = wl_container_of(listener, tz_devicemgr, backend_destroy);
+
+    ds_inf("Global destroy: ds_tizen_input_devicemgr(%p)", tz_devicemgr);
+
+    tz_devicemgr_destroy(tz_devicemgr);
+}
+
+static void
+seat_handle_destroy(struct wl_listener *listener, void *data)
+{
+    struct ds_tizen_input_devicemgr *tz_devicemgr;
+
+    tz_devicemgr = wl_container_of(listener, tz_devicemgr, backend_destroy);
+
+    wl_list_remove(&tz_devicemgr->seat_destroy.link);
+    wl_list_init(&tz_devicemgr->seat_destroy.link);
+    tz_devicemgr->seat = NULL;
+}
+
+static void
+backend_handle_input_device_add(struct wl_listener *listener, void *data)
+{
+    struct ds_input_device *dev = data;
+    struct ds_tizen_input_devicemgr *tz_devicemgr;
+    enum ds_input_device_type dev_type;
+
+    tz_devicemgr = wl_container_of(listener, tz_devicemgr, new_input);
+
+    dev_type = ds_input_device_get_type(dev);
+    if (dev_type == DS_INPUT_DEVICE_KEYBOARD) {
+        if (tz_devicemgr->devices.kbd->input_device) return;
+        ds_inf("devicemgr's kbd device is set");
+        tz_devicemgr->devices.kbd->input_device = dev;
+    }
+    else if (dev_type == DS_INPUT_DEVICE_POINTER) {
+        //TODO: assign input_device 'dev' to devices.ptr
+    }
+    else if (dev_type == DS_INPUT_DEVICE_TOUCH) {
+        //TODO: assign input_device 'dev' to devices.ptr
+    }
+}
+
+static const struct tizen_input_device_manager_interface _devicemgr_impl = {
+    .block_events = device_manager_handle_block_events,
+    .unblock_events = device_manager_handle_unblock_events,
+    .init_generator = device_manager_handle_init_generator,
+    .deinit_generator = device_manager_handle_deinit_generator,
+    .generate_key = device_manager_handle_generate_key,
+    .generate_pointer = NULL,
+    .generate_touch = NULL,
+    .pointer_warp = NULL,
+    .init_generator_with_name =
+            device_manager_handle_init_generator_with_name, // v2
+    .destroy = device_manager_handle_destroy, // v3
+    .generate_axis = NULL, // v3
+    .set_touch_count = NULL, // v4
+};
+
+static void
+device_manager_client_handle_resource_destroy(struct wl_resource *resource)
+{
+    struct ds_tizen_input_devicemgr *tz_devicemgr;
+    struct ds_tizen_input_devicemgr_client *client_data, *tmp;
+
+    tz_devicemgr = wl_resource_get_user_data(resource);
+
+    tz_devicemgr_deinit_generator(tz_devicemgr, resource);
+
+    if (resource == tz_devicemgr->block_resource) {
+        tz_devicemgr_ungrab_keyboard_check(tz_devicemgr);
+        if (tz_devicemgr->timer) {
+            wl_event_source_remove(tz_devicemgr->timer);
+            tz_devicemgr->timer = NULL;
+        }
+    }
+
+    wl_list_for_each_safe(client_data, tmp, &tz_devicemgr->clients, link) {
+        if (client_data->resource == resource) {
+            wl_list_remove(&client_data->link);
+            free(client_data);
+        }
+    }
+}
+
+static void
+device_manager_handle_bind(struct wl_client *client, void *data,
+        uint32_t version, uint32_t id)
+{
+    struct ds_tizen_input_devicemgr *tz_devicemgr = data;
+    struct ds_tizen_input_devicemgr_client *client_data;
+
+    client_data = calloc(1, sizeof *client_data);
+    if (!client_data) {
+        ds_err("Failed to allocate memory !\n");
+        wl_client_post_no_memory(client);
+        return;
+    }
+
+    client_data->resource = wl_resource_create(client,
+            &tizen_input_device_manager_interface, MIN(version,4), id);
+    if (!client_data->resource) {
+        ds_err("Failed to create resource! (ver. :%d, id:%d)", version, id);
+        free(client_data);
+        wl_client_post_no_memory(client);
+        return;
+    }
+
+    client_data->init = false;
+    wl_list_init(&client_data->link);
+    wl_list_insert(&tz_devicemgr->clients, &client_data->link);
+
+    wl_resource_set_implementation(client_data->resource, &_devicemgr_impl,
+            tz_devicemgr, device_manager_client_handle_resource_destroy);
+}
+
+static void
+device_manager_handle_init_generator(struct wl_client *client,
+        struct wl_resource *resource, uint32_t clas)
+{
+    struct ds_tizen_input_devicemgr *tz_devicemgr;
+    int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_SYSTEM_RESOURCES;
+
+    tz_devicemgr = wl_resource_get_user_data(resource);
+
+    if (!tz_devicemgr_check_privilege(tz_devicemgr, client,
+            TIZEN_PRIV_INPUT_GENERATOR)) {
+        ds_err("No permission to input generate");
+        ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_PERMISSION;
+        goto finish;
+    }
+
+    if (clas != TIZEN_INPUT_DEVICE_MANAGER_CLAS_KEYBOARD) {
+        ds_err("only support keyboard device. (requested: 0x%x)\n", clas);
+        ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_INVALID_PARAMETER;
+        goto finish;
+    }
+
+    ret = tz_devicemgr_init_generator(tz_devicemgr, resource,
+            "Input Generator");
+    if (ret != TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) {
+        ds_err("Failed to init input generator\n");
+        goto finish;
+    }
+
+finish:
+    tizen_input_device_manager_send_error(resource, ret);
+}
+
+static void
+device_manager_handle_init_generator_with_name(struct wl_client *client,
+        struct wl_resource *resource, uint32_t clas, const char *name)
+{
+    struct ds_tizen_input_devicemgr *tz_devicemgr;
+    int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_SYSTEM_RESOURCES;
+
+    tz_devicemgr = wl_resource_get_user_data(resource);
+
+    if (!name) {
+        ds_err("no name for device");
+        ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_INVALID_PARAMETER;
+        goto finish;
+    }
+
+    if (!tz_devicemgr_check_privilege(tz_devicemgr, client,
+            TIZEN_PRIV_INPUT_GENERATOR)) {
+        ds_err("No permission to input generate");
+        ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_PERMISSION;
+        goto finish;
+    }
+
+    if (clas != TIZEN_INPUT_DEVICE_MANAGER_CLAS_KEYBOARD) {
+        ds_err("only support keyboard device. (requested: 0x%x)\n", clas);
+        ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_INVALID_PARAMETER;
+        goto finish;
+    }
+
+    ret = tz_devicemgr_init_generator(tz_devicemgr, resource,
+            name);
+    if (ret != TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) {
+        ds_err("Failed to init input generator\n");
+        goto finish;
+    }
+
+finish:
+    tizen_input_device_manager_send_error(resource, ret);
+}
+
+static void
+device_manager_handle_deinit_generator(struct wl_client *client,
+        struct wl_resource *resource, uint32_t clas)
+{
+    struct ds_tizen_input_devicemgr *tz_devicemgr;
+    int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_SYSTEM_RESOURCES;
+
+    tz_devicemgr = wl_resource_get_user_data(resource);
+
+    if (!tz_devicemgr_check_privilege(tz_devicemgr, client,
+            TIZEN_PRIV_INPUT_GENERATOR)) {
+        ds_err("No permission to input generate");
+        ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_PERMISSION;
+        goto finish;
+    }
+
+    if (clas != TIZEN_INPUT_DEVICE_MANAGER_CLAS_KEYBOARD) {
+        ds_err("only support keyboard device. (requested: 0x%x)\n", clas);
+        ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_INVALID_PARAMETER;
+        goto finish;
+    }
+
+    ret = tz_devicemgr_deinit_generator(tz_devicemgr, resource);
+    if (ret != TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE) {
+        ds_err("Failed to deinit input generator\n");
+        goto finish;
+    }
+
+finish:
+    tizen_input_device_manager_send_error(resource, ret);
+}
+
+struct keycode_map{
+    xkb_keysym_t keysym;
+    xkb_keycode_t keycode;
+};
+
+static void
+find_keycode(struct xkb_keymap *keymap, xkb_keycode_t key, void *data)
+{
+    struct keycode_map *found_keycodes = (struct keycode_map *)data;
+    xkb_keysym_t keysym = found_keycodes->keysym;
+    int nsyms = 0;
+    const xkb_keysym_t *syms_out = NULL;
+
+    if (found_keycodes->keycode) return;
+
+    nsyms = xkb_keymap_key_get_syms_by_level(keymap, key, 0, 0, &syms_out);
+    if (nsyms && syms_out) {
+        if (*syms_out == keysym) {
+            found_keycodes->keycode = key;
+        }
+    }
+}
+
+static void
+tz_devicemgr_xkb_keycode_from_keysym(struct xkb_keymap *keymap,
+        xkb_keysym_t keysym, xkb_keycode_t *keycode)
+{
+    struct keycode_map found_keycodes = {0,};
+    found_keycodes.keysym = keysym;
+    xkb_keymap_key_for_each(keymap, find_keycode, &found_keycodes);
+
+    *keycode = found_keycodes.keycode;
+}
+
+static int
+tz_devicemgr_xkb_keyname_to_keycode(struct xkb_keymap *keymap,
+        const char *name)
+{
+    xkb_keysym_t keysym = 0x0;
+    xkb_keycode_t keycode = 0;
+
+    if (!strncmp(name, "Keycode-", sizeof("Keycode-")-1)) {
+        keycode = atoi(name + 8);
+    } else {
+        keysym = xkb_keysym_from_name(name, XKB_KEYSYM_NO_FLAGS);
+        tz_devicemgr_xkb_keycode_from_keysym(keymap, keysym, &keycode);
+    }
+
+    return keycode;
+}
+
+static void
+device_manager_handle_generate_key(struct wl_client *client,
+        struct wl_resource *resource, const char *keyname, uint32_t pressed)
+{
+    struct ds_tizen_input_devicemgr *tz_devicemgr;
+    int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_SYSTEM_RESOURCES;
+    int keycode = 0;
+    bool res;
+    struct ds_keyboard *kbd;
+
+    tz_devicemgr = wl_resource_get_user_data(resource);
+
+    if (!tz_devicemgr->devices.kbd ||
+        !tz_devicemgr->devices.kbd->input_device) {
+        ds_err("Keyboard device is not initialized\n");
+        goto finish;
+    }
+
+    if (!tz_devicemgr_check_privilege(tz_devicemgr, client,
+            TIZEN_PRIV_INPUT_GENERATOR)) {
+        ds_err("No permission to input generate");
+        ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_PERMISSION;
+        goto finish;
+    }
+
+    // keyname to keycode using xkb_info
+    kbd = ds_input_device_get_keyboard(
+            tz_devicemgr->devices.kbd->input_device);
+    if (kbd->keymap) {
+        keycode = tz_devicemgr_xkb_keyname_to_keycode(kbd->keymap, keyname);
+    }
+
+    if (keycode <= 0) {
+        keycode = tz_devicemgr_keyname_to_keycode(&tz_devicemgr->keymap_list,
+                keyname);
+    }
+    if (keycode <= 0)
+        goto finish;
+
+    res = tz_devicemgr_generate_key(tz_devicemgr->devices.kbd->input_device,
+            keycode, pressed);
+    if (!res) {
+        ds_err("Generating key is failed. key: %s, pressed: %d",
+                keyname, pressed);
+        goto finish;
+    }
+    res = tz_devicemgr_pressed_keys_update(tz_devicemgr, keycode, pressed);
+    if (!res) {
+        ds_err("Updating pressed keys is failed. key: %s, pressed: %d",
+                keyname, pressed);
+        goto finish;
+    }
+    ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE;
+
+finish:
+    tizen_input_device_manager_send_error(resource, ret);
+}
+
+static void
+device_manager_handle_destroy(struct wl_client *client,
+        struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static bool
+tz_devicemgr_check_privilege(struct ds_tizen_input_devicemgr *tz_devicemgr,
+        struct wl_client *client, const char *rule)
+{
+    pid_t pid = 0;
+    uid_t uid = 0;
+    gid_t gid = 0;
+
+    if (!client) return false;
+
+    wl_client_get_credentials(client, &pid, &uid, &gid);
+
+    return tizen_security_check_privilege(pid, uid, rule);
+}
+
+static const struct ds_input_device_interface input_device_iface =
+{
+    .destroy = NULL,
+};
+
+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 int
+tz_devicemgr_init_generator(struct ds_tizen_input_devicemgr *tz_devicemgr,
+        struct wl_resource *resource, const char *name)
+{
+    int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_SYSTEM_RESOURCES;
+    struct ds_tizen_input_devicemgr_client *client_data;
+    struct ds_tizen_input_devicemgr_device *kbd;
+
+    ds_inf("Init generator. name:%s", name);
+
+    kbd = tz_devicemgr->devices.kbd;
+    if (strlen(kbd->name) > 0) {
+        ds_inf("devices.kbd already has name. name:%s", kbd->name);
+        return TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE;
+    }
+
+    if (kbd->input_device) {
+        ds_inf("devices.kbd is already set. name:%s",
+                ds_input_device_get_name(kbd->input_device));
+        return TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE;
+    }
+
+    //input_device create
+    kbd->input_device = calloc(1, sizeof(struct ds_input_device));
+    if(!kbd->input_device) {
+        ds_err("Failed to create input device !\n");
+        return ret;
+    }
+
+    ds_input_device_init(kbd->input_device, DS_INPUT_DEVICE_KEYBOARD,
+            &input_device_iface, name, -1, -1);
+    kbd->input_device->keyboard = create_ds_keyboard();
+
+    wl_signal_emit(&tz_devicemgr->backend->events.new_input,
+            kbd->input_device);
+
+    kbd->created = true;
+    strncpy(kbd->name, name, UINPUT_MAX_NAME_SIZE);
+
+    wl_list_for_each(client_data, &tz_devicemgr->clients, link) {
+        if (client_data->resource == resource) {
+            if (client_data->init == false) {
+                client_data->init = true;
+                tz_devicemgr->ref++;
+            }
+            break;
+        }
+    }
+
+    ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE;
+
+    return ret;
+}
+
+static int
+tz_devicemgr_keyname_to_keycode(struct wl_list *list, const char *name)
+{
+    struct ds_tizen_input_devicemgr_keymap_data *data;
+
+    if (!wl_list_empty(list)) {
+        wl_list_for_each(data, list, link) {
+            if (!strcmp(data->name, name)) {
+                return data->keycode;
+            }
+        }
+    }
+
+    return 0;
+}
+
+static bool
+tz_devicemgr_generate_key(struct ds_input_device *device, int keycode,
+        int pressed)
+{
+    struct ds_event_keyboard_key ds_event;
+    struct timeval time;
+    unsigned int timestamp;
+    struct ds_keyboard *kbd;
+
+    kbd = ds_input_device_get_keyboard(device);
+    if (!kbd) {
+        ds_err("No ds_keyboard to notify event");
+        return false;
+    }
+
+    gettimeofday(&time, NULL);
+    timestamp = time.tv_sec * 1000 + time.tv_usec / 1000;
+
+    ds_event.time_msec = timestamp;
+    ds_event.keycode = keycode - 8;
+    if (pressed)
+        ds_event.state = WL_KEYBOARD_KEY_STATE_PRESSED;
+    else
+        ds_event.state = WL_KEYBOARD_KEY_STATE_RELEASED;
+
+    ds_inf("Generate key. kbd:%p, key:%d, state:%s", kbd, ds_event.keycode,
+            (ds_event.state == WL_KEYBOARD_KEY_STATE_PRESSED) ?
+            "PRESSED" : "RELEASED");
+
+    ds_keyboard_notify_key(kbd, &ds_event);
+
+    return true;
+}
+
+static bool
+tz_devicemgr_pressed_keys_update(struct ds_tizen_input_devicemgr *tz_devicemgr,
+        int keycode, bool pressed)
+{
+    struct ds_tizen_input_devicemgr_key_info *key, *tmp;
+
+    if (pressed) {
+        key = calloc(1, sizeof(*key));
+        if (!key) {
+            ds_err("Failed to alloc keydata memory.\n");
+            return false;
+        }
+        key->keycode = keycode;
+        wl_list_init(&key->link);
+        wl_list_insert(&tz_devicemgr->pressed_keys, &key->link);
+    }
+    else {
+        wl_list_for_each_safe(key, tmp, &tz_devicemgr->pressed_keys, link) {
+            if (key->keycode == keycode) {
+                wl_list_remove(&key->link);
+                free(key);
+                break;
+            }
+        }
+    }
+
+    ds_inf("Update pressed keys. length: %d, keycode:%d, pressed:%d",
+            wl_list_length(&tz_devicemgr->pressed_keys), keycode, pressed);
+
+    return true;
+}
+
+static void
+tz_devicemgr_pressed_keys_cleanup(struct ds_tizen_input_devicemgr *tz_devicemgr)
+{
+    struct ds_tizen_input_devicemgr_key_info *keydata, *tmp;
+
+    ds_inf("Clean up the pressed_keys. length: %d",
+            wl_list_length(&tz_devicemgr->pressed_keys));
+
+    wl_list_for_each_safe(keydata, tmp, &tz_devicemgr->pressed_keys, link) {
+        if (tz_devicemgr->devices.kbd)
+            tz_devicemgr_generate_key(tz_devicemgr->devices.kbd->input_device,
+                    keydata->keycode, false);
+        wl_list_remove(&keydata->link);
+        free(keydata);
+    }
+}
+
+static void
+tz_devicemgr_keymap_list_cleanup(struct ds_tizen_input_devicemgr *tz_devicemgr)
+{
+    struct ds_tizen_input_devicemgr_keymap_data *keymap, *tmp;
+
+    ds_inf("Clean up the keymap_list. length: %d",
+            wl_list_length(&tz_devicemgr->keymap_list));
+
+    wl_list_for_each_safe(keymap, tmp, &tz_devicemgr->keymap_list, link) {
+        free(keymap->name);
+        wl_list_remove(&keymap->link);
+        free(keymap);
+    }
+}
+
+static void
+tz_devicemgr_keyboard_close(struct ds_tizen_input_devicemgr *tz_devicemgr)
+{
+    if (!tz_devicemgr->devices.kbd->input_device) return;
+    ds_input_device_destroy(tz_devicemgr->devices.kbd->input_device);
+    tz_devicemgr->devices.kbd->input_device = NULL;
+    tz_devicemgr->devices.kbd->created = false;
+}
+
+static int
+tz_devicemgr_deinit_generator(struct ds_tizen_input_devicemgr *tz_devicemgr,
+        struct wl_resource *resource)
+{
+    int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE;
+    struct ds_tizen_input_devicemgr_client *client_data;
+
+    ds_inf("Deinit generator.");
+    wl_list_for_each(client_data, &tz_devicemgr->clients, link) {
+        if (client_data->resource == resource) {
+            if (client_data->init == true) {
+                client_data->init = false;
+                tz_devicemgr->ref--;
+                if (tz_devicemgr->ref < 0) tz_devicemgr->ref = 0;
+                break;
+            } else {
+                return ret;
+            }
+        }
+    }
+
+    if (tz_devicemgr->ref <= 0) {
+        tz_devicemgr_pressed_keys_cleanup(tz_devicemgr);
+
+        if (!tz_devicemgr->devices.kbd)
+            return TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE;
+
+        if (tz_devicemgr->devices.kbd->created)
+            tz_devicemgr_keyboard_close(tz_devicemgr);
+        memset(tz_devicemgr->devices.kbd->name, 0, UINPUT_MAX_NAME_SIZE);
+    }
+
+    return ret;
+}
+
+static void
+devicemgr_keyboard_grab_iface_enter(struct ds_seat_keyboard_grab *grab,
+            struct ds_surface *surface, uint32_t keycodes[],
+            size_t num_keycodes, struct ds_keyboard_modifiers *modifiers)
+{
+    ds_inf("devicemgr. keyboard_grab_iface_enter");
+}
+
+static void
+devicemgr_keyboard_grab_iface_clear_focus(struct ds_seat_keyboard_grab *grab)
+{
+    ds_inf("devicemgr. keyboard_grab_iface_clear_focus");
+}
+
+static void
+tz_devicemgr_blocked_keys_cleanup(struct ds_tizen_input_devicemgr *tz_devicemgr)
+{
+    struct ds_tizen_input_devicemgr_key_info *keydata, *tmp;
+
+    ds_inf("Clean up the blocked keys. length: %d",
+            wl_list_length(&tz_devicemgr->blocked_keys));
+
+    wl_list_for_each_safe(keydata, tmp, &tz_devicemgr->blocked_keys, link) {
+        wl_list_remove(&keydata->link);
+        free(keydata);
+    }
+}
+
+static void
+devicemgr_keyboard_grab_iface_key(struct ds_seat_keyboard_grab *grab,
+        uint32_t time_msec, uint32_t key, uint32_t state)
+{
+    struct ds_tizen_input_devicemgr *devicemgr = grab->data;
+    struct ds_tizen_input_devicemgr_key_info *keydata, *tmp;
+    bool key_blocked = false;
+
+    ds_inf("devicemgr. keyboard_grab_iface_key");
+
+    if (!devicemgr->block_resource) {
+        if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+            goto finish;
+        }
+        else {
+            wl_list_for_each_safe(keydata, tmp, &devicemgr->blocked_keys, link) {
+                if (keydata->keycode == (int)key) {
+                    wl_list_remove(&keydata->link);
+                    free(keydata);
+                    key_blocked = true;
+                    break;
+                }
+            }
+            if (wl_list_empty(&devicemgr->blocked_keys)) {
+                tz_devicemgr_ungrab_keyboard(devicemgr);
+            }
+            if (key_blocked) {
+                goto finish;
+            }
+        }
+    }
+
+    if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+        keydata = calloc(1, sizeof (*keydata));
+        if (!keydata)
+            goto finish;
+        keydata->keycode = key;
+        wl_list_init(&keydata->link);
+        wl_list_insert(&devicemgr->blocked_keys, &keydata->link);
+        key_blocked = true;
+    }
+    else {
+        if (wl_list_empty(&devicemgr->blocked_keys))
+            goto finish;
+        wl_list_for_each_safe(keydata, tmp, &devicemgr->blocked_keys, link) {
+            if (keydata->keycode == (int)key) {
+                wl_list_remove(&keydata->link);
+                free(keydata);
+                key_blocked = true;
+            }
+        }
+    }
+
+finish:
+    if (!key_blocked)
+        ds_inf("block key event: (%d %s)\n", key, (state ? "press" : "release"));
+}
+
+static void
+devicemgr_modifiers_grab_iface_key(struct ds_seat_keyboard_grab *grab,
+        struct ds_keyboard_modifiers *modifiers)
+{
+    ds_inf("devicemgr. modifiers_grab_iface_key");
+}
+
+static void
+devicemgr_cancel_grab_iface_key(struct ds_seat_keyboard_grab *grab)
+{
+    ds_inf("devicemgr. cancel_grab_iface_key");
+}
+
+static const struct ds_keyboard_grab_interface devicemgr_keyboard_grab_iface = {
+    .enter = devicemgr_keyboard_grab_iface_enter,
+    .clear_focus = devicemgr_keyboard_grab_iface_clear_focus,
+    .key = devicemgr_keyboard_grab_iface_key,
+    .modifiers = devicemgr_modifiers_grab_iface_key,
+    .cancel = devicemgr_cancel_grab_iface_key,
+};
+
+static void
+tz_devicemgr_grab_keyboard(struct ds_tizen_input_devicemgr *tz_devicemgr)
+{
+    ds_seat_keyboard_start_grab(tz_devicemgr->seat, tz_devicemgr->grab);
+}
+
+static void
+tz_devicemgr_ungrab_keyboard(struct ds_tizen_input_devicemgr *tz_devicemgr)
+{
+       ds_seat_keyboard_end_grab(tz_devicemgr->seat);
+}
+
+static void
+tz_devicemgr_ungrab_keyboard_check(struct ds_tizen_input_devicemgr *tz_devicemgr)
+{
+    if (wl_list_empty(&tz_devicemgr->blocked_keys))
+        tz_devicemgr_ungrab_keyboard(tz_devicemgr);
+
+    tz_devicemgr->block_resource = NULL;
+}
+
+static bool
+devicemgr_add_timer(struct ds_tizen_input_devicemgr *tz_devicemgr,
+        wl_event_loop_timer_func_t func, int time)
+{
+    struct wl_event_loop *event_loop;
+
+    event_loop = wl_display_get_event_loop(tz_devicemgr->backend->display);
+    if (!event_loop) {
+        ds_err("Failed to get event_loop from display: %p",
+                tz_devicemgr->backend->display);
+        return false;
+    }
+
+    tz_devicemgr->timer = wl_event_loop_add_timer(event_loop, func,
+            tz_devicemgr);
+    if (!tz_devicemgr->timer) {
+        ds_err("Failed to timer");
+        return false;
+    }
+    wl_event_source_timer_update(tz_devicemgr->timer, time);
+
+    return true;
+}
+
+static int
+devicemgr_block_timer(void *data)
+{
+       struct ds_tizen_input_devicemgr *devicemgr = data;
+
+       tizen_input_device_manager_send_block_expired(devicemgr->block_resource);
+
+       tz_devicemgr_ungrab_keyboard_check(devicemgr);
+
+       wl_event_source_remove(devicemgr->timer);
+       devicemgr->timer = NULL;
+
+       return 1;
+}
+
+static void
+device_manager_handle_block_events(struct wl_client *client,
+        struct wl_resource *resource, uint32_t serial, uint32_t clas,
+        uint32_t duration)
+{
+    struct ds_tizen_input_devicemgr *tz_devicemgr;
+    int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_SYSTEM_RESOURCES;
+    bool res;
+
+    tz_devicemgr = wl_resource_get_user_data(resource);
+
+    if (!tz_devicemgr_check_privilege(tz_devicemgr, client,
+            TIZEN_PRIV_INPUT_BLOCK)) {
+        ds_err("No permission to input generate");
+        ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_PERMISSION;
+        goto finish;
+    }
+
+    if (clas != TIZEN_INPUT_DEVICE_MANAGER_CLAS_KEYBOARD) {
+        ds_err("only support keyboard device. (requested: 0x%x)\n", clas);
+        ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_INVALID_PARAMETER;
+        goto finish;
+    }
+
+    if(tz_devicemgr->block_resource) {
+        ds_err("currently the input system is already blocked\n");
+        ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_INVALID_PARAMETER;
+        goto finish;
+    }
+
+    res = devicemgr_add_timer(tz_devicemgr, devicemgr_block_timer, duration);
+    if (!res) {
+        ds_err("Failed to add a timer\n");
+        goto finish;
+    }
+
+    tz_devicemgr_grab_keyboard(tz_devicemgr);
+    tz_devicemgr->block_resource = resource;
+    ds_inf("Block events. clas: %d, duration:%d", clas, duration);
+    ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE;
+
+finish:
+    tizen_input_device_manager_send_error(resource, ret);
+}
+
+static void
+device_manager_handle_unblock_events(struct wl_client *client,
+        struct wl_resource *resource, uint32_t serial)
+{
+    struct ds_tizen_input_devicemgr *tz_devicemgr;
+    int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_SYSTEM_RESOURCES;
+
+    tz_devicemgr = wl_resource_get_user_data(resource);
+
+    if (!tz_devicemgr_check_privilege(tz_devicemgr, client,
+            TIZEN_PRIV_INPUT_BLOCK)) {
+        ds_err("No permission to input generate");
+        ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_PERMISSION;
+        goto finish;
+    }
+
+    if (tz_devicemgr->block_resource != resource) {
+        ds_err("currently the input system is blocked by another resource");
+        ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_INVALID_PARAMETER;
+        goto finish;
+    }
+
+    tz_devicemgr_ungrab_keyboard_check(tz_devicemgr);
+    tz_devicemgr->block_resource = NULL;
+    ds_inf("Unblock events.");
+    ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE;
+
+    if (tz_devicemgr->timer) {
+               wl_event_source_remove(tz_devicemgr->timer);
+               tz_devicemgr->timer = NULL;
+       }
+
+finish:
+    tizen_input_device_manager_send_error(resource, ret);
+}
\ No newline at end of file
diff --git a/src/libds-tizen/input-devicemgr/input-devicemgr.h b/src/libds-tizen/input-devicemgr/input-devicemgr.h
new file mode 100644 (file)
index 0000000..8418b16
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef DS_TIZEN_DEVICEMGR_H
+#define DS_TIZEN_DEVICEMGR_H
+
+#include <stdbool.h>
+#include <linux/uinput.h>
+#include <wayland-server.h>
+#include <tizen-extension-server-protocol.h>
+#include "libds/interfaces/input_device.h"
+#include <libds/seat.h>
+
+struct ds_tizen_input_devicemgr_device {
+    char name[UINPUT_MAX_NAME_SIZE + 1];
+    struct ds_input_device *input_device;
+    bool created;
+};
+
+struct ds_tizen_input_devicemgr {
+    struct wl_global *global;
+    struct wl_display *display;
+    struct ds_backend *backend;
+    struct ds_seat *seat;
+
+    struct {
+        struct wl_signal destroy;
+    } events;
+
+    struct wl_listener new_input;
+    struct wl_listener backend_destroy;
+    struct wl_listener seat_destroy;
+    struct {
+        struct ds_tizen_input_devicemgr_device *kbd;
+        struct ds_tizen_input_devicemgr_device *ptr;
+        struct ds_tizen_input_devicemgr_device *touch;
+    } devices;
+
+    struct wl_list clients;
+    int ref;
+
+    struct wl_list pressed_keys;
+    struct wl_list keymap_list;
+
+    struct wl_list blocked_keys;
+    struct wl_resource *block_resource;
+    struct wl_event_source *timer;
+    struct ds_seat_keyboard_grab *grab;
+};
+
+struct ds_tizen_input_devicemgr_client {
+    struct wl_resource *resource;
+    bool init;
+    struct wl_list link; // ds_tizen_input_devicemgr::clients
+};
+
+struct ds_tizen_input_devicemgr_key_info {
+    int keycode;
+    struct wl_list link; // ds_tizen_input_devicemgr::pressed_keys;
+};
+
+#endif
diff --git a/src/libds-tizen/input-devicemgr/meson.build b/src/libds-tizen/input-devicemgr/meson.build
new file mode 100644 (file)
index 0000000..30924a4
--- /dev/null
@@ -0,0 +1,30 @@
+libds_tizen_input_devicemgr_files = [
+  'input-devicemgr.c',
+]
+
+libds_tizen_input_devicemgr_deps = [
+  dep_libds,
+  dep_libds_tizen,
+  dependency('tizen-extension-server', required: true),
+]
+
+lib_libds_tizen_input_devicemgr = shared_library('ds-tizen-input-devicemgr', libds_tizen_input_devicemgr_files,
+  dependencies: libds_tizen_input_devicemgr_deps,
+  include_directories: [ common_inc, include_directories('.'), include_directories('..') ],
+  version: meson.project_version(),
+  install: true
+)
+
+dep_libds_tizen_input_devicemgr = declare_dependency(
+  link_with: lib_libds_tizen_input_devicemgr,
+  dependencies: libds_tizen_input_devicemgr_deps,
+  include_directories: [ common_inc, include_directories('.') ],
+)
+
+pkgconfig = import('pkgconfig')
+pkgconfig.generate(lib_libds_tizen_input_devicemgr,
+  version: meson.project_version(),
+  filebase: 'libds-tizen-input-devicemgr',
+  name: 'libds-tizen-input-devicemgr',
+  description: 'tizen input devicemgr extension of libds-tizen for tizen platform',
+)
index 6779a72..8c7673b 100644 (file)
@@ -38,4 +38,5 @@ pkgconfig.generate(lib_libds_tizen,
 )
 
 subdir('keyrouter')
+subdir('input-devicemgr')
 
index 641374a..dee97ca 100644 (file)
@@ -50,9 +50,11 @@ ds_backend_add_new_input_listener(struct ds_backend *backend,
 
 void
 ds_backend_init(struct ds_backend *backend,
+        struct wl_display *display,
         const struct ds_backend_interface *iface)
 {
     backend->iface = iface;
+    backend->display = display;
     wl_signal_init(&backend->events.destroy);
     wl_signal_init(&backend->events.new_output);
     wl_signal_init(&backend->events.new_input);
index b6dc4f1..b7e1bc4 100644 (file)
@@ -25,7 +25,7 @@ ds_libinput_backend_create(struct wl_display *display)
         return NULL;
     }
 
-    ds_backend_init(&libinput_backend->base, &libinput_backend_interface);
+    ds_backend_init(&libinput_backend->base, display, &libinput_backend_interface);
 
     libinput_backend->display = display;
     wl_list_init(&libinput_backend->devices);
@@ -52,9 +52,7 @@ 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
index 2457a06..b6e943f 100644 (file)
@@ -25,6 +25,8 @@ input_device_iface_destroy(struct ds_input_device *ds_dev)
 
     dev = get_libinput_input_device_from_input_device(ds_dev);
 
+    libinput_device_unref(dev->handle);
+
     free(dev);
 }
 
index 5719e09..fd663f4 100644 (file)
@@ -33,7 +33,7 @@ ds_wl_backend_create(struct wl_display *display, const char *server_name)
         return NULL;
     }
 
-    ds_backend_init(&wl_backend->base, &wl_backend_interface);
+    ds_backend_init(&wl_backend->base, display, &wl_backend_interface);
 
     wl_backend->display = display;
     wl_list_init(&wl_backend->buffers);
index ad18e71..534bced 100644 (file)
@@ -15,6 +15,12 @@ ds_input_device_get_type(struct ds_input_device *dev)
     return dev->type;
 }
 
+WL_EXPORT const char *
+ds_input_device_get_name(struct ds_input_device *dev)
+{
+    return dev->name;
+}
+
 WL_EXPORT struct ds_pointer *
 ds_input_device_get_pointer(struct ds_input_device *dev)
 {
@@ -81,6 +87,9 @@ ds_input_device_destroy(struct ds_input_device *dev)
             case DS_INPUT_DEVICE_KEYBOARD:
                 ds_keyboard_destroy(dev->keyboard);
                 break;
+            case DS_INPUT_DEVICE_TOUCH:
+                ds_touch_destroy(dev->touch);
+                break;
             default:
                 ds_err("Warning: leaking memory %p %p %d",
                         dev->_device, dev, dev->type);
index 381e2d6..8931a5c 100644 (file)
@@ -362,7 +362,7 @@ seat_client_send_keyboard_leave_raw(struct ds_seat_client *seat_client,
     struct wl_resource *resource;
     uint32_t serial;
 
-    serial = wl_display_next_serial(seat_client->seat->display);
+    serial = wl_display_next_serial(wl_client_get_display(seat_client->wl_client));
     wl_resource_for_each(resource, &seat_client->keyboards) {
         wl_keyboard_send_leave(resource, serial,
                 ds_surface_get_wl_resource(surface));