--- /dev/null
+; 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
#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
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)
# 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)
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
%if %{with wayland}
%configure --prefix=/usr \
--enable-wayland-only \
- --enable-cynara
+ --enable-cynara \
+ TZ_SYS_RO_APP=%{TZ_SYS_RO_APP}
%endif
make
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}
%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
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
--- /dev/null
+/*\r
+ * @file e_mod_keyrouter_combination.c\r
+ * @brief Implementation of e_mod_keyrouter_combination.c\r
+ * @author Shubham Shrivastav shubham.sh@samsung.com\r
+ * @date 25th Feb 2016\r
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#define E_COMP_WL\r
+#include "e.h"\r
+#include "e_mod_main_wl.h"\r
+#include <dbus/dbus-glib.h>\r
+#include <dbus/dbus.h>\r
+#include "ini.h"\r
+\r
+#define MAX_LEN 64\r
+#define DBUS_PATH "/com/burtonini/dbus/ping"\r
+#define DBUS_IFACE "keyrouter.dbus.Signal"\r
+#define DBUS_MSG_NAME "KEY_COMBINATION"\r
+#define COMBINATION_TIME_OUT 4000\r
+#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0\r
+\r
+typedef unsigned long Time;\r
+typedef struct _DbusConf\r
+{\r
+ char path[MAX_LEN];\r
+ char interface[MAX_LEN];\r
+ char msg[MAX_LEN];\r
+} DbusConf;\r
+typedef struct _KeyCombination\r
+{\r
+ DBusConnection * keyrouter_dbus_conn;\r
+ DbusConf dbusconf;\r
+ DBusError DBus_error;\r
+ char combinationFilePath[MAX_LEN];\r
+ GArray* _master_combinations;\r
+ GArray* _current_matched_combinations;\r
+ Time combination_timeout;\r
+} KeyCombination;\r
+\r
+static int keyCombinationInitialize = 0;\r
+KeyCombination g_key_combination;\r
+\r
+static void _e_keyrouter_dbus_connection_init();\r
+static int _e_keyrouter_search_key_combination(int keycode, Time timestamp);\r
+static int _e_keyrouter_send_dbus_message(DBusConnection *bus, int Input);\r
+static char * _e_keyrouter_substring(char *string, int position);\r
+static int _e_keyrouter_parse_ini_config(void* user, const char* section, const char* name, const char* value);\r
+\r
+static void\r
+_e_keyrouter_dbus_connection_init()\r
+{\r
+ DBusError dBus_error;\r
+\r
+ KLINF("_e_keyrouter_dbus_connection_init() \n");\r
+\r
+ dbus_error_init(&dBus_error);\r
+ g_key_combination.keyrouter_dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dBus_error);\r
+\r
+ if (dbus_error_is_set(&dBus_error))\r
+ {\r
+ KLWRN("[DBUS-ERROR] %s \n",dBus_error.message);\r
+ dbus_error_free(&dBus_error);\r
+ }\r
+\r
+ if (!g_key_combination.keyrouter_dbus_conn)\r
+ {\r
+ KLWRN("[DBUS-CONNECTION-FAIL] DBUS connection is failed \n");\r
+ }\r
+}\r
+\r
+void\r
+e_keyrouter_key_combination_init()\r
+{\r
+ memset(&g_key_combination, 0, sizeof(g_key_combination));\r
+ g_key_combination.keyrouter_dbus_conn = NULL;\r
+ snprintf(g_key_combination.dbusconf.path, strlen(DBUS_PATH)+1, DBUS_PATH);\r
+ snprintf(g_key_combination.dbusconf.interface, strlen(DBUS_IFACE)+1, DBUS_IFACE);\r
+ snprintf(g_key_combination.dbusconf.msg, strlen(DBUS_MSG_NAME)+1, DBUS_MSG_NAME);\r
+ snprintf(g_key_combination.combinationFilePath, strlen(COMBINATION_FILE_PATH)+1, COMBINATION_FILE_PATH);\r
+\r
+ g_key_combination._master_combinations = g_array_new(FALSE, FALSE, sizeof(GArray*));\r
+ if (ini_parse((const char *) g_key_combination.combinationFilePath, _e_keyrouter_parse_ini_config, g_key_combination._master_combinations) < 0)\r
+ {\r
+ KLWRN("Can't load %s file\n", g_key_combination.combinationFilePath);\r
+ }\r
+\r
+ g_key_combination.combination_timeout = COMBINATION_TIME_OUT;\r
+ _e_keyrouter_dbus_connection_init();\r
+ keyCombinationInitialize = 1;\r
+}\r
+\r
+static char *\r
+_e_keyrouter_substring(char *string, int position)\r
+{\r
+ char *pointer;\r
+ int c;\r
+\r
+ for (c = 0; c < position - 1; c++)\r
+ string++;\r
+\r
+ pointer = malloc(strlen(string) + 1);\r
+ if (pointer == NULL)\r
+ {\r
+ KLWRN("Unable to allocate memory.\n");\r
+ return NULL;\r
+ }\r
+\r
+ for (c = 0; *string != '\0'; c++)\r
+ {\r
+ *(pointer + c) = *string;\r
+ string++;\r
+ }\r
+ *(pointer + c) = '\0';\r
+\r
+ return pointer;\r
+}\r
+\r
+static int\r
+_e_keyrouter_parse_ini_config(void* user, const char* section, const char* name, const char* value)\r
+{\r
+ int section_number, val;\r
+ size_t needed;\r
+ char *local_section, *c_num;\r
+ GArray *masterArray, *childArray;\r
+\r
+ c_num = _e_keyrouter_substring(strdup(section), 12/*"Combination"*/);\r
+ if (c_num == NULL)\r
+ {\r
+ KLWRN("\n Unable to read config. substring is null. \n");\r
+ return -1;\r
+ }\r
+\r
+ section_number = atoi(c_num);\r
+ free(c_num);\r
+ if (section_number == 0)\r
+ {\r
+ KLWRN("\n^[[36m Unable to read config. section_number is 0. ^[[0m\n");\r
+ return -1;\r
+ }\r
+ section_number--;\r
+\r
+ masterArray = (GArray*) user;\r
+ if (masterArray->len <= (unsigned int) section_number)\r
+ {\r
+ childArray = g_array_new(FALSE, FALSE, sizeof(int));\r
+ g_array_insert_val(masterArray, section_number, childArray);\r
+ }\r
+\r
+ needed = snprintf(NULL, 0, "%s%d", "Combination", section_number + 1);\r
+ local_section = malloc(needed + 1);\r
+ if (local_section == NULL)\r
+ {\r
+ KLWRN("\n^[[36m Failed to allocate memory for local_section ^[[0m\n");\r
+ return -1;\r
+ }\r
+ snprintf(local_section, needed + 1, "%s%d", "Combination", section_number + 1);\r
+\r
+ if (MATCH(local_section, "1"))\r
+ {\r
+ val = atoi(value);\r
+ childArray = g_array_index(masterArray,GArray*,section_number);\r
+ g_array_insert_val(childArray, 0, val);\r
+ }\r
+ else if (MATCH(local_section, "2"))\r
+ {\r
+ val = atoi(value);\r
+ childArray = g_array_index(masterArray,GArray*,section_number);\r
+ g_array_insert_val(childArray, 1, val);\r
+ }\r
+ else if (MATCH(local_section, "3"))\r
+ {\r
+ val = atoi(value);\r
+ childArray = g_array_index(masterArray,GArray*,section_number);\r
+ g_array_insert_val(childArray, 2, val);\r
+ }\r
+ else if (MATCH(local_section, "4"))\r
+ {\r
+ val = atoi(value);\r
+ childArray = g_array_index(masterArray,GArray*,section_number);\r
+ g_array_insert_val(childArray, 3, val);\r
+ }\r
+ else if (MATCH(local_section, "5"))\r
+ {\r
+ val = atoi(value);\r
+ childArray = g_array_index(masterArray,GArray*,section_number);\r
+ g_array_insert_val(childArray, 4, val);\r
+ }\r
+ else if (MATCH(local_section, "6"))\r
+ {\r
+ val = atoi(value);\r
+ childArray = g_array_index(masterArray,GArray*,section_number);\r
+ g_array_insert_val(childArray, 5, val);\r
+ }\r
+ else if (MATCH(local_section, "7"))\r
+ {\r
+ val = atoi(value);\r
+ childArray = g_array_index(masterArray,GArray*,section_number);\r
+ g_array_insert_val(childArray, 6, val);\r
+ }\r
+ else if (MATCH(local_section, "8"))\r
+ {\r
+ val = atoi(value);\r
+ childArray = g_array_index(masterArray,GArray*,section_number);\r
+ g_array_insert_val(childArray, 7, val);\r
+ }\r
+ else if (MATCH(local_section, "9"))\r
+ {\r
+ val = atoi(value);\r
+ childArray = g_array_index(masterArray,GArray*,section_number);\r
+ g_array_insert_val(childArray, 8, val);\r
+ }\r
+ else if (MATCH(local_section, "10"))\r
+ {\r
+ val = atoi(value);\r
+ childArray = g_array_index(masterArray,GArray*,section_number);\r
+ g_array_insert_val(childArray, 9, val);\r
+ }\r
+ else if (MATCH(local_section, "11"))\r
+ {\r
+ val = atoi(value);\r
+ childArray = g_array_index(masterArray,GArray*,section_number);\r
+ g_array_insert_val(childArray, 10, val);\r
+ }\r
+ else if (MATCH(local_section, "12"))\r
+ {\r
+ val = atoi(value);\r
+ childArray = g_array_index(masterArray,GArray*,section_number);\r
+ g_array_insert_val(childArray, 11, val);\r
+ }\r
+ else\r
+ {\r
+ free(local_section);\r
+ return 0; /* unknown section/name, error */\r
+ }\r
+ free(local_section);\r
+ return 1;\r
+}\r
+\r
+void\r
+e_keyrouter_process_key_combination(Time cur_time, int keycode, int state)\r
+{\r
+ int ret;\r
+\r
+ if (!keyCombinationInitialize)\r
+ {\r
+ KLWRN("KeyCombinatioin support is not initiazlied yet \n");\r
+ return ;\r
+ }\r
+ if (g_key_combination._master_combinations == NULL)\r
+ {\r
+ KLDBG(" Not searching key combination as Master combination is NULL \n");\r
+ }\r
+ if (state == ECORE_EVENT_KEY_UP)\r
+ {\r
+ ret = _e_keyrouter_search_key_combination(keycode, cur_time);\r
+\r
+ if(ret > 0)\r
+ {\r
+ _e_keyrouter_send_dbus_message(g_key_combination.keyrouter_dbus_conn, ret);\r
+ }\r
+ }\r
+}\r
+\r
+static int\r
+_e_keyrouter_send_dbus_message(DBusConnection *bus, int Input)\r
+{\r
+ DBusMessage *message = NULL;\r
+\r
+ message = dbus_message_new_signal(g_key_combination.dbusconf.path, g_key_combination.dbusconf.interface, g_key_combination.dbusconf.msg);\r
+ dbus_message_append_args(message, DBUS_TYPE_INT32, &Input, DBUS_TYPE_INVALID);\r
+\r
+ if (!dbus_connection_send(bus, message, NULL))\r
+ KLWRN( "DBUS sending MSG FAILED!!\n");\r
+\r
+ dbus_message_unref(message);\r
+ return 1;\r
+}\r
+\r
+static int\r
+_e_keyrouter_search_key_combination(int keycode, Time timestamp)\r
+{\r
+ static Time t = 0;\r
+ unsigned int i, j = 0;\r
+ int matchedIdx = 0, foundAt = 0;\r
+ static int keyIdx = 0;\r
+ static GArray *_source_Search_Array = NULL;\r
+ GArray *childArray, *matched;\r
+\r
+ if (timestamp - t >= g_key_combination.combination_timeout && keyIdx != 0)\r
+ {\r
+ t = timestamp;\r
+ keyIdx = 0;\r
+ g_array_free(_source_Search_Array, FALSE);\r
+\r
+ {\r
+ g_key_combination._current_matched_combinations = g_array_new(FALSE, FALSE, sizeof(GArray*));\r
+ _source_Search_Array = g_key_combination._master_combinations;/*now update _current_matched_combinations assuming last key that invalidated as first key*/\r
+ matchedIdx = 0;\r
+ for (i = 0; i < _source_Search_Array->len; i++)\r
+ {\r
+ GArray * childArray = g_array_index(_source_Search_Array,GArray*,i);\r
+ if (keycode == g_array_index(childArray,int,0))\r
+ {\r
+ g_array_insert_val(g_key_combination._current_matched_combinations, matchedIdx, childArray);\r
+ matchedIdx++;\r
+ }\r
+ }\r
+\r
+ if (g_key_combination._current_matched_combinations->len > 0)\r
+ {\r
+ keyIdx = 1;/*assumed that first key is the last key that invalidated the combinaton.*/\r
+ _source_Search_Array = g_key_combination._current_matched_combinations;/*start next key combination matching from this assumed _current_matched_combinations*/\r
+ t = timestamp;\r
+ }\r
+ else /* the key that invalidated is unavailable in any master_combinations as first element*/\r
+ {\r
+ keyIdx = 0;\r
+ t = timestamp;\r
+ g_array_free(g_key_combination._current_matched_combinations, FALSE);\r
+ }\r
+ }\r
+ return -1;\r
+ }\r
+\r
+ g_key_combination._current_matched_combinations = g_array_new(FALSE, FALSE, sizeof(GArray*));\r
+ if (keyIdx == 0) _source_Search_Array = g_key_combination._master_combinations;\r
+\r
+ for (i = 0; i < _source_Search_Array->len; i++)\r
+ {\r
+ childArray = g_array_index(_source_Search_Array,GArray*,i);\r
+ if (keycode == g_array_index(childArray,int,keyIdx))\r
+ {\r
+ g_array_insert_val(g_key_combination._current_matched_combinations, matchedIdx, childArray);\r
+ matchedIdx++;\r
+ }\r
+ }\r
+\r
+ if (keyIdx > 0)/* this needs to be freed for count > 0 as for keyIdx== 0 it will point to master_combinations!*/\r
+ {\r
+ g_array_free(_source_Search_Array, FALSE);/* this actually frees "last" current_matched_combinations*/\r
+ }\r
+ if (g_key_combination._current_matched_combinations->len < 1)/* the incoming key has invalidated the combination sequence*/\r
+ {\r
+ _source_Search_Array = g_key_combination._master_combinations;/*now update _current_matched_combinations assuming last key that invalidated as first key*/\r
+ matchedIdx = 0;\r
+\r
+ for (i = 0; i < _source_Search_Array->len; i++)\r
+ {\r
+ childArray = g_array_index(_source_Search_Array,GArray*,i);\r
+ if (keycode == g_array_index(childArray,int,0))\r
+ {\r
+ g_array_insert_val(g_key_combination._current_matched_combinations, matchedIdx, childArray);\r
+ matchedIdx++;\r
+ }\r
+ }\r
+\r
+ if (g_key_combination._current_matched_combinations->len > 0)\r
+ {\r
+ keyIdx = 1;/*assumed that first key is the last key that invalidated the combinaton.*/\r
+ _source_Search_Array = g_key_combination._current_matched_combinations;/*start next key combination matching from this assumed _current_matched_combinations*/\r
+ t = timestamp;\r
+ }\r
+ else/* the key that invalidated is unavailable in any master_combinations as first element*/\r
+ {\r
+ keyIdx = 0;\r
+ t = timestamp;\r
+ g_array_free(g_key_combination._current_matched_combinations, FALSE);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ 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)\r
+ {\r
+ keyIdx = 0;\r
+ t = timestamp;\r
+ matched = g_array_index(g_key_combination._current_matched_combinations,GArray*,0);\r
+\r
+ for (i = 0; i < matched->len; i++)\r
+ KLDBG("[32m Matched Combination:|%d| [0m\n", g_array_index(matched,int,i));\r
+ foundAt = 0;\r
+\r
+ for (i = 0; i < g_key_combination._master_combinations->len; i++)\r
+ {\r
+ childArray=g_array_index(g_key_combination._master_combinations,GArray*,i);\r
+ for (j = 0; j < childArray->len; j++)\r
+ {\r
+ if (childArray->len == matched->len && g_array_index(childArray,int,j) == g_array_index(matched,int,j))\r
+ {\r
+ foundAt = i + 1;\r
+ }\r
+ else\r
+ {\r
+ foundAt = FALSE;\r
+ break;\r
+ }\r
+ }\r
+ if (foundAt)\r
+ {\r
+ KLDBG("[32m COMBINATION FOUND AT : %d [0m\n", foundAt);\r
+ break;\r
+ }\r
+ }\r
+ 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.*/\r
+ return foundAt;\r
+ }\r
+ else/*continue search for next key*/\r
+ {\r
+ t = timestamp;\r
+ keyIdx++;\r
+ _source_Search_Array = g_key_combination._current_matched_combinations;\r
+ }\r
+ }\r
+\r
+ return -1;\r
+}\r
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);
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;
}
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;
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)
{
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;
}
//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;
}
}
krt->HardKeys[ev->keycode].press_ptr = NULL;
+ krt->isRegisterDelivery = EINA_FALSE;
return ret;
}
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)
}
}
- 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)
{
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 <Consider VISIBILITY>
+ // 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
_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)
{
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;
}
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;
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);
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;
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:
Eina_List *l, *ll, *ll_next;
E_Keyrouter_Registered_Window_Info *data;
int *ddata;
+ Eina_List *key_list = NULL;
_e_keyrouter_clean_register_list();
}
}
+ // 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",
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)
{
#define E_COMP_WL
#include "e_mod_main_wl.h"
#include <string.h>
+#include <device/power.h>
+#include <device/callback.h>
+#include <device/display.h>
+
+#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" };
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);
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;
}
/* 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;
}
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
_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 */
/* 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)
{
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);
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);
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
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;
Eina_List *shared_ptr;
Eina_List *press_ptr;
E_Keyrouter_Key_List_Node *registered_ptr;
+ Eina_List *pic_off_ptr;
};
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 {
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);
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
--- /dev/null
+/* 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 <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "ini.h"
+#include "errno.h"
+
+#if !INI_USE_STACK
+#include <stdlib.h>
+#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;
+}
--- /dev/null
+/* 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 <stdio.h>
+
+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__ */