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"
37 #include "wayland_imcontext.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 #ifndef ENABLE_HIDE_PANEL_KEY
86 static const char *_ecore_imf_event_empty = "";
89 // TIZEN_ONLY(20150708): Support back key
90 #define BACK_KEY "XF86Back"
91 #define OLD_BACK_KEY "XF86Stop"
93 static Eina_Bool will_hide = EINA_FALSE;
94 static Eina_Bool ignore_hide = EINA_FALSE;
96 static Ecore_Event_Filter *_ecore_event_filter_handler = NULL;
97 static Ecore_IMF_Context *_focused_ctx = NULL;
98 static Ecore_IMF_Context *_show_req_ctx = NULL;
99 static Ecore_IMF_Context *_hide_req_ctx = NULL;
100 static Ecore_IMF_Context *_focus_req_ctx = NULL;
101 static Ecore_IMF_Context *_input_panel_ctx = NULL;
103 static Eina_Rectangle _keyboard_geometry = {0, 0, 0, 0};
105 static Ecore_IMF_Input_Panel_State _input_panel_state = ECORE_IMF_INPUT_PANEL_STATE_HIDE;
106 static Ecore_Event_Handler *_win_focus_out_handler = NULL;
107 static Ecore_Event_Handler *_conformant_change_handler = NULL;
109 static Eina_Bool _custom_conformant_event = EINA_FALSE;
110 static Eina_Bool _received_will_hide_event = EINA_FALSE;
111 static Eina_Bool _conformant_reset_done = EINA_FALSE;
112 static Eina_Bool _conformant_reset_started = EINA_FALSE;
113 static Evas *_active_context_canvas = NULL;
114 static unsigned int _active_context_window_id = 0;
116 static Ecore_Device *_ime_device = NULL;
118 static double space_key_time = 0.0;
119 static Eina_Bool autoperiod_allow = EINA_FALSE;
120 static Eina_Bool autocap_allow = EINA_FALSE;
121 static Eina_Bool hw_keyboard_mode = EINA_FALSE;
123 static Input_Language input_lang = INPUT_LANG_OTHER;
126 typedef struct __LanguageInfo {
129 Eina_Unicode punc_code;
130 Eina_Bool auto_capital_valid;
133 static LanguageInfo __language_infos [] = {
134 { "ur_PK", INPUT_LANG_URDU, 0x06D4, EINA_TRUE },
135 { "hi_IN", INPUT_LANG_HINDI, 0x0964, EINA_FALSE },
136 { "bn_IN", INPUT_LANG_BENGALI_IN, 0x0964, EINA_TRUE },
137 { "bn_BD", INPUT_LANG_BENGALI_BD, 0x0964, EINA_TRUE },
138 { "as_IN", INPUT_LANG_ASSAMESE, 0x0964, EINA_TRUE },
139 { "pa_IN", INPUT_LANG_PUNJABI, 0x0964, EINA_TRUE },
140 { "ne_NP", INPUT_LANG_NEPALI, 0x0964, EINA_TRUE },
141 { "or_IN", INPUT_LANG_ORIYA, 0x0964, EINA_TRUE },
142 { "mai_IN", INPUT_LANG_MAITHILI, 0x0964, EINA_TRUE },
143 { "hy_AM", INPUT_LANG_ARMENIAN, 0x0589, EINA_TRUE },
144 { "zh_CN", INPUT_LANG_CN, 0x3002, EINA_FALSE },
145 { "zh_HK", INPUT_LANG_CN_HK, 0x3002, EINA_FALSE },
146 { "zh_TW", INPUT_LANG_CN_TW, 0x3002, EINA_FALSE },
147 { "ja_JP", INPUT_LANG_JAPANESE, 0x3002, EINA_FALSE },
148 { "km_KH", INPUT_LANG_KHMER, 0x17D4, EINA_TRUE },
149 { "ko_KR", INPUT_LANG_KOREAN, 0x002E, EINA_FALSE },
152 struct _WaylandIMContext
154 Ecore_IMF_Context *ctx;
156 struct wl_text_input_manager *text_input_manager;
157 struct wl_text_input *text_input;
159 Ecore_Wl_Window *window;
160 Ecore_Wl_Input *input;
164 char *preedit_commit;
166 Eina_List *preedit_attrs;
167 int32_t preedit_cursor;
175 int32_t cursor_position;
185 xkb_mod_mask_t control_mask;
186 xkb_mod_mask_t alt_mask;
187 xkb_mod_mask_t shift_mask;
188 xkb_mod_mask_t caps_mask;
189 xkb_mod_mask_t num_mask;
192 uint32_t content_purpose;
193 uint32_t content_hint;
194 Ecore_IMF_Input_Panel_Layout input_panel_layout;
196 // TIZEN_ONLY(20150716): Support return key type
197 uint32_t return_key_type;
199 Eina_Bool return_key_disabled;
202 uint32_t imdata_size;
204 uint32_t bidi_direction;
206 void *input_panel_data;
207 uint32_t input_panel_data_length;
213 } last_key_event_filter;
214 Eina_List *keysym_list;
216 uint32_t reset_serial;
218 Eina_Bool has_conformant;
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 _device_info_free (void *data EINA_UNUSED, void *ev)
229 Ecore_Event_Device_Info *e;
232 eina_stringshare_del (e->name);
233 eina_stringshare_del (e->identifier);
234 eina_stringshare_del (e->seatname);
240 _device_info_send (unsigned int window, Eina_Bool flag)
242 Ecore_Event_Device_Info *e;
244 if (!(e = calloc (1, sizeof (Ecore_Event_Device_Info)))) return;
246 e->name = eina_stringshare_ref (IME_DEVICE_NAME);
247 e->identifier = eina_stringshare_ref (IME_DEVICE_NAME);
248 e->seatname = eina_stringshare_ref (IME_DEVICE_NAME);
249 e->clas = ECORE_DEVICE_CLASS_KEYBOARD;
253 ecore_event_add (ECORE_EVENT_DEVICE_ADD, e, _device_info_free, NULL);
255 ecore_event_add (ECORE_EVENT_DEVICE_DEL, e, _device_info_free, NULL);
259 get_input_language ()
262 char *input_lang_str = vconf_get_str (VCONFKEY_ISF_INPUT_LANGUAGE);
263 if (!input_lang_str) return;
264 LOGD ("language %s", input_lang_str);
265 input_lang = INPUT_LANG_OTHER;
267 for (i = 0; i < (sizeof (__language_infos) / sizeof (__language_infos[0])); i++) {
268 if (strcmp (input_lang_str, __language_infos[i].code) == 0) {
269 input_lang = __language_infos[i].lang;
274 free (input_lang_str);
277 static void autoperiod_allow_changed_cb (keynode_t *key, void* data)
279 autoperiod_allow = vconf_keynode_get_bool (key);
282 static void autocapital_allow_changed_cb (keynode_t *key, void* data)
284 autocap_allow = vconf_keynode_get_bool (key);
287 static void input_language_changed_cb (keynode_t *key, void* data)
289 get_input_language ();
293 check_symbol (Eina_Unicode ucode, Eina_Unicode symbols[], int symbol_num)
296 for (i = 0; i < symbol_num; i++) {
298 if (ucode == symbols[i])
306 check_space_symbol (Eina_Unicode uchar)
308 Eina_Unicode space_symbols[] = {' ', 0x00A0 /* no-break space */, 0x3000 /* ideographic space */};
309 const int symbol_num = sizeof (space_symbols) / sizeof (space_symbols[0]);
311 return check_symbol (uchar, space_symbols, symbol_num);
315 autoperiod_insert (Ecore_IMF_Context *ctx)
317 char *plain_str = NULL;
319 Eina_Unicode *ustr = NULL;
320 Ecore_IMF_Event_Delete_Surrounding ev;
321 char *fullstop_mark = NULL;
324 WaylandIMContext *imcontext = NULL;
326 if (autoperiod_allow == EINA_FALSE)
331 Ecore_IMF_Input_Panel_Layout layout = ecore_imf_context_input_panel_layout_get (ctx);
332 if (layout != ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL)
335 if ((ecore_time_get () - space_key_time) > DOUBLE_SPACE_INTERVAL)
338 imcontext = (WaylandIMContext *)ecore_imf_context_data_get (ctx);
339 if (!imcontext) return;
341 ecore_imf_context_surrounding_get (ctx, &plain_str, NULL);
342 if (!plain_str) goto done;
344 cursor_pos = imcontext->cursor_position;
346 // Convert string from UTF-8 to unicode
347 ustr = eina_unicode_utf8_to_unicode (plain_str, NULL);
348 if (!ustr) goto done;
350 ulen = eina_unicode_strlen (ustr);
352 if (cursor_pos < 2 || cursor_pos > (int)ulen) {
353 LOGD ("invalid range. cursor pos : %d, length : %d\n", cursor_pos, ulen);
357 if (check_space_symbol (ustr[cursor_pos-1])) {
358 // any character (except space & punctuation) + press space key twice in short time
359 if (!(iswpunct (ustr[cursor_pos-2]) || check_space_symbol (ustr[cursor_pos-2])) &&
360 iswprint(ustr[cursor_pos-2])) {
363 // any character (except space & punctuation) + space + press space key twice in short time
364 else if (cursor_pos >= 3 &&
365 check_space_symbol (ustr[cursor_pos-2]) &&
366 !(iswpunct (ustr[cursor_pos-3]) || check_space_symbol (ustr[cursor_pos-3])) &&
367 iswprint(ustr[cursor_pos-3])) {
373 ev.n_chars = del_chars;
374 ev.offset = del_chars * -1;
376 ecore_imf_context_delete_surrounding_event_add (ctx, ev.offset, ev.n_chars);
377 ecore_imf_context_event_callback_call (ctx, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, &ev);
379 if (input_lang == INPUT_LANG_OTHER) {
380 fullstop_mark = strdup (".");
383 Eina_Unicode wbuf[2] = {0};
384 wbuf[0] = __language_infos[input_lang].punc_code;
386 fullstop_mark = eina_unicode_unicode_to_utf8 (wbuf, NULL);
389 ecore_imf_context_commit_event_add (ctx, fullstop_mark);
390 ecore_imf_context_event_callback_call (ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)fullstop_mark);
393 free (fullstop_mark);
394 fullstop_mark = NULL;
400 if (plain_str) free (plain_str);
401 if (ustr) free (ustr);
402 space_key_time = ecore_time_get ();
406 check_except_autocapital (Eina_Unicode *ustr, int cursor_pos)
408 const char *except_str[] = {"e.g.", "E.g."};
409 unsigned int i = 0, j = 0, len = 0;
410 for (i = 0; i < (sizeof (except_str) / sizeof (except_str[0])); i++) {
411 len = strlen (except_str[i]);
412 if (cursor_pos < (int)len)
415 for (j = len; j > 0; j--) {
416 if (ustr[cursor_pos-j] != except_str[i][len-j])
420 if (j == 0) return EINA_TRUE;
427 analyze_surrounding_text (Ecore_IMF_Context *ctx)
429 char *plain_str = NULL;
430 Eina_Unicode puncs[] = {'\n','.', '!', '?', 0x00BF /* ¿ */, 0x00A1 /* ¡ */,
431 0x3002 /* 。 */, 0x06D4 /* Urdu */, 0x0964 /* Hindi */,
432 0x0589 /* Armenian */, 0x17D4 /* Khmer */, 0x104A /* Myanmar */};
433 Eina_Unicode *ustr = NULL;
434 Eina_Bool ret = EINA_FALSE;
435 Eina_Bool detect_space = EINA_FALSE;
438 const int punc_num = sizeof (puncs) / sizeof (puncs[0]);
439 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get (ctx);
440 if (!imcontext) return EINA_FALSE;
442 switch (ecore_imf_context_autocapital_type_get (ctx)) {
443 case ECORE_IMF_AUTOCAPITAL_TYPE_NONE:
445 case ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER:
451 if (imcontext->preedit_text && strcmp (imcontext->preedit_text, "") != 0)
454 if (imcontext->cursor_position == 0)
457 ecore_imf_context_surrounding_get (ctx, &plain_str, &cursor_pos);
459 if (!plain_str) goto done;
461 if (cursor_pos == 0) {
466 // Convert string from UTF-8 to unicode
467 ustr = eina_unicode_utf8_to_unicode (plain_str, NULL);
468 if (!ustr) goto done;
470 if (eina_unicode_strlen (ustr) < (size_t)cursor_pos) goto done;
472 if (cursor_pos >= 1) {
473 if (ecore_imf_context_autocapital_type_get (ctx) == ECORE_IMF_AUTOCAPITAL_TYPE_WORD) {
474 // Check space or no-break space
475 if (check_space_symbol (ustr[cursor_pos-1])) {
481 // Check paragraph separator <PS> or carriage return <br>
482 if ((ustr[cursor_pos-1] == 0x2029) || (ustr[cursor_pos-1] == '\n')) {
487 for (i = cursor_pos; i > 0; i--) {
488 // Check space or no-break space
489 if (check_space_symbol (ustr[i-1])) {
490 detect_space = EINA_TRUE;
494 // Check punctuation and following the continuous space(s)
495 if (detect_space && check_symbol (ustr[i-1], puncs, punc_num)) {
496 if (check_except_autocapital (ustr, i))
508 if ((i == 0) && (detect_space == EINA_TRUE)) {
509 // continuous space(s) without any character
516 if (ustr) free (ustr);
517 if (plain_str) free (plain_str);
523 set_autocapital (Ecore_IMF_Context *ctx)
525 Eina_Bool uppercase = EINA_FALSE;
527 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get (ctx);
528 if (!imcontext || !imcontext->text_input || !imcontext->input) return;
530 if (hw_keyboard_mode) return;
532 if (input_lang != INPUT_LANG_OTHER && (!__language_infos[input_lang].auto_capital_valid))
535 if (ecore_imf_context_input_panel_layout_get (ctx) != ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL)
538 // Check autocapital type
539 if (ecore_imf_context_input_panel_caps_lock_mode_get (ctx)) {
540 uppercase = EINA_TRUE;
542 if (autocap_allow == EINA_FALSE)
545 uppercase = analyze_surrounding_text (ctx);
548 SECURE_LOGD ("ctx : %p, auto capital : %d\n", ctx, uppercase);
549 wl_text_input_set_capital_mode (imcontext->text_input, uppercase);
552 static Ecore_IMF_Context *
555 return (_show_req_ctx ? _show_req_ctx : _focused_ctx);
559 check_hide_key(const char *keyname)
561 if (!keyname) return EINA_FALSE;
563 if (strcmp(keyname, "Escape") == 0 ||
564 strcmp(keyname, BACK_KEY) == 0 ||
565 strcmp(keyname, OLD_BACK_KEY) == 0)
571 #ifndef ENABLE_HIDE_PANEL_KEY
573 _ecore_key_modifiers_to_ecore_imf_locks(unsigned int modifiers)
575 unsigned int locks = 0;
577 if (modifiers & ECORE_EVENT_LOCK_SCROLL)
578 locks |= ECORE_IMF_KEYBOARD_LOCK_SCROLL;
580 if (modifiers & ECORE_EVENT_LOCK_CAPS)
581 locks |= ECORE_IMF_KEYBOARD_LOCK_CAPS;
583 if (modifiers & ECORE_EVENT_LOCK_NUM)
584 locks |= ECORE_IMF_KEYBOARD_LOCK_NUM;
590 _ecore_key_modifiers_to_ecore_imf_modifiers(unsigned int modifiers)
592 unsigned int mask = 0;
594 /**< "Control" is pressed */
595 if (modifiers & ECORE_EVENT_MODIFIER_CTRL)
596 mask |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL;
598 /**< "Alt" is pressed */
599 if (modifiers & ECORE_EVENT_MODIFIER_ALT)
600 mask |= ECORE_IMF_KEYBOARD_MODIFIER_ALT;
602 /**< "Shift" is pressed */
603 if (modifiers & ECORE_EVENT_MODIFIER_SHIFT)
604 mask |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT;
606 /**< "Win" (between "Ctrl" and "Alt") is pressed */
607 if (modifiers & ECORE_EVENT_MODIFIER_WIN)
608 mask |= ECORE_IMF_KEYBOARD_MODIFIER_WIN;
610 /**< "AltGr" is pressed */
611 if (modifiers & ECORE_EVENT_MODIFIER_ALTGR)
612 mask |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR;
618 _ecore_event_to_ecore_imf_key_down_event(Ecore_Event_Key *ecore_event, Ecore_IMF_Event_Key_Down *imf_event)
620 if (!ecore_event || !imf_event)
623 imf_event->keyname = ecore_event->keyname ? ecore_event->keyname : _ecore_imf_event_empty;
624 imf_event->key = ecore_event->key ? ecore_event->key : _ecore_imf_event_empty;
625 imf_event->string = ecore_event->string ? ecore_event->string : _ecore_imf_event_empty;
626 imf_event->compose = ecore_event->compose ? ecore_event->compose : _ecore_imf_event_empty;
627 imf_event->timestamp = ecore_event->timestamp;
629 if (ecore_event->dev) {
630 imf_event->dev_name = ecore_device_name_get(ecore_event->dev) ? ecore_device_name_get(ecore_event->dev) : _ecore_imf_event_empty;
631 imf_event->dev_class = (Ecore_IMF_Device_Class)ecore_device_class_get(ecore_event->dev);
632 imf_event->dev_subclass = (Ecore_IMF_Device_Subclass)ecore_device_subclass_get(ecore_event->dev);
635 imf_event->dev_name = _ecore_imf_event_empty;
636 imf_event->dev_class = ECORE_IMF_DEVICE_CLASS_NONE;
637 imf_event->dev_subclass = ECORE_IMF_DEVICE_SUBCLASS_NONE;
640 imf_event->modifiers = _ecore_key_modifiers_to_ecore_imf_modifiers(ecore_event->modifiers);
641 imf_event->locks = _ecore_key_modifiers_to_ecore_imf_locks(ecore_event->modifiers);
645 _ecore_event_to_ecore_imf_key_up_event(Ecore_Event_Key *ecore_event, Ecore_IMF_Event_Key_Up *imf_event)
647 if (!ecore_event || !imf_event)
650 imf_event->keyname = ecore_event->keyname ? ecore_event->keyname : _ecore_imf_event_empty;
651 imf_event->key = ecore_event->key ? ecore_event->key : _ecore_imf_event_empty;
652 imf_event->string = ecore_event->string ? ecore_event->string : _ecore_imf_event_empty;
653 imf_event->compose = ecore_event->compose ? ecore_event->compose : _ecore_imf_event_empty;
654 imf_event->timestamp = ecore_event->timestamp;
656 if (ecore_event->dev) {
657 imf_event->dev_name = ecore_device_name_get(ecore_event->dev) ? ecore_device_name_get(ecore_event->dev) : _ecore_imf_event_empty;
658 imf_event->dev_class = (Ecore_IMF_Device_Class)ecore_device_class_get(ecore_event->dev);
659 imf_event->dev_subclass = (Ecore_IMF_Device_Subclass)ecore_device_subclass_get(ecore_event->dev);
662 imf_event->dev_name = _ecore_imf_event_empty;
663 imf_event->dev_class = ECORE_IMF_DEVICE_CLASS_NONE;
664 imf_event->dev_subclass = ECORE_IMF_DEVICE_SUBCLASS_NONE;
667 imf_event->modifiers = _ecore_key_modifiers_to_ecore_imf_modifiers(ecore_event->modifiers);
668 imf_event->locks = _ecore_key_modifiers_to_ecore_imf_locks(ecore_event->modifiers);
673 key_down_filter_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
675 Ecore_Event_Key *ev = (Ecore_Event_Key *)event;
676 if (!ev || !ev->keyname) return EINA_TRUE; /* the event is kept */
678 Ecore_IMF_Context *active_ctx = get_using_ctx ();
680 if (!active_ctx) return EINA_TRUE; /* the event is kept */
682 if ((_input_panel_state == ECORE_IMF_INPUT_PANEL_STATE_SHOW ||
683 _input_panel_state == ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW) &&
684 check_hide_key(ev->keyname)) {
686 LOGD ("%s key is pressed.\n", ev->keyname);
688 #ifdef ENABLE_HIDE_PANEL_KEY
689 return EINA_FALSE; /* the event is removed from the queue */
691 Ecore_IMF_Event_Key_Down imf_event;
692 Eina_Bool filter_ret = EINA_FALSE;
694 _ecore_event_to_ecore_imf_key_down_event(ev, &imf_event);
697 filter_ret = ecore_imf_context_filter_event(_focused_ctx, ECORE_IMF_EVENT_KEY_DOWN, (Ecore_IMF_Event *)&imf_event);
701 LOGD ("%s key is pressed. ret : %d\n", ev->keyname, filter_ret);
703 return EINA_FALSE; /* the event is removed from the queue */
707 return EINA_TRUE; /* the event is kept */
709 return EINA_FALSE; /* the event is removed from the queue */
711 #endif /* ENABLE_HIDE_PANEL_KEY */
713 return EINA_TRUE; /* the event is kept */
717 key_up_filter_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
719 Ecore_Event_Key *ev = (Ecore_Event_Key *)event;
720 if (!ev || !ev->keyname) return EINA_TRUE; /* the event is kept */
722 Ecore_IMF_Context *active_ctx = get_using_ctx ();
724 if (!active_ctx) return EINA_TRUE; /* the event is kept */
726 if (_input_panel_state == ECORE_IMF_INPUT_PANEL_STATE_HIDE ||
727 !check_hide_key(ev->keyname))
728 return EINA_TRUE; /* the event is kept */
730 LOGD ("%s key is released.\n", ev->keyname);
732 #ifdef ENABLE_HIDE_PANEL_KEY
733 ecore_imf_context_reset(active_ctx);
734 _input_panel_hide(active_ctx, EINA_TRUE);
736 return EINA_FALSE; /* the event is removed from the queue */
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 */
763 #endif /* ENABLE_HIDE_PANEL_KEY */
768 rotary_event_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
770 Ecore_Event_Detent_Rotate *ev = event;
771 if (!ev) return EINA_TRUE;
773 Ecore_IMF_Context *active_ctx = NULL;
775 active_ctx = _show_req_ctx;
776 else if (_focused_ctx)
777 active_ctx = _focused_ctx;
779 if (!active_ctx) return EINA_TRUE;
781 if (_input_panel_state == ECORE_IMF_INPUT_PANEL_STATE_HIDE)
784 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(active_ctx);
785 if (imcontext && imcontext->input && imcontext->text_input) {
786 wl_text_input_process_input_device_event(imcontext->text_input,
787 (unsigned int)ECORE_EVENT_DETENT_ROTATE, (char*)event, sizeof(Ecore_Event_Detent_Rotate));
795 _ecore_event_filter_cb(void *data, void *loop_data EINA_UNUSED, int type, void *event)
797 if (type == ECORE_EVENT_KEY_DOWN) {
798 return key_down_filter_cb(data, type, event);
800 else if (type == ECORE_EVENT_KEY_UP) {
801 return key_up_filter_cb(data, type, event);
804 /* The IME needs to process Rotary event prior to client application */
805 else if (type == ECORE_EVENT_DETENT_ROTATE) {
806 return rotary_event_cb(data, type, event);
814 register_key_handler()
816 if (!_ecore_event_filter_handler)
817 _ecore_event_filter_handler = ecore_event_filter_add(NULL, _ecore_event_filter_cb, NULL, NULL);
821 unregister_key_handler()
823 if (_ecore_event_filter_handler) {
824 ecore_event_filter_del(_ecore_event_filter_handler);
825 _ecore_event_filter_handler = NULL;
836 ecore_timer_del(_hide_timer);
844 static void _win_focus_out_handler_del ()
846 if (_win_focus_out_handler) {
847 ecore_event_handler_del (_win_focus_out_handler);
848 _win_focus_out_handler = NULL;
852 static void _conformant_change_handler_del()
854 if (_conformant_change_handler) {
855 ecore_event_handler_del(_conformant_change_handler);
856 _conformant_change_handler = NULL;
861 _send_input_panel_hide_request(Ecore_IMF_Context *ctx)
866 // TIZEN_ONLY(20150708): Support back key
867 _hide_req_ctx = NULL;
870 _win_focus_out_handler_del ();
872 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
873 if (imcontext && imcontext->text_input) {
874 wl_text_input_hide_input_panel(imcontext->text_input);
876 LOGD("creating temporary context for sending hide request\n");
877 const char *ctx_id = ecore_imf_context_default_id_get();
878 Ecore_IMF_Context *temp_context = ecore_imf_context_add(ctx_id);
880 imcontext = (WaylandIMContext *)ecore_imf_context_data_get(temp_context);
881 if (imcontext && imcontext->text_input)
882 wl_text_input_hide_input_panel(imcontext->text_input);
884 ecore_imf_context_del(temp_context);
889 static void _conformant_area_free (void *data EINA_UNUSED, void *ev)
891 Ecore_Wl_Event_Conformant_Change *e = ev;
896 static void add_conformant_change_event(Ecore_Wl_Window *window)
898 Ecore_Wl_Event_Conformant_Change *ev;
899 ev = calloc(1, sizeof(Ecore_Wl_Event_Conformant_Change));
901 ev->win = ecore_wl_window_id_get(window);
904 ecore_event_add(ECORE_WL_EVENT_CONFORMANT_CHANGE, ev, _conformant_area_free, NULL);
908 static Eina_Rectangle _conformant_area_backup = { 0, 0, 0, 0 };
909 static Eina_Bool reset_conformant_area(Ecore_IMF_Context *ctx)
911 Eina_Bool reset = EINA_FALSE;
912 Eina_Bool has_conformant = EINA_FALSE;
913 Ecore_Wl_Window *window = NULL;
915 if (!ctx) return EINA_FALSE;
917 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
919 window = imcontext->window;
920 has_conformant = imcontext->has_conformant;
924 int x = 0, y = 0, w = 0, h = 0;
925 Eina_Bool result = ecore_wl_window_keyboard_geometry_get(window, &x, &y, &w, &h);
928 if (ecore_imf_context_client_canvas_get(ctx) && has_conformant && (w != 0 || h != 0)) {
930 _conformant_area_backup.x = x;
931 _conformant_area_backup.y = y;
932 _conformant_area_backup.w = w;
933 _conformant_area_backup.h = h;
937 LOGD("reset %d", reset);
939 ecore_wl_window_keyboard_geometry_set(window, 0, 0, 0, 0);
941 add_conformant_change_event(window);
943 _conformant_reset_started = EINA_TRUE;
949 static void restore_conformant_area(Ecore_IMF_Context *ctx)
951 Eina_Bool restore = EINA_FALSE;
952 Eina_Bool has_conformant = EINA_FALSE;
953 Ecore_Wl_Window *window = NULL;
957 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
959 window = imcontext->window;
960 has_conformant = imcontext->has_conformant;
964 int x = 0, y = 0, w = 0, h = 0;
965 Eina_Bool result = ecore_wl_window_keyboard_geometry_get(window, &x, &y, &w, &h);
968 if (ecore_imf_context_client_canvas_get(ctx) && has_conformant && (w == 0 || h == 0)) {
973 LOGD("restore %d", restore);
975 ecore_wl_window_keyboard_geometry_set(window,
976 _conformant_area_backup.x, _conformant_area_backup.y,
977 _conformant_area_backup.w, _conformant_area_backup.h);
979 add_conformant_change_event(window);
981 _conformant_reset_started = EINA_FALSE;
986 _send_will_hide_ack(WaylandIMContext *imcontext)
988 if (!imcontext) return;
989 if (!(imcontext->text_input)) return;
992 const char *szWillHideAck = "WILL_HIDE_ACK";
993 wl_text_input_set_input_panel_data(imcontext->text_input, szWillHideAck, strlen(szWillHideAck));
994 _received_will_hide_event = EINA_FALSE;
998 _hide_timer_handler(void *data)
1000 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)data;
1001 _send_input_panel_hide_request(ctx);
1003 if (!reset_conformant_area(ctx) && !_conformant_reset_started) {
1004 LOGD("No need to reset conformant, sending ACK right away");
1005 _send_will_hide_ack((WaylandIMContext *)ecore_imf_context_data_get(ctx));
1009 return ECORE_CALLBACK_CANCEL;
1013 _input_panel_hide_timer_start(void *data)
1016 _hide_timer = ecore_timer_add(HIDE_TIMER_INTERVAL, _hide_timer_handler, data);
1020 _input_panel_hide(Ecore_IMF_Context *ctx, Eina_Bool instant)
1022 LOGD ("ctx : %p", ctx);
1026 will_hide = EINA_TRUE;
1027 _conformant_reset_started = EINA_FALSE;
1029 if (instant || (_hide_timer && ecore_timer_pending_get(_hide_timer) <= 0.0)) {
1030 _clear_hide_timer();
1031 _send_input_panel_hide_request(ctx);
1033 if (!reset_conformant_area(ctx) && !_conformant_reset_started) {
1034 LOGD("No need to reset conformant, sending ACK right away");
1035 _send_will_hide_ack((WaylandIMContext *)ecore_imf_context_data_get(ctx));
1038 _input_panel_hide_timer_start(ctx);
1039 // TIZEN_ONLY(20150708): Support back key
1040 _hide_req_ctx = ctx;
1046 utf8_offset_to_characters(const char *str, int offset)
1051 for (; index < offset; i++) {
1052 if (eina_unicode_utf8_next_get(str, &index) == 0)
1060 send_cursor_location(WaylandIMContext *imcontext)
1062 Ecore_Evas *ee = NULL;
1063 int canvas_x = 0, canvas_y = 0;
1065 if (imcontext->canvas) {
1066 ee = ecore_evas_ecore_evas_get(imcontext->canvas);
1068 ecore_evas_geometry_get(ee, &canvas_x, &canvas_y, NULL, NULL);
1071 if (imcontext->input && imcontext->text_input) {
1072 wl_text_input_set_cursor_rectangle(imcontext->text_input,
1073 imcontext->cursor_location.x + canvas_x,
1074 imcontext->cursor_location.y + canvas_y,
1075 imcontext->cursor_location.width,
1076 imcontext->cursor_location.height);
1081 update_state(WaylandIMContext *imcontext)
1083 if (!imcontext->ctx)
1086 send_cursor_location (imcontext);
1088 if (imcontext->input && imcontext->text_input) {
1089 wl_text_input_commit_state(imcontext->text_input, ++imcontext->serial);
1094 check_serial(WaylandIMContext *imcontext, uint32_t serial)
1099 Ecore_IMF_Preedit_Attr *attr;
1101 if ((imcontext->serial - serial) >
1102 (imcontext->serial - imcontext->reset_serial)) {
1103 LOGD("outdated serial: %u, current: %u, reset: %u",
1104 serial, imcontext->serial, imcontext->reset_serial);
1106 imcontext->pending_preedit.cursor = 0;
1108 if (imcontext->pending_preedit.attrs) {
1109 EINA_LIST_FREE(imcontext->pending_preedit.attrs, attr) free(attr);
1110 imcontext->pending_preedit.attrs = NULL;
1120 clear_preedit_text(WaylandIMContext *imcontext)
1122 Ecore_IMF_Preedit_Attr *attr = NULL;
1124 imcontext->preedit_cursor = 0;
1126 if (imcontext->preedit_text) {
1127 free(imcontext->preedit_text);
1128 imcontext->preedit_text = NULL;
1131 if (imcontext->preedit_attrs) {
1132 EINA_LIST_FREE(imcontext->preedit_attrs, attr)
1136 imcontext->preedit_attrs = NULL;
1140 clear_preedit(WaylandIMContext *imcontext)
1142 clear_preedit_text(imcontext);
1144 if (imcontext->preedit_commit) {
1145 free(imcontext->preedit_commit);
1146 imcontext->preedit_commit = NULL;
1151 check_preedit_empty(WaylandIMContext *imcontext)
1153 if (!imcontext) return EINA_TRUE;
1155 if (imcontext->preedit_text) return EINA_FALSE;
1156 if (imcontext->preedit_attrs) return EINA_FALSE;
1157 if (imcontext->preedit_cursor != 0) return EINA_FALSE;
1158 if (imcontext->preedit_commit) return EINA_FALSE;
1164 text_input_commit_string(void *data,
1165 struct wl_text_input *text_input EINA_UNUSED,
1169 WaylandIMContext *imcontext = (WaylandIMContext *)data;
1170 Eina_Bool old_preedit = EINA_FALSE;
1172 SECURE_LOGD("ctx : %p, commit event (text: '%s', current pre-edit: '%s')",
1175 imcontext->preedit_text ? imcontext->preedit_text : "");
1177 if (!imcontext->ctx)
1181 imcontext->preedit_text && strlen(imcontext->preedit_text) > 0;
1183 if (!check_serial(imcontext, serial))
1187 ecore_imf_context_preedit_end_event_add(imcontext->ctx);
1188 ecore_imf_context_event_callback_call(imcontext->ctx,
1189 ECORE_IMF_CALLBACK_PREEDIT_END,
1193 clear_preedit(imcontext);
1198 Eina_Unicode *ustr = eina_unicode_utf8_to_unicode (text, NULL);
1201 if (eina_unicode_strcmp (ustr, L" ") == 0 ||
1202 eina_unicode_strcmp (ustr, L" ") == 0)
1203 autoperiod_insert (imcontext->ctx);
1208 ecore_imf_context_commit_event_add(imcontext->ctx, text);
1209 ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)text);
1213 commit_preedit(WaylandIMContext *imcontext)
1216 if (!imcontext->preedit_commit)
1219 if (!imcontext->ctx)
1222 clear_preedit_text(imcontext);
1224 size_t commit_len = strlen(imcontext->preedit_commit);
1226 if (commit_len == 0) {
1227 ecore_imf_context_preedit_changed_event_add(imcontext->ctx);
1228 ecore_imf_context_event_callback_call(imcontext->ctx,
1229 ECORE_IMF_CALLBACK_PREEDIT_CHANGED,
1233 ecore_imf_context_preedit_end_event_add(imcontext->ctx);
1234 ecore_imf_context_event_callback_call(imcontext->ctx,
1235 ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
1237 if (commit_len > 0) {
1238 ecore_imf_context_commit_event_add(imcontext->ctx,
1239 imcontext->preedit_commit);
1240 ecore_imf_context_event_callback_call(imcontext->ctx,
1241 ECORE_IMF_CALLBACK_COMMIT,
1242 (void *)imcontext->preedit_commit);
1247 set_focus(Ecore_IMF_Context *ctx)
1249 LOGD("ctx : %p", ctx);
1250 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
1251 if (!imcontext) return EINA_FALSE;
1253 if (!imcontext->window) {
1254 LOGW("window is not given\n");
1258 Ecore_Wl_Input *input = ecore_wl_window_keyboard_get(imcontext->window);
1260 LOGW("ctx : %p, Can't get Wl_Input\n", ctx);
1264 struct wl_seat *seat = ecore_wl_input_seat_get(input);
1266 LOGW("ctx : %p, Can't get Wl_seat\n", ctx);
1270 imcontext->input = input;
1273 wl_text_input_activate(imcontext->text_input, seat,
1274 ecore_wl_window_surface_get(imcontext->window));
1280 set_focus_out(Ecore_IMF_Context *ctx)
1282 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
1283 if (!imcontext || !imcontext->input) return;
1286 if (imcontext->text_input)
1287 wl_text_input_deactivate(imcontext->text_input,
1288 ecore_wl_input_seat_get(imcontext->input));
1290 if (ctx == _focused_ctx)
1291 _focused_ctx = NULL;
1293 imcontext->input = NULL;
1296 // TIZEN_ONLY(20160217): ignore the duplicate show request
1297 static Eina_Bool _compare_context(Ecore_IMF_Context *ctx1, Ecore_IMF_Context *ctx2)
1299 if (!ctx1 || !ctx2) return EINA_FALSE;
1301 if ((ecore_imf_context_autocapital_type_get(ctx1) == ecore_imf_context_autocapital_type_get(ctx2)) &&
1302 (ecore_imf_context_input_panel_layout_get(ctx1) == ecore_imf_context_input_panel_layout_get(ctx2)) &&
1303 (ecore_imf_context_input_panel_layout_variation_get(ctx1) == ecore_imf_context_input_panel_layout_variation_get(ctx2)) &&
1304 (ecore_imf_context_input_panel_language_get(ctx1) == ecore_imf_context_input_panel_language_get(ctx2)) &&
1305 (ecore_imf_context_input_panel_return_key_type_get(ctx1) == ecore_imf_context_input_panel_return_key_type_get(ctx2)) &&
1306 (ecore_imf_context_input_panel_return_key_disabled_get(ctx1) == ecore_imf_context_input_panel_return_key_disabled_get(ctx2)) &&
1307 (ecore_imf_context_input_panel_caps_lock_mode_get(ctx1) == ecore_imf_context_input_panel_caps_lock_mode_get(ctx2)))
1314 static void send_get_hide_permission(WaylandIMContext *imcontext)
1316 if (imcontext->text_input) {
1317 ignore_hide = EINA_FALSE;
1318 wl_text_input_get_hide_permission(imcontext->text_input);
1322 static Eina_Bool _client_window_focus_out_cb(void *data, int ev_type, void *ev)
1324 Ecore_Wl_Event_Focus_Out *e = (Ecore_Wl_Event_Focus_Out *)ev;
1325 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)data;
1326 if (!ctx || !e) return ECORE_CALLBACK_PASS_ON;
1328 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get (ctx);
1329 if (!imcontext || !imcontext->window) return ECORE_CALLBACK_PASS_ON;
1331 unsigned int client_win_id = ecore_wl_window_id_get (imcontext->window);
1333 LOGD ("ctx : %p, client_window id : %#x, focus-out win : %#x\n", ctx, client_win_id, e->win);
1335 if (client_win_id > 0) {
1336 if (e->win == client_win_id) {
1337 LOGD ("window focus out\n");
1339 if (_focused_ctx == ctx) {
1340 wayland_im_context_focus_out (ctx);
1343 if (_show_req_ctx == ctx) {
1344 send_get_hide_permission(imcontext);
1349 send_get_hide_permission(imcontext);
1352 return ECORE_CALLBACK_PASS_ON;
1355 static void send_will_hide_ack(Ecore_IMF_Context *ctx)
1357 Eina_Bool need_temporary_context = EINA_FALSE;
1358 Eina_Bool has_conformant = EINA_FALSE;
1359 WaylandIMContext *imcontext = NULL;
1362 LOGD("ctx is NULL\n");
1363 need_temporary_context = EINA_TRUE;
1365 imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
1367 LOGD("imcontext is NULL :%p\n", ctx);
1368 need_temporary_context = EINA_TRUE;
1370 has_conformant = imcontext->has_conformant;
1374 /* When the RENDER_POST event is emitted, it is possible that our IMF_Context is already deleted,
1375 meaning that there is no connection available for communicating with the window manager.
1376 So we are creating a temporary context for sending WILL_HIDE_ACK message */
1377 if (need_temporary_context) {
1378 LOGD("creating temporary context for sending WILL_HIDE_ACK\n");
1379 const char *ctx_id = ecore_imf_context_default_id_get();
1380 ctx = ecore_imf_context_add(ctx_id);
1382 imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
1386 if (ctx && imcontext) {
1387 if (ecore_imf_context_client_canvas_get(ctx) && has_conformant) {
1388 if (_conformant_reset_done && _received_will_hide_event) {
1389 LOGD("Send will hide ack, _conformant_reset_done = 1, received_will_hide_event = 1\n");
1390 _send_will_hide_ack(imcontext);
1391 _conformant_reset_done = EINA_FALSE;
1392 _received_will_hide_event = EINA_FALSE;
1394 LOGD ("_conformant_reset_done=%d, received_will_hide_event=%d\n",
1395 _conformant_reset_done, _received_will_hide_event);
1398 LOGD("Send will hide ack right away, since there is no conformant available : %p %d\n",
1399 ecore_imf_context_client_canvas_get(ctx), has_conformant);
1400 _send_will_hide_ack (imcontext);
1404 if (need_temporary_context) {
1406 ecore_imf_context_del(ctx);
1411 static void _render_post_cb(void *data, Evas *e, void *event_info)
1413 void *callback = evas_event_callback_del(e, EVAS_CALLBACK_RENDER_POST, _render_post_cb);
1414 _conformant_reset_done = EINA_TRUE;
1415 _conformant_reset_started = EINA_FALSE;
1416 LOGD("[_render_post_cb], _conformant_reset_done = 1 , %p\n", callback);
1417 send_will_hide_ack(NULL);
1420 static Eina_Bool _conformant_change_cb(void *data, int ev_type, void *ev)
1422 Ecore_Wl_Event_Conformant_Change *e = (Ecore_Wl_Event_Conformant_Change *)ev;
1423 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)data;
1424 if (!e || !ctx) return ECORE_CALLBACK_PASS_ON;
1426 LOGD ("CONFORMANT changed!! part type : %d, state : %d, win : %d", e->part_type, e->state, e->win);
1428 if (_active_context_window_id != e->win)
1429 return ECORE_CALLBACK_PASS_ON;
1431 Ecore_Wl_Window *window = ecore_wl_window_find(e->win);
1432 if (!window) return ECORE_CALLBACK_PASS_ON;
1435 LOGD("_conformant_reset_done = 0, registering _render_post_cb : %p %p\n", _active_context_canvas, window);
1436 _conformant_reset_done = EINA_FALSE;
1437 if (_active_context_canvas && ecore_wl_window_conformant_get(window) && !_custom_conformant_event) {
1438 evas_event_callback_del(_active_context_canvas, EVAS_CALLBACK_RENDER_POST, _render_post_cb);
1439 evas_event_callback_add(_active_context_canvas, EVAS_CALLBACK_RENDER_POST, _render_post_cb, ctx);
1442 _conformant_reset_done = EINA_FALSE;
1443 if (_active_context_canvas) {
1444 evas_event_callback_del(_active_context_canvas, EVAS_CALLBACK_RENDER_POST, _render_post_cb);
1446 /* Since the input_panel_geometry is not delivered right at the moment, we use conformant geometry instead */
1447 int x = 0, y = 0, w = 0, h = 0;
1448 Eina_Bool result = ecore_wl_window_keyboard_geometry_get(window, &x, &y, &w, &h);
1450 Evas_Coord scr_w = 0, scr_h = 0;
1452 ecore_wl_screen_size_get(&scr_w, &scr_h);
1453 int rot = ecore_wl_window_rotation_get(window);
1454 /* Assume we are using keyboard that has the same width to the screen width*/
1457 _keyboard_geometry.h = w;
1458 _keyboard_geometry.w = h;
1459 _keyboard_geometry.y = scr_w - _keyboard_geometry.h;
1460 _keyboard_geometry.x = 0;
1463 _keyboard_geometry.w = w;
1464 _keyboard_geometry.h = h;
1465 _keyboard_geometry.x = 0;
1466 _keyboard_geometry.y = scr_h - _keyboard_geometry.h;
1469 _keyboard_geometry.h = w;
1470 _keyboard_geometry.w = h;
1471 _keyboard_geometry.y = scr_w - _keyboard_geometry.h;
1472 _keyboard_geometry.x = 0;
1475 _keyboard_geometry.x = x;
1476 _keyboard_geometry.y = y;
1477 _keyboard_geometry.w = w;
1478 _keyboard_geometry.h = h;
1480 LOGD("[KEYPAD]: scr %dx%d, rot %d, orig (%d,%d, %dx%d)", scr_w, scr_h, rot, x, y, w, h);
1481 LOGD ("IME geometry x : %d, y : %d, w : %d, h : %d\n", _keyboard_geometry.x, _keyboard_geometry.y, _keyboard_geometry.w, _keyboard_geometry.h);
1482 ecore_imf_context_input_panel_event_callback_call(ctx, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
1486 return ECORE_CALLBACK_PASS_ON;
1490 get_purpose(Ecore_IMF_Context *ctx)
1492 int layout_variation = ecore_imf_context_input_panel_layout_variation_get (ctx);
1493 uint32_t new_purpose = 0;
1495 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
1499 switch (imcontext->content_purpose) {
1500 case WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS:
1501 if (layout_variation == ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_SIGNED)
1502 new_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS_SIGNED;
1503 else if (layout_variation == ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_DECIMAL)
1504 new_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS_DECIMAL;
1505 else if (layout_variation == ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_SIGNED_AND_DECIMAL)
1506 new_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS_SIGNEDDECIMAL;
1508 new_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS;
1510 case WL_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD:
1511 if (layout_variation == ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD_VARIATION_NUMBERONLY)
1512 new_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD_DIGITS;
1514 new_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD;
1516 case WL_TEXT_INPUT_CONTENT_PURPOSE_NORMAL:
1517 if (layout_variation == ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL_VARIATION_FILENAME)
1518 new_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_FILENAME;
1519 else if (layout_variation == ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL_VARIATION_PERSON_NAME)
1520 new_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NAME;
1522 new_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NORMAL;
1525 new_purpose = imcontext->content_purpose;
1532 static void _canvas_focus_in_cb(void *data, Evas *e, void *event_info)
1534 LOGD("ctx : %p", _focus_req_ctx);
1536 if (_focus_req_ctx) {
1537 set_focus(_focus_req_ctx);
1538 show_input_panel(_focus_req_ctx);
1540 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(_focus_req_ctx);
1541 if (imcontext && imcontext->canvas)
1542 evas_event_callback_del(imcontext->canvas, EVAS_CALLBACK_CANVAS_FOCUS_IN, _canvas_focus_in_cb);
1543 _focus_req_ctx = NULL;
1548 show_input_panel(Ecore_IMF_Context *ctx)
1550 LOGD("ctx : %p", ctx);
1551 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
1553 char *surrounding = NULL;
1556 if ((!imcontext) || (!imcontext->text_input))
1559 if (!imcontext->input) {
1561 if (!imcontext->input) {
1562 _focus_req_ctx = ctx;
1563 if (imcontext->canvas) {
1564 evas_event_callback_del(imcontext->canvas, EVAS_CALLBACK_CANVAS_FOCUS_IN, _canvas_focus_in_cb);
1565 evas_event_callback_add(imcontext->canvas, EVAS_CALLBACK_CANVAS_FOCUS_IN, _canvas_focus_in_cb, NULL);
1570 _clear_hide_timer ();
1572 _win_focus_out_handler_del ();
1574 if (!imcontext->input)
1577 ignore_hide = EINA_TRUE;
1579 _win_focus_out_handler = ecore_event_handler_add (ECORE_WL_EVENT_FOCUS_OUT, _client_window_focus_out_cb, ctx);
1580 _conformant_change_handler_del ();
1581 _conformant_change_handler = ecore_event_handler_add(ECORE_WL_EVENT_CONFORMANT_CHANGE, _conformant_change_cb, ctx);
1583 // TIZEN_ONLY(20160217): ignore the duplicate show request
1584 if ((_show_req_ctx == ctx) && _compare_context(_show_req_ctx, ctx) && (!will_hide)) {
1585 if (_input_panel_state == ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW ||
1586 _input_panel_state == ECORE_IMF_INPUT_PANEL_STATE_SHOW) {
1587 LOGD("already show. ctx : %p", ctx);
1593 will_hide = EINA_FALSE;
1594 _show_req_ctx = ctx;
1595 _input_panel_ctx = ctx;
1596 _active_context_canvas = ecore_imf_context_client_canvas_get(ctx);
1598 if (imcontext->window) {
1599 _active_context_window_id = ecore_wl_window_id_get(imcontext->window);
1600 imcontext->has_conformant = ecore_wl_window_conformant_get(imcontext->window);
1602 imcontext->has_conformant = EINA_FALSE;
1606 // TIZEN_ONLY(20150715): Support input_panel_state_get
1607 _input_panel_state = ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW;
1608 int layout = ecore_imf_context_input_panel_layout_get (ctx);
1609 int layout_variation = ecore_imf_context_input_panel_layout_variation_get (ctx);
1612 if (layout == ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD)
1613 imcontext->content_hint |= (WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA | WL_TEXT_INPUT_CONTENT_HINT_PASSWORD);
1615 wl_text_input_set_content_type(imcontext->text_input,
1616 imcontext->content_hint,
1619 if (ecore_imf_context_surrounding_get(imcontext->ctx, &surrounding, &cursor_pos)) {
1620 SECURE_LOGD ("surrounding text : %s\n", surrounding);
1624 imcontext->cursor_position = cursor_pos;
1625 wl_text_input_set_cursor_position(imcontext->text_input, cursor_pos);
1627 // TIZEN_ONLY(20150716): Support return key type
1628 wl_text_input_set_return_key_type(imcontext->text_input,
1629 imcontext->return_key_type);
1631 wl_text_input_set_return_key_disabled(imcontext->text_input,
1632 imcontext->return_key_disabled);
1634 if (imcontext->imdata_size > 0)
1635 wl_text_input_set_input_panel_data(imcontext->text_input, (const char *)imcontext->imdata, imcontext->imdata_size);
1637 set_autocapital (ctx);
1639 SECURE_LOGD ("ctx : %p, layout : %d, layout variation : %d\n", ctx,
1640 layout, layout_variation);
1641 SECURE_LOGD ("language : %d, cursor position : %d\n",
1642 ecore_imf_context_input_panel_language_get (ctx),
1644 SECURE_LOGD ("return key type : %d, return key disabled : %d, autocapital type : %d\n",
1645 ecore_imf_context_input_panel_return_key_type_get (ctx),
1646 ecore_imf_context_input_panel_return_key_disabled_get (ctx),
1647 ecore_imf_context_autocapital_type_get (ctx));
1648 SECURE_LOGD ("client_window : %#x, password mode : %d, prediction_allow : %d\n",
1649 ecore_imf_context_client_window_get (ctx),
1650 (imcontext->content_hint & WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA) ? 1 : 0,
1651 ecore_imf_context_prediction_allow_get (ctx));
1652 SECURE_LOGD ("input hint : %#x, bidi direction : %d\n", ecore_imf_context_input_hint_get (ctx), imcontext->bidi_direction);
1654 if (_active_context_canvas && !evas_focus_state_get (_active_context_canvas)) {
1655 LOGW ("Canvas does not have focus!\n");
1659 wl_text_input_show_input_panel(imcontext->text_input);
1664 static void delete_surrounding_text(WaylandIMContext *imcontext, int index, int length)
1666 Ecore_IMF_Event_Delete_Surrounding ev;
1667 LOGD("delete surrounding text (index: %d, length: %u)",
1671 ev.n_chars = length;
1673 ecore_imf_context_delete_surrounding_event_add(imcontext->ctx, ev.offset, ev.n_chars);
1674 ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, &ev);
1678 text_input_preedit_string(void *data,
1679 struct wl_text_input *text_input EINA_UNUSED,
1684 WaylandIMContext *imcontext = (WaylandIMContext *)data;
1685 Eina_Bool old_preedit = EINA_FALSE;
1686 Eina_Bool preedit_changed = EINA_FALSE;
1688 SECURE_LOGD("ctx : %p, preedit event (text: '%s', current pre-edit: '%s')",
1691 imcontext->preedit_text ? imcontext->preedit_text : "");
1693 if (!check_serial(imcontext, serial))
1697 imcontext->preedit_text && strlen(imcontext->preedit_text) > 0;
1699 if (imcontext->preedit_text)
1700 preedit_changed = (strcmp(imcontext->preedit_text, text) != 0);
1702 preedit_changed = (strlen(text) != 0);
1704 clear_preedit(imcontext);
1706 imcontext->preedit_text = strdup(text);
1707 imcontext->preedit_commit = (strlen(text) > 0 ? strdup(commit) : NULL);
1708 imcontext->preedit_cursor =
1709 utf8_offset_to_characters(text, imcontext->pending_preedit.cursor);
1710 imcontext->preedit_attrs = imcontext->pending_preedit.attrs;
1712 imcontext->pending_preedit.attrs = NULL;
1714 if (preedit_changed) {
1716 ecore_imf_context_preedit_start_event_add(imcontext->ctx);
1717 ecore_imf_context_event_callback_call(imcontext->ctx,
1718 ECORE_IMF_CALLBACK_PREEDIT_START,
1722 ecore_imf_context_preedit_changed_event_add(imcontext->ctx);
1723 ecore_imf_context_event_callback_call(imcontext->ctx,
1724 ECORE_IMF_CALLBACK_PREEDIT_CHANGED,
1727 if (imcontext->preedit_text && strlen(imcontext->preedit_text) == 0) {
1728 ecore_imf_context_preedit_end_event_add(imcontext->ctx);
1729 ecore_imf_context_event_callback_call(imcontext->ctx,
1730 ECORE_IMF_CALLBACK_PREEDIT_END,
1737 text_input_delete_surrounding_text(void *data,
1738 struct wl_text_input *text_input EINA_UNUSED,
1742 WaylandIMContext *imcontext = (WaylandIMContext *)data;
1743 delete_surrounding_text(imcontext, index, length);
1747 text_input_cursor_position(void *data EINA_UNUSED,
1748 struct wl_text_input *text_input EINA_UNUSED,
1752 LOGD("cursor_position for next commit (index: %d, anchor: %d)",
1757 text_input_preedit_styling(void *data,
1758 struct wl_text_input *text_input EINA_UNUSED,
1763 WaylandIMContext *imcontext = (WaylandIMContext *)data;
1764 Ecore_IMF_Preedit_Attr *attr = calloc(1, sizeof(*attr));
1768 case WL_TEXT_INPUT_PREEDIT_STYLE_DEFAULT:
1769 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1;
1771 case WL_TEXT_INPUT_PREEDIT_STYLE_UNDERLINE:
1772 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1;
1774 case WL_TEXT_INPUT_PREEDIT_STYLE_INCORRECT:
1776 case WL_TEXT_INPUT_PREEDIT_STYLE_HIGHLIGHT:
1777 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB3;
1779 case WL_TEXT_INPUT_PREEDIT_STYLE_ACTIVE:
1781 case WL_TEXT_INPUT_PREEDIT_STYLE_INACTIVE:
1783 case WL_TEXT_INPUT_PREEDIT_STYLE_SELECTION:
1784 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2;
1787 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1;
1791 attr->start_index = index;
1792 attr->end_index = index + length;
1794 imcontext->pending_preedit.attrs =
1795 eina_list_append(imcontext->pending_preedit.attrs, attr);
1799 text_input_preedit_cursor(void *data,
1800 struct wl_text_input *text_input EINA_UNUSED,
1803 WaylandIMContext *imcontext = (WaylandIMContext *)data;
1805 imcontext->pending_preedit.cursor = index;
1808 static xkb_mod_index_t
1809 modifiers_get_index(struct wl_array *modifiers_map, const char *name)
1811 xkb_mod_index_t index = 0;
1812 char *p = modifiers_map->data;
1814 while ((const char *)p < ((const char *)modifiers_map->data + modifiers_map->size))
1816 if (strcmp(p, name) == 0)
1823 return XKB_MOD_INVALID;
1826 static xkb_mod_mask_t
1827 modifiers_get_mask(struct wl_array *modifiers_map,
1830 xkb_mod_index_t index = modifiers_get_index(modifiers_map, name);
1832 if (index == XKB_MOD_INVALID)
1833 return XKB_MOD_INVALID;
1839 text_input_modifiers_map(void *data,
1840 struct wl_text_input *text_input EINA_UNUSED,
1841 struct wl_array *map)
1843 WaylandIMContext *imcontext = (WaylandIMContext *)data;
1845 imcontext->shift_mask = modifiers_get_mask(map, "Shift");
1846 imcontext->control_mask = modifiers_get_mask(map, "Control");
1847 imcontext->alt_mask = modifiers_get_mask(map, "Mod1");
1848 imcontext->caps_mask = modifiers_get_mask(map, "Lock");
1849 imcontext->num_mask = modifiers_get_mask(map, "Mod2");
1853 _ecore_keyevent_free (void *data EINA_UNUSED, void *ev)
1855 Ecore_Event_Key *e = ev;
1861 text_input_keysym(void *data,
1862 struct wl_text_input *text_input EINA_UNUSED,
1863 uint32_t serial EINA_UNUSED,
1869 WaylandIMContext *imcontext = (WaylandIMContext *)data;
1870 char string[32], key[32], keyname[32];
1873 memset(key, 0, sizeof(key));
1874 xkb_keysym_get_name(sym, key, sizeof(key));
1876 memset(keyname, 0, sizeof(keyname));
1877 xkb_keysym_get_name(sym, keyname, sizeof(keyname));
1878 if (keyname[0] == '\0')
1879 snprintf(keyname, sizeof(keyname), "Keysym-%u", sym);
1881 memset(string, 0, sizeof(string));
1882 xkb_keysym_to_utf8(sym, string, 32);
1884 SECURE_LOGD("key event (key: %s)", keyname);
1886 e = calloc(1, sizeof(Ecore_Event_Key) + strlen(key) + strlen(keyname) +
1887 strlen(string) + 3);
1890 e->keyname = (char *)(e + 1);
1891 e->key = e->keyname + strlen(keyname) + 1;
1892 e->string = e->key + strlen(key) + 1;
1893 e->compose = e->string;
1895 strncpy((char *)e->keyname, keyname, strlen(keyname));
1896 strncpy((char *)e->key, key, strlen(key));
1897 strncpy((char *)e->string, string, strlen(string));
1899 e->window = (Ecore_Window)ecore_wl_window_id_get(imcontext->window);
1900 e->event_window = (Ecore_Window)ecore_wl_window_id_get(imcontext->window);
1901 e->dev = _ime_device;
1902 e->timestamp = 0; /* For distinguishing S/W keyboard event */
1905 if (modifiers & imcontext->shift_mask)
1906 e->modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
1908 if (modifiers & imcontext->control_mask)
1909 e->modifiers |= ECORE_EVENT_MODIFIER_CTRL;
1911 if (modifiers & imcontext->alt_mask)
1912 e->modifiers |= ECORE_EVENT_MODIFIER_ALT;
1914 if (modifiers & MOD_Mod5_MASK)
1915 e->modifiers |= MOD_Mod5_MASK;
1917 if (modifiers & imcontext->caps_mask)
1918 e->modifiers |= ECORE_EVENT_LOCK_CAPS;
1920 if (modifiers & imcontext->num_mask)
1921 e->modifiers |= ECORE_EVENT_LOCK_NUM;
1923 //Save "wl_text_input::keysym" keysym to list if list is not empty,
1924 //if not, send keysym to ecore loop as key event.
1925 //This code let key event which will be filtered by IME one by one.
1926 if (eina_list_count(imcontext->keysym_list)) {
1927 e->data = (void *)(unsigned long int)(state ? ECORE_EVENT_KEY_DOWN : ECORE_EVENT_KEY_UP);
1928 imcontext->keysym_list = eina_list_prepend(imcontext->keysym_list, e);
1932 ecore_event_add(ECORE_EVENT_KEY_DOWN, e, _ecore_keyevent_free, NULL);
1934 ecore_event_add(ECORE_EVENT_KEY_UP, e, _ecore_keyevent_free, NULL);
1939 text_input_enter(void *data,
1940 struct wl_text_input *text_input EINA_UNUSED,
1941 struct wl_surface *surface EINA_UNUSED)
1943 WaylandIMContext *imcontext = (WaylandIMContext *)data;
1945 update_state(imcontext);
1947 imcontext->reset_serial = imcontext->serial;
1951 text_input_leave(void *data,
1952 struct wl_text_input *text_input EINA_UNUSED)
1954 WaylandIMContext *imcontext = (WaylandIMContext *)data;
1957 commit_preedit(imcontext);
1958 clear_preedit(imcontext);
1962 text_input_input_panel_state(void *data EINA_UNUSED,
1963 struct wl_text_input *text_input EINA_UNUSED,
1964 uint32_t state EINA_UNUSED)
1966 // TIZEN_ONLY(20150708): Support input panel state callback
1967 WaylandIMContext *imcontext = (WaylandIMContext *)data;
1968 LOGD("input panel state: %d", state);
1970 case WL_TEXT_INPUT_INPUT_PANEL_STATE_HIDE:
1971 _input_panel_state = ECORE_IMF_INPUT_PANEL_STATE_HIDE;
1972 if (imcontext->ctx == _show_req_ctx)
1973 _show_req_ctx = NULL;
1975 will_hide = EINA_FALSE;
1977 _received_will_hide_event = EINA_TRUE;
1978 LOGD("_received_will_hide_event = 1\n");
1979 send_will_hide_ack(imcontext->ctx);
1981 case WL_TEXT_INPUT_INPUT_PANEL_STATE_SHOW:
1982 _input_panel_state = ECORE_IMF_INPUT_PANEL_STATE_SHOW;
1983 _received_will_hide_event = EINA_FALSE;
1985 _show_req_ctx = imcontext->ctx;
1986 LOGD("_received_will_hide_event = 0\n");
1989 _input_panel_state = (Ecore_IMF_Input_Panel_State)state;
1993 ecore_imf_context_input_panel_event_callback_call(imcontext->ctx,
1994 ECORE_IMF_INPUT_PANEL_STATE_EVENT,
1995 _input_panel_state);
1997 if (state == WL_TEXT_INPUT_INPUT_PANEL_STATE_HIDE) {
1998 static Evas_Coord scr_w = 0, scr_h = 0;
1999 if (scr_w == 0 || scr_h == 0) {
2001 ecore_wl_screen_size_get(&scr_w, &scr_h);
2003 _keyboard_geometry.x = 0;
2004 _keyboard_geometry.y = scr_h;
2005 _keyboard_geometry.w = 0;
2006 _keyboard_geometry.h = 0;
2007 LOGD ("IME geometry x : %d, y : %d, w : %d, h : %d\n", _keyboard_geometry.x, _keyboard_geometry.y, _keyboard_geometry.w, _keyboard_geometry.h);
2008 ecore_imf_context_input_panel_event_callback_call(imcontext->ctx, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
2013 // TIZEN_ONLY(20151221): Support input panel geometry
2015 text_input_input_panel_geometry(void *data EINA_UNUSED,
2016 struct wl_text_input *text_input EINA_UNUSED,
2022 WaylandIMContext *imcontext = (WaylandIMContext *)data;
2024 if (_keyboard_geometry.x != (int)x || _keyboard_geometry.y != (int)y ||
2025 _keyboard_geometry.w != (int)w || _keyboard_geometry.h != (int)h)
2027 _keyboard_geometry.x = x;
2028 _keyboard_geometry.y = y;
2029 _keyboard_geometry.w = w;
2030 _keyboard_geometry.h = h;
2031 LOGD ("IME geometry x : %d, y : %d, w : %d, h : %d\n", _keyboard_geometry.x, _keyboard_geometry.y, _keyboard_geometry.w, _keyboard_geometry.h);
2032 ecore_imf_context_input_panel_event_callback_call(imcontext->ctx, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0);
2038 text_input_language(void *data,
2039 struct wl_text_input *text_input EINA_UNUSED,
2040 uint32_t serial EINA_UNUSED,
2041 const char *language)
2043 WaylandIMContext *imcontext = (WaylandIMContext *)data;
2044 Eina_Bool changed = EINA_FALSE;
2046 if (!imcontext || !language) return;
2048 if (imcontext->language) {
2049 if (strcmp(imcontext->language, language) != 0) {
2050 changed = EINA_TRUE;
2051 free(imcontext->language);
2055 changed = EINA_TRUE;
2059 imcontext->language = strdup(language);
2062 ecore_imf_context_input_panel_event_callback_call(imcontext->ctx, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, 0);
2067 text_input_text_direction(void *data EINA_UNUSED,
2068 struct wl_text_input *text_input EINA_UNUSED,
2069 uint32_t serial EINA_UNUSED,
2070 uint32_t direction EINA_UNUSED)
2074 // TIZEN_ONLY(20150918): Support to set the selection region
2076 text_input_selection_region(void *data,
2077 struct wl_text_input *text_input EINA_UNUSED,
2078 uint32_t serial EINA_UNUSED,
2082 WaylandIMContext *imcontext = (WaylandIMContext *)data;
2083 if (!imcontext || !imcontext->ctx) return;
2085 Ecore_IMF_Event_Selection ev;
2086 ev.ctx = imcontext->ctx;
2089 ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_SELECTION_SET, &ev);
2093 text_input_private_command(void *data,
2094 struct wl_text_input *text_input EINA_UNUSED,
2095 uint32_t serial EINA_UNUSED,
2096 const char *command)
2098 WaylandIMContext *imcontext = (WaylandIMContext *)data;
2099 if (!imcontext || !imcontext->ctx) return;
2101 const char *szConformantReset = "CONFORMANT_RESET";
2102 const char *szConformantRestore = "CONFORMANT_RESTORE";
2103 LOGD("Checking command : %s", command);
2105 if (strncmp(command, szConformantReset, strlen(szConformantReset)) == 0) {
2106 Ecore_Wl_Window *window = imcontext->window;
2107 if (!window) return;
2109 if (!reset_conformant_area(imcontext->ctx) && !_conformant_reset_started) {
2110 LOGD("Could not reset conformant area, send will_hide_ack right away %d", _conformant_reset_started);
2111 _send_will_hide_ack(imcontext);
2112 } else if (_conformant_reset_done) {
2113 LOGD("Conformant reset has been already finished, send will_hide_ack right away");
2114 _send_will_hide_ack(imcontext);
2116 } else if (strncmp(command, szConformantRestore, strlen(szConformantRestore)) == 0) {
2117 Ecore_Wl_Window *window = imcontext->window;
2118 if (!window) return;
2120 restore_conformant_area(imcontext->ctx);
2122 ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, (void *)command);
2127 text_input_input_panel_data(void *data,
2128 struct wl_text_input *text_input EINA_UNUSED,
2129 uint32_t serial EINA_UNUSED,
2130 const char *input_panel_data,
2133 WaylandIMContext *imcontext = (WaylandIMContext *)data;
2134 if (!imcontext || !imcontext->ctx) return;
2136 if (imcontext->input_panel_data)
2137 free (imcontext->input_panel_data);
2139 imcontext->input_panel_data = calloc (1, length);
2140 memcpy (imcontext->input_panel_data, input_panel_data, length);
2141 imcontext->input_panel_data_length = length;
2145 text_input_get_selection_text (void *data,
2146 struct wl_text_input *text_input EINA_UNUSED,
2149 char *selection = NULL;
2151 WaylandIMContext *imcontext = (WaylandIMContext *)data;
2152 if (!imcontext || !imcontext->ctx) {
2158 ecore_imf_context_selection_get (imcontext->ctx, &selection);
2159 if (imcontext->text_input) {
2160 SECURE_LOGD ("selection :%s", selection ? selection : "");
2162 char *_selection = selection;
2163 size_t len = strlen (selection);
2165 ssize_t ret = write (fd, _selection, len);
2169 LOGW ("write pipe failed, errno: %d", errno);
2183 text_input_get_surrounding_text (void *data,
2184 struct wl_text_input *text_input EINA_UNUSED,
2185 uint32_t maxlen_before,
2186 uint32_t maxlen_after,
2190 char *surrounding = NULL;
2191 LOGD("fd: %d maxlen_before: %d maxlen_after: %d", fd, maxlen_before, maxlen_after);
2192 WaylandIMContext *imcontext = (WaylandIMContext *)data;
2193 if (!imcontext || !imcontext->ctx) {
2199 /* cursor_pos is a byte index */
2200 if (ecore_imf_context_surrounding_get (imcontext->ctx, &surrounding, &cursor_pos)) {
2201 SECURE_LOGD ("surrounding : '%s', cursor: %d", surrounding ? surrounding : "", cursor_pos);
2202 if (imcontext->text_input) {
2203 Eina_Unicode *wide_surrounding = eina_unicode_utf8_to_unicode (surrounding, NULL);
2204 size_t wlen = eina_unicode_strlen (wide_surrounding);
2206 if (cursor_pos > (int)wlen || cursor_pos < 0)
2209 if (maxlen_before > cursor_pos)
2212 maxlen_before = cursor_pos - maxlen_before;
2214 if (maxlen_after > wlen - cursor_pos)
2215 maxlen_after = wlen;
2217 maxlen_after = cursor_pos + maxlen_after;
2219 char *req_surrounding = eina_unicode_unicode_to_utf8_range (wide_surrounding + maxlen_before, maxlen_after - maxlen_before, NULL);
2221 ssize_t ret = write(fd, &cursor_pos, sizeof(cursor_pos));
2223 LOGW ("write pipe failed, errno: %d", errno);
2224 } else if (req_surrounding) {
2225 char *_surrounding = req_surrounding;
2226 size_t len = strlen(req_surrounding);
2228 ssize_t ret = write(fd, _surrounding, len);
2232 LOGW ("write pipe failed, errno: %d", errno);
2235 _surrounding += ret;
2240 if (req_surrounding)
2241 free (req_surrounding);
2243 if (wide_surrounding)
2244 free (wide_surrounding);
2254 text_input_filter_key_event_done(void *data,
2255 struct wl_text_input *text_input EINA_UNUSED,
2259 LOGD("serial: %d, state: %d", serial, state);
2260 WaylandIMContext *imcontext = (WaylandIMContext *)data;
2261 if (!imcontext) return;
2263 imcontext->last_key_event_filter.serial = serial;
2264 imcontext->last_key_event_filter.state = state;
2268 text_input_hide_permission(void *data,
2269 struct wl_text_input *text_input EINA_UNUSED,
2270 uint32_t permission)
2272 LOGD("permission : %d", permission);
2273 WaylandIMContext *imcontext = (WaylandIMContext *)data;
2274 if (!imcontext || !imcontext->ctx || ignore_hide)
2278 ecore_imf_context_input_panel_hide(imcontext->ctx);
2282 text_input_recapture_string(void *data,
2283 struct wl_text_input *text_input EINA_UNUSED,
2287 const char *preedit,
2288 const char *preedit_commit,
2291 WaylandIMContext *imcontext = (WaylandIMContext *)data;
2292 Eina_Bool old_preedit = EINA_FALSE;
2293 Eina_Bool preedit_changed = EINA_FALSE;
2295 SECURE_LOGD("ctx : %p, preedit event (preedit: '%s', current pre-edit: '%s')",
2298 imcontext->preedit_text ? imcontext->preedit_text : "");
2300 if (!check_serial(imcontext, serial))
2304 imcontext->preedit_text && strlen(imcontext->preedit_text) > 0;
2306 if (imcontext->preedit_text)
2307 preedit_changed = (strcmp(imcontext->preedit_text, preedit) != 0);
2309 preedit_changed = (strlen(preedit) != 0);
2311 clear_preedit(imcontext);
2313 // send transaction start
2314 ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, (void *)"TRANSACTION_START");
2316 // delete surrounding text
2317 delete_surrounding_text(imcontext, index, length);
2319 // update preedit string
2320 imcontext->preedit_text = strdup(preedit);
2321 imcontext->preedit_commit = (strlen(preedit) > 0 ? strdup(preedit_commit) : NULL);
2322 imcontext->preedit_cursor =
2323 utf8_offset_to_characters(preedit, imcontext->pending_preedit.cursor);
2324 imcontext->preedit_attrs = imcontext->pending_preedit.attrs;
2326 imcontext->pending_preedit.attrs = NULL;
2328 if (preedit_changed) {
2330 ecore_imf_context_preedit_start_event_add(imcontext->ctx);
2331 ecore_imf_context_event_callback_call(imcontext->ctx,
2332 ECORE_IMF_CALLBACK_PREEDIT_START,
2336 ecore_imf_context_preedit_changed_event_add(imcontext->ctx);
2337 ecore_imf_context_event_callback_call(imcontext->ctx,
2338 ECORE_IMF_CALLBACK_PREEDIT_CHANGED,
2341 if (imcontext->preedit_text && strlen(imcontext->preedit_text) == 0) {
2342 ecore_imf_context_preedit_end_event_add(imcontext->ctx);
2343 ecore_imf_context_event_callback_call(imcontext->ctx,
2344 ECORE_IMF_CALLBACK_PREEDIT_END,
2350 if (commit && strlen(commit) != 0) {
2351 ecore_imf_context_commit_event_add(imcontext->ctx, commit);
2352 ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)commit);
2355 // send transaction end
2356 ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, (void *)"TRANSACTION_END");
2360 static const struct wl_text_input_listener text_input_listener =
2364 text_input_modifiers_map,
2365 text_input_input_panel_state,
2366 text_input_preedit_string,
2367 text_input_preedit_styling,
2368 text_input_preedit_cursor,
2369 text_input_commit_string,
2370 text_input_cursor_position,
2371 text_input_delete_surrounding_text,
2373 text_input_language,
2374 text_input_text_direction,
2375 // TIZEN_ONLY(20150918): Support to set the selection region
2376 text_input_selection_region,
2377 text_input_private_command,
2378 text_input_input_panel_geometry,
2379 text_input_input_panel_data,
2380 text_input_get_selection_text,
2381 text_input_get_surrounding_text,
2382 text_input_filter_key_event_done,
2383 text_input_hide_permission,
2384 text_input_recapture_string
2390 keyboard_mode_changed_cb (keynode_t *key, void* data)
2392 hw_keyboard_mode = vconf_keynode_get_bool (key);
2393 Ecore_IMF_Context *active_ctx = get_using_ctx ();
2395 LOGD ("ctx : %p, input detect : %d\n", active_ctx, hw_keyboard_mode);
2397 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;
2398 ecore_imf_context_input_panel_event_callback_call (active_ctx, ECORE_IMF_INPUT_PANEL_KEYBOARD_MODE_EVENT, input_mode);
2400 if ((input_mode == ECORE_IMF_INPUT_PANEL_SW_KEYBOARD_MODE) && _focused_ctx && (active_ctx == _focused_ctx)) {
2401 if (ecore_imf_context_input_panel_enabled_get (active_ctx)) {
2402 ecore_imf_context_input_panel_show (active_ctx);
2409 static Eina_Bool read_devices = EINA_FALSE;
2410 char ** device_names = NULL;
2413 filter_devices (const char *dev_name)
2421 if (read_devices == EINA_FALSE) {
2422 char *devices = getenv("ISF_REMOTE_CONTROL_DEVICES");
2424 device_names = eina_str_split(devices, ",", 0);
2426 read_devices = EINA_TRUE;
2429 if (device_names == NULL) {
2433 for (i = 0; device_names[i]; i++) {
2434 if (!strcmp (dev_name, device_names[i])) {
2444 void wayland_im_initialize ()
2446 register_key_handler ();
2448 /* get input language vconf value */
2449 get_input_language ();
2452 /* get autoperiod allow vconf value */
2454 if (vconf_get_bool (VCONFKEY_AUTOPERIOD_ALLOW_BOOL, &val) == 0) {
2455 if (val == EINA_TRUE)
2456 autoperiod_allow = EINA_TRUE;
2459 /* get autocapital allow vconf value */
2460 if (vconf_get_bool (VCONFKEY_AUTOCAPITAL_ALLOW_BOOL, &val) == 0) {
2461 if (val == EINA_TRUE)
2462 autocap_allow = EINA_TRUE;
2465 /* get hardware keyboard input detected vconf value */
2466 if (vconf_get_bool (VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, &val) == 0) {
2467 if (val == EINA_TRUE)
2468 hw_keyboard_mode = EINA_TRUE;
2471 vconf_notify_key_changed (VCONFKEY_AUTOCAPITAL_ALLOW_BOOL, autocapital_allow_changed_cb, NULL);
2472 vconf_notify_key_changed (VCONFKEY_AUTOPERIOD_ALLOW_BOOL, autoperiod_allow_changed_cb, NULL);
2473 vconf_notify_key_changed (VCONFKEY_ISF_INPUT_LANGUAGE, input_language_changed_cb, NULL);
2474 vconf_notify_key_changed (VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, keyboard_mode_changed_cb, NULL);
2477 _ime_device = ecore_device_add();
2479 ecore_device_name_set (_ime_device, IME_DEVICE_NAME);
2480 ecore_device_description_set (_ime_device, IME_DEVICE_NAME);
2481 ecore_device_identifier_set (_ime_device, IME_DEVICE_NAME);
2482 ecore_device_class_set (_ime_device, ECORE_DEVICE_CLASS_KEYBOARD);
2486 void wayland_im_uninitialize ()
2488 unregister_key_handler ();
2490 _win_focus_out_handler_del ();
2491 _conformant_change_handler_del ();
2494 vconf_ignore_key_changed (VCONFKEY_AUTOPERIOD_ALLOW_BOOL, autoperiod_allow_changed_cb);
2495 vconf_ignore_key_changed (VCONFKEY_AUTOCAPITAL_ALLOW_BOOL, autocapital_allow_changed_cb);
2496 vconf_ignore_key_changed (VCONFKEY_ISF_INPUT_LANGUAGE, input_language_changed_cb);
2497 vconf_ignore_key_changed (VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, keyboard_mode_changed_cb);
2501 if (device_names[0])
2502 free (device_names[0]);
2503 free (device_names);
2504 device_names = NULL;
2510 ecore_device_del (_ime_device);
2516 wayland_im_context_add(Ecore_IMF_Context *ctx)
2518 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2520 LOGD("ctx : %p", ctx);
2522 if (!imcontext) return;
2524 imcontext->ctx = ctx;
2525 imcontext->input_panel_layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL;
2526 imcontext->keysym_list = NULL;
2528 imcontext->shift_mask = MOD_SHIFT_MASK;
2529 imcontext->control_mask = MOD_CONTROL_MASK;
2530 imcontext->alt_mask = MOD_ALT_MASK;
2531 imcontext->caps_mask = MOD_CAPS_MASK;
2532 imcontext->num_mask = MOD_NUM_MASK;
2534 imcontext->text_input =
2535 wl_text_input_manager_create_text_input(imcontext->text_input_manager);
2537 if (imcontext->text_input)
2538 wl_text_input_add_listener(imcontext->text_input,
2539 &text_input_listener, imcontext);
2543 wayland_im_context_del (Ecore_IMF_Context *ctx)
2545 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2547 Ecore_Event_Key *ev;
2548 LOGD ("ctx : %p, focused_ctx : %p, show_req_ctx : %p", ctx, _focused_ctx, _show_req_ctx);
2550 if (!imcontext) return;
2552 if (_ime_device && imcontext->window)
2553 _device_info_send (ecore_wl_window_id_get (imcontext->window), EINA_FALSE);
2555 // TIZEN_ONLY(20150708): Support back key
2556 if (_input_panel_ctx == ctx) {
2557 _clear_hide_timer();
2558 _input_panel_hide(ctx, EINA_TRUE);
2559 _input_panel_state = ECORE_IMF_INPUT_PANEL_STATE_HIDE;
2560 _input_panel_ctx = NULL;
2563 if (_focused_ctx == ctx)
2564 _focused_ctx = NULL;
2566 if (_show_req_ctx == ctx)
2567 _show_req_ctx = NULL;
2569 if (_focus_req_ctx == ctx) {
2570 if (imcontext->canvas)
2571 evas_event_callback_del(imcontext->canvas, EVAS_CALLBACK_CANVAS_FOCUS_IN, _canvas_focus_in_cb);
2573 _focus_req_ctx = NULL;
2577 if (imcontext->language) {
2578 free (imcontext->language);
2579 imcontext->language = NULL;
2582 // TIZEN_ONLY(20150922): Support to set input panel data
2583 if (imcontext->imdata) {
2584 free (imcontext->imdata);
2585 imcontext->imdata = NULL;
2586 imcontext->imdata_size = 0;
2589 if (imcontext->input_panel_data) {
2590 free (imcontext->input_panel_data);
2591 imcontext->input_panel_data = NULL;
2592 imcontext->input_panel_data_length = 0;
2596 if (imcontext->text_input)
2597 wl_text_input_destroy (imcontext->text_input);
2599 clear_preedit (imcontext);
2601 EINA_LIST_FREE(imcontext->keysym_list, ev) {
2609 wayland_im_context_reset(Ecore_IMF_Context *ctx)
2611 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2613 LOGD("ctx : %p", ctx);
2615 if (!imcontext) return;
2617 Eina_Bool preedit_empty = check_preedit_empty(imcontext);
2619 commit_preedit (imcontext);
2620 clear_preedit(imcontext);
2622 if (!imcontext->input) return;
2624 if (imcontext->text_input && !preedit_empty) {
2625 wl_text_input_reset(imcontext->text_input);
2627 update_state(imcontext);
2629 imcontext->reset_serial = imcontext->serial;
2633 wayland_im_context_focus_in(Ecore_IMF_Context *ctx)
2636 LOGD ("ctx : %p. enable : %d, on demand : %d\n", ctx,
2637 ecore_imf_context_input_panel_enabled_get(ctx),
2638 ecore_imf_context_input_panel_show_on_demand_get (ctx));
2640 if (!set_focus(ctx)) {
2641 LOGW("ctx : %p. Fail to set focus!", ctx);
2645 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2646 if (imcontext && imcontext->input && imcontext->text_input)
2647 wl_text_input_set_return_key_disabled(imcontext->text_input,
2648 imcontext->return_key_disabled);
2650 if (ecore_imf_context_input_panel_enabled_get(ctx))
2651 if (!ecore_imf_context_input_panel_show_on_demand_get (ctx))
2652 show_input_panel(ctx);
2654 LOGD ("ctx : %p input panel on demand mode : TRUE\n", ctx);
2656 LOGD ("ctx : %p input panel enable : FALSE\n", ctx);
2660 wayland_im_context_focus_out(Ecore_IMF_Context *ctx)
2662 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2664 LOGD("ctx : %p", ctx);
2666 if (_focus_req_ctx == ctx)
2667 _focus_req_ctx = NULL;
2669 if (!imcontext || !imcontext->input) return;
2671 if (ecore_imf_context_input_panel_enabled_get(ctx)) {
2672 ecore_imf_context_input_panel_hide(ctx);
2679 wayland_im_context_preedit_string_get(Ecore_IMF_Context *ctx,
2683 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2684 if (!imcontext) return;
2686 SECURE_LOGD("pre-edit string requested (preedit: '%s')",
2687 imcontext->preedit_text ? imcontext->preedit_text : "");
2690 *str = strdup(imcontext->preedit_text ? imcontext->preedit_text : "");
2693 *cursor_pos = imcontext->preedit_cursor;
2697 wayland_im_context_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx,
2702 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2703 if (!imcontext) return;
2705 SECURE_LOGD("pre-edit string with attributes requested (preedit: '%s')",
2706 imcontext->preedit_text ? imcontext->preedit_text : "");
2709 *str = strdup(imcontext->preedit_text ? imcontext->preedit_text : "");
2713 Ecore_IMF_Preedit_Attr *a, *attr;
2715 if (imcontext->preedit_attrs) {
2716 EINA_LIST_FOREACH(imcontext->preedit_attrs, l, a) {
2717 attr = malloc(sizeof(*attr));
2718 attr = memcpy(attr, a, sizeof(*attr));
2719 *attrs = eina_list_append(*attrs, attr);
2723 if (imcontext->preedit_text) {
2724 Ecore_IMF_Preedit_Attr *attr = calloc(1, sizeof(*attr));
2725 // use REVERSE style as default
2726 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2;
2727 attr->start_index = 0;
2728 attr->end_index = strlen(imcontext->preedit_text);
2729 *attrs = eina_list_append(*attrs, attr);
2735 *cursor_pos = imcontext->preedit_cursor;
2739 wayland_im_context_cursor_position_set (Ecore_IMF_Context *ctx,
2742 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2743 if (!imcontext) return;
2745 if (imcontext->cursor_position != cursor_pos) {
2746 imcontext->cursor_position = cursor_pos;
2748 if (imcontext->input && imcontext->text_input) {
2749 LOGD ("ctx : %p, cursor pos : %d\n", ctx, cursor_pos);
2751 set_autocapital (ctx);
2753 if (!imcontext->preedit_text || strlen(imcontext->preedit_text) == 0)
2754 wl_text_input_set_cursor_position (imcontext->text_input, cursor_pos);
2760 wayland_im_context_use_preedit_set(Ecore_IMF_Context *ctx EINA_UNUSED,
2761 Eina_Bool use_preedit EINA_UNUSED)
2766 wayland_im_context_client_window_set(Ecore_IMF_Context *ctx,
2769 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2771 LOGD("client window set (window: %p)", window);
2773 if (imcontext && window) {
2774 imcontext->window = ecore_wl_window_find((Ecore_Window)window);
2776 if (_ime_device && imcontext->window)
2777 _device_info_send (ecore_wl_window_id_get (imcontext->window), EINA_TRUE);
2782 wayland_im_context_client_canvas_set(Ecore_IMF_Context *ctx,
2785 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2787 LOGD("client canvas set (canvas: %p)", canvas);
2789 if (imcontext && canvas) {
2790 imcontext->canvas = canvas;
2792 if (!imcontext->window)
2793 imcontext->window = ecore_wl_window_find(ecore_evas_window_get(ecore_evas_ecore_evas_get(canvas)));
2795 if (_ime_device && imcontext->window)
2796 _device_info_send (ecore_wl_window_id_get (imcontext->window), EINA_TRUE);
2801 wayland_im_context_show(Ecore_IMF_Context *ctx)
2803 LOGD("ctx : %p", ctx);
2805 show_input_panel(ctx);
2809 wayland_im_context_hide(Ecore_IMF_Context *ctx)
2811 LOGD("ctx : %p", ctx);
2813 if (!get_using_ctx()) {
2814 LOGW("Can't hide input_panel because there is no using context!!");
2818 _input_panel_hide(ctx, EINA_FALSE);
2821 #if !(ENABLE_GRAB_KEYBOARD)
2823 _ecore_imf_lock_to_ecore_key_modifier(unsigned int locks)
2825 unsigned int mask = 0;
2827 if (locks & ECORE_IMF_KEYBOARD_LOCK_SCROLL)
2828 mask |= ECORE_EVENT_LOCK_SCROLL;
2830 if (locks & ECORE_IMF_KEYBOARD_LOCK_CAPS)
2831 mask |= ECORE_EVENT_LOCK_CAPS;
2833 if (locks & ECORE_IMF_KEYBOARD_LOCK_NUM)
2834 mask |= ECORE_EVENT_LOCK_NUM;
2840 _ecore_imf_modifier_to_ecore_key_modifier(Ecore_IMF_Keyboard_Modifiers modifiers)
2842 unsigned int mask = 0;
2844 /**< "Control" is pressed */
2845 if (modifiers & ECORE_IMF_KEYBOARD_MODIFIER_CTRL)
2846 mask |= ECORE_EVENT_MODIFIER_CTRL;
2848 /**< "Alt" is pressed */
2849 if (modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALT)
2850 mask |= ECORE_EVENT_MODIFIER_ALT;
2852 /**< "Shift" is pressed */
2853 if (modifiers & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT)
2854 mask |= ECORE_EVENT_MODIFIER_SHIFT;
2856 /**< "Win" (between "Ctrl" and "Alt") is pressed */
2857 if (modifiers & ECORE_IMF_KEYBOARD_MODIFIER_WIN)
2858 mask |= ECORE_EVENT_MODIFIER_WIN;
2860 /**< "AltGr" is pressed */
2861 if (modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALTGR)
2862 mask |= ECORE_EVENT_MODIFIER_ALTGR;
2869 wayland_im_context_filter_event(Ecore_IMF_Context *ctx,
2870 Ecore_IMF_Event_Type type,
2871 Ecore_IMF_Event *imf_event)
2874 #if !(ENABLE_GRAB_KEYBOARD)
2875 Eina_Bool ret = EINA_FALSE;
2876 Ecore_Event_Key ecore_key_ev;
2877 char *key_dev_name = NULL;
2878 uint32_t key_dev_class = 0;
2879 uint32_t key_dev_subclass = 0;
2881 if (type == ECORE_IMF_EVENT_MOUSE_UP) {
2882 if (ecore_imf_context_input_panel_enabled_get(ctx)) {
2883 LOGD ("[Mouse-up event] ctx : %p\n", ctx);
2884 if (ctx == _focused_ctx) {
2885 ecore_imf_context_input_panel_show(ctx);
2888 LOGE ("Can't show IME because there is no focus. ctx : %p\n", ctx);
2891 #if !(ENABLE_GRAB_KEYBOARD)
2892 else if (type == ECORE_IMF_EVENT_KEY_UP) {
2893 Ecore_IMF_Event_Key_Up *key_ev = (Ecore_IMF_Event_Key_Up *)imf_event;
2894 ecore_key_ev.keyname = key_ev->keyname;
2895 ecore_key_ev.key = key_ev->key;
2896 ecore_key_ev.string = key_ev->string;
2897 ecore_key_ev.compose = key_ev->compose;
2898 ecore_key_ev.timestamp = key_ev->timestamp;
2899 ecore_key_ev.modifiers = _ecore_imf_modifier_to_ecore_key_modifier(key_ev->modifiers);
2900 ecore_key_ev.modifiers |= _ecore_imf_lock_to_ecore_key_modifier(key_ev->locks);
2901 key_dev_name = (char *)key_ev->dev_name;
2902 key_dev_class = key_ev->dev_class;
2903 key_dev_subclass = key_ev->dev_subclass;
2905 else if (type == ECORE_IMF_EVENT_KEY_DOWN) {
2906 Ecore_IMF_Event_Key_Down *key_ev = (Ecore_IMF_Event_Key_Down *)imf_event;
2907 ecore_key_ev.keyname = key_ev->keyname;
2908 ecore_key_ev.key = key_ev->key;
2909 ecore_key_ev.string = key_ev->string;
2910 ecore_key_ev.compose = key_ev->compose;
2911 ecore_key_ev.timestamp = key_ev->timestamp;
2912 ecore_key_ev.modifiers = _ecore_imf_modifier_to_ecore_key_modifier(key_ev->modifiers);
2913 ecore_key_ev.modifiers |= _ecore_imf_lock_to_ecore_key_modifier(key_ev->locks);
2914 key_dev_name = (char *)key_ev->dev_name;
2915 key_dev_class = key_ev->dev_class;
2916 key_dev_subclass = key_ev->dev_subclass;
2919 if (type == ECORE_IMF_EVENT_KEY_UP || type == ECORE_IMF_EVENT_KEY_DOWN) {
2920 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
2921 if (!imcontext || !imcontext->input || !imcontext->text_input)
2924 if (!_focused_ctx) {
2925 LOGD ("no focus\n");
2930 if (strcmp (ecore_key_ev.keyname, "Return") == 0 && type == ECORE_IMF_EVENT_KEY_DOWN && filter_devices (key_dev_name) && hw_keyboard_mode == EINA_TRUE) {
2931 LOGD ("Changed keyboard mode from H/W to S/W ");
2932 hw_keyboard_mode = EINA_FALSE;
2933 vconf_set_bool (VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, 0);
2935 if (ecore_imf_context_input_panel_enabled_get (ctx)) {
2936 ecore_imf_context_input_panel_show (ctx);
2943 if (!ecore_key_ev.timestamp && (ecore_key_ev.modifiers & MOD_Mod5_MASK)) {
2944 if (type == ECORE_IMF_EVENT_KEY_DOWN) {
2945 if (strcmp (ecore_key_ev.key, "space") == 0 ||
2946 strcmp (ecore_key_ev.key, "KP_Space") == 0 ) {
2947 autoperiod_insert (ctx);
2951 LOGD("Return! This is SW keyboard fake event!");
2955 int serial = imcontext->serial++;
2956 double start_time = ecore_time_get();
2959 uint32_t modifiers = 0;
2960 if (ecore_key_ev.modifiers & ECORE_EVENT_MODIFIER_SHIFT)
2961 modifiers |= imcontext->shift_mask;
2962 if (ecore_key_ev.modifiers & ECORE_EVENT_MODIFIER_CTRL)
2963 modifiers |= imcontext->control_mask;
2964 if (ecore_key_ev.modifiers & ECORE_EVENT_MODIFIER_ALT)
2965 modifiers |= imcontext->alt_mask;
2966 if (ecore_key_ev.modifiers & ECORE_EVENT_LOCK_CAPS)
2967 modifiers |= imcontext->caps_mask;
2968 if (ecore_key_ev.modifiers & ECORE_EVENT_LOCK_NUM)
2969 modifiers |= imcontext->num_mask;
2971 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);
2972 //Send key event to IME.
2973 wl_text_input_filter_key_event(imcontext->text_input, serial, ecore_key_ev.timestamp, ecore_key_ev.key,
2974 type == ECORE_IMF_EVENT_KEY_UP? WL_KEYBOARD_KEY_STATE_RELEASED : WL_KEYBOARD_KEY_STATE_PRESSED,
2975 modifiers, (key_dev_name ? key_dev_name : ""), key_dev_class, key_dev_subclass);
2976 //Waiting for filter_key_event_done from IME.
2977 //This function should return IME filtering result with boolean type.
2978 struct wl_display *display = ecore_wl_display_get();
2980 while (ecore_time_get() - start_time < WAIT_FOR_FILTER_DONE_SECOND && wl_display_roundtrip(display) != -1) {
2981 if (imcontext->last_key_event_filter.serial == serial) {
2982 ret = imcontext->last_key_event_filter.state;
2984 } else if (imcontext->last_key_event_filter.serial > serial)
2988 LOGD ("elapsed : %.3f ms, serial (last, require) : (%d, %d)", (ecore_time_get() - start_time)*1000, imcontext->last_key_event_filter.serial, serial);
2991 if (type == ECORE_IMF_EVENT_KEY_DOWN) {
2992 if (ret == EINA_FALSE) {
2993 if (strcmp (ecore_key_ev.key, "space") == 0 ||
2994 strcmp (ecore_key_ev.key, "KP_Space") == 0) {
2995 autoperiod_insert (ctx);
3000 //Deal with the next key event in list.
3001 Ecore_Event_Key *ev = NULL;
3002 if (eina_list_count (imcontext->keysym_list)) {
3003 Eina_List *n = eina_list_last(imcontext->keysym_list);
3004 ev = (Ecore_Event_Key *)eina_list_data_get(n);
3005 int type = (unsigned long int)ev->data;
3008 ecore_event_add(type, ev, NULL, NULL);
3009 imcontext->keysym_list = eina_list_remove_list(imcontext->keysym_list, n);
3020 wayland_im_context_cursor_location_set(Ecore_IMF_Context *ctx, int x, int y, int width, int height)
3022 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3023 if (!imcontext) return;
3025 if ((imcontext->cursor_location.x != x) ||
3026 (imcontext->cursor_location.y != y) ||
3027 (imcontext->cursor_location.width != width) ||
3028 (imcontext->cursor_location.height != height)) {
3029 imcontext->cursor_location.x = x;
3030 imcontext->cursor_location.y = y;
3031 imcontext->cursor_location.width = width;
3032 imcontext->cursor_location.height = height;
3034 if (_focused_ctx == ctx)
3035 send_cursor_location (imcontext);
3039 void wayland_im_context_autocapital_type_set(Ecore_IMF_Context *ctx,
3040 Ecore_IMF_Autocapital_Type autocapital_type)
3042 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3043 if (!imcontext) return;
3045 imcontext->content_hint &= ~(WL_TEXT_INPUT_CONTENT_HINT_AUTO_CAPITALIZATION |
3046 // TIZEN_ONLY(20160201): Add autocapitalization word
3047 WL_TEXT_INPUT_CONTENT_HINT_WORD_CAPITALIZATION |
3049 WL_TEXT_INPUT_CONTENT_HINT_UPPERCASE |
3050 WL_TEXT_INPUT_CONTENT_HINT_LOWERCASE);
3052 if (autocapital_type == ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE)
3053 imcontext->content_hint |= WL_TEXT_INPUT_CONTENT_HINT_AUTO_CAPITALIZATION;
3054 // TIZEN_ONLY(20160201): Add autocapitalization word
3055 else if (autocapital_type == ECORE_IMF_AUTOCAPITAL_TYPE_WORD)
3056 imcontext->content_hint |= WL_TEXT_INPUT_CONTENT_HINT_WORD_CAPITALIZATION;
3058 else if (autocapital_type == ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER)
3059 imcontext->content_hint |= WL_TEXT_INPUT_CONTENT_HINT_UPPERCASE;
3061 imcontext->content_hint |= WL_TEXT_INPUT_CONTENT_HINT_LOWERCASE;
3063 if (imcontext->input && imcontext->text_input) {
3064 LOGD ("ctx : %p. set autocapital type : %d\n", ctx, autocapital_type);
3065 wl_text_input_set_content_type(imcontext->text_input,
3066 imcontext->content_hint,
3072 wayland_im_context_input_panel_layout_set(Ecore_IMF_Context *ctx,
3073 Ecore_IMF_Input_Panel_Layout layout)
3075 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3076 if (!imcontext) return;
3078 imcontext->input_panel_layout = layout;
3081 case ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBER:
3082 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER;
3084 case ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL:
3085 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_EMAIL;
3087 case ECORE_IMF_INPUT_PANEL_LAYOUT_URL:
3088 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_URL;
3090 case ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER:
3091 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_PHONE;
3093 case ECORE_IMF_INPUT_PANEL_LAYOUT_IP:
3094 // TIZEN_ONLY(20150710): Support IP and emoticon layout
3095 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_IP;
3098 case ECORE_IMF_INPUT_PANEL_LAYOUT_MONTH:
3099 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_DATE;
3101 case ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY:
3102 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS;
3104 case ECORE_IMF_INPUT_PANEL_LAYOUT_HEX:
3105 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_HEX;
3107 case ECORE_IMF_INPUT_PANEL_LAYOUT_TERMINAL:
3108 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_TERMINAL;
3110 case ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD:
3111 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD;
3112 imcontext->content_hint |= (WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA | WL_TEXT_INPUT_CONTENT_HINT_PASSWORD);
3114 case ECORE_IMF_INPUT_PANEL_LAYOUT_DATETIME:
3115 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_DATETIME;
3117 // TIZEN_ONLY(20150710): Support IP and emoticon layout
3118 case ECORE_IMF_INPUT_PANEL_LAYOUT_EMOTICON:
3119 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_EMOTICON;
3122 case ECORE_IMF_INPUT_PANEL_LAYOUT_VOICE:
3123 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_VOICE;
3126 imcontext->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NORMAL;
3130 if (imcontext->input && imcontext->text_input) {
3131 LOGD ("ctx : %p, layout type : %d\n", ctx, layout);
3132 wl_text_input_set_content_type(imcontext->text_input,
3133 imcontext->content_hint,
3138 Ecore_IMF_Input_Panel_Layout
3139 wayland_im_context_input_panel_layout_get(Ecore_IMF_Context *ctx)
3141 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3142 if (!imcontext) return ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL;
3144 return imcontext->input_panel_layout;
3148 wayland_im_context_input_mode_set(Ecore_IMF_Context *ctx,
3149 Ecore_IMF_Input_Mode input_mode)
3151 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3152 if (!imcontext) return;
3154 if (input_mode & ECORE_IMF_INPUT_MODE_INVISIBLE)
3155 imcontext->content_hint |= (WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA | WL_TEXT_INPUT_CONTENT_HINT_PASSWORD);
3157 imcontext->content_hint &= ~(WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA | WL_TEXT_INPUT_CONTENT_HINT_PASSWORD);
3159 if (imcontext->input && imcontext->text_input) {
3160 LOGD ("ctx : %p, input mode : %d\n", ctx, input_mode);
3161 wl_text_input_set_content_type(imcontext->text_input,
3162 imcontext->content_hint,
3168 wayland_im_context_input_hint_set(Ecore_IMF_Context *ctx,
3169 Ecore_IMF_Input_Hints input_hints)
3171 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3172 if (!imcontext) return;
3174 if (input_hints & ECORE_IMF_INPUT_HINT_AUTO_COMPLETE)
3175 imcontext->content_hint |= WL_TEXT_INPUT_CONTENT_HINT_AUTO_COMPLETION;
3177 imcontext->content_hint &= ~WL_TEXT_INPUT_CONTENT_HINT_AUTO_COMPLETION;
3179 if (input_hints & ECORE_IMF_INPUT_HINT_SENSITIVE_DATA)
3180 imcontext->content_hint |= WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA;
3182 imcontext->content_hint &= ~WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA;
3184 if (input_hints & ECORE_IMF_INPUT_HINT_MULTILINE)
3185 imcontext->content_hint |= WL_TEXT_INPUT_CONTENT_HINT_MULTILINE;
3187 imcontext->content_hint &= ~WL_TEXT_INPUT_CONTENT_HINT_MULTILINE;
3189 if (imcontext->input && imcontext->text_input) {
3190 LOGD("ctx : %p, input hint : %#x\n", ctx, input_hints);
3191 wl_text_input_set_content_type(imcontext->text_input,
3192 imcontext->content_hint,
3198 wayland_im_context_input_panel_language_set(Ecore_IMF_Context *ctx,
3199 Ecore_IMF_Input_Panel_Lang lang)
3201 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3202 if (!imcontext) return;
3204 if (lang == ECORE_IMF_INPUT_PANEL_LANG_ALPHABET)
3205 imcontext->content_hint |= WL_TEXT_INPUT_CONTENT_HINT_LATIN;
3207 imcontext->content_hint &= ~WL_TEXT_INPUT_CONTENT_HINT_LATIN;
3209 if (imcontext->input && imcontext->text_input)
3210 wl_text_input_set_content_type(imcontext->text_input,
3211 imcontext->content_hint,
3215 // TIZEN_ONLY(20150708): Support input_panel_state_get
3216 Ecore_IMF_Input_Panel_State
3217 wayland_im_context_input_panel_state_get(Ecore_IMF_Context *ctx EINA_UNUSED)
3219 return _input_panel_state;
3223 wayland_im_context_input_panel_return_key_type_set(Ecore_IMF_Context *ctx,
3224 Ecore_IMF_Input_Panel_Return_Key_Type return_key_type)
3226 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3227 if (!imcontext) return;
3229 imcontext->return_key_type = return_key_type;
3231 if (imcontext->input && imcontext->text_input)
3232 wl_text_input_set_return_key_type(imcontext->text_input,
3233 imcontext->return_key_type);
3237 wayland_im_context_input_panel_return_key_disabled_set(Ecore_IMF_Context *ctx,
3240 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3241 if (!imcontext) return;
3243 imcontext->return_key_disabled = disabled;
3245 if (imcontext->input && imcontext->text_input)
3246 wl_text_input_set_return_key_disabled(imcontext->text_input,
3247 imcontext->return_key_disabled);
3252 wayland_im_context_input_panel_language_locale_get(Ecore_IMF_Context *ctx,
3255 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3256 if (!imcontext) return;
3259 *locale = strdup(imcontext->language ? imcontext->language : "");
3263 wayland_im_context_prediction_allow_set(Ecore_IMF_Context *ctx,
3264 Eina_Bool prediction)
3266 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3267 if (!imcontext) return;
3270 imcontext->content_hint |= WL_TEXT_INPUT_CONTENT_HINT_AUTO_COMPLETION;
3272 imcontext->content_hint &= ~WL_TEXT_INPUT_CONTENT_HINT_AUTO_COMPLETION;
3274 if (imcontext->input && imcontext->text_input)
3275 wl_text_input_set_content_type(imcontext->text_input,
3276 imcontext->content_hint,
3280 // TIZEN_ONLY(20151221): Support input panel geometry
3282 wayland_im_context_input_panel_geometry_get(Ecore_IMF_Context *ctx EINA_UNUSED,
3283 int *x, int *y, int *w, int *h)
3286 *x = _keyboard_geometry.x;
3288 *y = _keyboard_geometry.y;
3290 *w = _keyboard_geometry.w;
3292 *h = _keyboard_geometry.h;
3296 wayland_im_context_input_panel_imdata_set(Ecore_IMF_Context *ctx, const void *data, int length)
3298 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3299 if (!imcontext) return;
3301 if (data && length > 0) {
3302 const char *custom_conformant_enabled = "conformant:custom,enabled";
3303 const char *custom_conformant_disabled = "conformant:custom,disabled";
3304 const char *custom_conformant_finished = "conformant:custom,finished";
3306 if(strncmp(data, custom_conformant_enabled, strlen(custom_conformant_enabled)) == 0) {
3307 _custom_conformant_event = EINA_TRUE;
3310 if(strncmp(data, custom_conformant_disabled, strlen(custom_conformant_disabled)) == 0) {
3311 _custom_conformant_event = EINA_FALSE;
3314 if(strncmp(data, custom_conformant_finished, strlen(custom_conformant_finished)) == 0) {
3315 if (_custom_conformant_event) {
3316 _conformant_reset_done = EINA_TRUE;
3317 LOGD("[conformant:custom,finished], _conformant_reset_done = 1\n");
3318 send_will_hide_ack(NULL);
3324 if (imcontext->imdata)
3325 free(imcontext->imdata);
3327 imcontext->imdata = calloc(1, length);
3328 memcpy(imcontext->imdata, data, length);
3329 imcontext->imdata_size = length;
3331 if (imcontext->input && imcontext->text_input && (imcontext->imdata_size > 0))
3332 wl_text_input_set_input_panel_data(imcontext->text_input, (const char *)imcontext->imdata, imcontext->imdata_size);
3336 wayland_im_context_input_panel_imdata_get(Ecore_IMF_Context *ctx, void *data, int *length)
3339 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3341 if (imcontext && imcontext->input_panel_data && (imcontext->input_panel_data_length > 0)) {
3343 memcpy(data, imcontext->input_panel_data, imcontext->input_panel_data_length);
3346 *length = imcontext->input_panel_data_length;
3354 // TIZEN_ONLY(20160218): Support BiDi direction
3356 wayland_im_context_bidi_direction_set(Ecore_IMF_Context *ctx, Ecore_IMF_BiDi_Direction bidi_direction)
3358 WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
3359 if (!imcontext) return;
3361 imcontext->bidi_direction = bidi_direction;
3363 if (imcontext->input && imcontext->text_input) {
3364 LOGD ("ctx : %p, bidi direction : %#x\n", ctx, bidi_direction);
3365 wl_text_input_bidi_direction(imcontext->text_input, imcontext->bidi_direction);
3370 WaylandIMContext *wayland_im_context_new (struct wl_text_input_manager *text_input_manager)
3372 WaylandIMContext *context = calloc(1, sizeof(WaylandIMContext));
3374 LOGD("new context created");
3375 context->text_input_manager = text_input_manager;