2 * ISF(Input Service Framework)
4 * ISF is based on SCIM 1.4.7 and extended for supporting more mobile fitable.
5 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
7 * Contact: Jihoon Kim <jihoon48.kim@samsung.com>, Haifeng Deng <haifeng.deng@samsung.com>
9 * This library is free software; you can redistribute it and/or modify it under
10 * the terms of the GNU Lesser General Public License as published by the
11 * Free Software Foundation; either version 2.1 of the License, or (at your option)
14 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17 * License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software Foundation, Inc., 51
21 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #define Uses_SCIM_TRANSACTION
28 /* IM control UI part */
30 #include <Ecore_Evas.h>
31 #include <Ecore_IMF.h>
34 #include "isf_imf_control_ui.h"
35 #include "isf_imf_context.h"
36 #include "isf_imf_control.h"
37 #include "ise_context.h"
41 #define IMFCONTROLUIDBG(str...)
42 #define IMFCONTROLUIERR(str...) printf(str)
46 void (*func)(void *data, Ecore_IMF_Context *ctx, int value);
48 Ecore_IMF_Input_Panel_Event type;
49 Ecore_IMF_Context *imf_context;
53 /* IM control related variables */
54 static Ise_Context iseContext;
55 static bool IfInitContext = false;
56 static Eina_List *EventCallbackList = NULL;
57 static Ecore_IMF_Context *show_req_ic = NULL;
58 static Ecore_IMF_Context *hide_req_ic = NULL;
59 static Ecore_Event_Handler *_prop_change_handler = NULL;
60 static Ecore_X_Atom prop_x_ext_keyboard_exist = 0;
61 static Ecore_X_Window _rootwin;
62 static unsigned int hw_kbd_num = 0;
63 static Ecore_Timer *hide_timer = NULL;
65 Ecore_IMF_Context *input_panel_ctx = NULL;
68 static Eina_Bool _prop_change (void *data, int ev_type, void *ev)
70 Ecore_X_Event_Window_Property *event = (Ecore_X_Event_Window_Property *)ev;
73 if (event->win != _rootwin) return ECORE_CALLBACK_PASS_ON;
74 if (event->atom != prop_x_ext_keyboard_exist) return ECORE_CALLBACK_PASS_ON;
76 if (!ecore_x_window_prop_card32_get (event->win, prop_x_ext_keyboard_exist, &val, 1) > 0)
77 return ECORE_CALLBACK_PASS_ON;
81 isf_imf_context_input_panel_hide (show_req_ic);
86 return ECORE_CALLBACK_PASS_ON;
89 static void _save_current_xid (Evas *evas)
91 Ecore_X_Window xid = 0, rootwin_xid = 0;
92 Ecore_Evas *ee = NULL;
95 ee = ecore_evas_ecore_evas_get (evas);
97 xid = (Ecore_X_Window)ecore_evas_window_get (ee);
101 rootwin_xid = ecore_x_window_root_first_get ();
103 rootwin_xid = ecore_x_window_root_get (xid);
105 Ecore_X_Atom isf_active_window_atom = ecore_x_atom_get ("_ISF_ACTIVE_WINDOW");
106 ecore_x_window_prop_property_set (rootwin_xid, isf_active_window_atom, ((Ecore_X_Atom) 33), 32, &xid, 1);
111 static Ecore_IMF_Input_Panel_Orient _orient_get (Evas *evas)
113 Ecore_Evas *ee = NULL;
115 Ecore_IMF_Input_Panel_Orient orient;
118 return ECORE_IMF_INPUT_PANEL_ORIENT_NONE;
119 ee = ecore_evas_ecore_evas_get (evas);
121 return ECORE_IMF_INPUT_PANEL_ORIENT_NONE;
123 degree = ecore_evas_rotation_get (ee);
125 orient = (Ecore_IMF_Input_Panel_Orient)(degree % 360 / 90);
130 static void _event_callback_call (Ecore_IMF_Input_Panel_Event type, int value)
132 void *list_data = NULL;
133 EventCallbackNode *fn = NULL;
135 Ecore_IMF_Context *using_ic = show_req_ic;
137 if (type == ECORE_IMF_INPUT_PANEL_STATE_EVENT &&
138 value == ECORE_IMF_INPUT_PANEL_STATE_HIDE) {
140 using_ic = hide_req_ic;
145 EINA_LIST_FOREACH(EventCallbackList, l, list_data) {
146 fn = (EventCallbackNode *)list_data;
148 if ((fn) && (fn->imf_context == using_ic) &&
149 (fn->type == type) && (fn->func))
150 fn->func (fn->data, fn->imf_context, value);
152 IMFCONTROLUIDBG("\tFunc : %p\tType : %d\n", fn->func, fn->type);
156 static void _isf_imf_context_init (void)
158 IMFCONTROLUIDBG("debug start --%s\n", __FUNCTION__);
159 memset (iseContext.name, '\0', sizeof (iseContext.name));
160 iseContext.IfAlwaysShow = FALSE;
161 iseContext.IfFullStyle = FALSE;
162 iseContext.state = ECORE_IMF_INPUT_PANEL_STATE_HIDE;
163 iseContext.language = ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC;
164 iseContext.orient = ECORE_IMF_INPUT_PANEL_ORIENT_NONE;
165 iseContext.fUseImEffect = TRUE;
167 if (!IfInitContext) {
168 IfInitContext = true;
171 IMFCONTROLUIDBG("debug end\n");
174 static Eina_Bool _hide_timer_handler (void *data)
176 LOGD("input panel hide. ctx : %p\n", data);
177 _isf_imf_context_input_panel_hide ();
180 return ECORE_CALLBACK_CANCEL;
183 static void _input_panel_hide_timer_start(void *data)
186 hide_timer = ecore_timer_add (0.05, _hide_timer_handler, data);
189 static void _input_panel_hide (Ecore_IMF_Context *ctx, Eina_Bool instant)
191 IMFCONTROLUIDBG("[%s]\n", __func__);
193 if (IfInitContext == false) {
194 _isf_imf_context_init ();
197 if (iseContext.state == ECORE_IMF_INPUT_PANEL_STATE_SHOW) {
201 iseContext.IfAlwaysShow = FALSE;
205 ecore_timer_del (hide_timer);
209 LOGD("input panel hide. ctx : %p\n", ctx);
210 _isf_imf_context_input_panel_hide ();
212 _input_panel_hide_timer_start (ctx);
216 EAPI void isf_imf_context_control_panel_show (Ecore_IMF_Context *ctx)
218 IMFCONTROLUIDBG("[%s]\n", __FUNCTION__);
220 if (IfInitContext == false) {
221 _isf_imf_context_init ();
223 _isf_imf_context_control_panel_show ();
226 EAPI void isf_imf_context_control_panel_hide (Ecore_IMF_Context *ctx)
228 IMFCONTROLUIDBG("[%s]\n", __FUNCTION__);
230 if (IfInitContext == false) {
231 _isf_imf_context_init ();
233 _isf_imf_context_control_panel_hide ();
236 EAPI void isf_imf_input_panel_init (void)
238 IMFCONTROLUIDBG("[%s]\n", __FUNCTION__);
240 if (_prop_change_handler) return;
242 _rootwin = ecore_x_window_root_first_get ();
243 ecore_x_event_mask_set (_rootwin, ECORE_X_EVENT_MASK_WINDOW_PROPERTY);
245 _prop_change_handler = ecore_event_handler_add (ECORE_X_EVENT_WINDOW_PROPERTY, _prop_change, NULL);
247 if (!prop_x_ext_keyboard_exist)
248 prop_x_ext_keyboard_exist = ecore_x_atom_get (PROP_X_EXT_KEYBOARD_EXIST);
250 if (!ecore_x_window_prop_card32_get (_rootwin, prop_x_ext_keyboard_exist, &hw_kbd_num, 1)) {
251 printf ("Error! cannot get hw_kbd_num\n");
256 EAPI void isf_imf_input_panel_shutdown (void)
258 IMFCONTROLUIDBG("[%s]\n", __FUNCTION__);
260 if (_prop_change_handler) {
261 ecore_event_handler_del (_prop_change_handler);
262 _prop_change_handler = NULL;
266 ecore_timer_del (hide_timer);
271 EAPI void isf_imf_context_input_panel_show (Ecore_IMF_Context* ctx)
275 Disable_Key_Item *dkey_item = NULL;
276 Private_Key_Item *pkey_item = NULL;
277 Eina_List *disable_key_list = NULL;
278 Eina_List *private_key_list = NULL;
280 void *list_data = NULL;
285 input_panel_ctx = ctx;
287 IMFCONTROLUIDBG("debug start --%s\n", __FUNCTION__);
289 if (hw_kbd_num != 0) {
290 printf ("H/W keyboard is existed.\n");
295 ecore_timer_del(hide_timer);
299 if (IfInitContext == false) {
300 _isf_imf_context_init ();
305 /* get input language */
306 iseContext.language = ecore_imf_context_input_panel_language_get (ctx);
307 IMFCONTROLUIDBG("[%s] language : %d\n", __func__, iseContext.language);
310 iseContext.layout = ecore_imf_context_input_panel_layout_get (ctx);
311 IMFCONTROLUIDBG("[%s] layout : %d\n", __func__, iseContext.layout);
314 iseContext.language = ecore_imf_context_input_panel_language_get (ctx);
315 IMFCONTROLUIDBG("[%s] language : %d\n", __func__, iseContext.language);
317 /* get disable key list */
318 disable_key_list = ecore_imf_context_input_panel_key_disabled_list_get (ctx);
319 iseContext.disabled_key_num = eina_list_count (disable_key_list);
320 IMFCONTROLUIDBG("disable key_num : %d\n", iseContext.disabled_key_num);
322 /* get private key list */
323 private_key_list = ecore_imf_context_input_panel_private_key_list_get (ctx);
324 iseContext.private_key_num = eina_list_count (private_key_list);
325 IMFCONTROLUIDBG("private key_num : %d\n", iseContext.private_key_num);
327 evas = (Evas *)ecore_imf_context_client_canvas_get (ctx);
330 iseContext.orient = _orient_get (evas);
333 /* calculate packet size */
334 length = sizeof (iseContext);
335 length += iseContext.disabled_key_num * sizeof (Disable_Key_Item);
336 length += iseContext.private_key_num * sizeof (Private_Key_Item);
339 packet = calloc (1, length);
343 memcpy (packet, (void *)&iseContext, sizeof (iseContext));
346 offset = (void *)((unsigned int)packet + sizeof (iseContext));
347 EINA_LIST_FOREACH(disable_key_list, l, list_data) {
348 dkey_item = (Disable_Key_Item *)list_data;
350 memcpy ((void *)((unsigned int)offset+i*sizeof(Disable_Key_Item)), dkey_item, sizeof (Disable_Key_Item));
351 IMFCONTROLUIDBG("[Disable Key] layout : %d, key : %d, disable : %d\n", dkey_item->layout_idx, dkey_item->key_idx, dkey_item->disabled);
355 offset = (void *)((unsigned int)offset + iseContext.disabled_key_num * sizeof (Disable_Key_Item));
358 EINA_LIST_FOREACH(private_key_list, l, list_data) {
359 pkey_item = (Private_Key_Item *)list_data;
360 memcpy ((void *)((unsigned int)offset + i * sizeof (Private_Key_Item)), pkey_item, sizeof (Private_Key_Item));
361 IMFCONTROLUIDBG("[Private Key] layout : %d, key : %d, label : %s, key_value : %d, key_str : %s\n", pkey_item->layout_idx, pkey_item->key_idx, pkey_item->data, pkey_item->key_value, pkey_item->key_string);
365 /* Set the current XID of the active window into the root window property */
366 _save_current_xid (evas);
368 iseContext.state = ECORE_IMF_INPUT_PANEL_STATE_SHOW;
370 LOGD("input panel show. ctx : %p\n", ctx);
372 _isf_imf_context_input_panel_show (packet ,length);
375 send_caps_mode (ctx);
378 EAPI void isf_imf_context_input_panel_hide (Ecore_IMF_Context *ctx)
380 IMFCONTROLUIDBG("[%s]\n", __func__);
382 _input_panel_hide (ctx, EINA_FALSE);
385 EAPI void isf_imf_context_input_panel_instant_hide (Ecore_IMF_Context *ctx)
387 IMFCONTROLUIDBG("[%s]\n", __func__);
389 _input_panel_hide (ctx, EINA_TRUE);
392 EAPI void isf_imf_context_input_panel_language_set (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Lang language)
394 IMFCONTROLUIDBG("[%s] language : %d\n", __func__, language);
396 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get (ctx);
399 _isf_imf_context_init ();
400 iseContext.language = language;
402 if (context_scim == get_focused_ic ())
403 _isf_imf_context_input_panel_language_set (language);
406 EAPI Ecore_IMF_Input_Panel_Lang isf_imf_context_input_panel_language_get (Ecore_IMF_Context *ctx)
408 IMFCONTROLUIDBG("[%s] language : %d\n", __func__, iseContext.language);
409 if (!IfInitContext) _isf_imf_context_init();
410 return iseContext.language;
413 EAPI void isf_imf_context_input_panel_caps_mode_set (Ecore_IMF_Context *ctx, unsigned int mode)
415 IMFCONTROLUIDBG("[%s] shift mode : %d\n", __func__, mode);
418 _isf_imf_context_init ();
419 _isf_imf_context_input_panel_caps_mode_set (mode);
423 * Set up an ISE specific data
425 * @param[in] ctx a #Ecore_IMF_Context
426 * @param[in] data pointer of data to sets up to ISE
427 * @param[in] length length of data
429 EAPI void isf_imf_context_input_panel_imdata_set (Ecore_IMF_Context *ctx, const char* data, int length)
431 IMFCONTROLUIDBG("[%s] data : %s, len : %d\n", __func__, data, length);
436 _isf_imf_context_init ();
437 _isf_imf_context_input_panel_imdata_set (data, length);
441 * Get the ISE specific data from ISE
443 * @param[in] ctx a #Ecore_IMF_Context
444 * @param[out] data pointer of data to return
445 * @param[out] length length of data
447 EAPI void isf_imf_context_input_panel_imdata_get (Ecore_IMF_Context *ctx, char* data, int* length)
450 _isf_imf_context_init ();
451 _isf_imf_context_input_panel_imdata_get (data, length);
452 IMFCONTROLUIDBG("[%s] imdata : %s, len : %d\n", __func__, data, *length);
455 EAPI void isf_imf_context_input_panel_move (Ecore_IMF_Context *ctx, int x, int y)
457 IMFCONTROLUIDBG("[%s] x : %d, y : %d\n", __func__, x, y);
460 _isf_imf_context_init ();
461 iseContext.input_panel_x = x;
462 iseContext.input_panel_x = y;
466 * Get ISE's position and size, in screen coodinates of the ISE rectangle not the client area,
467 * the represents the size and location of the ISE
469 * @param[in] ctx a #Ecore_IMF_Context
470 * @param[out] x the x position of ISE window
471 * @param[out] y the y position of ISE window
472 * @param[out] w the width of ISE window
473 * @param[out] h the height of ISE window
475 EAPI void isf_imf_context_input_panel_geometry_get (Ecore_IMF_Context *ctx, int *x, int *y, int *w, int *h)
478 _isf_imf_context_init ();
479 _isf_imf_context_input_panel_geometry_get (x, y, w, h);
481 IMFCONTROLUIDBG("[%s] x : %d, y : %d, w : %d, h : %d\n", __func__, *x, *y, *w, *h);
485 * Sets up a private key in active ISE keyboard layout for own's application.
486 * In some case which does not support the private key will be ignored even
487 * through the application requested.
489 * @param[in] ctx a #Ecore_IMF_Context
490 * @param[in] layout_idx an index of layout page to be set
491 * @param[in] key_idx an index of key to be set
492 * @param[in] img_path the image file to be set
493 * @param[in] label a text label to be displayed on private key
494 * @param[in] value a value of key. If null, it will use original value of key
496 EAPI void isf_imf_context_input_panel_private_key_set (Ecore_IMF_Context *ctx,
499 const char *img_path,
503 IMFCONTROLUIDBG("[%s] layout : %d, key_index : %d, img_path : %s, label : %s, value : %s\n", __func__, layout_index, key_index, img_path, label, value);
505 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get (ctx);
508 _isf_imf_context_init ();
510 if (context_scim != get_focused_ic ())
514 _isf_imf_context_input_panel_private_key_set_by_image (layout_index, key_index, img_path, value);
516 _isf_imf_context_input_panel_private_key_set (layout_index, key_index, label, value);
521 * Make a key to be disabled in active ISE keyboard layout for own's application.
522 * In some case which does not support the disable key will be ignored
523 * even through the application requested.
525 * @param[in] ctx a #Ecore_IMF_Context
526 * @param[in] layout_idx an index of layout page to be set
527 * @param[in] key_idx an index of key to be set
528 * @param[in] disabled the state
530 EAPI void isf_imf_context_input_panel_key_disabled_set (Ecore_IMF_Context *ctx, int layout_index, int key_index, Eina_Bool disabled)
532 IMFCONTROLUIDBG("[%s] layout : %d, key_index : %d, value : %d\n", __func__, layout_index, key_index, disabled);
534 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get (ctx);
537 _isf_imf_context_init ();
539 if (context_scim == get_focused_ic())
540 _isf_imf_context_input_panel_key_disabled_set (layout_index, key_index, disabled);
544 * Sets up the layout infomation of active ISE
546 * @param[in] ctx a #Ecore_IMF_Context
547 * @param[in] layout sets a layout ID to be shown. The layout ID will define by the configuration of selected ISE.
550 isf_imf_context_input_panel_layout_set (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Layout layout)
552 IMFCONTROLUIDBG("[%s] layout : %d\n", __func__, layout);
554 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get (ctx);
557 _isf_imf_context_init ();
559 if (context_scim == get_focused_ic ())
560 _isf_imf_context_input_panel_layout_set (layout);
564 * Get current ISE layout
566 * @param[in] ctx a #Ecore_IMF_Context
568 * @return the layout of current ISE.
570 EAPI Ecore_IMF_Input_Panel_Layout isf_imf_context_input_panel_layout_get (Ecore_IMF_Context *ctx)
572 Ecore_IMF_Input_Panel_Layout layout;
574 _isf_imf_context_init ();
575 _isf_imf_context_input_panel_layout_get (&layout);
577 IMFCONTROLUIDBG("[%s] layout : %d\n", __func__, layout);
583 * Get current ISE state
585 * @param[in] ctx a #Ecore_IMF_Context
587 * @return the state of current ISE.
589 EAPI Ecore_IMF_Input_Panel_State isf_imf_context_input_panel_state_get (Ecore_IMF_Context *ctx)
591 IMFCONTROLUIDBG("[%s] state : %d\n", __func__, iseContext.state);
594 _isf_imf_context_init ();
595 return iseContext.state;
598 EAPI void isf_imf_context_input_panel_event_callback_add (Ecore_IMF_Context *ctx,
599 Ecore_IMF_Input_Panel_Event type,
600 void (*func) (void *data, Ecore_IMF_Context *ctx, int value),
603 EventCallbackNode *fn = NULL;
605 fn = (EventCallbackNode *)calloc (1, sizeof (EventCallbackNode));
609 IMFCONTROLUIDBG("[%s]\n", __func__);
614 fn->imf_context = ctx;
616 EventCallbackList = eina_list_append (EventCallbackList, fn);
619 EAPI void isf_imf_context_input_panel_event_callback_del (Ecore_IMF_Context *ctx,
620 Ecore_IMF_Input_Panel_Event type,
621 void (*func) (void *data, Ecore_IMF_Context *ctx, int value))
624 EventCallbackNode *fn = NULL;
626 IMFCONTROLUIDBG("[%s]\n", __func__);
628 for (l = EventCallbackList; l;) {
629 fn = (EventCallbackNode *)l->data;
631 if ((fn) && (fn->func == func) && (fn->type == type)) {
632 EventCallbackList = eina_list_remove (EventCallbackList, fn);
640 EAPI void isf_imf_context_input_panel_event_callback_clear (Ecore_IMF_Context *ctx)
643 EventCallbackNode *fn;
645 IMFCONTROLUIDBG("[%s]\n", __func__);
647 for (l = EventCallbackList; l;) {
648 fn = (EventCallbackNode *)l->data;
650 if ((fn) && (fn->imf_context == ctx)) {
651 EventCallbackList = eina_list_remove (EventCallbackList, fn);
659 * process command message, ISM_TRANS_CMD_ISE_PANEL_SHOWED of ecore_ise_process_event()
661 static bool _process_ise_panel_showed (void)
663 /* When the size of ISE gets changed, STATE_SHOW is be delivered again to letting applications know the change.
664 Later, an event type for notifying the size change of ISE needs to be added instead. */
665 iseContext.state = ECORE_IMF_INPUT_PANEL_STATE_SHOW;
667 /* Notify that ISE status has changed */
668 _event_callback_call (ECORE_IMF_INPUT_PANEL_STATE_EVENT, ECORE_IMF_INPUT_PANEL_STATE_SHOW);
674 * process command message, ISM_TRANS_CMD_ISE_PANEL_HIDED of ecore_ise_process_event()
676 static bool _process_ise_panel_hided (void)
678 if (iseContext.state == ECORE_IMF_INPUT_PANEL_STATE_HIDE) {
679 IMFCONTROLUIDBG("ISE is already hided (_process_ise_panel_hided)\n");
683 iseContext.state = ECORE_IMF_INPUT_PANEL_STATE_HIDE;
685 /* Notify that ISE status has changed */
686 _event_callback_call (ECORE_IMF_INPUT_PANEL_STATE_EVENT, ECORE_IMF_INPUT_PANEL_STATE_HIDE);
692 * process command message, ISM_TRANS_CMD_UPDATE_ISE_INPUT_CONTEXT of gtk_ise_process_event()
694 static bool _process_update_input_context (Transaction &trans)
699 if (!(trans.get_data (type) && trans.get_data (value)))
702 IMFCONTROLUIDBG("[%s] receive input context: [%d:%d]\n", __FUNCTION__, type, value);
704 if (type == (uint32)ECORE_IMF_INPUT_PANEL_STATE_EVENT && value == (uint32)ECORE_IMF_INPUT_PANEL_STATE_HIDE) {
705 _process_ise_panel_hided ();
709 if (type == (uint32)ECORE_IMF_INPUT_PANEL_STATE_EVENT && value == (uint32)ECORE_IMF_INPUT_PANEL_STATE_SHOW) {
710 _process_ise_panel_showed ();
714 _event_callback_call ((Ecore_IMF_Input_Panel_Event)type, (int)value);
720 * process ISE data of command message with ISF
722 * @param[in] trans packet data to be processed
723 * @param[in] cmd command ID that defines with ISF
725 void ecore_ise_process_data (Transaction &trans, int cmd)
728 case ISM_TRANS_CMD_ISE_PANEL_SHOWED : {
729 IMFCONTROLUIDBG ("cmd is ISM_TRANS_CMD_ISE_PANEL_SHOWED\n");
730 _process_ise_panel_showed ();
733 case ISM_TRANS_CMD_ISE_PANEL_HIDED : {
734 IMFCONTROLUIDBG ("cmd is ISM_TRANS_CMD_ISE_PANEL_HIDED\n");
735 _process_ise_panel_hided ();
738 case ISM_TRANS_CMD_UPDATE_ISE_INPUT_CONTEXT : {
739 IMFCONTROLUIDBG ("cmd is ISM_TRANS_CMD_UPDATE_ISE_INPUT_CONTEXT\n");
740 _process_update_input_context (trans);
744 IMFCONTROLUIDBG("unknown command");