From: JengHyun Kang Date: Mon, 30 May 2016 06:26:27 +0000 (+0900) Subject: Add some features to support tv profile. X-Git-Tag: submit/tizen/20160614.021500^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=646330c0036829aaa19e46091b6084e40bc7a8d1;p=platform%2Fcore%2Fuifw%2Fe-mod-tizen-keyrouter.git Add some features to support tv profile. - Modify key register logic - Add register grab / pass interface - Add none register mode - Add monitor key mode - Add picturoff mode - Add key combination mode - Add get register delivery status Change-Id: Idf015c62b1740a3655c2ba114a0caed53ef3414d --- diff --git a/config/key_combinations.ini b/config/key_combinations.ini new file mode 100644 index 0000000..d4c0dd7 --- /dev/null +++ b/config/key_combinations.ini @@ -0,0 +1,396 @@ +; Rules for this config file. +;ANY NEW ADDITION HERE SHOULD MATCH A CORRESPONDING ADDITION TO THE ENUM "__key_comb_enum" DEFINED IN keyEvent.h IN libslp-UtilX MODULE,SUCH THAT THE COMBINATION +;NUMBER HERE IS EQUAL TO ENUM VALUE OF THE COMBINATION ADDED IN KeyEvent.h +; Add a new combination like[CombinationN] where N is next count from the last combination added. THIS IS IMPORTANT! +;keys are added like: +;1=74 +;2=90 +;3=97 here in 1=74, '1' is the 'index' :first key index in combination and '74' is the keycode expected at the 1st index among incoming keys. +; here index has to be in sequence. THIS IS IMPORTANT! +; KEYSYM=Keycodes mapping: +;mute=74;exit=182;power=124;info=196;menu=133;return=9;enter=36;source=72;VolUp=76;VolDown=75;ChannelUp=96;ChannelDown=95; +;blue key=70;RED key=67;green key=68;yellow key=69;tools key=135;FF=216;RW=176;play=208;stop=174 +;1=10;2=11;3=12;4=13;5=14;6=15;7=16;8=17;9=18;0=19; + +;Mute + 1 + 8 + 2 + Power +[Combination1]; +1=74 +2=10 +3=17 +4=11 +5=124 +;Info + Menu + Mute + Power +[Combination2] +1=196 +2=133 +3=74 +4=124 +;Mute + Enter + Mute + Enter +[Combination3] +1=74 +2=36 +3=74 +4=36 +;Mute + 9 + 4 + 8 + Exit +[Combination4] +1=74 +2=18 +3=13 +4=17 +5=182 +;Mute + 3 + 6 + 9 + Exit +[Combination5] +1=74 +2=12 +3=15 +4=18 +5=182 +;Mute + 2 + 5 + 8 + Exit +[Combination6] +1=74 +2=11 +3=14 +4=17 +5=182 +;Info + Factory +[Combination7] +1=196 +2=0 +;Source + Exit + Power +[Combination8] +1=72 +2=182 +3=124 +;Mute + 1 + 8 + 6 + Exit +[Combination9] +1=74 +2=10 +3=17 +4=15 +5=182 +;Mute + 7 + 8 + 2 + Exit +[Combination10] +1=74 +2=16 +3=17 +4=11 +5=182 +;Mute + 7 + 8 + 3 + Exit +[Combination11] +1=74 +2=16 +3=17 +4=12 +5=182 +;Mute + 7 + 3 + 7 + Enter +[Combination12] +1=74 +2=16 +3=12 +4=16 +5=36 +;Mute + 4 + 3 + 7 + Exit +[Combination13] +1=74 +2=13 +3=12 +4=16 +5=182 +;Mute + 1 + 1 + 9 + Enter +[Combination14] +1=74 +2=10 +3=10 +4=18 +5=36 +;Mute + 5 + 6 + 7 + Exit +[Combination15] +1=74 +2=14 +3=15 +4=16 +5=182 +;Mute + 1 + 4 + 7 + Mute +[Combination16] +1=74 +2=10 +3=13 +4=16 +5=74 +;Mute + 3 + 6 + 9 + Mute +[Combination17] +1=74 +2=12 +3=15 +4=18 +5=74 +;Info + Mute +[Combination18] +1=196 +2=74 +;Mute + 2 + 2 + 7 + Exit +[Combination19] +1=74 +2=11 +3=11 +4=16 +5=182 +;Info + Source +[Combination20] +1=196 +2=72 +;Mute + RSS +[Combination21] +1=74 +2=0 +;Mute + 2 + 4 + 7 + Exit +[Combination22] +1=74 +2=11 +3=13 +4=16 +5=182 +;Mute + 2 + 0 + 7 + Exit +[Combination23] +1=74 +2=11 +3=19 +4=16 +5=182 +;Mute + 2 + 0 + 9 + Exit +[Combination24] +1=74 +2=11 +3=19 +4=18 +5=182 +;Mute + 0 + Mute + 0 +[Combination25] +1=74 +2=19 +3=74 +4=19 +;Mute + 5 + 6 + 4 + Exit +[Combination26] +1=74 +2=14 +3=15 +4=13 +5=182 +;Mute + 1 + 8 + 4 + Exit +[Combination27] +1=74 +2=10 +3=17 +4=13 +5=182 +;'>>'(FF) + 2 + 8 + 7 + '<<'(RW) +[Combination28] +1=216 +2=11 +3=17 +4=16 +5=176 +;Mute + 8 + 2 + 4 + Power +[Combination29] +1=74 +2=17 +3=11 +4=13 +5=124 +;Mute + Vol Up + Return + Vol Down + Return + Vol Up + Return (smartctrl) +[Combination30] +1=74 +2=76 +3=9 +4=75 +5=9 +6=76 +7=9 +;Mute + 5 + 7 + 9 + Exit +[Combination31] +1=74 +2=14 +3=16 +4=18 +5=182 +;FF+2+8+9+RW +[Combination32] +1=216 +2=11 +3=17 +4=18 +5=176 +;FF+2+8+9+1 +[Combination33] +1=216 +2=11 +3=17 +4=18 +5=10 +;Mute+5+6+9+Exit +[Combination34] +1=74 +2=14 +3=15 +4=18 +5=182 +;Info+Menu+Mute+Menu+Exit +[Combination35] +1=196 +2=133 +3=74 +4=133 +5=182 +;Mute + 7 + 4 + 7 + Exit +[Combination36] +1=74 +2=16 +3=13 +4=16 +5=182 +;Mute + 7 + 8 + 7 + Exit +[Combination37] +1=74 +2=16 +3=17 +4=16 +5=182 +;FF+2+8+9+2 +[Combination38] +1=216 +2=11 +3=17 +4=18 +5=11 +;FF+1+8+2+REW +[Combination39] +1=216 +2=10 +3=17 +4=11 +5=176 +;Mute+9+8+7+Exit "start key recording" +[Combination40] +1=74 +2=18 +3=17 +4=16 +5=182 +;Mute+Mute+Exit+Exit+Exit "stop key recording" +[Combination41] +1=74 +2=74 +3=182 +4=182 +5=182 +;Mute+Play+Play+Play+Exit "start playing recorded keys" +[Combination42] +1=74 +2=208 +3=208 +4=208 +5=182 +;Mute+Stop+Stop+Stop+Exit "stop playing recorded keys" +[Combination43] +1=74 +2=174 +3=174 +4=174 +5=182 +;Mute+Return+VolUp+ChannelUp+Mute +[Combination44] +1=74 +2=9 +3=76 +4=96 +5=74 +;Info+Stop +[Combination45] +1=196 +2=174 +;mute + 9 + 9 + 0 + 0 + exit +[Combination46] +1=74 +2=18 +3=18 +4=19 +5=19 +6=182 +;mute + 3 + mute +3 +[Combination47] +1=74 +2=12 +3=74 +4=12 +;mute + 7 + mute + 7 +[Combination48] +1=74 +2=16 +3=74 +4=16 +;info + exit + mute +[Combination49] +1=196 +2=182 +3=74 +;KEY_SOURCE + 2 + 5 + 8 + 9 + KEY_PRECH +[Combination50] +1=72 +2=11 +3=14 +4=17 +5=18 +6=190 +;FF + 2 + 0 + 0 + 6 + 2 + 0 + 1 + 4 + 0 + 9 +[Combination51] +1=216 +2=11 +3=19 +4=19 +5=15 +6=11 +7=19 +8=10 +9=13 +10=19 +11=18 +;FF + 2 + 0 + 0 + 6 + 2 + 0 + 1 + 4 + 0 + 8 +[Combination52] +1=216 +2=11 +3=19 +4=19 +5=15 +6=11 +7=19 +8=10 +9=13 +10=19 +11=17 +;FF + 2 + 0 + 0 + 6 + 2 + 0 + 1 + 5 + 0 + 9 +[Combination53] +1=216 +2=11 +3=19 +4=19 +5=15 +6=11 +7=19 +8=10 +9=14 +10=19 +11=18 +;Mute+VolUp+ChannelUp+Mute +[Combination54] +1=74 +2=76 +3=96 +4=74 +;Mute+0+0+7+Exit +[Combination55] +1=74 +2=19 +3=19 +4=16 +5=182 diff --git a/configure.ac b/configure.ac index f0e9f2a..5b77c2f 100644 --- a/configure.ac +++ b/configure.ac @@ -40,6 +40,8 @@ dnl ======================================================================== #AC_HEADER_STDC AC_CHECK_HEADERS([math.h fcntl.h stdlib.h string.h unistd.h]) +COMBINATION_FILE_PATH="$TZ_SYS_RO_APP/keyrouter/key_combinations.ini" +AC_DEFINE_UNQUOTED(COMBINATION_FILE_PATH, "$COMBINATION_FILE_PATH", [Path to Key Combination File]) dnl ======================================================================== # checks for typedefs, structures, and compiler characteristics AC_C_CONST @@ -59,8 +61,7 @@ PKG_PROG_PKG_CONFIG dnl ======================================================================== # checks for pkg-config dnl ======================================================================== -PKG_CHECK_MODULES(ENLIGHTENMENT, [enlightenment, - dlog]) +PKG_CHECK_MODULES(ENLIGHTENMENT, [enlightenment]) ENLIGHTENMENT_CFLAGS="${ENLIGHTENMENT_CFLAGS} -D_GNU_SOURCE " AC_SUBST(ENLIGHTENMENT_CFLAGS) AC_SUBST(ENLIGHTENMENT_LIBS) @@ -113,7 +114,7 @@ dnl ======================================================================== # checks for wayland only argument dnl ======================================================================== if test "x${have_wayland_only}" = "xyes"; then - PKG_CHECK_MODULES(WAYLAND, [wayland-server, tizen-extension-server]) + PKG_CHECK_MODULES(WAYLAND, [wayland-server, tizen-extension-server, capi-system-device]) fi release=$(pkg-config --variable=release enlightenment) diff --git a/packaging/e-mod-tizen-keyrouter.spec b/packaging/e-mod-tizen-keyrouter.spec index 9ab47bf..552d713 100644 --- a/packaging/e-mod-tizen-keyrouter.spec +++ b/packaging/e-mod-tizen-keyrouter.spec @@ -16,8 +16,10 @@ BuildRequires: pkgconfig(wayland-server) BuildRequires: pkgconfig(tizen-extension-server) BuildRequires: pkgconfig(cynara-client) BuildRequires: pkgconfig(cynara-creds-socket) +BuildRequires: pkgconfig(capi-system-device) %endif -BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(dbus-glib-1) +BuildRequires: pkgconfig(libtzplatform-config) %if "%{?profile}" == "common" %else BuildRequires: xkb-tizen-data @@ -41,7 +43,8 @@ export LDFLAGS+=" -Wl,--hash-style=both -Wl,--as-needed -Wl,--rpath=/usr/lib" %if %{with wayland} %configure --prefix=/usr \ --enable-wayland-only \ - --enable-cynara + --enable-cynara \ + TZ_SYS_RO_APP=%{TZ_SYS_RO_APP} %endif make @@ -53,6 +56,9 @@ rm -rf %{buildroot} mkdir -p %{buildroot}/%{TZ_SYS_RO_SHARE}/license cp -a %{_builddir}/%{buildsubdir}/COPYING %{buildroot}/%{TZ_SYS_RO_SHARE}/license/%{name} +# for install combination key's configuration +mkdir -p %{buildroot}%{TZ_SYS_RO_APP}/keyrouter +cp -af config/key_combinations.ini %{buildroot}%{TZ_SYS_RO_APP}/keyrouter/ # install make install DESTDIR=%{buildroot} @@ -64,3 +70,4 @@ find %{buildroot}%{_libdir}/enlightenment/modules/%{name} -name *.la | xargs rm %defattr(-,root,root,-) %{_libdir}/enlightenment/modules/e-mod-tizen-keyrouter %{TZ_SYS_RO_SHARE}/license/%{name} +%attr(754, app, root) %{TZ_SYS_RO_APP}/keyrouter diff --git a/src/Makefile.am b/src/Makefile.am index d014c6d..ec6354c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,7 +10,10 @@ module_la_SOURCES = e_mod_main_wl.c \ e_mod_main_wl.h \ e_mod_keyrouter_list.c \ e_mod_keyrouter_events.c \ - e_mod_keyrouter_conf.c + e_mod_keyrouter_conf.c \ + e_mod_keyrouter_combination.c \ + ini.c \ + ini.h module_la_CFLAGS = @ENLIGHTENMENT_CFLAGS@ @WAYLAND_CFLAGS@ -DHAVE_WAYLAND_ONLY @CYNARA_CFLAGS@ @TTRACE_CFLAGS@ module_la_LDFLAGS = -module -avoid-version @WAYLAND_LIBS@ @ENLIGHTENMENT_LIBS@ @CYNARA_LIBS@ @TTRACE_LIBS@ endif diff --git a/src/e_mod_keyrouter_combination.c b/src/e_mod_keyrouter_combination.c new file mode 100644 index 0000000..4111e22 --- /dev/null +++ b/src/e_mod_keyrouter_combination.c @@ -0,0 +1,422 @@ +/* + * @file e_mod_keyrouter_combination.c + * @brief Implementation of e_mod_keyrouter_combination.c + * @author Shubham Shrivastav shubham.sh@samsung.com + * @date 25th Feb 2016 + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define E_COMP_WL +#include "e.h" +#include "e_mod_main_wl.h" +#include +#include +#include "ini.h" + +#define MAX_LEN 64 +#define DBUS_PATH "/com/burtonini/dbus/ping" +#define DBUS_IFACE "keyrouter.dbus.Signal" +#define DBUS_MSG_NAME "KEY_COMBINATION" +#define COMBINATION_TIME_OUT 4000 +#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0 + +typedef unsigned long Time; +typedef struct _DbusConf +{ + char path[MAX_LEN]; + char interface[MAX_LEN]; + char msg[MAX_LEN]; +} DbusConf; +typedef struct _KeyCombination +{ + DBusConnection * keyrouter_dbus_conn; + DbusConf dbusconf; + DBusError DBus_error; + char combinationFilePath[MAX_LEN]; + GArray* _master_combinations; + GArray* _current_matched_combinations; + Time combination_timeout; +} KeyCombination; + +static int keyCombinationInitialize = 0; +KeyCombination g_key_combination; + +static void _e_keyrouter_dbus_connection_init(); +static int _e_keyrouter_search_key_combination(int keycode, Time timestamp); +static int _e_keyrouter_send_dbus_message(DBusConnection *bus, int Input); +static char * _e_keyrouter_substring(char *string, int position); +static int _e_keyrouter_parse_ini_config(void* user, const char* section, const char* name, const char* value); + +static void +_e_keyrouter_dbus_connection_init() +{ + DBusError dBus_error; + + KLINF("_e_keyrouter_dbus_connection_init() \n"); + + dbus_error_init(&dBus_error); + g_key_combination.keyrouter_dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dBus_error); + + if (dbus_error_is_set(&dBus_error)) + { + KLWRN("[DBUS-ERROR] %s \n",dBus_error.message); + dbus_error_free(&dBus_error); + } + + if (!g_key_combination.keyrouter_dbus_conn) + { + KLWRN("[DBUS-CONNECTION-FAIL] DBUS connection is failed \n"); + } +} + +void +e_keyrouter_key_combination_init() +{ + memset(&g_key_combination, 0, sizeof(g_key_combination)); + g_key_combination.keyrouter_dbus_conn = NULL; + snprintf(g_key_combination.dbusconf.path, strlen(DBUS_PATH)+1, DBUS_PATH); + snprintf(g_key_combination.dbusconf.interface, strlen(DBUS_IFACE)+1, DBUS_IFACE); + snprintf(g_key_combination.dbusconf.msg, strlen(DBUS_MSG_NAME)+1, DBUS_MSG_NAME); + snprintf(g_key_combination.combinationFilePath, strlen(COMBINATION_FILE_PATH)+1, COMBINATION_FILE_PATH); + + g_key_combination._master_combinations = g_array_new(FALSE, FALSE, sizeof(GArray*)); + if (ini_parse((const char *) g_key_combination.combinationFilePath, _e_keyrouter_parse_ini_config, g_key_combination._master_combinations) < 0) + { + KLWRN("Can't load %s file\n", g_key_combination.combinationFilePath); + } + + g_key_combination.combination_timeout = COMBINATION_TIME_OUT; + _e_keyrouter_dbus_connection_init(); + keyCombinationInitialize = 1; +} + +static char * +_e_keyrouter_substring(char *string, int position) +{ + char *pointer; + int c; + + for (c = 0; c < position - 1; c++) + string++; + + pointer = malloc(strlen(string) + 1); + if (pointer == NULL) + { + KLWRN("Unable to allocate memory.\n"); + return NULL; + } + + for (c = 0; *string != '\0'; c++) + { + *(pointer + c) = *string; + string++; + } + *(pointer + c) = '\0'; + + return pointer; +} + +static int +_e_keyrouter_parse_ini_config(void* user, const char* section, const char* name, const char* value) +{ + int section_number, val; + size_t needed; + char *local_section, *c_num; + GArray *masterArray, *childArray; + + c_num = _e_keyrouter_substring(strdup(section), 12/*"Combination"*/); + if (c_num == NULL) + { + KLWRN("\n Unable to read config. substring is null. \n"); + return -1; + } + + section_number = atoi(c_num); + free(c_num); + if (section_number == 0) + { + KLWRN("\n^[[36m Unable to read config. section_number is 0. ^[[0m\n"); + return -1; + } + section_number--; + + masterArray = (GArray*) user; + if (masterArray->len <= (unsigned int) section_number) + { + childArray = g_array_new(FALSE, FALSE, sizeof(int)); + g_array_insert_val(masterArray, section_number, childArray); + } + + needed = snprintf(NULL, 0, "%s%d", "Combination", section_number + 1); + local_section = malloc(needed + 1); + if (local_section == NULL) + { + KLWRN("\n^[[36m Failed to allocate memory for local_section ^[[0m\n"); + return -1; + } + snprintf(local_section, needed + 1, "%s%d", "Combination", section_number + 1); + + if (MATCH(local_section, "1")) + { + val = atoi(value); + childArray = g_array_index(masterArray,GArray*,section_number); + g_array_insert_val(childArray, 0, val); + } + else if (MATCH(local_section, "2")) + { + val = atoi(value); + childArray = g_array_index(masterArray,GArray*,section_number); + g_array_insert_val(childArray, 1, val); + } + else if (MATCH(local_section, "3")) + { + val = atoi(value); + childArray = g_array_index(masterArray,GArray*,section_number); + g_array_insert_val(childArray, 2, val); + } + else if (MATCH(local_section, "4")) + { + val = atoi(value); + childArray = g_array_index(masterArray,GArray*,section_number); + g_array_insert_val(childArray, 3, val); + } + else if (MATCH(local_section, "5")) + { + val = atoi(value); + childArray = g_array_index(masterArray,GArray*,section_number); + g_array_insert_val(childArray, 4, val); + } + else if (MATCH(local_section, "6")) + { + val = atoi(value); + childArray = g_array_index(masterArray,GArray*,section_number); + g_array_insert_val(childArray, 5, val); + } + else if (MATCH(local_section, "7")) + { + val = atoi(value); + childArray = g_array_index(masterArray,GArray*,section_number); + g_array_insert_val(childArray, 6, val); + } + else if (MATCH(local_section, "8")) + { + val = atoi(value); + childArray = g_array_index(masterArray,GArray*,section_number); + g_array_insert_val(childArray, 7, val); + } + else if (MATCH(local_section, "9")) + { + val = atoi(value); + childArray = g_array_index(masterArray,GArray*,section_number); + g_array_insert_val(childArray, 8, val); + } + else if (MATCH(local_section, "10")) + { + val = atoi(value); + childArray = g_array_index(masterArray,GArray*,section_number); + g_array_insert_val(childArray, 9, val); + } + else if (MATCH(local_section, "11")) + { + val = atoi(value); + childArray = g_array_index(masterArray,GArray*,section_number); + g_array_insert_val(childArray, 10, val); + } + else if (MATCH(local_section, "12")) + { + val = atoi(value); + childArray = g_array_index(masterArray,GArray*,section_number); + g_array_insert_val(childArray, 11, val); + } + else + { + free(local_section); + return 0; /* unknown section/name, error */ + } + free(local_section); + return 1; +} + +void +e_keyrouter_process_key_combination(Time cur_time, int keycode, int state) +{ + int ret; + + if (!keyCombinationInitialize) + { + KLWRN("KeyCombinatioin support is not initiazlied yet \n"); + return ; + } + if (g_key_combination._master_combinations == NULL) + { + KLDBG(" Not searching key combination as Master combination is NULL \n"); + } + if (state == ECORE_EVENT_KEY_UP) + { + ret = _e_keyrouter_search_key_combination(keycode, cur_time); + + if(ret > 0) + { + _e_keyrouter_send_dbus_message(g_key_combination.keyrouter_dbus_conn, ret); + } + } +} + +static int +_e_keyrouter_send_dbus_message(DBusConnection *bus, int Input) +{ + DBusMessage *message = NULL; + + message = dbus_message_new_signal(g_key_combination.dbusconf.path, g_key_combination.dbusconf.interface, g_key_combination.dbusconf.msg); + dbus_message_append_args(message, DBUS_TYPE_INT32, &Input, DBUS_TYPE_INVALID); + + if (!dbus_connection_send(bus, message, NULL)) + KLWRN( "DBUS sending MSG FAILED!!\n"); + + dbus_message_unref(message); + return 1; +} + +static int +_e_keyrouter_search_key_combination(int keycode, Time timestamp) +{ + static Time t = 0; + unsigned int i, j = 0; + int matchedIdx = 0, foundAt = 0; + static int keyIdx = 0; + static GArray *_source_Search_Array = NULL; + GArray *childArray, *matched; + + if (timestamp - t >= g_key_combination.combination_timeout && keyIdx != 0) + { + t = timestamp; + keyIdx = 0; + g_array_free(_source_Search_Array, FALSE); + + { + g_key_combination._current_matched_combinations = g_array_new(FALSE, FALSE, sizeof(GArray*)); + _source_Search_Array = g_key_combination._master_combinations;/*now update _current_matched_combinations assuming last key that invalidated as first key*/ + matchedIdx = 0; + for (i = 0; i < _source_Search_Array->len; i++) + { + GArray * childArray = g_array_index(_source_Search_Array,GArray*,i); + if (keycode == g_array_index(childArray,int,0)) + { + g_array_insert_val(g_key_combination._current_matched_combinations, matchedIdx, childArray); + matchedIdx++; + } + } + + if (g_key_combination._current_matched_combinations->len > 0) + { + keyIdx = 1;/*assumed that first key is the last key that invalidated the combinaton.*/ + _source_Search_Array = g_key_combination._current_matched_combinations;/*start next key combination matching from this assumed _current_matched_combinations*/ + t = timestamp; + } + else /* the key that invalidated is unavailable in any master_combinations as first element*/ + { + keyIdx = 0; + t = timestamp; + g_array_free(g_key_combination._current_matched_combinations, FALSE); + } + } + return -1; + } + + g_key_combination._current_matched_combinations = g_array_new(FALSE, FALSE, sizeof(GArray*)); + if (keyIdx == 0) _source_Search_Array = g_key_combination._master_combinations; + + for (i = 0; i < _source_Search_Array->len; i++) + { + childArray = g_array_index(_source_Search_Array,GArray*,i); + if (keycode == g_array_index(childArray,int,keyIdx)) + { + g_array_insert_val(g_key_combination._current_matched_combinations, matchedIdx, childArray); + matchedIdx++; + } + } + + if (keyIdx > 0)/* this needs to be freed for count > 0 as for keyIdx== 0 it will point to master_combinations!*/ + { + g_array_free(_source_Search_Array, FALSE);/* this actually frees "last" current_matched_combinations*/ + } + if (g_key_combination._current_matched_combinations->len < 1)/* the incoming key has invalidated the combination sequence*/ + { + _source_Search_Array = g_key_combination._master_combinations;/*now update _current_matched_combinations assuming last key that invalidated as first key*/ + matchedIdx = 0; + + for (i = 0; i < _source_Search_Array->len; i++) + { + childArray = g_array_index(_source_Search_Array,GArray*,i); + if (keycode == g_array_index(childArray,int,0)) + { + g_array_insert_val(g_key_combination._current_matched_combinations, matchedIdx, childArray); + matchedIdx++; + } + } + + if (g_key_combination._current_matched_combinations->len > 0) + { + keyIdx = 1;/*assumed that first key is the last key that invalidated the combinaton.*/ + _source_Search_Array = g_key_combination._current_matched_combinations;/*start next key combination matching from this assumed _current_matched_combinations*/ + t = timestamp; + } + else/* the key that invalidated is unavailable in any master_combinations as first element*/ + { + keyIdx = 0; + t = timestamp; + g_array_free(g_key_combination._current_matched_combinations, FALSE); + } + } + else + { + if (g_key_combination._current_matched_combinations->len == 1 && (unsigned int)(keyIdx+1) == g_array_index(g_key_combination._current_matched_combinations,GArray*,0)->len) + { + keyIdx = 0; + t = timestamp; + matched = g_array_index(g_key_combination._current_matched_combinations,GArray*,0); + + for (i = 0; i < matched->len; i++) + KLDBG("[32m Matched Combination:|%d| [0m\n", g_array_index(matched,int,i)); + foundAt = 0; + + for (i = 0; i < g_key_combination._master_combinations->len; i++) + { + childArray=g_array_index(g_key_combination._master_combinations,GArray*,i); + for (j = 0; j < childArray->len; j++) + { + if (childArray->len == matched->len && g_array_index(childArray,int,j) == g_array_index(matched,int,j)) + { + foundAt = i + 1; + } + else + { + foundAt = FALSE; + break; + } + } + if (foundAt) + { + KLDBG("[32m COMBINATION FOUND AT : %d [0m\n", foundAt); + break; + } + } + g_array_free(g_key_combination._current_matched_combinations, FALSE);/* we free this as combination is found and we need to start fresh for next key.*/ + return foundAt; + } + else/*continue search for next key*/ + { + t = timestamp; + keyIdx++; + _source_Search_Array = g_key_combination._current_matched_combinations; + } + } + + return -1; +} diff --git a/src/e_mod_keyrouter_events.c b/src/e_mod_keyrouter_events.c index 6072e3c..4682f78 100644 --- a/src/e_mod_keyrouter_events.c +++ b/src/e_mod_keyrouter_events.c @@ -7,7 +7,8 @@ static Eina_Bool _e_keyrouter_send_key_events_press(int type, Ecore_Event_Key *e static Eina_Bool _e_keyrouter_send_key_events_release(int type, Ecore_Event_Key *ev); static Eina_Bool _e_keyrouter_send_key_event(int type, struct wl_resource *surface, struct wl_client *wc, Ecore_Event_Key *ev, Eina_Bool focused, unsigned int mode); -static Eina_Bool _e_keyrouter_send_key_events_register(int type, Ecore_Event_Key *ev); +static Eina_Bool _e_keyrouter_send_key_events_focus(int type, struct wl_resource *surface, Ecore_Event_Key *ev, struct wl_resource **delivered_surface); +static void _e_keyrouter_event_generate_key(Ecore_Event_Key *ev, int type, struct wl_client *send_surface); static Eina_Bool _e_keyrouter_is_key_grabbed(int key); static Eina_Bool _e_keyrouter_check_top_visible_window(E_Client *ec_focus, int arr_idx); @@ -22,8 +23,7 @@ _e_keyrouter_is_key_grabbed(int key) if (krt->HardKeys[key].excl_ptr || krt->HardKeys[key].or_excl_ptr || krt->HardKeys[key].top_ptr || - krt->HardKeys[key].shared_ptr || - krt->HardKeys[key].registered_ptr) + krt->HardKeys[key].shared_ptr) { return EINA_TRUE; } @@ -31,12 +31,32 @@ _e_keyrouter_is_key_grabbed(int key) return EINA_FALSE; } +static void +_e_keyrouter_event_generate_key(Ecore_Event_Key *ev, int type, struct wl_client *send_surface) +{ + Ecore_Event_Key *ev_cpy; + int len; + + KLDBG("Generate new key event! wc_send: %p(%d)\n", send_surface, e_keyrouter_util_get_pid(send_surface, NULL)); + + len = sizeof(Ecore_Event_Key) + strlen(ev->key) + strlen(ev->keyname) + ((ev->compose) ? strlen(ev->compose) : 0) + 3; + ev_cpy = calloc(1, len); + memcpy(ev_cpy, ev, len); + ev_cpy->data = send_surface; + + if (ECORE_EVENT_KEY_DOWN == type) + ecore_event_add(ECORE_EVENT_KEY_DOWN, ev_cpy, NULL, NULL); + else + ecore_event_add(ECORE_EVENT_KEY_UP, ev_cpy, NULL, NULL); +} + /* Function for checking the existing grab for a key and sending key event(s) */ Eina_Bool e_keyrouter_process_key_event(void *event, int type) { Eina_Bool res = EINA_TRUE; Ecore_Event_Key *ev = event; + struct wl_client *wc; if (!ev) goto finish; @@ -47,6 +67,15 @@ e_keyrouter_process_key_event(void *event, int type) KLDBG("data is exist send to compositor: %p\n", ev->data); goto finish; } + if (krt->playback_daemon_surface) + { + wc = wl_resource_get_client(krt->playback_daemon_surface); + if (wc) + { + _e_keyrouter_event_generate_key(ev, type, wc); + KLDBG("Sent key to playback-daemon\n"); + } + } if (krt->max_tizen_hwkeys < ev->keycode) { @@ -54,7 +83,7 @@ e_keyrouter_process_key_event(void *event, int type) goto finish; } - if ((ECORE_EVENT_KEY_DOWN == type) && (!_e_keyrouter_is_key_grabbed(ev->keycode))) + if ((ECORE_EVENT_KEY_DOWN == type) && !krt->HardKeys[ev->keycode].keycode) { KLDBG("The press key(%d) isn't a grabbable key or has not been grabbed yet !\n", ev->keycode); goto finish; @@ -67,9 +96,11 @@ e_keyrouter_process_key_event(void *event, int type) } //KLDBG("The key(%d) is going to be sent to the proper wl client(s) !\n", ev->keycode); - - if (_e_keyrouter_send_key_events(type, ev)) - res = EINA_FALSE; + /* Call process key combination to lookup for any particular combinaton */ + e_keyrouter_process_key_combination(ev->timestamp, ev->keycode, type); + KLDBG("[%s] keyname: %s, key: %s, keycode: %d\n", (type == ECORE_EVENT_KEY_DOWN) ? "KEY_PRESS" : "KEY_RELEASE", ev->keyname, ev->key, ev->keycode); + if (_e_keyrouter_send_key_events(type, ev)) + res = EINA_FALSE; finish: return res; @@ -112,6 +143,7 @@ _e_keyrouter_send_key_events_release(int type, Ecore_Event_Key *ev) } } krt->HardKeys[ev->keycode].press_ptr = NULL; + krt->isRegisterDelivery = EINA_FALSE; return ret; } @@ -122,11 +154,34 @@ _e_keyrouter_send_key_events_press(int type, Ecore_Event_Key *ev) unsigned int keycode = ev->keycode; struct wl_resource *surface_focus = NULL; E_Client *ec_focus = NULL; + struct wl_resource *delivered_surface = NULL; Eina_Bool res = EINA_TRUE; E_Keyrouter_Key_List_NodePtr key_node_data; Eina_List *l = NULL; + ec_focus = e_client_focused_get(); + surface_focus = e_keyrouter_util_get_surface_from_eclient(ec_focus); + + if (krt->isPictureOffEnabled == 1) + { + EINA_LIST_FOREACH(krt->HardKeys[keycode].pic_off_ptr, l, key_node_data) + { + if (key_node_data) + { + res = _e_keyrouter_send_key_event(type, key_node_data->surface, key_node_data->wc, ev, key_node_data->focused, TIZEN_KEYROUTER_MODE_REGISTERED); + KLINF("PICTURE OFF Mode : Key %s(%d) ===> Surface (%p) WL_Client (%p)\n", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keycode, key_node_data->surface, key_node_data->wc); + } + } + return res; + } + if (!_e_keyrouter_is_key_grabbed(ev->keycode)) + { + res = _e_keyrouter_send_key_events_focus(type, surface_focus, ev, &delivered_surface); + return res; + } + EINA_LIST_FOREACH(krt->HardKeys[keycode].excl_ptr, l, key_node_data) { if (key_node_data) @@ -155,9 +210,6 @@ _e_keyrouter_send_key_events_press(int type, Ecore_Event_Key *ev) } } - ec_focus = e_client_focused_get(); - surface_focus = e_keyrouter_util_get_surface_from_eclient(ec_focus); - // Top position grab must need a focus surface. if (surface_focus) { @@ -190,79 +242,166 @@ _e_keyrouter_send_key_events_press(int type, Ecore_Event_Key *ev) break; } } + goto need_shared; } if (krt->HardKeys[keycode].shared_ptr) { - res = _e_keyrouter_send_key_event(type, surface_focus, NULL, ev, EINA_TRUE, TIZEN_KEYROUTER_MODE_SHARED); - KLINF("SHARED [Focus client] : Key %s (%s:%d) ===> Surface (%p) (pid: %d)\n", - ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up "), ev->keyname, ev->keycode, - surface_focus, e_keyrouter_util_get_pid(NULL, surface_focus)); - e_keyrouter_add_surface_destroy_listener(surface_focus); - +need_shared: + //res = _e_keyrouter_send_key_event(type, surface_focus, NULL, ev, EINA_TRUE, TIZEN_KEYROUTER_MODE_SHARED); + res = _e_keyrouter_send_key_events_focus(type, surface_focus, ev, &delivered_surface); EINA_LIST_FOREACH(krt->HardKeys[keycode].shared_ptr, l, key_node_data) { if (key_node_data) { - if (key_node_data->surface) + if (delivered_surface && key_node_data->surface == delivered_surface) { - if (key_node_data->surface != surface_focus) - { - _e_keyrouter_send_key_event(type, key_node_data->surface, - key_node_data->wc, ev, EINA_FALSE, - TIZEN_KEYROUTER_MODE_SHARED); - KLINF("SHARED Mode : Key %s(%s:%d) ===> Surface (%p) WL_Client (%p) (pid: %d)\n", - ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode, - key_node_data->surface, key_node_data->wc, e_keyrouter_util_get_pid(key_node_data->wc, key_node_data->surface)); - } + // Check for already delivered surface + // do not deliver double events in this case. + continue; } else { - if (((surface_focus) && (key_node_data->wc != wl_resource_get_client(surface_focus))) || - (!surface_focus)) - { - _e_keyrouter_send_key_event(type, key_node_data->surface, - key_node_data->wc, ev, EINA_FALSE, - TIZEN_KEYROUTER_MODE_SHARED); - KLINF("SHARED Mode : Key %s(%s:%d) ===> Surface (%p) WL_Client (%p) (pid: %d)\n", - ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode, - key_node_data->surface, key_node_data->wc, e_keyrouter_util_get_pid(key_node_data->wc, key_node_data->surface)); - } + _e_keyrouter_send_key_event(type, key_node_data->surface, key_node_data->wc, ev, key_node_data->focused, TIZEN_KEYROUTER_MODE_SHARED); + KLINF("SHARED Mode : Key %s(%s:%d) ===> Surface (%p) WL_Client (%p) (pid: %d)\n", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode, + key_node_data->surface, key_node_data->wc, e_keyrouter_util_get_pid(key_node_data->wc, key_node_data->surface)); } } } - return res; } - if (_e_keyrouter_send_key_events_register(type, ev)) - { - return EINA_TRUE; - } - return EINA_FALSE; } static Eina_Bool -_e_keyrouter_send_key_events_register(int type, Ecore_Event_Key *ev) +_e_keyrouter_send_key_events_focus(int type, struct wl_resource *surface_focus, Ecore_Event_Key *ev, struct wl_resource **delivered_surface) { - unsigned int keycode = ev->keycode; + E_Client *ec_top = NULL, *ec_focus = NULL; + Eina_Bool below_focus = EINA_FALSE; + struct wl_resource *surface = NULL; + Eina_List* key_list = NULL; + int *key_data = NULL; + Eina_List *ll = NULL; + int deliver_invisible = 0; Eina_Bool res = EINA_TRUE; - if (!krt->HardKeys[keycode].registered_ptr) + ec_top = e_client_top_get(); + ec_focus = e_client_focused_get(); + + // loop over to next window from top of window stack + for (; ec_top != NULL; ec_top = e_client_below_get(ec_top)) { - KLDBG("This keycode is not registered\n"); - return EINA_FALSE; - } + surface = e_keyrouter_util_get_surface_from_eclient(ec_top); + if(surface == NULL) + { + // Not a valid surface. + continue; + } - res = _e_keyrouter_send_key_event(type, krt->HardKeys[keycode].registered_ptr->surface, - NULL, ev, krt->HardKeys[keycode].registered_ptr->focused, - TIZEN_KEYROUTER_MODE_REGISTERED); - KLINF("REGISTER Mode : Key %s(%s:%d) ===> Surface (%p) (pid: %d)\n", - ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode, - krt->HardKeys[keycode].registered_ptr->surface, e_keyrouter_util_get_pid(NULL, krt->HardKeys[keycode].registered_ptr->surface)); + // Check if window stack reaches to focus window + if (ec_top == ec_focus) + { + KLINF("%p is focus client & surface_focus %p. ==> %p\n", ec_top, surface_focus, surface); + below_focus = EINA_TRUE; + } - return res; + // Check for FORCE DELIVER to INVISIBLE WINDOW + if (deliver_invisible && IsInvisibleGetWindow(surface)) + { + res = _e_keyrouter_send_key_event(type, surface, NULL, ev, EINA_TRUE, TIZEN_KEYROUTER_MODE_REGISTERED); + KLINF("FORCE DELIVER : Key %s(%s:%d) ===> Surface (%p) (pid: %d)\n", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode, + surface, e_keyrouter_util_get_pid(NULL, surface)); + *delivered_surface = surface; + return res; + } + + // Check for visible window first + // return if not visible + if (ec_top->visibility.obscured == E_VISIBILITY_FULLY_OBSCURED || ec_top->visibility.obscured == E_VISIBILITY_UNKNOWN) + { + continue; + } + + // Set key Event Delivery for INVISIBLE WINDOW + if (IsInvisibleSetWindow(surface)) + { + deliver_invisible = 1; + } + + if (IsNoneKeyRegisterWindow(surface)) + { + // Registered None property is set for this surface + // No event will be delivered to this surface. + KLINF("Surface(%p) is a none register window.\n", surface); + continue; + } + + if (e_keyrouter_is_registered_window(surface)) + { + // get the key list and deliver events if it has registered for that key + // Write a function to get the key list for register window. + key_list = _e_keyrouter_registered_window_key_list(surface); + if (key_list) + { + EINA_LIST_FOREACH(key_list, ll, key_data) + { + if(!key_data) continue; + + if(*key_data == ev->keycode) + { + res = _e_keyrouter_send_key_event(type, surface, NULL, ev, EINA_TRUE, TIZEN_KEYROUTER_MODE_REGISTERED); + KLINF("REGISTER Mode : Key %s(%s:%d) ===> Surface (%p) (pid: %d)\n", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode, + surface, e_keyrouter_util_get_pid(NULL, surface)); + *delivered_surface = surface; + krt->isRegisterDelivery = EINA_TRUE; + return res; + } + } + } + else + { + KLDBG("Key_list is Null for registered surface %p\n", surface); + } + } + + if (surface != surface_focus) + { + if (below_focus == EINA_FALSE) continue; + + // Deliver to below Non Registered window + else if (!e_keyrouter_is_registered_window(surface)) + { + res = _e_keyrouter_send_key_event(type, surface, NULL, ev, EINA_TRUE, TIZEN_KEYROUTER_MODE_SHARED); + KLINF("NOT REGISTER : Key %s(%s:%d) ===> Surface (%p) (pid: %d)\n", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode, + surface, e_keyrouter_util_get_pid(NULL, surface)); + *delivered_surface = surface; + return res; + } + else continue; + } + else + { + // Deliver to Focus if Non Registered window + if (!e_keyrouter_is_registered_window(surface)) + { + res = _e_keyrouter_send_key_event(type, surface, NULL,ev, EINA_TRUE, TIZEN_KEYROUTER_MODE_SHARED); + KLINF("FOCUS : Key %s(%s:%d) ===> Surface (%p) (pid: %d)\n", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode, + surface, e_keyrouter_util_get_pid(NULL, surface)); + *delivered_surface = surface; + return res; + } + else continue; + } + } + + KLINF("Couldnt Deliver key:(%s:%d) to any window. Focused Surface: %p\n", ev->keyname, ev->keycode, surface_focus); + return res; } static Eina_Bool @@ -314,8 +453,6 @@ static Eina_Bool _e_keyrouter_send_key_event(int type, struct wl_resource *surface, struct wl_client *wc, Ecore_Event_Key *ev, Eina_Bool focused, unsigned int mode) { struct wl_client *wc_send; - Ecore_Event_Key *ev_cpy; - int len; if (surface == NULL) { @@ -356,17 +493,7 @@ _e_keyrouter_send_key_event(int type, struct wl_resource *surface, struct wl_cli if (focused == EINA_TRUE) return EINA_FALSE; - KLDBG("Generate new key event! wc_send: %p(%d)\n", wc_send, e_keyrouter_util_get_pid(wc_send, NULL)); - - len = sizeof(Ecore_Event_Key) + strlen(ev->key) + strlen(ev->keyname) + ((ev->compose) ? strlen(ev->compose) : 0) + 3; - ev_cpy = calloc(1, len); - memcpy(ev_cpy, ev, len); - ev_cpy->data = wc_send; - - if (ECORE_EVENT_KEY_DOWN == type) - ecore_event_add(ECORE_EVENT_KEY_DOWN, ev_cpy, NULL, NULL); - else - ecore_event_add(ECORE_EVENT_KEY_UP, ev_cpy, NULL, NULL); + _e_keyrouter_event_generate_key(ev, type, wc_send); return EINA_TRUE; } diff --git a/src/e_mod_keyrouter_list.c b/src/e_mod_keyrouter_list.c index fe68890..4c38454 100644 --- a/src/e_mod_keyrouter_list.c +++ b/src/e_mod_keyrouter_list.c @@ -86,7 +86,9 @@ _e_keyrouter_find_duplicated_client(struct wl_resource *surface, struct wl_clien case TIZEN_KEYROUTER_MODE_PRESSED: keylist_ptr = krt->HardKeys[key].press_ptr; break; - + case TIZEN_KEYROUTER_MODE_PICTURE_OFF: + keylist_ptr = krt->HardKeys[key].pic_off_ptr; + break; default: KLWRN("Unknown key(%d) and grab mode(%d)\n", key, mode); return TIZEN_KEYROUTER_ERROR_INVALID_MODE; @@ -185,7 +187,9 @@ e_keyrouter_prepend_to_keylist(struct wl_resource *surface, struct wl_client *wc case TIZEN_KEYROUTER_MODE_PRESSED: krt->HardKeys[key].press_ptr = eina_list_prepend(krt->HardKeys[key].press_ptr, new_keyptr); break; - + case TIZEN_KEYROUTER_MODE_PICTURE_OFF: + krt->HardKeys[key].pic_off_ptr = eina_list_prepend(krt->HardKeys[key].pic_off_ptr, new_keyptr); + break; default: KLWRN("Unknown key(%d) and grab mode(%d)\n", key, mode); E_FREE(new_keyptr); @@ -361,14 +365,55 @@ e_keyrouter_remove_client_from_list(struct wl_resource *surface, struct wl_clien KLINF("Remove a Pressed key(%d) by wc(%p)\n", i, wc); } } + EINA_LIST_FOREACH_SAFE(krt->HardKeys[i].pic_off_ptr, l, l_next, key_node_data) + { + if (!key_node_data) continue; + if (surface) + { + krt->HardKeys[i].pic_off_ptr = eina_list_remove_list(krt->HardKeys[i].pic_off_ptr, l); + E_FREE(key_node_data); + } + else if ( wc == key_node_data->wc) + { + krt->HardKeys[i].pic_off_ptr = eina_list_remove_list(krt->HardKeys[i].pic_off_ptr, l); + E_FREE(key_node_data); + } + } } _e_keyrouter_remove_registered_surface_in_list(surface); } +Eina_Bool +e_keyrouter_find_key_in_register_list(uint32_t key) +{ + E_Keyrouter_Registered_Window_Info* rwin_info = NULL; + int *key_data = NULL; + Eina_List *l = NULL, *ll = NULL; + + EINA_LIST_FOREACH(krt->registered_window_list, l, rwin_info) + { + if (!rwin_info) continue; + EINA_LIST_FOREACH(rwin_info->keys, ll, key_data) + { + if(*key_data == key) + { + KLDBG("Find %d key by register surface %p\n", key, rwin_info->surface); + return EINA_TRUE; + } + } + } + + return EINA_FALSE; +} + int e_keyrouter_find_key_in_list(struct wl_resource *surface, struct wl_client *wc, uint32_t key) { + E_Keyrouter_Registered_Window_Info* rwin_info = NULL; + int *key_data = NULL; + Eina_List *l = NULL, *ll = NULL; + int mode = TIZEN_KEYROUTER_MODE_NONE; Eina_Bool found = EINA_FALSE; @@ -388,6 +433,22 @@ e_keyrouter_find_key_in_list(struct wl_resource *surface, struct wl_client *wc, found = _e_keyrouter_find_key_in_list(surface, wc, key, mode); if (found) goto finish; + EINA_LIST_FOREACH(krt->registered_window_list, l, rwin_info) + { + if (rwin_info->surface == surface) + { + EINA_LIST_FOREACH(rwin_info->keys, ll, key_data) + { + if(*key_data == key) + { + KLDBG("Find %d key grabbed by (surface: %p, in %s mode\n", key, surface, "TIZEN_KEYROUTER_MODE_REGISTERED"); + return TIZEN_KEYROUTER_MODE_REGISTERED; + } + } + } + } + + KLDBG("%d key is not grabbed by (surface: %p, wl_client: %p)\n", key, surface, wc); return TIZEN_KEYROUTER_MODE_NONE; finish: @@ -511,6 +572,7 @@ e_keyrouter_unset_keyregister(struct wl_resource *surface, struct wl_client *cli Eina_List *l, *ll, *ll_next; E_Keyrouter_Registered_Window_Info *data; int *ddata; + Eina_List *key_list = NULL; _e_keyrouter_clean_register_list(); @@ -533,6 +595,15 @@ e_keyrouter_unset_keyregister(struct wl_resource *surface, struct wl_client *cli } } + // Remove the surface from Registry list if all registered keys were removed. + key_list = _e_keyrouter_registered_window_key_list(surface); + + if (!key_list) + { + KLDBG("Removing %p surface from register list, as NULL key list \n", surface); + _e_keyrouter_remove_registered_surface_in_list(surface); + } + _e_keyrouter_build_register_list(); KLDBG("Succeed to set keyregister info surface: %p, client: %p key: %d\n", @@ -640,6 +711,23 @@ e_keyrouter_is_registered_window(struct wl_resource *surface) return EINA_FALSE; } +Eina_List* +_e_keyrouter_registered_window_key_list(struct wl_resource *surface) +{ + Eina_List *l = NULL; + E_Keyrouter_Registered_Window_Info *data = NULL; + + EINA_LIST_FOREACH(krt->registered_window_list, l, data) + { + if (data->surface == surface) + { + return data->keys; + } + } + return NULL; +} + + void e_keyrouter_clear_registered_window(void) { diff --git a/src/e_mod_main_wl.c b/src/e_mod_main_wl.c index 3df7f11..3e41088 100644 --- a/src/e_mod_main_wl.c +++ b/src/e_mod_main_wl.c @@ -1,6 +1,11 @@ #define E_COMP_WL #include "e_mod_main_wl.h" #include +#include +#include +#include + +#define KRT_IPD_INPUT_CONFIG 444 E_KeyrouterPtr krt = NULL; E_API E_Module_Api e_modapi = { E_MODULE_API_VERSION, "Keyrouter Module of Window Manager" }; @@ -19,7 +24,8 @@ static void _e_keyrouter_wl_surface_cb_destroy(struct wl_listener *l, void *data static int _e_keyrouter_keygrab_set(struct wl_client *client, struct wl_resource *surface, uint32_t key, uint32_t mode); static int _e_keyrouter_keygrab_unset(struct wl_client *client, struct wl_resource *surface, uint32_t key); - +static Eina_Bool _e_keyrouter_cb_idler(void *data); +static void _e_keyrouter_cb_power_change(device_callback_e type, void* value, void* user_data); #ifdef ENABLE_CYNARA static void _e_keyrouter_util_cynara_log(const char *func_name, int err); static Eina_Bool _e_keyrouter_util_do_privilege_check(struct wl_client *client, int socket_fd, uint32_t mode, uint32_t keycode); @@ -52,9 +58,10 @@ _e_keyrouter_keygrab_set(struct wl_client *client, struct wl_resource *surface, if (!surface) { /* Regarding topmost mode, a client must request to grab a key with a valid surface. */ - if (mode == TIZEN_KEYROUTER_MODE_TOPMOST) + if (mode == TIZEN_KEYROUTER_MODE_TOPMOST || + mode == TIZEN_KEYROUTER_MODE_REGISTERED) { - KLWRN("Invalid surface for TOPMOST grab mode ! (key=%d, mode=%d)\n", key, mode); + KLWRN("Invalid surface for %d grab mode ! (key=%d)\n", mode, key); return TIZEN_KEYROUTER_ERROR_INVALID_SURFACE; } @@ -198,9 +205,12 @@ _e_keyrouter_cb_keygrab_set_list(struct wl_client *client, struct wl_resource *r /* FIX ME: Which way is effectively to notify invalid pair to client */ KLWRN("Invalid keycode and grab mode pair. Check arguments in a list\n"); grab_result = wl_array_add(&grab_result_list, sizeof(E_Keyrouter_Grab_Result)); - grab_result->request_data.key = 0; - grab_result->request_data.mode = 0; - grab_result->err = TIZEN_KEYROUTER_ERROR_INVALID_ARRAY; + if (grab_result) + { + grab_result->request_data.key = 0; + grab_result->request_data.mode = 0; + grab_result->err = TIZEN_KEYROUTER_ERROR_INVALID_ARRAY; + } goto send_notify; } @@ -253,6 +263,252 @@ _e_keyrouter_cb_keygrab_unset_list(struct wl_client *client, struct wl_resource wl_array_release(&grab_result_list); } +static void +_e_keyrouter_cb_get_keyregister_status(struct wl_client *client, struct wl_resource *resource, uint32_t key) +{ + (void) client; + (void) key; + + Eina_Bool res = EINA_FALSE; + + if (krt->isRegisterDelivery) + { + res = EINA_TRUE; + } + + tizen_keyrouter_send_keyregister_notify(resource, (int)res); +} + +static void +_e_keyrouter_cb_set_input_config(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, uint32_t config_mode, uint32_t value) +{ + Eina_Bool res = EINA_TRUE; + KLINF("Given Surface(%p) for mode %d with value = %d \n", surface, config_mode, value); + + if (surface == NULL && config_mode != TIZEN_KEYROUTER_CONFIG_MODE_PICTURE_OFF) + { + KLWRN("Error Surface is NULL \n"); + res = EINA_FALSE; + goto send_input_config_notify; + } + + switch (config_mode) + { + case TIZEN_KEYROUTER_CONFIG_MODE_INVISIBLE_SET: + if (value) + { + krt->invisible_set_window_list= eina_list_append(krt->invisible_set_window_list, surface); + } + else + { + krt->invisible_set_window_list= eina_list_remove(krt->invisible_set_window_list, surface); + } + break; + + case KRT_IPD_INPUT_CONFIG: + krt->playback_daemon_surface = surface; + KLINF("Registered playback daemon surface: %p",surface); + break; + + case TIZEN_KEYROUTER_CONFIG_MODE_INVISIBLE_GET: + if (value) + { + krt->invisible_get_window_list= eina_list_append(krt->invisible_get_window_list, surface); + } + else + { + krt->invisible_get_window_list= eina_list_remove(krt->invisible_get_window_list, surface); + } + break; + + case TIZEN_KEYROUTER_CONFIG_MODE_NUM_KEY_FOCUS: + // to do ; + break; + + case TIZEN_KEYROUTER_CONFIG_MODE_PICTURE_OFF: + res = e_keyrouter_prepend_to_keylist(surface, surface ? NULL : client, value, TIZEN_KEYROUTER_MODE_PICTURE_OFF, EINA_FALSE); + /* As surface/client destroy listener got added in e_keyrouter_prepend_to_keylist() function already */ + value = 0; + break; + + default: + KLWRN("Wrong mode requested: %d \n", config_mode); + res= EINA_FALSE; + goto send_input_config_notify; + } + + if (value) + { + KLDBG("Add a surface(%p) destory listener\n", surface); + e_keyrouter_add_surface_destroy_listener(surface); + } +send_input_config_notify: + tizen_keyrouter_send_set_input_config_notify(resource, (int)res); +} + +/* tizen_keyrouter check if given surface in register none key list */ +Eina_Bool +IsNoneKeyRegisterWindow(struct wl_resource *surface) +{ + struct wl_resource *surface_ldata = NULL; + Eina_List *l = NULL, *l_next = NULL; + + EINA_LIST_FOREACH_SAFE (krt->registered_none_key_window_list, l, l_next, surface_ldata) + { + if (surface_ldata == surface) + { + KLDBG("Given surface(%p) is in NoneKeyRegisterWindow \n", surface); + return EINA_TRUE; + } + } + return EINA_FALSE; +} + +/* tizen_keyrouter check if given surface in register invisible set list */ +Eina_Bool +IsInvisibleSetWindow(struct wl_resource *surface) +{ + struct wl_resource *surface_ldata = NULL; + Eina_List *l = NULL, *l_next = NULL; + + EINA_LIST_FOREACH_SAFE(krt->invisible_set_window_list, l, l_next, surface_ldata) + { + if (surface_ldata == surface) + { + return EINA_TRUE; + } + } + return EINA_FALSE; +} + +/* tizen_keyrouter check if given surface in register invisible get list */ +Eina_Bool +IsInvisibleGetWindow(struct wl_resource *surface) +{ + struct wl_resource *surface_ldata = NULL; + Eina_List *l = NULL, *l_next = NULL; + + EINA_LIST_FOREACH_SAFE(krt->invisible_get_window_list, l, l_next, surface_ldata) + { + if (surface_ldata == surface) + { + return EINA_TRUE; + } + } + return EINA_FALSE; +} + +static void +_e_keyrouter_cb_set_register_none_key(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, uint32_t data) +{ + (void) client; + + // Register None key set/get + krt->register_none_key = data; + if (krt->register_none_key) + { + krt->registered_none_key_window_list = eina_list_append(krt->registered_none_key_window_list, surface); + if (surface) + { + e_keyrouter_add_surface_destroy_listener(surface); + /* TODO: if failed add surface_destory_listener, remove keygrabs */ + } + } + else + { + krt->registered_none_key_window_list = eina_list_remove(krt->registered_none_key_window_list, surface); + } + + KLDBG("Set Registered None Key called on surface (%p) with data (%d)\n", surface, krt->register_none_key); + tizen_keyrouter_send_set_register_none_key_notify(resource, NULL, krt->register_none_key); +} + +static void +_e_keyrouter_cb_keygrab_get_list(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface) +{ + E_Keyrouter_Key_List_NodePtr key_node_data = NULL; + struct wl_array grab_result_list = {0,}; + E_Keyrouter_Grab_Result *grab_result = NULL; + E_Keyrouter_Registered_Window_Info *rwin_info = NULL; + Eina_List *l = NULL, *ll = NULL, *l_next = NULL; + int *key_data; + int i; + + wl_array_init(&grab_result_list); + + for (i = 0; i < krt->max_tizen_hwkeys; i++) + { + if (0 == krt->HardKeys[i].keycode) continue; + + EINA_LIST_FOREACH_SAFE(krt->HardKeys[i].excl_ptr, l, l_next, key_node_data) + { + if (surface == key_node_data->surface) + { + grab_result = wl_array_add(&grab_result_list, sizeof(E_Keyrouter_Grab_Result)); + if (grab_result) + { + grab_result->request_data.key = i; + grab_result->request_data.mode = TIZEN_KEYROUTER_MODE_EXCLUSIVE; + } + } + } + EINA_LIST_FOREACH_SAFE(krt->HardKeys[i].or_excl_ptr, l, l_next, key_node_data) + { + if (surface == key_node_data->surface) + { + grab_result = wl_array_add(&grab_result_list, sizeof(E_Keyrouter_Grab_Result)); + if (grab_result) + { + grab_result->request_data.key = i; + grab_result->request_data.mode = TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE; + } + } + } + EINA_LIST_FOREACH_SAFE(krt->HardKeys[i].top_ptr, l, l_next, key_node_data) + { + if (surface == key_node_data->surface) + { + grab_result = wl_array_add(&grab_result_list, sizeof(E_Keyrouter_Grab_Result)); + if (grab_result) + { + grab_result->request_data.key = i; + grab_result->request_data.mode = TIZEN_KEYROUTER_MODE_TOPMOST; + } + } + } + EINA_LIST_FOREACH_SAFE(krt->HardKeys[i].shared_ptr, l, l_next, key_node_data) + { + if (surface == key_node_data->surface) + { + grab_result = wl_array_add(&grab_result_list, sizeof(E_Keyrouter_Grab_Result)); + if (grab_result) + { + grab_result->request_data.key = i; + grab_result->request_data.mode = TIZEN_KEYROUTER_MODE_SHARED; + } + } + } + } + // handle register mode here + EINA_LIST_FOREACH(krt->registered_window_list, l, rwin_info) + { + if (rwin_info->surface == surface) + { + EINA_LIST_FOREACH(rwin_info->keys, ll, key_data) + { + grab_result = wl_array_add(&grab_result_list, sizeof(E_Keyrouter_Grab_Result)); + if (grab_result) + { + grab_result->request_data.key = *key_data; + grab_result->request_data.mode = TIZEN_KEYROUTER_MODE_REGISTERED; + } + } + } + } + + tizen_keyrouter_send_getgrab_notify_list(resource, surface, &grab_result_list); + wl_array_release(&grab_result_list); +} /* Function for registering wl_client destroy listener */ int @@ -332,7 +588,11 @@ static const struct tizen_keyrouter_interface _e_keyrouter_implementation = { _e_keyrouter_cb_keygrab_unset, _e_keyrouter_cb_get_keygrab_status, _e_keyrouter_cb_keygrab_set_list, - _e_keyrouter_cb_keygrab_unset_list + _e_keyrouter_cb_keygrab_unset_list, + _e_keyrouter_cb_keygrab_get_list, + _e_keyrouter_cb_set_register_none_key, + _e_keyrouter_cb_get_keyregister_status, + _e_keyrouter_cb_set_input_config }; /* tizen_keyrouter global object destroy function */ @@ -373,12 +633,57 @@ _event_filter(void *data, void *loop_data EINA_UNUSED, int type, void *event) /* Filter only for key down/up event */ if (ECORE_EVENT_KEY_DOWN == type || ECORE_EVENT_KEY_UP == type) { + if (ECORE_EVENT_KEY_DOWN == type) + { + TRACE_INPUT_BEGIN(event_filter:KEY_PRESS); + TRACE_INPUT_END(); + } + else if (ECORE_EVENT_KEY_UP == type) + { + TRACE_INPUT_BEGIN(event_filter:KEY_RELEASE); + TRACE_INPUT_END(); + } return e_keyrouter_process_key_event(event, type); } return EINA_TRUE; } +static void +_e_keyrouter_cb_power_change(device_callback_e type, void* value, void* user_data) +{ + if (type != DEVICE_CALLBACK_DISPLAY_STATE) + { + KLWRN("type is not DISPLAY_STATE"); + return; + } + + display_state_e state = (display_state_e)value; + switch (state) + { + case DISPLAY_STATE_SCREEN_OFF: + krt->isPictureOffEnabled = 1; + break; + case DISPLAY_STATE_NORMAL: + krt->isPictureOffEnabled = 0; + break; + case DISPLAY_STATE_SCREEN_DIM: + krt->isPictureOffEnabled = 0; + break; + default: + krt->isPictureOffEnabled = 0; + break; + } + KLDBG("Picture off flag changed to %d \n", krt->isPictureOffEnabled); +} + +static Eina_Bool _e_keyrouter_cb_idler(void *data) +{ + device_add_callback(DEVICE_CALLBACK_DISPLAY_STATE,_e_keyrouter_cb_power_change,NULL); + return ECORE_CALLBACK_CANCEL; +} + + static E_Keyrouter_Config_Data * _e_keyrouter_init(E_Module *m) { @@ -411,12 +716,16 @@ _e_keyrouter_init(E_Module *m) EINA_SAFETY_ON_NULL_GOTO(kconfig->conf, err); krt->conf = kconfig; + e_keyrouter_key_combination_init(); + /* Get keyname and keycode pair from Tizen Key Layout file */ res = _e_keyrouter_query_tizen_key_table(); EINA_SAFETY_ON_FALSE_GOTO(res, err); /* Add filtering mechanism */ krt->ef_handler = ecore_event_filter_add(NULL, _event_filter, NULL, NULL); + //ecore handler add for power callback registration + ecore_idle_enterer_add(_e_keyrouter_cb_idler, NULL); _e_keyrouter_init_handlers(); krt->global = wl_global_create(e_comp_wl->wl.disp, &tizen_keyrouter_interface, 1, krt, _e_keyrouter_cb_bind); @@ -633,7 +942,7 @@ _e_keyrouter_wl_client_cb_destroy(struct wl_listener *l, void *data) static void _e_keyrouter_wl_surface_cb_destroy(struct wl_listener *l, void *data) { - struct wl_resource *surface = data; + struct wl_resource *surface = (struct wl_resource *)data; KLDBG("Listener(%p) called: surface: %p is died\n", l, surface); e_keyrouter_remove_client_from_list(surface, NULL); @@ -642,6 +951,14 @@ _e_keyrouter_wl_surface_cb_destroy(struct wl_listener *l, void *data) l = NULL; krt->grab_surface_list = eina_list_remove(krt->grab_surface_list, surface); + krt->registered_none_key_window_list = eina_list_remove(krt->registered_none_key_window_list, surface); + krt->invisible_set_window_list= eina_list_remove(krt->invisible_set_window_list, surface); + krt->invisible_get_window_list= eina_list_remove(krt->invisible_get_window_list, surface); + if (surface == krt->playback_daemon_surface) + { + krt->playback_daemon_surface = NULL; + KLDBG("playback daemon surface destroyed!"); + } } #ifdef ENABLE_CYNARA diff --git a/src/e_mod_main_wl.h b/src/e_mod_main_wl.h index 3f252ed..c5de001 100644 --- a/src/e_mod_main_wl.h +++ b/src/e_mod_main_wl.h @@ -52,6 +52,9 @@ typedef struct _E_Keyrouter_Conf_Edd E_Keyrouter_Conf_Edd; typedef struct _E_Keyrouter_Config_Data E_Keyrouter_Config_Data; #define TIZEN_KEYROUTER_MODE_PRESSED TIZEN_KEYROUTER_MODE_REGISTERED+1 +#define TIZEN_KEYROUTER_MODE_PICTURE_OFF TIZEN_KEYROUTER_MODE_REGISTERED+2 + +typedef unsigned long Time; extern E_KeyrouterPtr krt; @@ -104,6 +107,7 @@ struct _E_Keyrouter_Grabbed_Key Eina_List *shared_ptr; Eina_List *press_ptr; E_Keyrouter_Key_List_Node *registered_ptr; + Eina_List *pic_off_ptr; }; struct _E_Keyrouter @@ -123,9 +127,16 @@ struct _E_Keyrouter Eina_Bool isWindowStackChanged; int numTizenHWKeys; int max_tizen_hwkeys; + int register_none_key; + Eina_List *registered_none_key_window_list; + Eina_List *invisible_set_window_list; + Eina_List *invisible_get_window_list; + struct wl_resource * playback_daemon_surface; #ifdef ENABLE_CYNARA cynara *p_cynara; #endif + int isPictureOffEnabled; + Eina_Bool isRegisterDelivery; }; struct _E_Keyrouter_Grab_Request { @@ -150,6 +161,7 @@ int e_keyrouter_prepend_to_keylist(struct wl_resource *surface, struct wl_client void e_keyrouter_find_and_remove_client_from_list(struct wl_resource *surface, struct wl_client *wc, uint32_t key, uint32_t mode); void e_keyrouter_remove_client_from_list(struct wl_resource *surface, struct wl_client *wc); int e_keyrouter_find_key_in_list(struct wl_resource *surface, struct wl_client *wc, uint32_t key); +Eina_Bool e_keyrouter_find_key_in_register_list(uint32_t key); int e_keyrouter_add_client_destroy_listener(struct wl_client *client); int e_keyrouter_add_surface_destroy_listener(struct wl_resource *surface); @@ -160,11 +172,18 @@ int e_keyrouter_set_keyregister(struct wl_client *client, struct wl_resource *su int e_keyrouter_unset_keyregister(struct wl_resource *surface, struct wl_client *client, uint32_t key); Eina_Bool e_keyrouter_is_registered_window(struct wl_resource *surface); void e_keyrouter_clear_registered_window(void); +Eina_List* _e_keyrouter_registered_window_key_list(struct wl_resource *surface); +Eina_Bool IsNoneKeyRegisterWindow(struct wl_resource *surface); +Eina_Bool IsInvisibleSetWindow(struct wl_resource *surface); +Eina_Bool IsInvisibleGetWindow(struct wl_resource *surface); + struct wl_resource *e_keyrouter_util_get_surface_from_eclient(E_Client *client); int e_keyrouter_util_get_pid(struct wl_client *client, struct wl_resource *surface); void e_keyrouter_conf_init(E_Keyrouter_Config_Data *kconfig); void e_keyrouter_conf_deinit(E_Keyrouter_Config_Data *kconfig); - +void e_keyrouter_key_combination_init(); +void e_keyrouter_process_key_combination(Time cur_time, int keycode, int state); +int e_keyrouter_cb_picture_off(const int option, void *data); #endif diff --git a/src/ini.c b/src/ini.c new file mode 100644 index 0000000..a4e79c3 --- /dev/null +++ b/src/ini.c @@ -0,0 +1,185 @@ +/* inih -- simple .INI file parser + +inih is released under the New BSD license (see LICENSE.txt). Go to the project +home page for more info: + + +*/ + +#include +#include +#include + +#include "ini.h" +#include "errno.h" + +#if !INI_USE_STACK +#include +#endif + +#define MAX_SECTION 50 +#define MAX_NAME 50 + +static char * +rstrip(char* s) +{ + char* p = s + strlen(s); + while (p > s && isspace((unsigned char)(*--p))) + *p = '\0'; + return s; +} + +static char * +lskip(char* s) +{ + while (*s && isspace((unsigned char)(*s))) + s++; + return (char*)s; +} + +static char * +find_char_or_comment(char* s, char c) +{ + int was_whitespace = 0; + while (*s && *s != c && !(was_whitespace && *s == ';')) + { + was_whitespace = isspace((unsigned char)(*s)); + s++; + } + return (char*)s; +} + +static char * +strncpy0(char* dest, const char* src, size_t size) +{ + strncpy(dest, src, size); + dest[size - 1] = '\0'; + return dest; +} + +int +ini_parse_file(FILE* file, + int (*handler)(void*, const char*, const char*, const char*), + void* user) +{ +#if INI_USE_STACK + char line[INI_MAX_LINE]; +#else + char* line; +#endif + char section[MAX_SECTION] = ""; + char prev_name[MAX_NAME] = ""; + + char* start; + char* end; + char* name; + char* value; + int lineno = 0; + int error = 0; + +#if !INI_USE_STACK + line = (char*)malloc(INI_MAX_LINE); + if (!line) + { + return -2; + } +#endif + + while (fgets(line, INI_MAX_LINE, file) != NULL) + { + lineno++; + + start = line; +#if INI_ALLOW_BOM + if (lineno == 1 && (unsigned char)start[0] == 0xEF && + (unsigned char)start[1] == 0xBB && + (unsigned char)start[2] == 0xBF) + { + start += 3; + } +#endif + start = lskip(rstrip(start)); + + if (*start == ';' || *start == '#') + { + ; + } +#if INI_ALLOW_MULTILINE + else if (*prev_name && *start && start > line) + { + if (!handler(user, section, prev_name, start) && !error) + error = lineno; + } +#endif + else if (*start == '[') + { + end = find_char_or_comment(start + 1, ']'); + if (*end == ']') + { + *end = '\0'; + strncpy0(section, start + 1, sizeof(section)); + *prev_name = '\0'; + } + else if (!error) + { + error = lineno; + } + } + else if (*start && *start != ';') + { + end = find_char_or_comment(start, '='); + if (*end != '=') + { + end = find_char_or_comment(start, ':'); + } + if (*end == '=' || *end == ':') + { + *end = '\0'; + name = rstrip(start); + value = lskip(end + 1); + end = find_char_or_comment(value, '\0'); + + if (*end == ';') + *end = '\0'; + rstrip(value); + + strncpy0(prev_name, name, sizeof(prev_name)); + + if (!handler(user, section, name, value) && !error) + error = lineno; + } + else if (!error) + { + error = lineno; + } + } + +#if INI_STOP_ON_FIRST_ERROR + if (error) + break; +#endif + } + +#if !INI_USE_STACK + free(line); +#endif + + return error; +} + + +int +ini_parse(const char* filename, + int (*handler)(void*, const char*, const char*, const char*), + void* user) +{ + FILE* file; + int error; + + file = fopen(filename, "r"); + if (!file) + return -1; + error = ini_parse_file(file, handler, user); + fclose(file); + return error; +} diff --git a/src/ini.h b/src/ini.h new file mode 100644 index 0000000..0411663 --- /dev/null +++ b/src/ini.h @@ -0,0 +1,52 @@ +/* inih -- simple .INI file parser + +inih is released under the New BSD license (see LICENSE.txt). Go to the project +home page for more info: + + +*/ + +#ifndef __INI_H__ +#define __INI_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +int ini_parse(const char* filename, + int (*handler)(void* user, const char* section, + const char* name, const char* value), + void* user); + +int ini_parse_file(FILE* file, + int (*handler)(void* user, const char* section, + const char* name, const char* value), + void* user); + +#ifndef INI_ALLOW_MULTILINE +#define INI_ALLOW_MULTILINE 1 +#endif + +#ifndef INI_ALLOW_BOM +#define INI_ALLOW_BOM 1 +#endif + +#ifndef INI_USE_STACK +#define INI_USE_STACK 1 +#endif + +#ifndef INI_STOP_ON_FIRST_ERROR +#define INI_STOP_ON_FIRST_ERROR 0 +#endif + +#ifndef INI_MAX_LINE +#define INI_MAX_LINE 200 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __INI_H__ */