2 * Copyright © 2012, 2013 Intel Corporation
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 #include "scim_private.h"
27 #include <Ecore_Evas.h>
28 #include <Ecore_Input.h>
29 #include <Ecore_Wayland.h>
35 #include "isf_debug.h"
36 #include "wayland_imcontext.h"
37 #include "tizen_profile.h"
42 #define LOG_TAG "IMMODULE"
44 #define IME_DEVICE_NAME "ime"
46 #define HIDE_TIMER_INTERVAL 0.05
47 #define WAIT_FOR_FILTER_DONE_SECOND 2
49 #define MOD_SHIFT_MASK 0x01
50 #define MOD_CAPS_MASK 0x02
51 #define MOD_CONTROL_MASK 0x04
52 #define MOD_ALT_MASK 0x08
53 #define MOD_NUM_MASK 0x100
54 #define MOD_Mod5_MASK 0x80
56 #define VCONFKEY_AUTOPERIOD_ALLOW_BOOL "file/private/isf/autoperiod_allow"
57 #define VCONFKEY_AUTOCAPITAL_ALLOW_BOOL "file/private/isf/autocapital_allow"
62 INPUT_LANG_BENGALI_IN,
63 INPUT_LANG_BENGALI_BD,
80 const double DOUBLE_SPACE_INTERVAL = 1.0;
82 static Eina_Bool _clear_hide_timer();
83 static Ecore_Timer *_hide_timer = NULL;
85 static const char *_ecore_imf_event_empty = "";
87 // TIZEN_ONLY(20150708): Support back key
88 #define BACK_KEY "XF86Back"
89 #define OLD_BACK_KEY "XF86Stop"
91 static Eina_Bool will_hide = EINA_FALSE;
92 static Eina_Bool ignore_hide = EINA_FALSE;
94 static Ecore_Event_Filter *_ecore_event_filter_handler = NULL;
95 static Ecore_IMF_Context *_focused_ctx = NULL;
96 static Ecore_IMF_Context *_show_req_ctx = NULL;
97 static Ecore_IMF_Context *_hide_req_ctx = NULL;
98 static Ecore_IMF_Context *_focus_req_ctx = NULL;
99 static Ecore_IMF_Context *_input_panel_ctx = NULL;
101 static Eina_Rectangle _keyboard_geometry = {0, 0, 0, 0};
103 static Ecore_IMF_Input_Panel_State _input_panel_state = ECORE_IMF_INPUT_PANEL_STATE_HIDE;
104 static Ecore_Event_Handler *_win_focus_out_handler = NULL;
105 static Ecore_Event_Handler *_conformant_change_handler = NULL;
107 static Eina_Bool _custom_conformant_event = EINA_FALSE;
108 static Eina_Bool _received_will_hide_event = EINA_FALSE;
109 static Eina_Bool _conformant_reset_done = EINA_FALSE;
110 static Eina_Bool _conformant_reset_started = EINA_FALSE;
111 static Evas *_active_context_canvas = NULL;
112 static unsigned int _active_context_window_id = 0;
114 static Ecore_Device *_ime_device = NULL;
116 static double space_key_time = 0.0;
117 static Eina_Bool autoperiod_allow = EINA_FALSE;
118 static Eina_Bool autocap_allow = EINA_FALSE;
119 static Eina_Bool hw_keyboard_mode = EINA_FALSE;
121 static Input_Language input_lang = INPUT_LANG_OTHER;
122 static Evas_Coord g_scr_w = 0, g_scr_h = 0;
125 typedef struct __LanguageInfo {
128 Eina_Unicode punc_code;
129 Eina_Bool auto_capital_valid;
132 static LanguageInfo __language_infos [] = {
133 { "ur_PK", INPUT_LANG_URDU, 0x06D4, EINA_TRUE },
134 { "hi_IN", INPUT_LANG_HINDI, 0x0964, EINA_FALSE },
135 { "bn_IN", INPUT_LANG_BENGALI_IN, 0x0964, EINA_TRUE },
136 { "bn_BD", INPUT_LANG_BENGALI_BD, 0x0964, EINA_TRUE },
137 { "as_IN", INPUT_LANG_ASSAMESE, 0x0964, EINA_TRUE },
138 { "pa_IN", INPUT_LANG_PUNJABI, 0x0964, EINA_TRUE },
139 { "ne_NP", INPUT_LANG_NEPALI, 0x0964, EINA_TRUE },
140 { "or_IN", INPUT_LANG_ORIYA, 0x0964, EINA_TRUE },
141 { "mai_IN", INPUT_LANG_MAITHILI, 0x0964, EINA_TRUE },
142 { "hy_AM", INPUT_LANG_ARMENIAN, 0x0589, EINA_TRUE },
143 { "zh_CN", INPUT_LANG_CN, 0x3002, EINA_FALSE },
144 { "zh_HK", INPUT_LANG_CN_HK, 0x3002, EINA_FALSE },
145 { "zh_TW", INPUT_LANG_CN_TW, 0x3002, EINA_FALSE },
146 { "ja_JP", INPUT_LANG_JAPANESE, 0x3002, EINA_FALSE },
147 { "km_KH", INPUT_LANG_KHMER, 0x17D4, EINA_TRUE },
148 { "ko_KR", INPUT_LANG_KOREAN, 0x002E, EINA_FALSE },
151 struct _WaylandIMContext
153 Ecore_IMF_Context *ctx;
155 struct wl_text_input_manager *text_input_manager;
156 struct wl_text_input *text_input;
158 Ecore_Wl_Window *window;
159 Ecore_Wl_Input *input;
163 char *preedit_commit;
165 Eina_List *preedit_attrs;
166 int32_t preedit_cursor;
174 int32_t cursor_position;
184 xkb_mod_mask_t control_mask;
185 xkb_mod_mask_t alt_mask;
186 xkb_mod_mask_t shift_mask;
187 xkb_mod_mask_t caps_mask;
188 xkb_mod_mask_t num_mask;
191 uint32_t content_purpose;
192 uint32_t content_hint;
193 Ecore_IMF_Input_Panel_Layout input_panel_layout;
195 // TIZEN_ONLY(20150716): Support return key type
196 uint32_t return_key_type;
198 Eina_Bool return_key_disabled;
201 uint32_t imdata_size;
203 uint32_t bidi_direction;
205 void *input_panel_data;
206 uint32_t input_panel_data_length;
212 } last_key_event_filter;
213 Eina_List *keysym_list;
215 uint32_t reset_serial;
217 Eina_Bool has_conformant;
218 char *prediction_hint;
222 // TIZEN_ONLY(20150708): Support back key
223 static void _input_panel_hide(Ecore_IMF_Context *ctx, Eina_Bool instant);
224 static Eina_Bool show_input_panel(Ecore_IMF_Context *ctx);
227 reset_keyboard_geometry ()
229 if (g_scr_w == 0 || g_scr_h == 0) {
231 ecore_wl_screen_size_get(&g_scr_w, &g_scr_h);
233 _keyboard_geometry.x = 0;
234 _keyboard_geometry.y = g_scr_h;
235 _keyboard_geometry.w = 0;
236 _keyboard_geometry.h = 0;
240 _device_info_free (void *data EINA_UNUSED, void *ev)
242 Ecore_Event_Device_Info *e;
245 eina_stringshare_del (e->name);
246 eina_stringshare_del (e->identifier);
247 eina_stringshare_del (e->seatname);
253 _device_info_send (unsigned int window, Eina_Bool flag)
255 Ecore_Event_Device_Info *e;
257 if (!(e = calloc (1, sizeof (Ecore_Event_Device_Info)))) return;
259 e->name = eina_stringshare_ref (IME_DEVICE_NAME);
260 e->identifier = eina_stringshare_ref (IME_DEVICE_NAME);
261 e->seatname = eina_stringshare_ref (IME_DEVICE_NAME);
262 e->clas = ECORE_DEVICE_CLASS_KEYBOARD;
266 ecore_event_add (ECORE_EVENT_DEVICE_ADD, e, _device_info_free, NULL);
268 ecore_event_add (ECORE_EVENT_DEVICE_DEL, e, _device_info_free, NULL);
272 get_input_language ()
275 char *input_lang_str = vconf_get_str (VCONFKEY_ISF_INPUT_LANGUAGE);
276 if (!input_lang_str) return;
277 LOGD ("language %s", input_lang_str);
278 input_lang = INPUT_LANG_OTHER;
280 for (i = 0; i < (sizeof (__language_infos) / sizeof (__language_infos[0])); i++) {
281 if (strcmp (input_lang_str, __language_infos[i].code) == 0) {
282 input_lang = __language_infos[i].lang;
287 free (input_lang_str);
290 static void autoperiod_allow_changed_cb (keynode_t *key, void* data)
292 autoperiod_allow = vconf_keynode_get_bool (key);
295 static void autocapital_allow_changed_cb (keynode_t *key, void* data)
297 autocap_allow = vconf_keynode_get_bool (key);
300 static void input_language_changed_cb (keynode_t *key, void* data)
302 get_input_language ();
306 check_symbol (Eina_Unicode ucode, Eina_Unicode symbols[], int symbol_num)
309 for (i = 0; i < symbol_num; i++) {
311 if (ucode == symbols[i])
319 check_space_symbol (Eina_Unicode uchar)
321 Eina_Unicode space_symbols[] = {' ', 0x00A0 /* no-break space */, 0x3000 /* ideographic space */};
322 const int symbol_num = sizeof (space_symbols) / sizeof (space_symbols[0]);
324 return check_symbol (uchar, space_symbols, symbol_num);
328 autoperiod_insert (Ecore_IMF_Context *ctx)
330 char *plain_str = NULL;
332 Eina_Unicode *ustr = NULL;
333 Ecore_IMF_Event_Delete_Surrounding ev;
334 char *fullstop_mark = NULL;
337 WaylandIMContext *imcontext = NULL;
339 if (autoperiod_allow == EINA_FALSE)
344 Ecore_IMF_Input_Panel_Layout layout = ecore_imf_context_input_panel_layout_get (ctx);
345 if (layout != ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL)
348 if ((ecore_time_get () - space_key_time) > DOUBLE_SPACE_INTERVAL)
351 imcontext = (WaylandIMContext *)ecore_imf_context_data_get (ctx);
352 if (!imcontext) return;
354 ecore_imf_context_surrounding_get (ctx, &plain_str, NULL);
355 if (!plain_str) goto done;
357 cursor_pos = imcontext->cursor_position;
359 // Convert string from UTF-8 to unicode
360 ustr = eina_unicode_utf8_to_unicode (plain_str, NULL);
361 if (!ustr) goto done;
363 ulen = eina_unicode_strlen (ustr);
365 if (cursor_pos < 2 || cursor_pos > (int)ulen) {
366 LOGD ("invalid range. cursor pos : %d, length : %d\n", cursor_pos, ulen);
370 if (check_space_symbol (ustr[cursor_pos-1])) {
371 // any character (except space & punctuation) + press space key twice in short time
372 if (!(iswpunct (ustr[cursor_pos-2]) || check_space_symbol (ustr[cursor_pos-2])) &&
373 iswprint(ustr[cursor_pos-2])) {
376 // any character (except space & punctuation) + space + press space key twice in short time
377 else if (cursor_pos >= 3 &&
378 check_space_symbol (ustr[cursor_pos-2]) &&
379 !(iswpunct (ustr[cursor_pos-3]) || check_space_symbol (ustr[cursor_pos-3])) &&
380 iswprint(ustr[cursor_pos-3])) {
386 ev.n_chars = del_chars;
387 ev.offset = del_chars * -1;
389 ecore_imf_context_delete_surrounding_event_add (ctx, ev.offset, ev.n_chars);
390 ecore_imf_context_event_callback_call (ctx, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, &ev);
392 if (input_lang == INPUT_LANG_OTHER) {
393 fullstop_mark = strdup (".");
396 Eina_Unicode wbuf[2] = {0};
397 wbuf[0] = __language_infos[input_lang].punc_code;
399 fullstop_mark = eina_unicode_unicode_to_utf8 (wbuf, NULL);
402 ecore_imf_context_commit_event_add (ctx, fullstop_mark);
403 ecore_imf_context_event_callback_call (ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)fullstop_mark);
406 free (fullstop_mark);
407 fullstop_mark = NULL;
413 if (plain_str) free (plain_str);
414 if (ustr) free (ustr);
415 space_key_time = ecore_time_get ();
419 check_except_autocapital (Eina_Unicode *ustr, int cursor_pos)
421 const char *except_str[] = {"e.g.", "E.g."};
422 unsigned int i = 0, j = 0, len = 0;
423 for (i = 0; i < (sizeof (except_str) / sizeof (except_str[0])); i++) {
424 len = strlen (except_str[i]);
425 if (cursor_pos < (int)len)
428 for (j = len; j > 0; j--) {
429 if (ustr[cursor_pos-j] != except_str[i][len-j])
433 if (j == 0) return EINA_TRUE;
440 analyze_surrounding_text (Ecore_IMF_Context *ctx)
442 char *plain_str = NULL;
443 Eina_Unicode puncs[] = {'\n','.', '!', '?', 0x00BF /* ¿ */, 0x00A1 /* ¡ */,
444 0x3002 /* 。 */, 0x06D4 /* Urdu */, 0x0964 /* Hindi */,
445 0x0589 /* Armenian */, 0x17D4 /* Khmer */, 0x104A /* Myanmar */};
446 Eina_Unicode *ustr = NULL;
447 Eina_Bool ret = EINA_FALSE;
448 Eina_Bool detect_space = EINA_FALSE;
451 const int punc_num = sizeof (puncs) / sizeof (puncs[0]);
452 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get (ctx);
453 if (!imcontext) return EINA_FALSE;
455 switch (ecore_imf_context_autocapital_type_get (ctx)) {
456 case ECORE_IMF_AUTOCAPITAL_TYPE_NONE:
458 case ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER:
464 if (imcontext->preedit_text && strcmp (imcontext->preedit_text, "") != 0)
467 if (imcontext->cursor_position == 0)
470 ecore_imf_context_surrounding_get (ctx, &plain_str, &cursor_pos);
472 if (!plain_str) goto done;
474 if (cursor_pos == 0) {
479 // Convert string from UTF-8 to unicode
480 ustr = eina_unicode_utf8_to_unicode (plain_str, NULL);
481 if (!ustr) goto done;
483 if (eina_unicode_strlen (ustr) < (size_t)cursor_pos) goto done;
485 if (cursor_pos >= 1) {
486 if (ecore_imf_context_autocapital_type_get (ctx) == ECORE_IMF_AUTOCAPITAL_TYPE_WORD) {
487 // Check space or no-break space
488 if (check_space_symbol (ustr[cursor_pos-1])) {
494 // Check paragraph separator <PS> or carriage return <br>
495 if ((ustr[cursor_pos-1] == 0x2029) || (ustr[cursor_pos-1] == '\n')) {
500 for (i = cursor_pos; i > 0; i--) {
501 // Check space or no-break space
502 if (check_space_symbol (ustr[i-1])) {
503 detect_space = EINA_TRUE;
507 // Check punctuation and following the continuous space(s)
508 if (detect_space && check_symbol (ustr[i-1], puncs, punc_num)) {
509 if (check_except_autocapital (ustr, i))
521 if ((i == 0) && (detect_space == EINA_TRUE)) {
522 // continuous space(s) without any character
529 if (ustr) free (ustr);
530 if (plain_str) free (plain_str);
536 set_autocapital (Ecore_IMF_Context *ctx)
538 Eina_Bool uppercase = EINA_FALSE;
540 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get (ctx);
541 if (!imcontext || !imcontext->text_input || !imcontext->input) return;
543 if (hw_keyboard_mode) return;
545 if (input_lang != INPUT_LANG_OTHER && (!__language_infos[input_lang].auto_capital_valid))
548 if (ecore_imf_context_input_panel_layout_get (ctx) != ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL)
551 // Check autocapital type
552 if (ecore_imf_context_input_panel_caps_lock_mode_get (ctx)) {
553 uppercase = EINA_TRUE;
555 if (autocap_allow == EINA_FALSE)
558 uppercase = analyze_surrounding_text (ctx);
561 SECURE_LOGD ("ctx : %p, auto capital : %d\n", ctx, uppercase);
562 wl_text_input_set_capital_mode (imcontext->text_input, uppercase);
565 static Ecore_IMF_Context *
568 return (_show_req_ctx ? _show_req_ctx : _focused_ctx);
572 check_hide_key(const char *keyname)
574 if (!keyname) return EINA_FALSE;
576 if (strcmp(keyname, "Escape") == 0 ||
577 strcmp(keyname, BACK_KEY) == 0 ||
578 strcmp(keyname, OLD_BACK_KEY) == 0)
585 _ecore_key_modifiers_to_ecore_imf_locks(unsigned int modifiers)
587 unsigned int locks = 0;
589 if (modifiers & ECORE_EVENT_LOCK_SCROLL)
590 locks |= ECORE_IMF_KEYBOARD_LOCK_SCROLL;
592 if (modifiers & ECORE_EVENT_LOCK_CAPS)
593 locks |= ECORE_IMF_KEYBOARD_LOCK_CAPS;
595 if (modifiers & ECORE_EVENT_LOCK_NUM)
596 locks |= ECORE_IMF_KEYBOARD_LOCK_NUM;
602 _ecore_key_modifiers_to_ecore_imf_modifiers(unsigned int modifiers)
604 unsigned int mask = 0;
606 /**< "Control" is pressed */
607 if (modifiers & ECORE_EVENT_MODIFIER_CTRL)
608 mask |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL;
610 /**< "Alt" is pressed */
611 if (modifiers & ECORE_EVENT_MODIFIER_ALT)
612 mask |= ECORE_IMF_KEYBOARD_MODIFIER_ALT;
614 /**< "Shift" is pressed */
615 if (modifiers & ECORE_EVENT_MODIFIER_SHIFT)
616 mask |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT;
618 /**< "Win" (between "Ctrl" and "Alt") is pressed */
619 if (modifiers & ECORE_EVENT_MODIFIER_WIN)
620 mask |= ECORE_IMF_KEYBOARD_MODIFIER_WIN;
622 /**< "AltGr" is pressed */
623 if (modifiers & ECORE_EVENT_MODIFIER_ALTGR)
624 mask |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR;
630 _ecore_event_to_ecore_imf_key_down_event(Ecore_Event_Key *ecore_event, Ecore_IMF_Event_Key_Down *imf_event)
632 if (!ecore_event || !imf_event)
635 imf_event->keyname = ecore_event->keyname ? ecore_event->keyname : _ecore_imf_event_empty;
636 imf_event->key = ecore_event->key ? ecore_event->key : _ecore_imf_event_empty;
637 imf_event->string = ecore_event->string ? ecore_event->string : _ecore_imf_event_empty;
638 imf_event->compose = ecore_event->compose ? ecore_event->compose : _ecore_imf_event_empty;
639 imf_event->timestamp = ecore_event->timestamp;
641 if (ecore_event->dev) {
642 imf_event->dev_name = ecore_device_name_get(ecore_event->dev) ? ecore_device_name_get(ecore_event->dev) : _ecore_imf_event_empty;
643 imf_event->dev_class = (Ecore_IMF_Device_Class)ecore_device_class_get(ecore_event->dev);
644 imf_event->dev_subclass = (Ecore_IMF_Device_Subclass)ecore_device_subclass_get(ecore_event->dev);
647 imf_event->dev_name = _ecore_imf_event_empty;
648 imf_event->dev_class = ECORE_IMF_DEVICE_CLASS_NONE;
649 imf_event->dev_subclass = ECORE_IMF_DEVICE_SUBCLASS_NONE;
652 imf_event->modifiers = _ecore_key_modifiers_to_ecore_imf_modifiers(ecore_event->modifiers);
653 imf_event->locks = _ecore_key_modifiers_to_ecore_imf_locks(ecore_event->modifiers);
657 _ecore_event_to_ecore_imf_key_up_event(Ecore_Event_Key *ecore_event, Ecore_IMF_Event_Key_Up *imf_event)
659 if (!ecore_event || !imf_event)
662 imf_event->keyname = ecore_event->keyname ? ecore_event->keyname : _ecore_imf_event_empty;
663 imf_event->key = ecore_event->key ? ecore_event->key : _ecore_imf_event_empty;
664 imf_event->string = ecore_event->string ? ecore_event->string : _ecore_imf_event_empty;
665 imf_event->compose = ecore_event->compose ? ecore_event->compose : _ecore_imf_event_empty;
666 imf_event->timestamp = ecore_event->timestamp;
668 if (ecore_event->dev) {
669 imf_event->dev_name = ecore_device_name_get(ecore_event->dev) ? ecore_device_name_get(ecore_event->dev) : _ecore_imf_event_empty;
670 imf_event->dev_class = (Ecore_IMF_Device_Class)ecore_device_class_get(ecore_event->dev);
671 imf_event->dev_subclass = (Ecore_IMF_Device_Subclass)ecore_device_subclass_get(ecore_event->dev);
674 imf_event->dev_name = _ecore_imf_event_empty;
675 imf_event->dev_class = ECORE_IMF_DEVICE_CLASS_NONE;
676 imf_event->dev_subclass = ECORE_IMF_DEVICE_SUBCLASS_NONE;
679 imf_event->modifiers = _ecore_key_modifiers_to_ecore_imf_modifiers(ecore_event->modifiers);
680 imf_event->locks = _ecore_key_modifiers_to_ecore_imf_locks(ecore_event->modifiers);
684 key_down_filter_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
686 Ecore_Event_Key *ev = (Ecore_Event_Key *)event;
687 if (!ev || !ev->keyname) return EINA_TRUE; /* the event is kept */
689 Ecore_IMF_Context *active_ctx = get_using_ctx ();
691 if (!active_ctx) return EINA_TRUE; /* the event is kept */
693 if ((_input_panel_state == ECORE_IMF_INPUT_PANEL_STATE_SHOW ||
694 _input_panel_state == ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW) &&
695 check_hide_key(ev->keyname)) {
697 LOGD ("%s key is pressed.\n", ev->keyname);
699 Ecore_IMF_Event_Key_Down imf_event;
700 Eina_Bool filter_ret = EINA_FALSE;
702 _ecore_event_to_ecore_imf_key_down_event(ev, &imf_event);
705 filter_ret = ecore_imf_context_filter_event(_focused_ctx, ECORE_IMF_EVENT_KEY_DOWN, (Ecore_IMF_Event *)&imf_event);
709 LOGD ("%s key is pressed. ret : %d\n", ev->keyname, filter_ret);
711 return EINA_FALSE; /* the event is removed from the queue */
715 return EINA_TRUE; /* the event is kept */
717 return EINA_FALSE; /* the event is removed from the queue */
719 return EINA_TRUE; /* the event is kept */
723 key_up_filter_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
725 Ecore_Event_Key *ev = (Ecore_Event_Key *)event;
726 if (!ev || !ev->keyname) return EINA_TRUE; /* the event is kept */
728 Ecore_IMF_Context *active_ctx = get_using_ctx ();
730 if (!active_ctx) return EINA_TRUE; /* the event is kept */
732 if (_input_panel_state == ECORE_IMF_INPUT_PANEL_STATE_HIDE ||
733 !check_hide_key(ev->keyname))
734 return EINA_TRUE; /* the event is kept */
736 LOGD ("%s key is released.\n", ev->keyname);
738 Ecore_IMF_Event_Key_Up imf_event;
739 Eina_Bool filter_ret = EINA_FALSE;
741 _ecore_event_to_ecore_imf_key_up_event(ev, &imf_event);
744 filter_ret = ecore_imf_context_filter_event(_focused_ctx, ECORE_IMF_EVENT_KEY_UP, (Ecore_IMF_Event *)&imf_event);
748 LOGD ("%s key is released. ret : %d\n", ev->keyname, filter_ret);
750 return EINA_FALSE; /* the event is removed from the queue */
753 ecore_imf_context_reset(active_ctx);
756 return EINA_TRUE; /* the event is kept */
758 _input_panel_hide(active_ctx, EINA_TRUE);
760 return EINA_FALSE; /* the event is removed from the queue */
766 rotary_event_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
768 Ecore_Event_Detent_Rotate *ev = event;
769 if (!ev) return EINA_TRUE;
771 Ecore_IMF_Context *active_ctx = NULL;
773 active_ctx = _show_req_ctx;
774 else if (_focused_ctx)
775 active_ctx = _focused_ctx;
777 if (!active_ctx) return EINA_TRUE;
779 if (_input_panel_state == ECORE_IMF_INPUT_PANEL_STATE_HIDE)
782 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(active_ctx);
783 if (imcontext && imcontext->input && imcontext->text_input) {
784 wl_text_input_process_input_device_event(imcontext->text_input,
785 (unsigned int)ECORE_EVENT_DETENT_ROTATE, (char*)event, sizeof(Ecore_Event_Detent_Rotate));
792 _ecore_event_filter_cb(void *data, void *loop_data EINA_UNUSED, int type, void *event)
794 if (type == ECORE_EVENT_KEY_DOWN) {
795 return key_down_filter_cb(data, type, event);
797 else if (type == ECORE_EVENT_KEY_UP) {
798 return key_up_filter_cb(data, type, event);
800 /* The IME needs to process Rotary event prior to client application */
801 else if (type == ECORE_EVENT_DETENT_ROTATE) {
802 return rotary_event_cb(data, type, event);
809 register_key_handler()
811 if (!_ecore_event_filter_handler)
812 _ecore_event_filter_handler = ecore_event_filter_add(NULL, _ecore_event_filter_cb, NULL, NULL);
816 unregister_key_handler()
818 if (_ecore_event_filter_handler) {
819 ecore_event_filter_del(_ecore_event_filter_handler);
820 _ecore_event_filter_handler = NULL;
831 ecore_timer_del(_hide_timer);
839 static void _win_focus_out_handler_del ()
841 if (_win_focus_out_handler) {
842 ecore_event_handler_del (_win_focus_out_handler);
843 _win_focus_out_handler = NULL;
847 static void _conformant_change_handler_del()
849 if (_conformant_change_handler) {
850 ecore_event_handler_del(_conformant_change_handler);
851 _conformant_change_handler = NULL;
856 _send_input_panel_hide_request(Ecore_IMF_Context *ctx)
861 // TIZEN_ONLY(20150708): Support back key
862 _hide_req_ctx = NULL;
865 _win_focus_out_handler_del ();
867 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
868 if (imcontext && imcontext->text_input) {
869 wl_text_input_hide_input_panel(imcontext->text_input);
871 LOGD("creating temporary context for sending hide request\n");
872 const char *ctx_id = ecore_imf_context_default_id_get();
873 Ecore_IMF_Context *temp_context = ecore_imf_context_add(ctx_id);
875 imcontext = (WaylandIMContext *)ecore_imf_context_data_get(temp_context);
876 if (imcontext && imcontext->text_input)
877 wl_text_input_hide_input_panel(imcontext->text_input);
879 ecore_imf_context_del(temp_context);
884 static void _conformant_area_free (void *data EINA_UNUSED, void *ev)
886 Ecore_Wl_Event_Conformant_Change *e = ev;
891 static void add_conformant_change_event(Ecore_Wl_Window *window)
893 Ecore_Wl_Event_Conformant_Change *ev;
894 ev = calloc(1, sizeof(Ecore_Wl_Event_Conformant_Change));
896 ev->win = ecore_wl_window_id_get(window);
899 ecore_event_add(ECORE_WL_EVENT_CONFORMANT_CHANGE, ev, _conformant_area_free, NULL);
903 static Eina_Rectangle _conformant_area_backup = { 0, 0, 0, 0 };
904 static Eina_Bool reset_conformant_area(Ecore_IMF_Context *ctx)
906 Eina_Bool reset = EINA_FALSE;
907 Eina_Bool has_conformant = EINA_FALSE;
908 Ecore_Wl_Window *window = NULL;
910 if (!ctx) return EINA_FALSE;
912 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
914 window = imcontext->window;
915 has_conformant = imcontext->has_conformant;
919 int x = 0, y = 0, w = 0, h = 0;
920 Eina_Bool result = ecore_wl_window_keyboard_geometry_get(window, &x, &y, &w, &h);
923 if (ecore_imf_context_client_canvas_get(ctx) && has_conformant && (w != 0 || h != 0)) {
925 _conformant_area_backup.x = x;
926 _conformant_area_backup.y = y;
927 _conformant_area_backup.w = w;
928 _conformant_area_backup.h = h;
932 LOGD("reset %d", reset);
934 ecore_wl_window_keyboard_geometry_set(window, 0, 0, 0, 0);
936 add_conformant_change_event(window);
938 _conformant_reset_started = EINA_TRUE;
944 static void restore_conformant_area(Ecore_IMF_Context *ctx)
946 Eina_Bool restore = EINA_FALSE;
947 Eina_Bool has_conformant = EINA_FALSE;
948 Ecore_Wl_Window *window = NULL;
952 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
954 window = imcontext->window;
955 has_conformant = imcontext->has_conformant;
959 int x = 0, y = 0, w = 0, h = 0;
960 Eina_Bool result = ecore_wl_window_keyboard_geometry_get(window, &x, &y, &w, &h);
963 if (ecore_imf_context_client_canvas_get(ctx) && has_conformant && (w == 0 || h == 0)) {
968 LOGD("restore %d", restore);
970 ecore_wl_window_keyboard_geometry_set(window,
971 _conformant_area_backup.x, _conformant_area_backup.y,
972 _conformant_area_backup.w, _conformant_area_backup.h);
974 add_conformant_change_event(window);
976 _conformant_reset_started = EINA_FALSE;
981 _send_will_hide_ack(WaylandIMContext *imcontext)
983 if (!imcontext) return;
984 if (!(imcontext->text_input)) return;
987 const char *szWillHideAck = "WILL_HIDE_ACK";
988 wl_text_input_set_input_panel_data(imcontext->text_input, szWillHideAck, strlen(szWillHideAck));
989 _received_will_hide_event = EINA_FALSE;
993 _hide_timer_handler(void *data)
995 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)data;
996 _send_input_panel_hide_request(ctx);
998 if (!reset_conformant_area(ctx) && !_conformant_reset_started) {
999 LOGD("No need to reset conformant, sending ACK right away");
1000 _send_will_hide_ack((WaylandIMContext *)ecore_imf_context_data_get(ctx));
1004 reset_keyboard_geometry();
1007 return ECORE_CALLBACK_CANCEL;
1011 _input_panel_hide_timer_start(void *data)
1014 _hide_timer = ecore_timer_add(HIDE_TIMER_INTERVAL, _hide_timer_handler, data);
1018 _input_panel_hide(Ecore_IMF_Context *ctx, Eina_Bool instant)
1020 LOGD ("ctx : %p", ctx);
1024 will_hide = EINA_TRUE;
1025 _conformant_reset_started = EINA_FALSE;
1027 if (instant || (_hide_timer && ecore_timer_pending_get(_hide_timer) <= 0.0)) {
1028 _clear_hide_timer();
1029 _send_input_panel_hide_request(ctx);
1031 if (!reset_conformant_area(ctx) && !_conformant_reset_started) {
1032 LOGD("No need to reset conformant, sending ACK right away");
1033 _send_will_hide_ack((WaylandIMContext *)ecore_imf_context_data_get(ctx));
1037 reset_keyboard_geometry();
1039 _input_panel_hide_timer_start(ctx);
1040 // TIZEN_ONLY(20150708): Support back key
1041 _hide_req_ctx = ctx;
1047 utf8_offset_to_characters(const char *str, int offset)
1052 for (; index < offset; i++) {
1053 if (eina_unicode_utf8_next_get(str, &index) == 0)
1061 send_cursor_location(WaylandIMContext *imcontext)
1063 #if ENABLE_SEND_CURSOR_LOCATION
1064 Ecore_Evas *ee = NULL;
1065 int canvas_x = 0, canvas_y = 0;
1067 if (imcontext->canvas) {
1068 ee = ecore_evas_ecore_evas_get(imcontext->canvas);
1070 ecore_evas_geometry_get(ee, &canvas_x, &canvas_y, NULL, NULL);
1073 if (imcontext->input && imcontext->text_input) {
1074 wl_text_input_set_cursor_rectangle(imcontext->text_input,
1075 imcontext->cursor_location.x + canvas_x,
1076 imcontext->cursor_location.y + canvas_y,
1077 imcontext->cursor_location.width,
1078 imcontext->cursor_location.height);
1084 update_state(WaylandIMContext *imcontext)
1086 if (!imcontext->ctx)
1089 send_cursor_location (imcontext);
1091 if (imcontext->input && imcontext->text_input) {
1092 wl_text_input_commit_state(imcontext->text_input, ++imcontext->serial);
1097 check_serial(WaylandIMContext *imcontext, uint32_t serial)
1102 Ecore_IMF_Preedit_Attr *attr;
1104 if ((imcontext->serial - serial) >
1105 (imcontext->serial - imcontext->reset_serial)) {
1106 LOGD("outdated serial: %u, current: %u, reset: %u",
1107 serial, imcontext->serial, imcontext->reset_serial);
1109 imcontext->pending_preedit.cursor = 0;
1111 if (imcontext->pending_preedit.attrs) {
1112 EINA_LIST_FREE(imcontext->pending_preedit.attrs, attr) free(attr);
1113 imcontext->pending_preedit.attrs = NULL;
1124 clear_preedit_text(WaylandIMContext *imcontext)
1126 Ecore_IMF_Preedit_Attr *attr = NULL;
1128 imcontext->preedit_cursor = 0;
1130 if (imcontext->preedit_text) {
1131 free(imcontext->preedit_text);
1132 imcontext->preedit_text = NULL;
1135 if (imcontext->preedit_attrs) {
1136 EINA_LIST_FREE(imcontext->preedit_attrs, attr)
1140 imcontext->preedit_attrs = NULL;
1144 clear_preedit(WaylandIMContext *imcontext)
1146 clear_preedit_text(imcontext);
1148 if (imcontext->preedit_commit) {
1149 free(imcontext->preedit_commit);
1150 imcontext->preedit_commit = NULL;
1155 check_preedit_empty(WaylandIMContext *imcontext)
1157 if (!imcontext) return EINA_TRUE;
1159 if (imcontext->preedit_text) return EINA_FALSE;
1160 if (imcontext->preedit_attrs) return EINA_FALSE;
1161 if (imcontext->preedit_cursor != 0) return EINA_FALSE;
1162 if (imcontext->preedit_commit) return EINA_FALSE;
1168 text_input_commit_string(void *data,
1169 struct wl_text_input *text_input EINA_UNUSED,
1173 WaylandIMContext *imcontext = (WaylandIMContext *)data;
1174 Eina_Bool old_preedit = EINA_FALSE;
1176 SECURE_LOGD("ctx : %p, commit event (text: '%s', current pre-edit: '%s')",
1179 imcontext->preedit_text ? imcontext->preedit_text : "");
1181 if (!imcontext->ctx)
1185 imcontext->preedit_text && strlen(imcontext->preedit_text) > 0;
1187 if (!check_serial(imcontext, serial))
1191 ecore_imf_context_preedit_end_event_add(imcontext->ctx);
1192 ecore_imf_context_event_callback_call(imcontext->ctx,
1193 ECORE_IMF_CALLBACK_PREEDIT_END,
1197 clear_preedit(imcontext);
1202 Eina_Unicode *ustr = eina_unicode_utf8_to_unicode (text, NULL);
1205 if (eina_unicode_strcmp (ustr, L" ") == 0 ||
1206 eina_unicode_strcmp (ustr, L" ") == 0)
1207 autoperiod_insert (imcontext->ctx);
1212 ecore_imf_context_commit_event_add(imcontext->ctx, text);
1213 ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)text);
1217 commit_preedit(WaylandIMContext *imcontext)
1220 if (!imcontext->preedit_commit)
1223 if (!imcontext->ctx)
1226 clear_preedit_text(imcontext);
1228 size_t commit_len = strlen(imcontext->preedit_commit);
1230 if (commit_len == 0) {
1231 ecore_imf_context_preedit_changed_event_add(imcontext->ctx);
1232 ecore_imf_context_event_callback_call(imcontext->ctx,
1233 ECORE_IMF_CALLBACK_PREEDIT_CHANGED,
1237 ecore_imf_context_preedit_end_event_add(imcontext->ctx);
1238 ecore_imf_context_event_callback_call(imcontext->ctx,
1239 ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
1241 if (commit_len > 0) {
1242 ecore_imf_context_commit_event_add(imcontext->ctx,
1243 imcontext->preedit_commit);
1244 ecore_imf_context_event_callback_call(imcontext->ctx,
1245 ECORE_IMF_CALLBACK_COMMIT,
1246 (void *)imcontext->preedit_commit);
1251 set_focus(Ecore_IMF_Context *ctx)
1253 LOGD("ctx : %p", ctx);
1254 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
1255 if (!imcontext) return EINA_FALSE;
1257 if (!imcontext->window) {
1258 LOGW("window is not given\n");
1262 Ecore_Wl_Input *input = ecore_wl_window_keyboard_get(imcontext->window);
1264 LOGW("ctx : %p, Can't get Wl_Input\n", ctx);
1268 struct wl_seat *seat = ecore_wl_input_seat_get(input);
1270 LOGW("ctx : %p, Can't get Wl_seat\n", ctx);
1274 imcontext->input = input;
1277 wl_text_input_activate(imcontext->text_input, seat,
1278 ecore_wl_window_surface_get(imcontext->window));
1284 set_focus_out(Ecore_IMF_Context *ctx)
1286 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
1287 if (!imcontext || !imcontext->input) return;
1290 if (imcontext->text_input)
1291 wl_text_input_deactivate(imcontext->text_input,
1292 ecore_wl_input_seat_get(imcontext->input));
1294 if (ctx == _focused_ctx)
1295 _focused_ctx = NULL;
1297 imcontext->input = NULL;
1300 // TIZEN_ONLY(20160217): ignore the duplicate show request
1301 static Eina_Bool _compare_context(Ecore_IMF_Context *ctx1, Ecore_IMF_Context *ctx2)
1303 if (!ctx1 || !ctx2) return EINA_FALSE;
1305 if ((ecore_imf_context_autocapital_type_get(ctx1) == ecore_imf_context_autocapital_type_get(ctx2)) &&
1306 (ecore_imf_context_input_panel_layout_get(ctx1) == ecore_imf_context_input_panel_layout_get(ctx2)) &&
1307 (ecore_imf_context_input_panel_layout_variation_get(ctx1) == ecore_imf_context_input_panel_layout_variation_get(ctx2)) &&
1308 (ecore_imf_context_input_panel_language_get(ctx1) == ecore_imf_context_input_panel_language_get(ctx2)) &&
1309 (ecore_imf_context_input_panel_return_key_type_get(ctx1) == ecore_imf_context_input_panel_return_key_type_get(ctx2)) &&
1310 (ecore_imf_context_input_panel_return_key_disabled_get(ctx1) == ecore_imf_context_input_panel_return_key_disabled_get(ctx2)) &&
1311 (ecore_imf_context_input_panel_caps_lock_mode_get(ctx1) == ecore_imf_context_input_panel_caps_lock_mode_get(ctx2)))
1318 static void send_get_hide_permission(WaylandIMContext *imcontext)
1320 if (imcontext->text_input) {
1321 ignore_hide = EINA_FALSE;
1322 wl_text_input_get_hide_permission(imcontext->text_input);
1326 static Eina_Bool _client_window_focus_out_cb(void *data, int ev_type, void *ev)
1328 Ecore_Wl_Event_Focus_Out *e = (Ecore_Wl_Event_Focus_Out *)ev;
1329 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)data;
1330 if (!ctx || !e) return ECORE_CALLBACK_PASS_ON;
1332 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get (ctx);
1333 if (!imcontext || !imcontext->window) return ECORE_CALLBACK_PASS_ON;
1335 unsigned int client_win_id = ecore_wl_window_id_get (imcontext->window);
1337 LOGD ("ctx : %p, client_window id : %#x, focus-out win : %#x\n", ctx, client_win_id, e->win);
1339 if (client_win_id > 0) {
1340 if (e->win == client_win_id) {
1341 LOGD ("window focus out\n");
1343 if (_focused_ctx == ctx) {
1344 wayland_im_context_focus_out (ctx);
1347 if (_show_req_ctx == ctx) {
1348 send_get_hide_permission(imcontext);
1353 send_get_hide_permission(imcontext);
1356 return ECORE_CALLBACK_PASS_ON;
1359 static void send_will_hide_ack(Ecore_IMF_Context *ctx)
1361 Eina_Bool need_temporary_context = EINA_FALSE;
1362 Eina_Bool has_conformant = EINA_FALSE;
1363 WaylandIMContext *imcontext = NULL;
1366 LOGD("ctx is NULL\n");
1367 need_temporary_context = EINA_TRUE;
1369 imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
1371 LOGD("imcontext is NULL :%p\n", ctx);
1372 need_temporary_context = EINA_TRUE;
1374 has_conformant = imcontext->has_conformant;
1378 /* When the RENDER_POST event is emitted, it is possible that our IMF_Context is already deleted,
1379 meaning that there is no connection available for communicating with the window manager.
1380 So we are creating a temporary context for sending WILL_HIDE_ACK message */
1381 if (need_temporary_context) {
1382 LOGD("creating temporary context for sending WILL_HIDE_ACK\n");
1383 const char *ctx_id = ecore_imf_context_default_id_get();
1384 ctx = ecore_imf_context_add(ctx_id);
1386 imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
1390 if (ctx && imcontext) {
1391 if (ecore_imf_context_client_canvas_get(ctx) && has_conformant) {
1392 if (_conformant_reset_done && _received_will_hide_event) {
1393 LOGD("Send will hide ack, _conformant_reset_done = 1, received_will_hide_event = 1\n");
1394 _send_will_hide_ack(imcontext);
1395 _conformant_reset_done = EINA_FALSE;
1396 _received_will_hide_event = EINA_FALSE;
1398 LOGD ("_conformant_reset_done=%d, received_will_hide_event=%d\n",
1399 _conformant_reset_done, _received_will_hide_event);
1402 LOGD("Send will hide ack right away, since there is no conformant available : %p %d\n",
1403 ecore_imf_context_client_canvas_get(ctx), has_conformant);
1404 _send_will_hide_ack (imcontext);
1408 if (need_temporary_context) {
1410 ecore_imf_context_del(ctx);
1415 static void _render_post_cb(void *data, Evas *e, void *event_info)
1417 void *callback = evas_event_callback_del(e, EVAS_CALLBACK_RENDER_POST, _render_post_cb);
1418 _conformant_reset_done = EINA_TRUE;
1419 _conformant_reset_started = EINA_FALSE;
1420 LOGD("[_render_post_cb], _conformant_reset_done = 1 , %p\n", callback);
1421 send_will_hide_ack(NULL);
1424 static Eina_Bool _conformant_change_cb(void *data, int ev_type, void *ev)
1426 Ecore_Wl_Event_Conformant_Change *e = (Ecore_Wl_Event_Conformant_Change *)ev;
1427 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)data;
1428 if (!e || !ctx) return ECORE_CALLBACK_PASS_ON;
1430 LOGD ("CONFORMANT changed!! part type : %d, state : %d, win : %d", e->part_type, e->state, e->win);
1432 if (_active_context_window_id != e->win)
1433 return ECORE_CALLBACK_PASS_ON;
1435 Ecore_Wl_Window *window = ecore_wl_window_find(e->win);
1436 if (!window) return ECORE_CALLBACK_PASS_ON;
1439 LOGD("_conformant_reset_done = 0, registering _render_post_cb : %p %p\n", _active_context_canvas, window);
1440 _conformant_reset_done = EINA_FALSE;
1441 if (_active_context_canvas && ecore_wl_window_conformant_get(window) && !_custom_conformant_event) {
1442 evas_event_callback_del(_active_context_canvas, EVAS_CALLBACK_RENDER_POST, _render_post_cb);
1443 evas_event_callback_add(_active_context_canvas, EVAS_CALLBACK_RENDER_POST, _render_post_cb, ctx);
1446 _conformant_reset_done = EINA_FALSE;
1447 if (_active_context_canvas) {
1448 evas_event_callback_del(_active_context_canvas, EVAS_CALLBACK_RENDER_POST, _render_post_cb);
1451 Eina_Bool result = EINA_FALSE;
1452 int x = 0, y = 0, w = 0, h = 0;
1455 /* TV IME consists of two or three windows, so ecore_wl_window_keyboard_geometry_get() may return wrong size. */
1456 x = _keyboard_geometry.x, y = _keyboard_geometry.y, w = _keyboard_geometry.w, h = _keyboard_geometry.h;
1457 if (_keyboard_geometry.w == 0 || _keyboard_geometry.h == 0) {
1458 result = ecore_wl_window_keyboard_geometry_get(window, &x, &y, &w, &h);
1461 /* Since the input_panel_geometry is not delivered right at the moment, we use conformant geometry instead */
1462 x = 0, y = 0, w = 0, h = 0;
1463 result = ecore_wl_window_keyboard_geometry_get(window, &x, &y, &w, &h);
1467 Evas_Coord scr_w = 0, scr_h = 0;
1469 ecore_wl_screen_size_get(&scr_w, &scr_h);
1470 int rot = ecore_wl_window_rotation_get(window);
1471 /* Assume we are using keyboard that has the same width to the screen width*/
1474 _keyboard_geometry.h = w;
1475 _keyboard_geometry.w = h;
1476 _keyboard_geometry.y = scr_w - _keyboard_geometry.h;
1477 _keyboard_geometry.x = 0;
1480 _keyboard_geometry.w = w;
1481 _keyboard_geometry.h = h;
1482 _keyboard_geometry.x = 0;
1483 _keyboard_geometry.y = scr_h - _keyboard_geometry.h;
1486 _keyboard_geometry.h = w;
1487 _keyboard_geometry.w = h;
1488 _keyboard_geometry.y = scr_w - _keyboard_geometry.h;
1489 _keyboard_geometry.x = 0;
1492 _keyboard_geometry.x = x;
1493 _keyboard_geometry.y = y;
1494 _keyboard_geometry.w = w;
1495 _keyboard_geometry.h = h;
1497 LOGD("[KEYPAD]: scr %dx%d, rot %d, orig (%d,%d, %dx%d)", scr_w, scr_h, rot, x, y, w, h);
1498 LOGD ("IME geometry x : %d, y : %d, w : %d, h : %d\n", _keyboard_geometry.x, _keyboard_geometry.y, _keyboard_geometry.w, _keyboard_geometry.h);
1499 ecore_imf_context_input_panel_event_callback_call(ctx, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
1503 return ECORE_CALLBACK_PASS_ON;
1507 get_purpose(Ecore_IMF_Context *ctx)
1509 int layout_variation = ecore_imf_context_input_panel_layout_variation_get (ctx);
1510 uint32_t new_purpose = 0;
1512 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
1516 switch (imcontext->content_purpose) {
1517 case WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS:
1518 if (layout_variation == ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_SIGNED)
1519 new_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS_SIGNED;
1520 else if (layout_variation == ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_DECIMAL)
1521 new_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS_DECIMAL;
1522 else if (layout_variation == ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_SIGNED_AND_DECIMAL)
1523 new_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS_SIGNEDDECIMAL;
1525 new_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS;
1527 case WL_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD:
1528 if (layout_variation == ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD_VARIATION_NUMBERONLY)
1529 new_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD_DIGITS;
1531 new_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD;
1533 case WL_TEXT_INPUT_CONTENT_PURPOSE_NORMAL:
1534 if (layout_variation == ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL_VARIATION_FILENAME)
1535 new_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_FILENAME;
1536 else if (layout_variation == ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL_VARIATION_PERSON_NAME)
1537 new_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NAME;
1539 new_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NORMAL;
1542 new_purpose = imcontext->content_purpose;
1549 static void _canvas_focus_in_cb(void *data, Evas *e, void *event_info)
1551 LOGD("ctx : %p", _focus_req_ctx);
1553 if (_focus_req_ctx) {
1554 set_focus(_focus_req_ctx);
1555 show_input_panel(_focus_req_ctx);
1557 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(_focus_req_ctx);
1558 if (imcontext && imcontext->canvas)
1559 evas_event_callback_del(imcontext->canvas, EVAS_CALLBACK_CANVAS_FOCUS_IN, _canvas_focus_in_cb);
1560 _focus_req_ctx = NULL;
1565 show_input_panel(Ecore_IMF_Context *ctx)
1567 LOGD("ctx : %p", ctx);
1568 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
1570 char *surrounding = NULL;
1573 if ((!imcontext) || (!imcontext->text_input))
1576 if (!imcontext->input) {
1578 if (!imcontext->input) {
1579 _focus_req_ctx = ctx;
1580 if (imcontext->canvas) {
1581 evas_event_callback_del(imcontext->canvas, EVAS_CALLBACK_CANVAS_FOCUS_IN, _canvas_focus_in_cb);
1582 evas_event_callback_add(imcontext->canvas, EVAS_CALLBACK_CANVAS_FOCUS_IN, _canvas_focus_in_cb, NULL);
1587 _clear_hide_timer ();
1589 _win_focus_out_handler_del ();
1591 if (!imcontext->input)
1594 ignore_hide = EINA_TRUE;
1596 _win_focus_out_handler = ecore_event_handler_add (ECORE_WL_EVENT_FOCUS_OUT, _client_window_focus_out_cb, ctx);
1597 _conformant_change_handler_del ();
1598 _conformant_change_handler = ecore_event_handler_add(ECORE_WL_EVENT_CONFORMANT_CHANGE, _conformant_change_cb, ctx);
1600 // TIZEN_ONLY(20160217): ignore the duplicate show request
1601 if ((_show_req_ctx == ctx) && _compare_context(_show_req_ctx, ctx) && (!will_hide)) {
1602 if (_input_panel_state == ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW ||
1603 _input_panel_state == ECORE_IMF_INPUT_PANEL_STATE_SHOW) {
1604 LOGD("already show. ctx : %p", ctx);
1610 will_hide = EINA_FALSE;
1611 _show_req_ctx = ctx;
1612 _input_panel_ctx = ctx;
1613 _active_context_canvas = ecore_imf_context_client_canvas_get(ctx);
1615 if (imcontext->window) {
1616 _active_context_window_id = ecore_wl_window_id_get(imcontext->window);
1617 imcontext->has_conformant = ecore_wl_window_conformant_get(imcontext->window);
1619 imcontext->has_conformant = EINA_FALSE;
1623 // TIZEN_ONLY(20150715): Support input_panel_state_get
1624 int layout = ecore_imf_context_input_panel_layout_get (ctx);
1625 int layout_variation = ecore_imf_context_input_panel_layout_variation_get (ctx);
1628 if (layout == ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD)
1629 imcontext->content_hint |= (WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA | WL_TEXT_INPUT_CONTENT_HINT_PASSWORD);
1631 wl_text_input_set_content_type(imcontext->text_input,
1632 imcontext->content_hint,
1635 if (ecore_imf_context_surrounding_get(imcontext->ctx, &surrounding, &cursor_pos)) {
1636 SECURE_LOGD ("surrounding text : %s\n", surrounding);
1640 imcontext->cursor_position = cursor_pos;
1641 wl_text_input_set_cursor_position(imcontext->text_input, cursor_pos);
1643 // TIZEN_ONLY(20150716): Support return key type
1644 wl_text_input_set_return_key_type(imcontext->text_input,
1645 imcontext->return_key_type);
1647 wl_text_input_set_return_key_disabled(imcontext->text_input,
1648 imcontext->return_key_disabled);
1650 if (imcontext->imdata_size > 0)
1651 wl_text_input_set_input_panel_data(imcontext->text_input, (const char *)imcontext->imdata, imcontext->imdata_size);
1653 wl_text_input_bidi_direction(imcontext->text_input, imcontext->bidi_direction);
1655 set_autocapital (ctx);
1657 SECURE_LOGD ("ctx : %p, layout : %d, layout variation : %d\n", ctx,
1658 layout, layout_variation);
1659 SECURE_LOGD ("language : %d, cursor position : %d\n",
1660 ecore_imf_context_input_panel_language_get (ctx),
1662 SECURE_LOGD ("return key type : %d, return key disabled : %d, autocapital type : %d\n",
1663 ecore_imf_context_input_panel_return_key_type_get (ctx),
1664 ecore_imf_context_input_panel_return_key_disabled_get (ctx),
1665 ecore_imf_context_autocapital_type_get (ctx));
1666 SECURE_LOGD ("client_window : %#x, password mode : %d, prediction_allow : %d\n",
1667 ecore_imf_context_client_window_get (ctx),
1668 (imcontext->content_hint & WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA) ? 1 : 0,
1669 ecore_imf_context_prediction_allow_get (ctx));
1670 SECURE_LOGD ("input hint : %#x, bidi direction : %d\n", ecore_imf_context_input_hint_get (ctx), imcontext->bidi_direction);
1672 if (_active_context_canvas && !evas_focus_state_get (_active_context_canvas)) {
1673 LOGW ("Canvas does not have focus!\n");
1677 if (hw_keyboard_mode) {
1678 LOGD("hw_keyboard_mode is TRUE, returning");
1682 _input_panel_state = ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW;
1684 wl_text_input_show_input_panel(imcontext->text_input);
1689 static void delete_surrounding_text(WaylandIMContext *imcontext, int index, int length)
1691 Ecore_IMF_Event_Delete_Surrounding ev;
1692 LOGD("delete surrounding text (index: %d, length: %u)",
1696 ev.n_chars = length;
1698 ecore_imf_context_delete_surrounding_event_add(imcontext->ctx, ev.offset, ev.n_chars);
1699 ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, &ev);
1703 text_input_preedit_string(void *data,
1704 struct wl_text_input *text_input EINA_UNUSED,
1709 WaylandIMContext *imcontext = (WaylandIMContext *)data;
1710 Eina_Bool old_preedit = EINA_FALSE;
1711 Eina_Bool preedit_changed = EINA_FALSE;
1713 SECURE_LOGD("ctx : %p, preedit event (text: '%s', current pre-edit: '%s')",
1716 imcontext->preedit_text ? imcontext->preedit_text : "");
1718 if (!check_serial(imcontext, serial))
1722 imcontext->preedit_text && strlen(imcontext->preedit_text) > 0;
1724 if (imcontext->preedit_text)
1725 preedit_changed = (strcmp(imcontext->preedit_text, text) != 0);
1727 preedit_changed = (strlen(text) != 0);
1729 clear_preedit(imcontext);
1731 imcontext->preedit_text = strdup(text);
1732 imcontext->preedit_commit = (strlen(text) > 0 ? strdup(commit) : NULL);
1733 imcontext->preedit_cursor =
1734 utf8_offset_to_characters(text, imcontext->pending_preedit.cursor);
1735 imcontext->preedit_attrs = imcontext->pending_preedit.attrs;
1737 imcontext->pending_preedit.attrs = NULL;
1739 if (preedit_changed) {
1741 ecore_imf_context_preedit_start_event_add(imcontext->ctx);
1742 ecore_imf_context_event_callback_call(imcontext->ctx,
1743 ECORE_IMF_CALLBACK_PREEDIT_START,
1747 ecore_imf_context_preedit_changed_event_add(imcontext->ctx);
1748 ecore_imf_context_event_callback_call(imcontext->ctx,
1749 ECORE_IMF_CALLBACK_PREEDIT_CHANGED,
1752 if (imcontext->preedit_text && strlen(imcontext->preedit_text) == 0) {
1753 ecore_imf_context_preedit_end_event_add(imcontext->ctx);
1754 ecore_imf_context_event_callback_call(imcontext->ctx,
1755 ECORE_IMF_CALLBACK_PREEDIT_END,
1762 text_input_delete_surrounding_text(void *data,
1763 struct wl_text_input *text_input EINA_UNUSED,
1767 WaylandIMContext *imcontext = (WaylandIMContext *)data;
1768 delete_surrounding_text(imcontext, index, length);
1772 text_input_cursor_position(void *data EINA_UNUSED,
1773 struct wl_text_input *text_input EINA_UNUSED,
1777 LOGD("cursor_position for next commit (index: %d, anchor: %d)",
1782 text_input_preedit_styling(void *data,
1783 struct wl_text_input *text_input EINA_UNUSED,
1788 WaylandIMContext *imcontext = (WaylandIMContext *)data;
1789 Ecore_IMF_Preedit_Attr *attr = calloc(1, sizeof(*attr));
1793 case WL_TEXT_INPUT_PREEDIT_STYLE_DEFAULT:
1794 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1;
1796 case WL_TEXT_INPUT_PREEDIT_STYLE_UNDERLINE:
1797 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1;
1799 case WL_TEXT_INPUT_PREEDIT_STYLE_INCORRECT:
1801 case WL_TEXT_INPUT_PREEDIT_STYLE_HIGHLIGHT:
1802 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB3;
1804 case WL_TEXT_INPUT_PREEDIT_STYLE_ACTIVE:
1806 case WL_TEXT_INPUT_PREEDIT_STYLE_INACTIVE:
1808 case WL_TEXT_INPUT_PREEDIT_STYLE_SELECTION:
1809 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2;
1812 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1;
1816 attr->start_index = index;
1817 attr->end_index = index + length;
1819 imcontext->pending_preedit.attrs =
1820 eina_list_append(imcontext->pending_preedit.attrs, attr);
1824 text_input_preedit_cursor(void *data,
1825 struct wl_text_input *text_input EINA_UNUSED,
1828 WaylandIMContext *imcontext = (WaylandIMContext *)data;
1830 imcontext->pending_preedit.cursor = index;
1833 static xkb_mod_index_t
1834 modifiers_get_index(struct wl_array *modifiers_map, const char *name)
1836 xkb_mod_index_t index = 0;
1837 char *p = modifiers_map->data;
1839 while ((const char *)p < ((const char *)modifiers_map->data + modifiers_map->size))
1841 if (strcmp(p, name) == 0)
1848 return XKB_MOD_INVALID;
1851 static xkb_mod_mask_t
1852 modifiers_get_mask(struct wl_array *modifiers_map,
1855 xkb_mod_index_t index = modifiers_get_index(modifiers_map, name);
1857 if (index == XKB_MOD_INVALID)
1858 return XKB_MOD_INVALID;
1864 text_input_modifiers_map(void *data,
1865 struct wl_text_input *text_input EINA_UNUSED,
1866 struct wl_array *map)
1868 WaylandIMContext *imcontext = (WaylandIMContext *)data;
1870 imcontext->shift_mask = modifiers_get_mask(map, "Shift");
1871 imcontext->control_mask = modifiers_get_mask(map, "Control");
1872 imcontext->alt_mask = modifiers_get_mask(map, "Mod1");
1873 imcontext->caps_mask = modifiers_get_mask(map, "Lock");
1874 imcontext->num_mask = modifiers_get_mask(map, "Mod2");
1878 _ecore_keyevent_free (void *data EINA_UNUSED, void *ev)
1880 Ecore_Event_Key *e = ev;
1886 text_input_keysym(void *data,
1887 struct wl_text_input *text_input EINA_UNUSED,
1888 uint32_t serial EINA_UNUSED,
1894 WaylandIMContext *imcontext = (WaylandIMContext *)data;
1895 char string[32], key[32], keyname[32];
1898 memset(key, 0, sizeof(key));
1899 xkb_keysym_get_name(sym, key, sizeof(key));
1901 memset(keyname, 0, sizeof(keyname));
1902 xkb_keysym_get_name(sym, keyname, sizeof(keyname));
1903 if (keyname[0] == '\0')
1904 snprintf(keyname, sizeof(keyname), "Keysym-%u", sym);
1906 memset(string, 0, sizeof(string));
1907 xkb_keysym_to_utf8(sym, string, 32);
1909 SECURE_LOGD("key event (key: %s)", keyname);
1911 e = calloc(1, sizeof(Ecore_Event_Key) + strlen(key) + strlen(keyname) +
1912 strlen(string) + 3);
1915 e->keyname = (char *)(e + 1);
1916 e->key = e->keyname + strlen(keyname) + 1;
1917 e->string = e->key + strlen(key) + 1;
1918 e->compose = e->string;
1920 strncpy((char *)e->keyname, keyname, strlen(keyname));
1921 strncpy((char *)e->key, key, strlen(key));
1922 strncpy((char *)e->string, string, strlen(string));
1924 e->window = (Ecore_Window)ecore_wl_window_id_get(imcontext->window);
1925 e->event_window = (Ecore_Window)ecore_wl_window_id_get(imcontext->window);
1926 e->dev = _ime_device;
1927 e->timestamp = 0; /* For distinguishing S/W keyboard event */
1930 if (modifiers & imcontext->shift_mask)
1931 e->modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
1933 if (modifiers & imcontext->control_mask)
1934 e->modifiers |= ECORE_EVENT_MODIFIER_CTRL;
1936 if (modifiers & imcontext->alt_mask)
1937 e->modifiers |= ECORE_EVENT_MODIFIER_ALT;
1939 if (modifiers & MOD_Mod5_MASK)
1940 e->modifiers |= MOD_Mod5_MASK;
1942 if (modifiers & imcontext->caps_mask)
1943 e->modifiers |= ECORE_EVENT_LOCK_CAPS;
1945 if (modifiers & imcontext->num_mask)
1946 e->modifiers |= ECORE_EVENT_LOCK_NUM;
1948 //Save "wl_text_input::keysym" keysym to list if list is not empty,
1949 //if not, send keysym to ecore loop as key event.
1950 //This code let key event which will be filtered by IME one by one.
1951 if (eina_list_count(imcontext->keysym_list)) {
1952 e->data = (void *)(unsigned long int)(state ? ECORE_EVENT_KEY_DOWN : ECORE_EVENT_KEY_UP);
1953 imcontext->keysym_list = eina_list_prepend(imcontext->keysym_list, e);
1957 ecore_event_add(ECORE_EVENT_KEY_DOWN, e, _ecore_keyevent_free, NULL);
1959 ecore_event_add(ECORE_EVENT_KEY_UP, e, _ecore_keyevent_free, NULL);
1964 text_input_enter(void *data,
1965 struct wl_text_input *text_input EINA_UNUSED,
1966 struct wl_surface *surface EINA_UNUSED)
1968 WaylandIMContext *imcontext = (WaylandIMContext *)data;
1970 update_state(imcontext);
1972 imcontext->reset_serial = imcontext->serial;
1976 text_input_leave(void *data,
1977 struct wl_text_input *text_input EINA_UNUSED)
1979 WaylandIMContext *imcontext = (WaylandIMContext *)data;
1982 commit_preedit(imcontext);
1983 clear_preedit(imcontext);
1987 text_input_input_panel_state(void *data EINA_UNUSED,
1988 struct wl_text_input *text_input EINA_UNUSED,
1989 uint32_t state EINA_UNUSED)
1991 // TIZEN_ONLY(20150708): Support input panel state callback
1992 WaylandIMContext *imcontext = (WaylandIMContext *)data;
1993 LOGD("input panel state: %d", state);
1995 case WL_TEXT_INPUT_INPUT_PANEL_STATE_HIDE:
1996 _input_panel_state = ECORE_IMF_INPUT_PANEL_STATE_HIDE;
1997 if (imcontext->ctx == _show_req_ctx)
1998 _show_req_ctx = NULL;
2000 will_hide = EINA_FALSE;
2002 _received_will_hide_event = EINA_TRUE;
2003 LOGD("_received_will_hide_event = 1\n");
2004 send_will_hide_ack(imcontext->ctx);
2006 case WL_TEXT_INPUT_INPUT_PANEL_STATE_SHOW:
2007 _input_panel_state = ECORE_IMF_INPUT_PANEL_STATE_SHOW;
2008 _received_will_hide_event = EINA_FALSE;
2010 _show_req_ctx = imcontext->ctx;
2011 LOGD("_received_will_hide_event = 0\n");
2014 _input_panel_state = (Ecore_IMF_Input_Panel_State)state;
2018 ecore_imf_context_input_panel_event_callback_call(imcontext->ctx,
2019 ECORE_IMF_INPUT_PANEL_STATE_EVENT,
2020 _input_panel_state);
2022 if (state == WL_TEXT_INPUT_INPUT_PANEL_STATE_HIDE) {
2023 reset_keyboard_geometry();
2024 LOGD ("IME geometry x : %d, y : %d, w : %d, h : %d\n", _keyboard_geometry.x, _keyboard_geometry.y, _keyboard_geometry.w, _keyboard_geometry.h);
2025 ecore_imf_context_input_panel_event_callback_call(imcontext->ctx, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
2030 // TIZEN_ONLY(20151221): Support input panel geometry
2032 text_input_input_panel_geometry(void *data EINA_UNUSED,
2033 struct wl_text_input *text_input EINA_UNUSED,
2039 WaylandIMContext *imcontext = (WaylandIMContext *)data;
2041 if (_keyboard_geometry.x != (int)x || _keyboard_geometry.y != (int)y ||
2042 _keyboard_geometry.w != (int)w || _keyboard_geometry.h != (int)h)
2044 _keyboard_geometry.x = x;
2045 _keyboard_geometry.y = y;
2046 _keyboard_geometry.w = w;
2047 _keyboard_geometry.h = h;
2048 LOGD ("IME geometry x : %d, y : %d, w : %d, h : %d\n", _keyboard_geometry.x, _keyboard_geometry.y, _keyboard_geometry.w, _keyboard_geometry.h);
2049 ecore_imf_context_input_panel_event_callback_call(imcontext->ctx, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
2055 text_input_language(void *data,
2056 struct wl_text_input *text_input EINA_UNUSED,
2057 uint32_t serial EINA_UNUSED,
2058 const char *language)
2060 WaylandIMContext *imcontext = (WaylandIMContext *)data;
2061 Eina_Bool changed = EINA_FALSE;
2063 if (!imcontext || !language) return;
2065 if (imcontext->language) {
2066 if (strcmp(imcontext->language, language) != 0) {
2067 changed = EINA_TRUE;
2068 free(imcontext->language);
2072 changed = EINA_TRUE;
2076 imcontext->language = strdup(language);
2079 ecore_imf_context_input_panel_event_callback_call(imcontext->ctx, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, 0);
2084 text_input_text_direction(void *data EINA_UNUSED,
2085 struct wl_text_input *text_input EINA_UNUSED,
2086 uint32_t serial EINA_UNUSED,
2087 uint32_t direction EINA_UNUSED)
2091 // TIZEN_ONLY(20150918): Support to set the selection region
2093 text_input_selection_region(void *data,
2094 struct wl_text_input *text_input EINA_UNUSED,
2095 uint32_t serial EINA_UNUSED,
2099 WaylandIMContext *imcontext = (WaylandIMContext *)data;
2100 if (!imcontext || !imcontext->ctx) return;
2102 Ecore_IMF_Event_Selection ev;
2103 ev.ctx = imcontext->ctx;
2106 ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_SELECTION_SET, &ev);
2110 text_input_private_command(void *data,
2111 struct wl_text_input *text_input EINA_UNUSED,
2112 uint32_t serial EINA_UNUSED,
2113 const char *command)
2115 WaylandIMContext *imcontext = (WaylandIMContext *)data;
2116 if (!imcontext || !imcontext->ctx) return;
2118 const char *szConformantReset = "CONFORMANT_RESET";
2119 const char *szConformantRestore = "CONFORMANT_RESTORE";
2120 LOGD("Checking command : %s", command);
2122 if (strncmp(command, szConformantReset, strlen(szConformantReset)) == 0) {
2123 Ecore_Wl_Window *window = imcontext->window;
2124 if (!window) return;
2126 if (!reset_conformant_area(imcontext->ctx) && !_conformant_reset_started) {
2127 LOGD("Could not reset conformant area, send will_hide_ack right away %d", _conformant_reset_started);
2128 _send_will_hide_ack(imcontext);
2129 } else if (_conformant_reset_done) {
2130 LOGD("Conformant reset has been already finished, send will_hide_ack right away");
2131 _send_will_hide_ack(imcontext);
2133 } else if (strncmp(command, szConformantRestore, strlen(szConformantRestore)) == 0) {
2134 Ecore_Wl_Window *window = imcontext->window;
2135 if (!window) return;
2137 restore_conformant_area(imcontext->ctx);
2139 ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, (void *)command);
2144 text_input_input_panel_data(void *data,
2145 struct wl_text_input *text_input EINA_UNUSED,
2146 uint32_t serial EINA_UNUSED,
2147 const char *input_panel_data,
2150 WaylandIMContext *imcontext = (WaylandIMContext *)data;
2151 if (!imcontext || !imcontext->ctx) return;
2153 if (imcontext->input_panel_data)
2154 free (imcontext->input_panel_data);
2156 imcontext->input_panel_data = calloc (1, length);
2157 memcpy (imcontext->input_panel_data, input_panel_data, length);
2158 imcontext->input_panel_data_length = length;
2162 text_input_get_selection_text (void *data,
2163 struct wl_text_input *text_input EINA_UNUSED,
2166 char *selection = NULL;
2168 WaylandIMContext *imcontext = (WaylandIMContext *)data;
2169 if (!imcontext || !imcontext->ctx) {
2175 ecore_imf_context_selection_get (imcontext->ctx, &selection);
2176 if (imcontext->text_input) {
2177 SECURE_LOGD ("selection :%s", selection ? selection : "");
2179 char *_selection = selection;
2180 size_t len = strlen (selection);
2182 ssize_t ret = write (fd, _selection, len);
2186 LOGW ("write pipe failed, errno: %d", errno);
2200 text_input_get_surrounding_text (void *data,
2201 struct wl_text_input *text_input EINA_UNUSED,
2202 uint32_t maxlen_before,
2203 uint32_t maxlen_after,
2207 char *surrounding = NULL;
2208 LOGD("fd: %d maxlen_before: %d maxlen_after: %d", fd, maxlen_before, maxlen_after);
2209 WaylandIMContext *imcontext = (WaylandIMContext *)data;
2210 if (!imcontext || !imcontext->ctx) {
2216 /* cursor_pos is a byte index */
2217 if (ecore_imf_context_surrounding_get (imcontext->ctx, &surrounding, &cursor_pos)) {
2218 SECURE_LOGD ("surrounding : '%s', cursor: %d", surrounding ? surrounding : "", cursor_pos);
2219 if (imcontext->text_input) {
2220 Eina_Unicode *wide_surrounding = eina_unicode_utf8_to_unicode (surrounding, NULL);
2221 size_t wlen = eina_unicode_strlen (wide_surrounding);
2223 if (cursor_pos > (int)wlen || cursor_pos < 0)
2226 if (maxlen_before > cursor_pos)
2229 maxlen_before = cursor_pos - maxlen_before;
2231 if (maxlen_after > wlen - cursor_pos)
2232 maxlen_after = wlen;
2234 maxlen_after = cursor_pos + maxlen_after;
2236 char *req_surrounding = eina_unicode_unicode_to_utf8_range (wide_surrounding + maxlen_before, maxlen_after - maxlen_before, NULL);
2238 ssize_t ret = write(fd, &cursor_pos, sizeof(cursor_pos));
2240 LOGW ("write pipe failed, errno: %d", errno);
2241 } else if (req_surrounding) {
2242 char *_surrounding = req_surrounding;
2243 size_t len = strlen(req_surrounding);
2245 ssize_t ret = write(fd, _surrounding, len);
2249 LOGW ("write pipe failed, errno: %d", errno);
2252 _surrounding += ret;
2257 if (req_surrounding)
2258 free (req_surrounding);
2260 if (wide_surrounding)
2261 free (wide_surrounding);
2271 text_input_filter_key_event_done(void *data,
2272 struct wl_text_input *text_input EINA_UNUSED,
2276 LOGD("serial: %d, state: %d", serial, state);
2277 WaylandIMContext *imcontext = (WaylandIMContext *)data;
2278 if (!imcontext) return;
2280 imcontext->last_key_event_filter.serial = serial;
2281 imcontext->last_key_event_filter.state = state;
2285 text_input_hide_permission(void *data,
2286 struct wl_text_input *text_input EINA_UNUSED,
2287 uint32_t permission)
2289 LOGD("permission : %d", permission);
2290 WaylandIMContext *imcontext = (WaylandIMContext *)data;
2291 if (!imcontext || !imcontext->ctx || ignore_hide)
2295 ecore_imf_context_input_panel_hide(imcontext->ctx);
2299 text_input_recapture_string(void *data,
2300 struct wl_text_input *text_input EINA_UNUSED,
2304 const char *preedit,
2305 const char *preedit_commit,
2308 WaylandIMContext *imcontext = (WaylandIMContext *)data;
2309 Eina_Bool old_preedit = EINA_FALSE;
2310 Eina_Bool preedit_changed = EINA_FALSE;
2312 SECURE_LOGD("ctx : %p, preedit event (preedit: '%s', current pre-edit: '%s')",
2315 imcontext->preedit_text ? imcontext->preedit_text : "");
2317 if (!check_serial(imcontext, serial))
2321 imcontext->preedit_text && strlen(imcontext->preedit_text) > 0;
2323 if (imcontext->preedit_text)
2324 preedit_changed = (strcmp(imcontext->preedit_text, preedit) != 0);
2326 preedit_changed = (strlen(preedit) != 0);
2328 clear_preedit(imcontext);
2330 // send transaction start
2331 ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, (void *)"TRANSACTION_START");
2333 // delete surrounding text
2334 delete_surrounding_text(imcontext, index, length);
2336 // update preedit string
2337 imcontext->preedit_text = strdup(preedit);
2338 imcontext->preedit_commit = (strlen(preedit) > 0 ? strdup(preedit_commit) : NULL);
2339 imcontext->preedit_cursor =
2340 utf8_offset_to_characters(preedit, imcontext->pending_preedit.cursor);
2341 imcontext->preedit_attrs = imcontext->pending_preedit.attrs;
2343 imcontext->pending_preedit.attrs = NULL;
2345 if (preedit_changed) {
2347 ecore_imf_context_preedit_start_event_add(imcontext->ctx);
2348 ecore_imf_context_event_callback_call(imcontext->ctx,
2349 ECORE_IMF_CALLBACK_PREEDIT_START,
2353 ecore_imf_context_preedit_changed_event_add(imcontext->ctx);
2354 ecore_imf_context_event_callback_call(imcontext->ctx,
2355 ECORE_IMF_CALLBACK_PREEDIT_CHANGED,
2358 if (imcontext->preedit_text && strlen(imcontext->preedit_text) == 0) {
2359 ecore_imf_context_preedit_end_event_add(imcontext->ctx);
2360 ecore_imf_context_event_callback_call(imcontext->ctx,
2361 ECORE_IMF_CALLBACK_PREEDIT_END,
2367 if (commit && strlen(commit) != 0) {
2368 ecore_imf_context_commit_event_add(imcontext->ctx, commit);
2369 ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)commit);
2372 // send transaction end
2373 ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, (void *)"TRANSACTION_END");
2377 static const struct wl_text_input_listener text_input_listener =
2381 text_input_modifiers_map,
2382 text_input_input_panel_state,
2383 text_input_preedit_string,
2384 text_input_preedit_styling,
2385 text_input_preedit_cursor,
2386 text_input_commit_string,
2387 text_input_cursor_position,
2388 text_input_delete_surrounding_text,
2390 text_input_language,
2391 text_input_text_direction,
2392 // TIZEN_ONLY(20150918): Support to set the selection region
2393 text_input_selection_region,
2394 text_input_private_command,
2395 text_input_input_panel_geometry,
2396 text_input_input_panel_data,
2397 text_input_get_selection_text,
2398 text_input_get_surrounding_text,
2399 text_input_filter_key_event_done,
2400 text_input_hide_permission,
2401 text_input_recapture_string
2407 keyboard_mode_changed_cb (keynode_t *key, void* data)
2409 hw_keyboard_mode = vconf_keynode_get_bool (key);
2410 Ecore_IMF_Context *active_ctx = get_using_ctx ();
2412 LOGD ("ctx : %p, input detect : %d\n", active_ctx, hw_keyboard_mode);
2414 Ecore_IMF_Input_Panel_Keyboard_Mode input_mode = hw_keyboard_mode ? ECORE_IMF_INPUT_PANEL_HW_KEYBOARD_MODE : ECORE_IMF_INPUT_PANEL_SW_KEYBOARD_MODE;
2415 ecore_imf_context_input_panel_event_callback_call (active_ctx, ECORE_IMF_INPUT_PANEL_KEYBOARD_MODE_EVENT, input_mode);
2417 if ((input_mode == ECORE_IMF_INPUT_PANEL_SW_KEYBOARD_MODE) && _focused_ctx && (active_ctx == _focused_ctx)) {
2418 if (ecore_imf_context_input_panel_enabled_get (active_ctx)) {
2419 ecore_imf_context_input_panel_show (active_ctx);
2425 static Eina_Bool read_devices = EINA_FALSE;
2426 char ** device_names = NULL;
2429 filter_devices (const char *dev_name)
2437 if (read_devices == EINA_FALSE) {
2438 char *devices = getenv("ISF_REMOTE_CONTROL_DEVICES");
2440 device_names = eina_str_split(devices, ",", 0);
2442 read_devices = EINA_TRUE;
2445 if (device_names == NULL) {
2449 for (i = 0; device_names[i]; i++) {
2450 if (!strcmp (dev_name, device_names[i])) {
2459 void wayland_im_initialize ()
2461 register_key_handler ();
2463 /* get input language vconf value */
2464 get_input_language ();
2467 /* get autoperiod allow vconf value */
2469 if (vconf_get_bool (VCONFKEY_AUTOPERIOD_ALLOW_BOOL, &val) == 0) {
2470 if (val == EINA_TRUE)
2471 autoperiod_allow = EINA_TRUE;
2474 /* get autocapital allow vconf value */
2475 if (vconf_get_bool (VCONFKEY_AUTOCAPITAL_ALLOW_BOOL, &val) == 0) {
2476 if (val == EINA_TRUE)
2477 autocap_allow = EINA_TRUE;
2480 /* get hardware keyboard input detected vconf value */
2481 if (vconf_get_bool (VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, &val) == 0) {
2482 if (val == EINA_TRUE)
2483 hw_keyboard_mode = EINA_TRUE;
2486 vconf_notify_key_changed (VCONFKEY_AUTOCAPITAL_ALLOW_BOOL, autocapital_allow_changed_cb, NULL);
2487 vconf_notify_key_changed (VCONFKEY_AUTOPERIOD_ALLOW_BOOL, autoperiod_allow_changed_cb, NULL);
2488 vconf_notify_key_changed (VCONFKEY_ISF_INPUT_LANGUAGE, input_language_changed_cb, NULL);
2489 vconf_notify_key_changed (VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, keyboard_mode_changed_cb, NULL);
2492 _ime_device = ecore_device_add();
2494 ecore_device_name_set (_ime_device, IME_DEVICE_NAME);
2495 ecore_device_description_set (_ime_device, IME_DEVICE_NAME);
2496 ecore_device_identifier_set (_ime_device, IME_DEVICE_NAME);
2497 ecore_device_class_set (_ime_device, ECORE_DEVICE_CLASS_KEYBOARD);
2501 void wayland_im_uninitialize ()
2503 unregister_key_handler ();
2505 _win_focus_out_handler_del ();
2506 _conformant_change_handler_del ();
2509 vconf_ignore_key_changed (VCONFKEY_AUTOPERIOD_ALLOW_BOOL, autoperiod_allow_changed_cb);
2510 vconf_ignore_key_changed (VCONFKEY_AUTOCAPITAL_ALLOW_BOOL, autocapital_allow_changed_cb);
2511 vconf_ignore_key_changed (VCONFKEY_ISF_INPUT_LANGUAGE, input_language_changed_cb);
2512 vconf_ignore_key_changed (VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, keyboard_mode_changed_cb);
2516 if (device_names[0])
2517 free (device_names[0]);
2518 free (device_names);
2519 device_names = NULL;
2525 ecore_device_del (_ime_device);
2531 wayland_im_context_add(Ecore_IMF_Context *ctx)
2533 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2535 LOGD("ctx : %p", ctx);
2537 if (!imcontext) return;
2539 imcontext->ctx = ctx;
2540 imcontext->input_panel_layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL;
2541 imcontext->keysym_list = NULL;
2543 imcontext->shift_mask = MOD_SHIFT_MASK;
2544 imcontext->control_mask = MOD_CONTROL_MASK;
2545 imcontext->alt_mask = MOD_ALT_MASK;
2546 imcontext->caps_mask = MOD_CAPS_MASK;
2547 imcontext->num_mask = MOD_NUM_MASK;
2549 imcontext->text_input =
2550 wl_text_input_manager_create_text_input(imcontext->text_input_manager);
2552 if (imcontext->text_input)
2553 wl_text_input_add_listener(imcontext->text_input,
2554 &text_input_listener, imcontext);
2558 wayland_im_context_del (Ecore_IMF_Context *ctx)
2560 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2562 Ecore_Event_Key *ev;
2563 LOGD ("ctx : %p, focused_ctx : %p, show_req_ctx : %p", ctx, _focused_ctx, _show_req_ctx);
2565 if (!imcontext) return;
2567 if (_ime_device && imcontext->window)
2568 _device_info_send (ecore_wl_window_id_get (imcontext->window), EINA_FALSE);
2570 // TIZEN_ONLY(20150708): Support back key
2571 if (_input_panel_ctx == ctx) {
2572 _clear_hide_timer();
2573 _input_panel_hide(ctx, EINA_TRUE);
2574 _input_panel_state = ECORE_IMF_INPUT_PANEL_STATE_HIDE;
2575 _input_panel_ctx = NULL;
2578 if (_focused_ctx == ctx)
2579 _focused_ctx = NULL;
2581 if (_show_req_ctx == ctx)
2582 _show_req_ctx = NULL;
2584 if (_focus_req_ctx == ctx) {
2585 if (imcontext->canvas)
2586 evas_event_callback_del(imcontext->canvas, EVAS_CALLBACK_CANVAS_FOCUS_IN, _canvas_focus_in_cb);
2588 _focus_req_ctx = NULL;
2592 if (imcontext->language) {
2593 free (imcontext->language);
2594 imcontext->language = NULL;
2597 // TIZEN_ONLY(20150922): Support to set input panel data
2598 if (imcontext->imdata) {
2599 free (imcontext->imdata);
2600 imcontext->imdata = NULL;
2601 imcontext->imdata_size = 0;
2604 if (imcontext->input_panel_data) {
2605 free (imcontext->input_panel_data);
2606 imcontext->input_panel_data = NULL;
2607 imcontext->input_panel_data_length = 0;
2611 if (imcontext->prediction_hint) {
2612 free (imcontext->prediction_hint);
2613 imcontext->prediction_hint = NULL;
2616 if (imcontext->text_input)
2617 wl_text_input_destroy (imcontext->text_input);
2619 clear_preedit (imcontext);
2621 EINA_LIST_FREE(imcontext->keysym_list, ev) {
2629 wayland_im_context_reset(Ecore_IMF_Context *ctx)
2631 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2633 LOGD("ctx : %p", ctx);
2635 if (!imcontext) return;
2637 Eina_Bool preedit_empty = check_preedit_empty(imcontext);
2639 commit_preedit (imcontext);
2640 clear_preedit(imcontext);
2642 if (!imcontext->input) return;
2644 if (imcontext->text_input && !preedit_empty) {
2645 wl_text_input_reset(imcontext->text_input);
2647 update_state(imcontext);
2649 imcontext->reset_serial = imcontext->serial;
2653 wayland_im_context_focus_in(Ecore_IMF_Context *ctx)
2656 LOGD ("ctx : %p. enable : %d, on demand : %d\n", ctx,
2657 ecore_imf_context_input_panel_enabled_get(ctx),
2658 ecore_imf_context_input_panel_show_on_demand_get (ctx));
2660 if (!set_focus(ctx)) {
2661 LOGW("ctx : %p. Fail to set focus!", ctx);
2665 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2666 if (imcontext && imcontext->input && imcontext->text_input) {
2667 wl_text_input_set_return_key_disabled(imcontext->text_input,
2668 imcontext->return_key_disabled);
2670 if (imcontext->prediction_hint)
2671 wl_text_input_prediction_hint(imcontext->text_input, imcontext->prediction_hint);
2674 if (ecore_imf_context_input_panel_enabled_get(ctx))
2675 if (!ecore_imf_context_input_panel_show_on_demand_get (ctx))
2676 show_input_panel(ctx);
2678 LOGD ("ctx : %p input panel on demand mode : TRUE\n", ctx);
2680 LOGD ("ctx : %p input panel enable : FALSE\n", ctx);
2684 wayland_im_context_focus_out(Ecore_IMF_Context *ctx)
2686 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2688 LOGD("ctx : %p", ctx);
2690 if (_focus_req_ctx == ctx)
2691 _focus_req_ctx = NULL;
2693 if (!imcontext || !imcontext->input) return;
2695 if (ecore_imf_context_input_panel_enabled_get(ctx)) {
2696 ecore_imf_context_input_panel_hide(ctx);
2703 wayland_im_context_preedit_string_get(Ecore_IMF_Context *ctx,
2707 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2708 if (!imcontext) return;
2710 SECURE_LOGD("pre-edit string requested (preedit: '%s')",
2711 imcontext->preedit_text ? imcontext->preedit_text : "");
2714 *str = strdup(imcontext->preedit_text ? imcontext->preedit_text : "");
2717 *cursor_pos = imcontext->preedit_cursor;
2721 wayland_im_context_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx,
2726 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2727 if (!imcontext) return;
2729 SECURE_LOGD("pre-edit string with attributes requested (preedit: '%s')",
2730 imcontext->preedit_text ? imcontext->preedit_text : "");
2733 *str = strdup(imcontext->preedit_text ? imcontext->preedit_text : "");
2737 Ecore_IMF_Preedit_Attr *a, *attr;
2739 if (imcontext->preedit_attrs) {
2740 EINA_LIST_FOREACH(imcontext->preedit_attrs, l, a) {
2741 attr = malloc(sizeof(*attr));
2742 attr = memcpy(attr, a, sizeof(*attr));
2743 *attrs = eina_list_append(*attrs, attr);
2747 if (imcontext->preedit_text) {
2748 Ecore_IMF_Preedit_Attr *attr = calloc(1, sizeof(*attr));
2749 // use REVERSE style as default
2750 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2;
2751 attr->start_index = 0;
2752 attr->end_index = strlen(imcontext->preedit_text);
2753 *attrs = eina_list_append(*attrs, attr);
2759 *cursor_pos = imcontext->preedit_cursor;
2763 wayland_im_context_cursor_position_set (Ecore_IMF_Context *ctx,
2766 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2767 if (!imcontext) return;
2769 if (imcontext->cursor_position != cursor_pos) {
2770 imcontext->cursor_position = cursor_pos;
2772 if (imcontext->input && imcontext->text_input) {
2773 LOGD ("ctx : %p, cursor pos : %d\n", ctx, cursor_pos);
2775 set_autocapital (ctx);
2777 if (!imcontext->preedit_text || strlen(imcontext->preedit_text) == 0)
2778 wl_text_input_set_cursor_position (imcontext->text_input, cursor_pos);
2784 wayland_im_context_use_preedit_set(Ecore_IMF_Context *ctx EINA_UNUSED,
2785 Eina_Bool use_preedit EINA_UNUSED)
2790 wayland_im_context_client_window_set(Ecore_IMF_Context *ctx,
2793 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2795 LOGD("client window set (window: %p)", window);
2797 if (imcontext && window) {
2798 imcontext->window = ecore_wl_window_find((Ecore_Window)window);
2800 if (_ime_device && imcontext->window)
2801 _device_info_send (ecore_wl_window_id_get (imcontext->window), EINA_TRUE);
2806 wayland_im_context_client_canvas_set(Ecore_IMF_Context *ctx,
2809 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2811 LOGD("client canvas set (canvas: %p)", canvas);
2813 if (imcontext && canvas) {
2814 imcontext->canvas = canvas;
2816 if (!imcontext->window)
2817 imcontext->window = ecore_wl_window_find(ecore_evas_window_get(ecore_evas_ecore_evas_get(canvas)));
2819 if (_ime_device && imcontext->window)
2820 _device_info_send (ecore_wl_window_id_get (imcontext->window), EINA_TRUE);
2825 wayland_im_context_show(Ecore_IMF_Context *ctx)
2827 LOGD("ctx : %p", ctx);
2829 show_input_panel(ctx);
2833 wayland_im_context_hide(Ecore_IMF_Context *ctx)
2835 LOGD("ctx : %p", ctx);
2837 if (!get_using_ctx()) {
2838 LOGW("Can't hide input_panel because there is no using context!!");
2842 _input_panel_hide(ctx, EINA_FALSE);
2845 #if !(ENABLE_GRAB_KEYBOARD)
2847 _ecore_imf_lock_to_ecore_key_modifier(unsigned int locks)
2849 unsigned int mask = 0;
2851 if (locks & ECORE_IMF_KEYBOARD_LOCK_SCROLL)
2852 mask |= ECORE_EVENT_LOCK_SCROLL;
2854 if (locks & ECORE_IMF_KEYBOARD_LOCK_CAPS)
2855 mask |= ECORE_EVENT_LOCK_CAPS;
2857 if (locks & ECORE_IMF_KEYBOARD_LOCK_NUM)
2858 mask |= ECORE_EVENT_LOCK_NUM;
2864 _ecore_imf_modifier_to_ecore_key_modifier(Ecore_IMF_Keyboard_Modifiers modifiers)
2866 unsigned int mask = 0;
2868 /**< "Control" is pressed */
2869 if (modifiers & ECORE_IMF_KEYBOARD_MODIFIER_CTRL)
2870 mask |= ECORE_EVENT_MODIFIER_CTRL;
2872 /**< "Alt" is pressed */
2873 if (modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALT)
2874 mask |= ECORE_EVENT_MODIFIER_ALT;
2876 /**< "Shift" is pressed */
2877 if (modifiers & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT)
2878 mask |= ECORE_EVENT_MODIFIER_SHIFT;
2880 /**< "Win" (between "Ctrl" and "Alt") is pressed */
2881 if (modifiers & ECORE_IMF_KEYBOARD_MODIFIER_WIN)
2882 mask |= ECORE_EVENT_MODIFIER_WIN;
2884 /**< "AltGr" is pressed */
2885 if (modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALTGR)
2886 mask |= ECORE_EVENT_MODIFIER_ALTGR;
2893 wayland_im_context_filter_event(Ecore_IMF_Context *ctx,
2894 Ecore_IMF_Event_Type type,
2895 Ecore_IMF_Event *imf_event)
2898 #if !(ENABLE_GRAB_KEYBOARD)
2899 Eina_Bool ret = EINA_FALSE;
2900 Ecore_Event_Key ecore_key_ev;
2901 char *key_dev_name = NULL;
2902 uint32_t key_dev_class = 0;
2903 uint32_t key_dev_subclass = 0;
2905 if (type == ECORE_IMF_EVENT_MOUSE_UP) {
2906 if (ecore_imf_context_input_panel_enabled_get(ctx)) {
2907 LOGD ("[Mouse-up event] ctx : %p\n", ctx);
2908 if (ctx == _focused_ctx) {
2909 ecore_imf_context_input_panel_show(ctx);
2912 LOGE ("Can't show IME because there is no focus. ctx : %p\n", ctx);
2915 #if !(ENABLE_GRAB_KEYBOARD)
2916 else if (type == ECORE_IMF_EVENT_KEY_UP) {
2917 Ecore_IMF_Event_Key_Up *key_ev = (Ecore_IMF_Event_Key_Up *)imf_event;
2918 ecore_key_ev.keyname = key_ev->keyname;
2919 ecore_key_ev.key = key_ev->key;
2920 ecore_key_ev.string = key_ev->string;
2921 ecore_key_ev.compose = key_ev->compose;
2922 ecore_key_ev.timestamp = key_ev->timestamp;
2923 ecore_key_ev.modifiers = _ecore_imf_modifier_to_ecore_key_modifier(key_ev->modifiers);
2924 ecore_key_ev.modifiers |= _ecore_imf_lock_to_ecore_key_modifier(key_ev->locks);
2925 key_dev_name = (char *)key_ev->dev_name;
2926 key_dev_class = key_ev->dev_class;
2927 key_dev_subclass = key_ev->dev_subclass;
2929 else if (type == ECORE_IMF_EVENT_KEY_DOWN) {
2930 Ecore_IMF_Event_Key_Down *key_ev = (Ecore_IMF_Event_Key_Down *)imf_event;
2931 ecore_key_ev.keyname = key_ev->keyname;
2932 ecore_key_ev.key = key_ev->key;
2933 ecore_key_ev.string = key_ev->string;
2934 ecore_key_ev.compose = key_ev->compose;
2935 ecore_key_ev.timestamp = key_ev->timestamp;
2936 ecore_key_ev.modifiers = _ecore_imf_modifier_to_ecore_key_modifier(key_ev->modifiers);
2937 ecore_key_ev.modifiers |= _ecore_imf_lock_to_ecore_key_modifier(key_ev->locks);
2938 key_dev_name = (char *)key_ev->dev_name;
2939 key_dev_class = key_ev->dev_class;
2940 key_dev_subclass = key_ev->dev_subclass;
2943 if (type == ECORE_IMF_EVENT_KEY_UP || type == ECORE_IMF_EVENT_KEY_DOWN) {
2944 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2945 if (!imcontext || !imcontext->input || !imcontext->text_input)
2948 if (!_focused_ctx) {
2949 LOGW ("no focus\n");
2953 if (_focused_ctx != ctx) {
2954 LOGW ("focused context is different from the context used in ecore_imf_context_filter_event.\n");
2955 LOGW ("focus context : %p, context : %p\n", _focused_ctx, ctx);
2960 if (strcmp (ecore_key_ev.keyname, "Return") == 0 && type == ECORE_IMF_EVENT_KEY_DOWN && filter_devices (key_dev_name) && hw_keyboard_mode == EINA_TRUE) {
2961 LOGD ("Changed keyboard mode from H/W to S/W ");
2962 hw_keyboard_mode = EINA_FALSE;
2963 vconf_set_bool (VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, 0);
2965 if (ecore_imf_context_input_panel_enabled_get (ctx)) {
2966 ecore_imf_context_input_panel_show (ctx);
2973 if (!ecore_key_ev.timestamp && (ecore_key_ev.modifiers & MOD_Mod5_MASK)) {
2974 if (type == ECORE_IMF_EVENT_KEY_DOWN) {
2975 if (strcmp (ecore_key_ev.key, "space") == 0 ||
2976 strcmp (ecore_key_ev.key, "KP_Space") == 0 ) {
2977 autoperiod_insert (ctx);
2981 LOGD("Return! This is SW keyboard fake event!");
2985 int serial = imcontext->serial++;
2986 double start_time = ecore_time_get();
2989 uint32_t modifiers = 0;
2990 if (ecore_key_ev.modifiers & ECORE_EVENT_MODIFIER_SHIFT)
2991 modifiers |= imcontext->shift_mask;
2992 if (ecore_key_ev.modifiers & ECORE_EVENT_MODIFIER_CTRL)
2993 modifiers |= imcontext->control_mask;
2994 if (ecore_key_ev.modifiers & ECORE_EVENT_MODIFIER_ALT)
2995 modifiers |= imcontext->alt_mask;
2996 if (ecore_key_ev.modifiers & ECORE_EVENT_LOCK_CAPS)
2997 modifiers |= imcontext->caps_mask;
2998 if (ecore_key_ev.modifiers & ECORE_EVENT_LOCK_NUM)
2999 modifiers |= imcontext->num_mask;
3001 SECURE_LOGD ("ev:modifiers=0x%x, modifiers=0x%x, shift_mask=0x%x, control_mask=0x%0x, alt_mask=0x%x, caps_mask=0x%x, num_mask=0x%x", ecore_key_ev.modifiers, modifiers, imcontext->shift_mask, imcontext->control_mask, imcontext->alt_mask, imcontext->caps_mask, imcontext->num_mask);
3002 //Send key event to IME.
3003 wl_text_input_filter_key_event(imcontext->text_input, serial, ecore_key_ev.timestamp, ecore_key_ev.key,
3004 type == ECORE_IMF_EVENT_KEY_UP? WL_KEYBOARD_KEY_STATE_RELEASED : WL_KEYBOARD_KEY_STATE_PRESSED,
3005 modifiers, (key_dev_name ? key_dev_name : ""), key_dev_class, key_dev_subclass);
3006 //Waiting for filter_key_event_done from IME.
3007 //This function should return IME filtering result with boolean type.
3008 struct wl_display *display = ecore_wl_display_get();
3010 while (ecore_time_get() - start_time < WAIT_FOR_FILTER_DONE_SECOND && wl_display_roundtrip(display) != -1) {
3011 if (imcontext->last_key_event_filter.serial == serial) {
3012 ret = imcontext->last_key_event_filter.state;
3014 } else if (imcontext->last_key_event_filter.serial > serial)
3018 LOGD ("elapsed : %.3f ms, serial (last, require) : (%d, %d)", (ecore_time_get() - start_time)*1000, imcontext->last_key_event_filter.serial, serial);
3021 if (type == ECORE_IMF_EVENT_KEY_DOWN) {
3022 if (ret == EINA_FALSE) {
3023 if (strcmp (ecore_key_ev.key, "space") == 0 ||
3024 strcmp (ecore_key_ev.key, "KP_Space") == 0) {
3025 autoperiod_insert (ctx);
3030 //Deal with the next key event in list.
3031 Ecore_Event_Key *ev = NULL;
3032 if (eina_list_count (imcontext->keysym_list)) {
3033 Eina_List *n = eina_list_last(imcontext->keysym_list);
3034 ev = (Ecore_Event_Key *)eina_list_data_get(n);
3035 int type = (unsigned long int)ev->data;
3038 ecore_event_add(type, ev, NULL, NULL);
3039 imcontext->keysym_list = eina_list_remove_list(imcontext->keysym_list, n);
3050 wayland_im_context_cursor_location_set(Ecore_IMF_Context *ctx, int x, int y, int width, int height)
3052 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3053 if (!imcontext) return;
3055 if ((imcontext->cursor_location.x != x) ||
3056 (imcontext->cursor_location.y != y) ||
3057 (imcontext->cursor_location.width != width) ||
3058 (imcontext->cursor_location.height != height)) {
3059 imcontext->cursor_location.x = x;
3060 imcontext->cursor_location.y = y;
3061 imcontext->cursor_location.width = width;
3062 imcontext->cursor_location.height = height;
3064 if (_focused_ctx == ctx)
3065 send_cursor_location (imcontext);
3069 void wayland_im_context_autocapital_type_set(Ecore_IMF_Context *ctx,
3070 Ecore_IMF_Autocapital_Type autocapital_type)
3072 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3073 if (!imcontext) return;
3075 imcontext->content_hint &= ~(WL_TEXT_INPUT_CONTENT_HINT_AUTO_CAPITALIZATION |
3076 // TIZEN_ONLY(20160201): Add autocapitalization word
3077 WL_TEXT_INPUT_CONTENT_HINT_WORD_CAPITALIZATION |
3079 WL_TEXT_INPUT_CONTENT_HINT_UPPERCASE |
3080 WL_TEXT_INPUT_CONTENT_HINT_LOWERCASE);
3082 if (autocapital_type == ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE)
3083 imcontext->content_hint |= WL_TEXT_INPUT_CONTENT_HINT_AUTO_CAPITALIZATION;
3084 // TIZEN_ONLY(20160201): Add autocapitalization word
3085 else if (autocapital_type == ECORE_IMF_AUTOCAPITAL_TYPE_WORD)
3086 imcontext->content_hint |= WL_TEXT_INPUT_CONTENT_HINT_WORD_CAPITALIZATION;
3088 else if (autocapital_type == ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER)
3089 imcontext->content_hint |= WL_TEXT_INPUT_CONTENT_HINT_UPPERCASE;
3091 imcontext->content_hint |= WL_TEXT_INPUT_CONTENT_HINT_LOWERCASE;
3093 if (imcontext->input && imcontext->text_input) {
3094 LOGD ("ctx : %p. set autocapital type : %d\n", ctx, autocapital_type);
3095 wl_text_input_set_content_type(imcontext->text_input,
3096 imcontext->content_hint,
3102 wayland_im_context_input_panel_layout_set(Ecore_IMF_Context *ctx,
3103 Ecore_IMF_Input_Panel_Layout layout)
3105 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3106 if (!imcontext) return;
3108 imcontext->input_panel_layout = layout;
3111 case ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBER:
3112 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER;
3114 case ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL:
3115 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_EMAIL;
3117 case ECORE_IMF_INPUT_PANEL_LAYOUT_URL:
3118 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_URL;
3120 case ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER:
3121 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_PHONE;
3123 case ECORE_IMF_INPUT_PANEL_LAYOUT_IP:
3124 // TIZEN_ONLY(20150710): Support IP and emoticon layout
3125 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_IP;
3128 case ECORE_IMF_INPUT_PANEL_LAYOUT_MONTH:
3129 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_DATE;
3131 case ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY:
3132 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS;
3134 case ECORE_IMF_INPUT_PANEL_LAYOUT_HEX:
3135 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_HEX;
3137 case ECORE_IMF_INPUT_PANEL_LAYOUT_TERMINAL:
3138 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_TERMINAL;
3140 case ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD:
3141 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD;
3142 imcontext->content_hint |= (WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA | WL_TEXT_INPUT_CONTENT_HINT_PASSWORD);
3144 case ECORE_IMF_INPUT_PANEL_LAYOUT_DATETIME:
3145 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_DATETIME;
3147 // TIZEN_ONLY(20150710): Support IP and emoticon layout
3148 case ECORE_IMF_INPUT_PANEL_LAYOUT_EMOTICON:
3149 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_EMOTICON;
3152 case ECORE_IMF_INPUT_PANEL_LAYOUT_VOICE:
3153 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_VOICE;
3156 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NORMAL;
3160 if (imcontext->input && imcontext->text_input) {
3161 LOGD ("ctx : %p, layout type : %d\n", ctx, layout);
3162 wl_text_input_set_content_type(imcontext->text_input,
3163 imcontext->content_hint,
3168 Ecore_IMF_Input_Panel_Layout
3169 wayland_im_context_input_panel_layout_get(Ecore_IMF_Context *ctx)
3171 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3172 if (!imcontext) return ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL;
3174 return imcontext->input_panel_layout;
3178 wayland_im_context_input_mode_set(Ecore_IMF_Context *ctx,
3179 Ecore_IMF_Input_Mode input_mode)
3181 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3182 if (!imcontext) return;
3184 if (input_mode & ECORE_IMF_INPUT_MODE_INVISIBLE)
3185 imcontext->content_hint |= (WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA | WL_TEXT_INPUT_CONTENT_HINT_PASSWORD);
3187 imcontext->content_hint &= ~(WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA | WL_TEXT_INPUT_CONTENT_HINT_PASSWORD);
3189 if (imcontext->input && imcontext->text_input) {
3190 LOGD ("ctx : %p, input mode : %d\n", ctx, input_mode);
3191 wl_text_input_set_content_type(imcontext->text_input,
3192 imcontext->content_hint,
3198 wayland_im_context_input_hint_set(Ecore_IMF_Context *ctx,
3199 Ecore_IMF_Input_Hints input_hints)
3201 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3202 if (!imcontext) return;
3204 if (input_hints & ECORE_IMF_INPUT_HINT_AUTO_COMPLETE)
3205 imcontext->content_hint |= WL_TEXT_INPUT_CONTENT_HINT_AUTO_COMPLETION;
3207 imcontext->content_hint &= ~WL_TEXT_INPUT_CONTENT_HINT_AUTO_COMPLETION;
3209 if (input_hints & ECORE_IMF_INPUT_HINT_SENSITIVE_DATA)
3210 imcontext->content_hint |= WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA;
3212 imcontext->content_hint &= ~WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA;
3214 if (input_hints & ECORE_IMF_INPUT_HINT_MULTILINE)
3215 imcontext->content_hint |= WL_TEXT_INPUT_CONTENT_HINT_MULTILINE;
3217 imcontext->content_hint &= ~WL_TEXT_INPUT_CONTENT_HINT_MULTILINE;
3219 if (imcontext->input && imcontext->text_input) {
3220 LOGD("ctx : %p, input hint : %#x\n", ctx, input_hints);
3221 wl_text_input_set_content_type(imcontext->text_input,
3222 imcontext->content_hint,
3228 wayland_im_context_input_panel_language_set(Ecore_IMF_Context *ctx,
3229 Ecore_IMF_Input_Panel_Lang lang)
3231 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3232 if (!imcontext) return;
3234 if (lang == ECORE_IMF_INPUT_PANEL_LANG_ALPHABET)
3235 imcontext->content_hint |= WL_TEXT_INPUT_CONTENT_HINT_LATIN;
3237 imcontext->content_hint &= ~WL_TEXT_INPUT_CONTENT_HINT_LATIN;
3239 if (imcontext->input && imcontext->text_input)
3240 wl_text_input_set_content_type(imcontext->text_input,
3241 imcontext->content_hint,
3245 // TIZEN_ONLY(20150708): Support input_panel_state_get
3246 Ecore_IMF_Input_Panel_State
3247 wayland_im_context_input_panel_state_get(Ecore_IMF_Context *ctx EINA_UNUSED)
3249 return _input_panel_state;
3253 wayland_im_context_input_panel_return_key_type_set(Ecore_IMF_Context *ctx,
3254 Ecore_IMF_Input_Panel_Return_Key_Type return_key_type)
3256 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3257 if (!imcontext) return;
3259 imcontext->return_key_type = return_key_type;
3261 if (imcontext->input && imcontext->text_input)
3262 wl_text_input_set_return_key_type(imcontext->text_input,
3263 imcontext->return_key_type);
3267 wayland_im_context_input_panel_return_key_disabled_set(Ecore_IMF_Context *ctx,
3270 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3271 if (!imcontext) return;
3273 imcontext->return_key_disabled = disabled;
3275 if (imcontext->input && imcontext->text_input)
3276 wl_text_input_set_return_key_disabled(imcontext->text_input,
3277 imcontext->return_key_disabled);
3282 wayland_im_context_input_panel_language_locale_get(Ecore_IMF_Context *ctx,
3285 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3286 if (!imcontext) return;
3289 *locale = strdup(imcontext->language ? imcontext->language : "");
3293 wayland_im_context_prediction_allow_set(Ecore_IMF_Context *ctx,
3294 Eina_Bool prediction)
3296 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3297 if (!imcontext) return;
3300 imcontext->content_hint |= WL_TEXT_INPUT_CONTENT_HINT_AUTO_COMPLETION;
3302 imcontext->content_hint &= ~WL_TEXT_INPUT_CONTENT_HINT_AUTO_COMPLETION;
3304 if (imcontext->input && imcontext->text_input)
3305 wl_text_input_set_content_type(imcontext->text_input,
3306 imcontext->content_hint,
3310 // TIZEN_ONLY(20151221): Support input panel geometry
3312 wayland_im_context_input_panel_geometry_get(Ecore_IMF_Context *ctx EINA_UNUSED,
3313 int *x, int *y, int *w, int *h)
3316 *x = _keyboard_geometry.x;
3318 *y = _keyboard_geometry.y;
3320 *w = _keyboard_geometry.w;
3322 *h = _keyboard_geometry.h;
3326 wayland_im_context_input_panel_imdata_set(Ecore_IMF_Context *ctx, const void *data, int length)
3328 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3329 if (!imcontext) return;
3331 if (data && length > 0) {
3332 const char *custom_conformant_enabled = "conformant:custom,enabled";
3333 const char *custom_conformant_disabled = "conformant:custom,disabled";
3334 const char *custom_conformant_finished = "conformant:custom,finished";
3336 if (strncmp(data, custom_conformant_enabled, strlen(custom_conformant_enabled)) == 0) {
3337 _custom_conformant_event = EINA_TRUE;
3340 if (strncmp(data, custom_conformant_disabled, strlen(custom_conformant_disabled)) == 0) {
3341 _custom_conformant_event = EINA_FALSE;
3344 if (strncmp(data, custom_conformant_finished, strlen(custom_conformant_finished)) == 0) {
3345 if (_custom_conformant_event) {
3346 _conformant_reset_done = EINA_TRUE;
3347 LOGD("[conformant:custom,finished], _conformant_reset_done = 1\n");
3348 send_will_hide_ack(NULL);
3354 if (imcontext->imdata)
3355 free(imcontext->imdata);
3357 imcontext->imdata = calloc(1, length);
3358 memcpy(imcontext->imdata, data, length);
3359 imcontext->imdata_size = length;
3361 if (imcontext->input && imcontext->text_input && (imcontext->imdata_size > 0))
3362 wl_text_input_set_input_panel_data(imcontext->text_input, (const char *)imcontext->imdata, imcontext->imdata_size);
3366 wayland_im_context_input_panel_imdata_get(Ecore_IMF_Context *ctx, void *data, int *length)
3369 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3371 if (imcontext && imcontext->input_panel_data && (imcontext->input_panel_data_length > 0)) {
3373 memcpy(data, imcontext->input_panel_data, imcontext->input_panel_data_length);
3376 *length = imcontext->input_panel_data_length;
3384 // TIZEN_ONLY(20160218): Support BiDi direction
3386 wayland_im_context_bidi_direction_set(Ecore_IMF_Context *ctx, Ecore_IMF_BiDi_Direction bidi_direction)
3388 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3389 if (!imcontext) return;
3391 imcontext->bidi_direction = bidi_direction;
3393 if (imcontext->input && imcontext->text_input) {
3394 LOGD ("ctx : %p, bidi direction : %#x\n", ctx, bidi_direction);
3395 wl_text_input_bidi_direction(imcontext->text_input, imcontext->bidi_direction);
3400 Ecore_IMF_Input_Panel_Keyboard_Mode
3401 wayland_im_context_input_panel_keyboard_mode_get(Ecore_IMF_Context *ctx EINA_UNUSED)
3403 return hw_keyboard_mode ? ECORE_IMF_INPUT_PANEL_HW_KEYBOARD_MODE : ECORE_IMF_INPUT_PANEL_SW_KEYBOARD_MODE;
3407 wayland_im_context_prediction_hint_set (Ecore_IMF_Context *ctx, const char *prediction_hint)
3409 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3410 if (!imcontext) return;
3412 imcontext->prediction_hint = strdup(prediction_hint);
3414 if (imcontext->input && imcontext->text_input) {
3415 LOGD ("ctx : %p, prediction_hint : %s\n", ctx, imcontext->prediction_hint);
3416 wl_text_input_prediction_hint(imcontext->text_input, imcontext->prediction_hint);
3420 WaylandIMContext *wayland_im_context_new (struct wl_text_input_manager *text_input_manager)
3422 WaylandIMContext *context = calloc(1, sizeof(WaylandIMContext));
3424 LOGD("new context created");
3425 context->text_input_manager = text_input_manager;