From 18ddf884cac248e9dd798363da50edf2e03e4bd4 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Wed, 11 May 2022 16:48:55 +0900 Subject: [PATCH] implement the libds-tizen-keyrouter libds-tizen-keyrouter supports the tizen_keyrouter extension. This is the first impelemtaion for it. It can be added the additional apis onward. Change-Id: I53e8df054d3534c0fa84f14273a61761332b1bf6 --- include/libds-tizen/keyrouter.h | 23 ++ meson_options.txt | 1 + packaging/libds.spec | 35 ++- src/libds-tizen/keyrouter/keyrouter.c | 430 +++++++++++++++++++++++++++++ src/libds-tizen/keyrouter/keyrouter.h | 108 ++++++++ src/libds-tizen/keyrouter/keyrouter_grab.c | 351 +++++++++++++++++++++++ src/libds-tizen/keyrouter/meson.build | 34 +++ src/libds-tizen/meson.build | 3 + 8 files changed, 983 insertions(+), 2 deletions(-) create mode 100644 include/libds-tizen/keyrouter.h create mode 100644 src/libds-tizen/keyrouter/keyrouter.c create mode 100644 src/libds-tizen/keyrouter/keyrouter.h create mode 100644 src/libds-tizen/keyrouter/keyrouter_grab.c create mode 100644 src/libds-tizen/keyrouter/meson.build diff --git a/include/libds-tizen/keyrouter.h b/include/libds-tizen/keyrouter.h new file mode 100644 index 0000000..a870003 --- /dev/null +++ b/include/libds-tizen/keyrouter.h @@ -0,0 +1,23 @@ +#ifndef LIBDS_TIZEN_KEYROUTER_H +#define LIBDS_TIZEN_KEYROUTER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ds_tizen_keyrouter; + +struct ds_tizen_keyrouter * +ds_tizen_keyrouter_create(struct wl_display *display); + +void +ds_tizen_keyrouter_add_destroy_listener(struct ds_tizen_keyrouter *keyrouter, + struct wl_listener *listener); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/meson_options.txt b/meson_options.txt index 6ef6c8e..1d6ff21 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1 +1,2 @@ option('tizen', type: 'boolean', value: false, description: 'Build Tizen features') +option('keylayout_dir', type: 'string', value: '', description: 'Directory where tizen key layout file is') \ No newline at end of file diff --git a/packaging/libds.spec b/packaging/libds.spec index efba8cb..bee3972 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -11,6 +11,7 @@ BuildRequires: meson BuildRequires: pkgconfig(wayland-server) BuildRequires: pkgconfig(wayland-client) BuildRequires: pkgconfig(wayland-protocols) +BuildRequires: pkgconfig(tizen-extension-server) BuildRequires: pkgconfig(pixman-1) BuildRequires: pkgconfig(libdrm) BuildRequires: pkgconfig(xkbcommon) @@ -37,6 +38,20 @@ Summary: Wayland Compositor development package on Tizen %description tizen-devel Wayland Compositor development library for Tizen platform +%package tizen-keyrouter +Summary: Wayland Compositor Library for keyrouter +Group: Development/Libraries + +%description tizen-keyrouter +Wayland Compositor Library for tizen keyrouter + +%package tizen-keyrouter-devel +Summary: Keyrouter Development package for Wayland Compositor Library +Group: Development/Libraries + +%description tizen-keyrouter-devel +Keyrouter Development package for Wayland Compositor Library + %prep %setup -q cp %{SOURCE1001} . @@ -47,7 +62,8 @@ meson setup \ --libdir %{_libdir} \ --bindir %{_bindir} \ builddir \ - -Dtizen=true + -Dtizen=true \ + -Dkeylayout_dir="%{TZ_SYS_RO_SHARE}/X11/xkb/tizen_key_layout.txt" ninja -C builddir all %install @@ -58,7 +74,8 @@ ninja -C builddir install %manifest %{name}.manifest %defattr(-,root,root,-) %license LICENSE -%{_libdir}/*.so.* +%{_libdir}/libds.so.* +%{_libdir}/libds-tizen.so.* %files devel %manifest %{name}.manifest @@ -81,3 +98,17 @@ ninja -C builddir install %{_bindir}/tdm-backend %{_bindir}/tinyds-tdm %{_bindir}/ds-simple-tbm + +%files tizen-keyrouter +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_libdir}/libds-tizen-keyrouter.so.* + +%files tizen-keyrouter-devel +%manifest %{name}.manifest +%defattr(-,root,root,-) +%license LICENSE +%{_includedir}/libds-tizen/keyrouter.h +%{_libdir}/pkgconfig/libds-tizen-keyrouter.pc +%{_libdir}/libds-tizen-keyrouter.so diff --git a/src/libds-tizen/keyrouter/keyrouter.c b/src/libds-tizen/keyrouter/keyrouter.c new file mode 100644 index 0000000..eaa831a --- /dev/null +++ b/src/libds-tizen/keyrouter/keyrouter.c @@ -0,0 +1,430 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "libds/log.h" +#include "libds-tizen/keyrouter.h" + +#include "util.h" +#include "keyrouter.h" + +static void +tizen_keyrouter_bind(struct wl_client *client, void *data, uint32_t version, + uint32_t id); +static bool +keyrouter_check_privilege(struct ds_tizen_keyrouter_client *keyrouter_client, + struct wl_client *client, uint32_t mode, uint32_t keycode); +static void +tizen_keyrouter_options_set(struct ds_tizen_keyrouter *keyrouter); + +static void +keyrouter_handle_display_destroy(struct wl_listener *listener, void *data) +{ + struct ds_tizen_keyrouter *keyrouter; + + keyrouter = wl_container_of(listener, keyrouter, display_destroy); + + ds_inf("Global destroy: ds_tizen_keyrouter(%p)", keyrouter); + + wl_signal_emit(&keyrouter->events.destroy, keyrouter); + + tizen_security_finish(); + + free(keyrouter->opts); + + wl_list_remove(&keyrouter->display_destroy.link); + + wl_global_destroy(keyrouter->global); + + tizen_keyrouter_grab_destroy(keyrouter->keyrouter_grab); + + free(keyrouter); +} + +WL_EXPORT struct ds_tizen_keyrouter * +ds_tizen_keyrouter_create(struct wl_display *display) +{ + struct ds_tizen_keyrouter *keyrouter; + + keyrouter = calloc(1, sizeof *keyrouter); + if (!keyrouter) { + return NULL; + } + + keyrouter->keyrouter_grab = tizen_keyrouter_grab_create(); + if (keyrouter->keyrouter_grab == NULL) { + ds_err("Failed to create keyrouter."); + free(keyrouter); + return NULL; + } + + keyrouter->global = wl_global_create(display, &tizen_keyrouter_interface, + 2, keyrouter, tizen_keyrouter_bind); + if (!keyrouter->global) { + tizen_keyrouter_grab_destroy(keyrouter->keyrouter_grab); + free(keyrouter); + return NULL; + } + + wl_list_init(&keyrouter->clients); + + wl_signal_init(&keyrouter->events.destroy); + + keyrouter->display_destroy.notify = keyrouter_handle_display_destroy; + wl_display_add_destroy_listener(display, &keyrouter->display_destroy); + + tizen_keyrouter_options_set(keyrouter); + + if (!tizen_security_init()) { + ds_inf("tizen_security_init() is not sucessful. keyrouter works without security."); + } + + ds_inf("Global created: ds_tizen_keyrouter(%p)", keyrouter); + + return keyrouter; +} + +WL_EXPORT void +ds_tizen_keyrouter_add_destroy_listener(struct ds_tizen_keyrouter *keyrouter, + struct wl_listener *listener) +{ + wl_signal_add(&keyrouter->events.destroy, listener); +} + +static void +keyrouter_handle_keygrab_set(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *surface, + uint32_t key, uint32_t mode) +{ + struct ds_tizen_keyrouter_client *keyrouter_client; + struct ds_tizen_keyrouter *keyrouter; + int res = TIZEN_KEYROUTER_ERROR_NONE; + bool ret; + + keyrouter_client = wl_resource_get_user_data(resource); + keyrouter = keyrouter_client->keyrouter; + + ret = keyrouter_check_privilege(keyrouter_client, client, mode, key); + if (ret == false) { + tizen_keyrouter_send_keygrab_notify(resource, surface, + key, mode, TIZEN_KEYROUTER_ERROR_NO_PERMISSION); + return; + } + + res = tizen_keyrouter_grab_grab_key(keyrouter->keyrouter_grab, + mode, key, (void *)client); + if (res == TIZEN_KEYROUTER_ERROR_NONE && keyrouter_client->grabbed != true) + keyrouter_client->grabbed = true; + + tizen_keyrouter_send_keygrab_notify(resource, surface, key, mode, res); +} + +static void +keyrouter_handle_keygrab_unset(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *surface, uint32_t key) +{ + struct ds_tizen_keyrouter_client *keyrouter_client; + struct ds_tizen_keyrouter *keyrouter; + int res = TIZEN_KEYROUTER_ERROR_NONE; + bool ret; + + keyrouter_client = wl_resource_get_user_data(resource); + keyrouter = keyrouter_client->keyrouter; + + /* ungrab TOP POSITION grab first, this grab mode is not check privilege */ + tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, + TIZEN_KEYROUTER_MODE_TOPMOST, key, (void *)client); + + ret = keyrouter_check_privilege(keyrouter_client, + client, TIZEN_KEYROUTER_MODE_NONE, key); + if (ret == false) { + tizen_keyrouter_send_keygrab_notify(resource, surface, key, + TIZEN_KEYROUTER_MODE_NONE, TIZEN_KEYROUTER_ERROR_NO_PERMISSION); + return; + } + + tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, + TIZEN_KEYROUTER_MODE_EXCLUSIVE, key, (void *)client); + tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, + TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE, key, (void *)client); + tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, + TIZEN_KEYROUTER_MODE_TOPMOST, key, (void *)client); + tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, + TIZEN_KEYROUTER_MODE_SHARED, key, (void *)client); + + tizen_keyrouter_send_keygrab_notify(resource, surface, key, TIZEN_KEYROUTER_MODE_NONE, res); +} + +static void +keyrouter_handle_get_keygrab_status(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *surface, uint32_t key) +{ + tizen_keyrouter_send_keygrab_notify(resource, surface, key, + TIZEN_KEYROUTER_MODE_NONE, TIZEN_KEYROUTER_ERROR_NO_PERMISSION); +} + +static int +keyrouter_get_array_length(const struct wl_array *array) +{ + int *data = NULL; + int count = 0; + + wl_array_for_each(data, array) { + count++; + } + + return count; +} + +static void +keyrouter_handle_keygrab_set_list(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *surface, struct wl_array *grab_list) +{ + struct ds_tizen_keyrouter_client *keyrouter_client; + struct ds_tizen_keyrouter *keyrouter; + struct wl_array *return_list; + struct ds_tizen_grab_data *grab_data = NULL; + int res = TIZEN_KEYROUTER_ERROR_NONE; + bool ret; + + keyrouter_client = wl_resource_get_user_data(resource); + keyrouter = keyrouter_client->keyrouter; + + if ((keyrouter_get_array_length(grab_list) % 3) != 0) { + ds_err("Invalid keycode and grab mode pair. Check arguments in a list."); + tizen_keyrouter_send_keygrab_notify_list(resource, surface, NULL); + return; + } + + wl_array_for_each(grab_data, grab_list) { + ret = keyrouter_check_privilege(keyrouter_client, client, grab_data->mode, grab_data->key); + if (ret == false) { + grab_data->err = TIZEN_KEYROUTER_ERROR_NO_PERMISSION; + } else { + res = tizen_keyrouter_grab_grab_key(keyrouter->keyrouter_grab, + grab_data->mode, grab_data->key, (void *)client); + if (res == TIZEN_KEYROUTER_ERROR_NONE && keyrouter_client->grabbed != true) + keyrouter_client->grabbed = true; + + grab_data->err = res; + } + } + + return_list = grab_list; + + tizen_keyrouter_send_keygrab_notify_list(resource, surface, return_list); +} + +static void +keyrouter_handle_keygrab_unset_list(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *surface, + struct wl_array *ungrab_list) +{ + struct ds_tizen_keyrouter_client *keyrouter_client; + struct ds_tizen_keyrouter *keyrouter; + struct wl_array *return_list = NULL; + struct ds_tizen_ungrab_data *ungrab_data = NULL; + bool ret; + + keyrouter_client = wl_resource_get_user_data(resource); + keyrouter = keyrouter_client->keyrouter; + + if ((keyrouter_get_array_length(ungrab_list) % 3) != 0) { + ds_err("Invalid keycode and grab mode pair. Check arguments in a list."); + tizen_keyrouter_send_keygrab_notify_list(resource, surface, NULL); + return; + } + + wl_array_for_each(ungrab_data, ungrab_list) { + tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, + TIZEN_KEYROUTER_MODE_TOPMOST, ungrab_data->key, (void *)client); + + ret = keyrouter_check_privilege(keyrouter_client, client, + TIZEN_KEYROUTER_MODE_TOPMOST, ungrab_data->key); + if (!ret) { + ungrab_data->err = TIZEN_KEYROUTER_ERROR_NO_PERMISSION; + } else { + tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, + TIZEN_KEYROUTER_MODE_EXCLUSIVE, ungrab_data->key, (void *)client); + + tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, + TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE, ungrab_data->key, (void *)client); + + tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, + TIZEN_KEYROUTER_MODE_TOPMOST, ungrab_data->key, (void *)client); + + tizen_keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab, + TIZEN_KEYROUTER_MODE_SHARED, ungrab_data->key, (void *)client); + + ungrab_data->err = TIZEN_KEYROUTER_ERROR_NONE; + } + } + + return_list = ungrab_list; + + tizen_keyrouter_send_keygrab_notify_list(resource, surface, return_list); +} + +static void +keyrouter_handle_get_keygrab_list(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *surface) +{ + tizen_keyrouter_send_getgrab_notify_list(resource, surface, NULL); +} + +static void +keyrouter_handle_set_register_none_key(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *surface, + uint32_t data) +{ + tizen_keyrouter_send_set_register_none_key_notify(resource, NULL, 0); +} + +static void +keyrouter_handle_get_keyregister_status(struct wl_client *client, + struct wl_resource *resource, uint32_t key) +{ + tizen_keyrouter_send_keyregister_notify(resource, (int)false); +} + +static void +keyrouter_handle_set_input_config(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *surface, + uint32_t config_mode, uint32_t value) +{ + tizen_keyrouter_send_set_input_config_notify(resource, (int)false); +} + +static void +keyrouter_handle_destory(struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static const struct tizen_keyrouter_interface tizen_keyrouter_impl = { + keyrouter_handle_keygrab_set, + keyrouter_handle_keygrab_unset, + keyrouter_handle_get_keygrab_status, + keyrouter_handle_keygrab_set_list, + keyrouter_handle_keygrab_unset_list, + keyrouter_handle_get_keygrab_list, + keyrouter_handle_set_register_none_key, + keyrouter_handle_get_keyregister_status, + keyrouter_handle_set_input_config, + keyrouter_handle_destory +}; + +static void +keyrouter_handle_resource_destory(struct wl_resource *resource) +{ + struct ds_tizen_keyrouter_client *keyrouter_client = wl_resource_get_user_data(resource); + + wl_list_remove(&keyrouter_client->link); + free(keyrouter_client); +} + +static void +tizen_keyrouter_bind(struct wl_client *client, void *data, uint32_t version, + uint32_t id) +{ + struct ds_tizen_keyrouter *keyrouter = data; + struct ds_tizen_keyrouter_client *keyrouter_client; + + keyrouter_client = calloc(1, sizeof *keyrouter_client); + if (keyrouter_client == NULL) { + wl_client_post_no_memory(client); + return; + } + + keyrouter_client->resource = + wl_resource_create(client, &tizen_keyrouter_interface, MIN(version, 2), id); + if (keyrouter_client->resource == NULL) { + ds_err("wl_resource_create() failed.(version :%d, id:%d)", version, id); + free(keyrouter_client); + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(keyrouter_client->resource, &tizen_keyrouter_impl, + keyrouter_client, keyrouter_handle_resource_destory); + + wl_list_insert(&keyrouter->clients, &keyrouter_client->link); +} + +static bool +keyrouter_check_privilege(struct ds_tizen_keyrouter_client *keyrouter_client, + struct wl_client *client, uint32_t mode, uint32_t keycode) +{ + struct ds_tizen_keyrouter *keyrouter = keyrouter_client->keyrouter; + + pid_t pid = 0; + uid_t uid = 0; + gid_t gid = 0; + + /* Top position grab is always allowed. This mode do not need privilege.*/ + if (mode == TIZEN_KEYROUTER_MODE_TOPMOST) + return true; + + // check no privilege option on the keycode + if (keyrouter->opts) { + if (keyrouter->opts[keycode].no_privilege) + return true; + } + + // grabbed client is already checked the privilege before. + if (keyrouter_client->grabbed) + return true; + + wl_client_get_credentials(client, &pid, &uid, &gid); + + return tizen_security_check_privilege(pid, uid, "http://tizen.org/privilege/keygrab"); +} + +static void +tizen_keyrouter_options_set(struct ds_tizen_keyrouter *keyrouter) +{ + FILE *file; + int keycode; + char *ret, *tmp, *buf_ptr, buf[1024] = {0,}; + + keyrouter->opts = calloc(KEYROUTER_MAX_KEYS, + sizeof(struct ds_tizen_keyrouter_key_options)); + if (!keyrouter->opts) { + return; + } + + file = fopen(KEYLAYOUT_DIR, "r"); + if (!file) { + ds_err("Failed to open key layout file(%s): (err msg: %m)\n", KEYLAYOUT_DIR); + free(keyrouter->opts); + keyrouter->opts = NULL; + return; + } + + while (!feof(file)) { + ret = fgets(buf, 1024, file); + if (!ret) continue; + + tmp = strtok_r(buf, " ", &buf_ptr); + tmp = strtok_r(NULL, " ", &buf_ptr); + if (!tmp) continue; + keycode = atoi(tmp); + if ((0 >= keycode) || (keycode >= KEYROUTER_MAX_KEYS)) { + ds_err("Currently %d key is invalid to support\n", keycode); + continue; + } + + keyrouter->opts[keycode].enabled = true; + + if (strstr(buf_ptr, "no_priv") != NULL) { + keyrouter->opts[keycode].no_privilege = true; + } + } + + fclose(file); +} diff --git a/src/libds-tizen/keyrouter/keyrouter.h b/src/libds-tizen/keyrouter/keyrouter.h new file mode 100644 index 0000000..c8dfa0f --- /dev/null +++ b/src/libds-tizen/keyrouter/keyrouter.h @@ -0,0 +1,108 @@ +#ifndef DS_TIZEN_KEYROUTER_H +#define DS_TIZEN_KEYROUTER_H + +#include +#include +#include + +#define KEYROUTER_MAX_KEYS 512 + +struct ds_tizen_keyrouter_key_info +{ + void *data; + struct wl_list link; +}; + +struct ds_tizen_keyrouter_grabbed +{ + int keycode; + + struct { + struct wl_list excl; + struct wl_list or_excl; + struct wl_list top; + struct wl_list shared; + } grab; + + struct wl_list pressed; +}; + +struct ds_tizen_keyrouter_grab +{ + struct ds_tizen_keyrouter_grabbed *hard_keys; + + void *focus_client; + void *top_client; +}; + +struct ds_tizen_keyrouter_key_options +{ + bool enabled; + bool no_privilege; +}; + +struct ds_tizen_keyrouter +{ + struct wl_global *global; + + struct wl_list clients; + + struct wl_listener display_destroy; + + struct { + struct wl_signal destroy; + } events; + + struct ds_tizen_keyrouter_key_options *opts; + + struct ds_tizen_keyrouter_grab *keyrouter_grab; +}; + +struct ds_tizen_keyrouter_client +{ + struct ds_tizen_keyrouter *keyrouter; + + struct wl_resource *resource; + + bool grabbed; + + struct wl_list link; // ds_tizen_keyrouter::clients +}; + +struct ds_tizen_grab_data +{ + int key; + int mode; + int err; +}; + +struct ds_tizen_ungrab_data +{ + int key; + int err; +}; + +struct ds_tizen_keyrouter_grab * +tizen_keyrouter_grab_create(void); +void +tizen_keyrouter_grab_destroy(struct ds_tizen_keyrouter_grab *keyrouter_grab); +int +tizen_keyrouter_grab_grab_key(struct ds_tizen_keyrouter_grab *keyrouter_grab, + int type, int keycode, void *data); +void +tizen_keyrouter_grab_ungrab_key(struct ds_tizen_keyrouter_grab *keyrouter_grab, + int type, int keycode, void *data); +int +tizen_keyrouter_grab_key_process(struct ds_tizen_keyrouter_grab *keyrouter_grab, + int keycode, int pressed, struct wl_list *delivery_list); +void +tizen_keyrouter_grab_set_focus_client(struct ds_tizen_keyrouter_grab *keyrouter_grab, + void *focus_client); +void +tizen_keyrouter_grab_set_top_client(struct ds_tizen_keyrouter_grab *keyrouter_grab, + void *top_client); +bool +tizen_keyrouter_grab_check_grabbed_key(struct ds_tizen_keyrouter_grab *keyrouter_grab, + int keycode); + +#endif diff --git a/src/libds-tizen/keyrouter/keyrouter_grab.c b/src/libds-tizen/keyrouter/keyrouter_grab.c new file mode 100644 index 0000000..873f4b1 --- /dev/null +++ b/src/libds-tizen/keyrouter/keyrouter_grab.c @@ -0,0 +1,351 @@ +#include +#include + +#include "libds/log.h" + +#include "keyrouter.h" + +static struct wl_list * +keyrouter_grab_get_grabbed_list(struct ds_tizen_keyrouter_grab *keyrouter_grab, + int type, int keycode) +{ + switch(type) { + case TIZEN_KEYROUTER_MODE_EXCLUSIVE: + return &keyrouter_grab->hard_keys[keycode].grab.excl; + case TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE: + return &keyrouter_grab->hard_keys[keycode].grab.or_excl; + case TIZEN_KEYROUTER_MODE_TOPMOST: + return &keyrouter_grab->hard_keys[keycode].grab.top; + case TIZEN_KEYROUTER_MODE_SHARED: + return &keyrouter_grab->hard_keys[keycode].grab.shared; + default: + return NULL; + } +} + +bool +tizen_keyrouter_grab_check_grabbed_key(struct ds_tizen_keyrouter_grab *keyrouter_grab, int keycode) +{ + struct wl_list *list; + + list = keyrouter_grab_get_grabbed_list(keyrouter_grab, TIZEN_KEYROUTER_MODE_EXCLUSIVE, keycode); + if (list && !wl_list_empty(list)) + return true; + + list = keyrouter_grab_get_grabbed_list(keyrouter_grab, TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE, keycode); + if (list && !wl_list_empty(list)) + return true; + + list = keyrouter_grab_get_grabbed_list(keyrouter_grab, TIZEN_KEYROUTER_MODE_TOPMOST, keycode); + if (list && !wl_list_empty(list)) + return true; + + list = keyrouter_grab_get_grabbed_list(keyrouter_grab, TIZEN_KEYROUTER_MODE_SHARED, keycode); + if (list && !wl_list_empty(list)) + return true; + + return false; +} + +static bool +keyrouter_grab_check_duplicated_data(struct wl_list *list, void *data) +{ + struct ds_tizen_keyrouter_key_info *info; + + if (wl_list_empty(list)) + return false; + + wl_list_for_each(info, list, link) { + if (info->data == data) + return true; + } + + return false; +} + +static bool +keyrouter_grab_check_grabbed(struct ds_tizen_keyrouter_grab *keyrouter_grab, + int type, int keycode, void *data) +{ + struct wl_list *list; + bool ret; + + list = keyrouter_grab_get_grabbed_list(keyrouter_grab, type, keycode); + if (list == NULL) { + ds_err("keycode(%d) had no list for type(%d).", keycode, type); + return false; + } + + switch(type) { + case TIZEN_KEYROUTER_MODE_EXCLUSIVE: + if (wl_list_empty(list) == false) + ret = false; + else + ret = true; + break; + case TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE: + ret = keyrouter_grab_check_duplicated_data(list, data); + break; + case TIZEN_KEYROUTER_MODE_TOPMOST: + ret = keyrouter_grab_check_duplicated_data(list, data); + break; + case TIZEN_KEYROUTER_MODE_SHARED: + ret = keyrouter_grab_check_duplicated_data(list, data); + break; + default: + ret = TIZEN_KEYROUTER_ERROR_INVALID_MODE; + break; + } + + return ret; +} + +void +tizen_keyrouter_grab_set_focus_client(struct ds_tizen_keyrouter_grab *keyrouter_grab, + void *focus_client) +{ + keyrouter_grab->focus_client = focus_client; + + if (focus_client) + ds_dbg("[%s] focus client has been set. (focus_client=0x%p)", __FUNCTION__, focus_client); + else + ds_dbg("[%s] focus client has been set to NULL.", __FUNCTION__); +} + +void +tizen_keyrouter_grab_set_top_client(struct ds_tizen_keyrouter_grab *keyrouter_grab, void *top_client) +{ + keyrouter_grab->top_client = top_client; + + if (top_client) + ds_dbg("[%s] top client has been set. (top_client=0x%p)", __FUNCTION__, top_client); + else + ds_dbg("[%s] top client has been set to NULL.", __FUNCTION__); +} + +int +tizen_keyrouter_grab_key_process(struct ds_tizen_keyrouter_grab *keyrouter_grab, + int keycode, int pressed, struct wl_list *delivery_list) +{ + struct ds_tizen_keyrouter_key_info *info, *delivery; + int count = 0; + + if (keycode <= 0 && keycode >= KEYROUTER_MAX_KEYS) { + ds_err("Invalid keycode(%d)", keycode); + return 0; + } + + if (!wl_list_empty(&keyrouter_grab->hard_keys[keycode].grab.excl)) { + info = wl_container_of(keyrouter_grab->hard_keys[keycode].grab.excl.next, info, link); + if (info) { + delivery = calloc(1, sizeof(struct ds_tizen_keyrouter_key_info)); + if (delivery == NULL) { + ds_err("Failed to allocate memory."); + return 0; + } + delivery->data = info->data; + wl_list_insert(delivery_list, &delivery->link); + ds_dbg("Exclusive Mode: keycode: %d to data: %p", keycode, info->data); + return 1; + } + } else if (!wl_list_empty(&keyrouter_grab->hard_keys[keycode].grab.or_excl)) { + info = wl_container_of(keyrouter_grab->hard_keys[keycode].grab.or_excl.next, info, link); + if (info) { + delivery = calloc(1, sizeof(struct ds_tizen_keyrouter_key_info)); + if (delivery == NULL) { + ds_err("Failed to allocate memory."); + return 0; + } + delivery->data = info->data; + wl_list_insert(delivery_list, &delivery->link); + ds_dbg("OR-Excl Mode: keycode: %d to data: %p", keycode, info->data); + return 1; + } + } else if (!wl_list_empty(&keyrouter_grab->hard_keys[keycode].grab.top)) { + wl_list_for_each(info, &keyrouter_grab->hard_keys[keycode].grab.top, link) { + if (keyrouter_grab->top_client && keyrouter_grab->top_client == info->data) { + delivery = calloc(1, sizeof(struct ds_tizen_keyrouter_key_info)); + if (delivery == NULL) { + ds_err("Failed to allocate memory."); + return 0; + } + delivery->data = info->data; + wl_list_insert(delivery_list, &delivery->link); + ds_dbg("Topmost Mode: keycode: %d to data: %p", keycode, info->data); + return 1; + } + } + } + + if (keyrouter_grab->focus_client) { + delivery = calloc(1, sizeof(struct ds_tizen_keyrouter_key_info)); + if (delivery == NULL) { + ds_err("Failed to allocate memory."); + return 0; + } + delivery->data = keyrouter_grab->focus_client; + wl_list_insert(delivery_list, &delivery->link); + count++; + ds_dbg("Focus: keycode: %d to data: %p, count: %d", keycode, delivery->data, count); + } + + if (!wl_list_empty(&keyrouter_grab->hard_keys[keycode].grab.shared)) { + wl_list_for_each(info, &keyrouter_grab->hard_keys[keycode].grab.shared, link) { + if (keyrouter_grab->focus_client && keyrouter_grab->focus_client == info->data) + continue; + delivery = calloc(1, sizeof(struct ds_tizen_keyrouter_key_info)); + if (delivery == NULL) { + ds_err("Failed to allocate memory."); + return 0; + } + delivery->data = info->data; + wl_list_insert(delivery_list, &delivery->link); + count++; + ds_dbg("Shared: keycode: %d to data: %p, count: %d", keycode, info->data, count); + } + } + + return count; +} + +int +tizen_keyrouter_grab_grab_key(struct ds_tizen_keyrouter_grab *keyrouter_grab, + int type, int keycode, void *data) +{ + struct ds_tizen_keyrouter_key_info *info = NULL; + struct wl_list *list = NULL; + + if (keycode <= 0 && keycode >= KEYROUTER_MAX_KEYS) { + ds_err("Invalid keycode(%d)", keycode); + return TIZEN_KEYROUTER_ERROR_INVALID_KEY; + } + + if (keyrouter_grab_check_grabbed(keyrouter_grab, type, keycode, data)) + return TIZEN_KEYROUTER_ERROR_GRABBED_ALREADY; + + info = calloc(1, sizeof(struct ds_tizen_keyrouter_key_info)); + if (info == NULL) { + ds_err("Failed to allocate memory."); + return TIZEN_KEYROUTER_ERROR_NO_SYSTEM_RESOURCES; + } + info->data = data; + + wl_list_init(&info->link); + + list = keyrouter_grab_get_grabbed_list(keyrouter_grab, type, keycode); + if (!list) { + ds_err("keycode(%d) had no list for type(%d)", keycode, type); + free(info); + return TIZEN_KEYROUTER_ERROR_INVALID_MODE; + } + + if (!keyrouter_grab->hard_keys[keycode].keycode) + keyrouter_grab->hard_keys[keycode].keycode = keycode; + + wl_list_insert(list, &info->link); + + return TIZEN_KEYROUTER_ERROR_NONE; +} + +static void +keyrouter_list_remove_data(struct wl_list *list, void *data) +{ + struct ds_tizen_keyrouter_key_info *info, *tmp; + + if (wl_list_empty(list)) + return; + + wl_list_for_each_safe(info ,tmp, list, link) { + if (info->data == data) { + wl_list_remove(&info->link); + free(info); + } + } +} + +void +tizen_keyrouter_grab_ungrab_key(struct ds_tizen_keyrouter_grab *keyrouter_grab, + int type, int keycode, void *data) +{ + struct wl_list *list; + + if (keycode <= 0 && keycode >= KEYROUTER_MAX_KEYS) { + ds_err("Invalid keycode(%d)", keycode); + return; + } + + if (keyrouter_grab->hard_keys[keycode].keycode == 0) + return; + + list = keyrouter_grab_get_grabbed_list(keyrouter_grab, type, keycode); + if (list == NULL) { + ds_err("keycode(%d) had no list for type(%d)", keycode, type); + return; + } + + keyrouter_list_remove_data(list, data); +} + +struct ds_tizen_keyrouter_grab * +tizen_keyrouter_grab_create(void) +{ + struct ds_tizen_keyrouter_grab *keyrouter_grab = NULL; + int i; + + keyrouter_grab = calloc(1, sizeof(struct ds_tizen_keyrouter_grab)); + if (keyrouter_grab == NULL) { + ds_err("Failed to allocate memory."); + return NULL; + } + + /* FIXME: Who defined max keycode? */ + keyrouter_grab->hard_keys = calloc(KEYROUTER_MAX_KEYS, sizeof(struct ds_tizen_keyrouter_grabbed)); + if (keyrouter_grab == NULL) { + ds_err("Failed to allocate memory."); + free(keyrouter_grab); + return NULL; + } + + for (i = 0; i < KEYROUTER_MAX_KEYS; i++) { + /* Enable all of keys to grab */ + //keyrouter_grab->hard_keys[i].keycode = i; + wl_list_init(&keyrouter_grab->hard_keys[i].grab.excl); + wl_list_init(&keyrouter_grab->hard_keys[i].grab.or_excl); + wl_list_init(&keyrouter_grab->hard_keys[i].grab.top); + wl_list_init(&keyrouter_grab->hard_keys[i].grab.shared); + wl_list_init(&keyrouter_grab->hard_keys[i].pressed); + } + + return keyrouter_grab; +} + +static void +keyrouter_grab_delete_list(struct wl_list *list) +{ + struct ds_tizen_keyrouter_key_info *info, *tmp; + + if (wl_list_empty(list)) + return; + + wl_list_for_each_safe(info, tmp, list, link) { + wl_list_remove(&info->link); + free(info); + } +} + +void +tizen_keyrouter_grab_destroy(struct ds_tizen_keyrouter_grab *keyrouter_grab) +{ + int i; + + for (i = 0; i < KEYROUTER_MAX_KEYS; i++) { + keyrouter_grab_delete_list(&keyrouter_grab->hard_keys[i].grab.excl); + keyrouter_grab_delete_list(&keyrouter_grab->hard_keys[i].grab.or_excl); + keyrouter_grab_delete_list(&keyrouter_grab->hard_keys[i].grab.top); + keyrouter_grab_delete_list(&keyrouter_grab->hard_keys[i].grab.shared); + keyrouter_grab_delete_list(&keyrouter_grab->hard_keys[i].pressed); + } + + free(keyrouter_grab->hard_keys); + free(keyrouter_grab); +} diff --git a/src/libds-tizen/keyrouter/meson.build b/src/libds-tizen/keyrouter/meson.build new file mode 100644 index 0000000..7b27d3b --- /dev/null +++ b/src/libds-tizen/keyrouter/meson.build @@ -0,0 +1,34 @@ +libds_tizen_keyrouter_files = [ + 'keyrouter_grab.c', + 'keyrouter.c', +] + +libds_tizen_keyrouter_deps = [ + dep_libds, + dep_libds_tizen, + dependency('tizen-extension-server', required: true), +] + +keylayout_dir = get_option('keylayout_dir') + +lib_libds_tizen_keyrouter = shared_library('ds-tizen-keyrouter', libds_tizen_keyrouter_files, + dependencies: libds_tizen_keyrouter_deps, + include_directories: [ common_inc, include_directories('.'), include_directories('..') ], + version: meson.project_version(), + c_args: [ '-DKEYLAYOUT_DIR="@0@"'.format(keylayout_dir) ], + install: true +) + +dep_libds_tizen_keyrouter = declare_dependency( + link_with: lib_libds_tizen_keyrouter, + dependencies: libds_tizen_keyrouter_deps, + include_directories: [ common_inc, include_directories('.') ], +) + +pkgconfig = import('pkgconfig') +pkgconfig.generate(lib_libds_tizen_keyrouter, + version: meson.project_version(), + filebase: 'libds-tizen-keyrouter', + name: 'libds-tizen-keyrouter', + description: 'tizen keyrouter extension of libds-tizen for tizen platform', +) \ No newline at end of file diff --git a/src/libds-tizen/meson.build b/src/libds-tizen/meson.build index 81370e6..0d780a3 100644 --- a/src/libds-tizen/meson.build +++ b/src/libds-tizen/meson.build @@ -34,3 +34,6 @@ pkgconfig.generate(lib_libds_tizen, name: 'libds-tizen', description: 'extension of libds for tizen platform', ) + +subdir('keyrouter') + -- 2.7.4