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;
67 static Eina_Bool _prop_change (void *data, int ev_type, void *ev)
69 Ecore_X_Event_Window_Property *event = (Ecore_X_Event_Window_Property *)ev;
72 if (event->win != _rootwin) return ECORE_CALLBACK_PASS_ON;
73 if (event->atom != prop_x_ext_keyboard_exist) return ECORE_CALLBACK_PASS_ON;
75 if (!ecore_x_window_prop_card32_get (event->win, prop_x_ext_keyboard_exist, &val, 1) > 0)
76 return ECORE_CALLBACK_PASS_ON;
80 isf_imf_context_input_panel_hide (show_req_ic);
85 return ECORE_CALLBACK_PASS_ON;
88 static void _save_current_xid (Ecore_IMF_Context *ctx)
90 Ecore_X_Window xid = 0, rootwin_xid = 0;
91 Ecore_Evas *ee = NULL;
94 evas = (Evas *)ecore_imf_context_client_canvas_get(ctx);
97 ee = ecore_evas_ecore_evas_get (evas);
99 xid = (Ecore_X_Window)ecore_evas_window_get (ee);
101 xid = (Ecore_X_Window)ecore_imf_context_client_window_get (ctx);
105 rootwin_xid = ecore_x_window_root_first_get ();
107 rootwin_xid = ecore_x_window_root_get (xid);
109 Ecore_X_Atom isf_active_window_atom = ecore_x_atom_get ("_ISF_ACTIVE_WINDOW");
110 ecore_x_window_prop_property_set (rootwin_xid, isf_active_window_atom, ((Ecore_X_Atom) 33), 32, &xid, 1);
115 static void _event_callback_call (Ecore_IMF_Input_Panel_Event type, int value)
117 void *list_data = NULL;
118 EventCallbackNode *fn = NULL;
120 Ecore_IMF_Context *using_ic = show_req_ic;
122 if (type == ECORE_IMF_INPUT_PANEL_STATE_EVENT &&
123 value == ECORE_IMF_INPUT_PANEL_STATE_HIDE) {
125 using_ic = hide_req_ic;
130 EINA_LIST_FOREACH(EventCallbackList, l, list_data) {
131 fn = (EventCallbackNode *)list_data;
133 if ((fn) && (fn->imf_context == using_ic) &&
134 (fn->type == type) && (fn->func))
135 fn->func (fn->data, fn->imf_context, value);
137 IMFCONTROLUIDBG("\tFunc : %p\tType : %d\n", fn->func, fn->type);
141 static void _isf_imf_context_init (void)
143 IMFCONTROLUIDBG("debug start --%s\n", __FUNCTION__);
144 memset (iseContext.name, '\0', sizeof (iseContext.name));
145 iseContext.IfAlwaysShow = FALSE;
146 iseContext.IfFullStyle = FALSE;
147 iseContext.state = ECORE_IMF_INPUT_PANEL_STATE_HIDE;
148 iseContext.language = ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC;
149 iseContext.orient = 0;
150 iseContext.fUseImEffect = TRUE;
152 if (!IfInitContext) {
153 IfInitContext = true;
156 IMFCONTROLUIDBG("debug end\n");
159 static Eina_Bool _hide_timer_handler (void *data)
161 LOGD("input panel hide. ctx : %p\n", data);
162 _isf_imf_context_input_panel_hide ();
165 return ECORE_CALLBACK_CANCEL;
168 static void _input_panel_hide_timer_start(void *data)
171 hide_timer = ecore_timer_add (0.05, _hide_timer_handler, data);
174 static void _input_panel_hide (Ecore_IMF_Context *ctx, Eina_Bool instant)
176 IMFCONTROLUIDBG("[%s]\n", __func__);
178 if (IfInitContext == false) {
179 _isf_imf_context_init ();
182 if (iseContext.state == ECORE_IMF_INPUT_PANEL_STATE_SHOW) {
186 iseContext.IfAlwaysShow = FALSE;
190 ecore_timer_del (hide_timer);
194 LOGD("input panel hide. ctx : %p\n", ctx);
195 _isf_imf_context_input_panel_hide ();
197 _input_panel_hide_timer_start (ctx);
201 EAPI void isf_imf_context_control_panel_show (Ecore_IMF_Context *ctx)
203 IMFCONTROLUIDBG("[%s]\n", __FUNCTION__);
205 if (IfInitContext == false) {
206 _isf_imf_context_init ();
208 _isf_imf_context_control_panel_show ();
211 EAPI void isf_imf_context_control_panel_hide (Ecore_IMF_Context *ctx)
213 IMFCONTROLUIDBG("[%s]\n", __FUNCTION__);
215 if (IfInitContext == false) {
216 _isf_imf_context_init ();
218 _isf_imf_context_control_panel_hide ();
221 EAPI void isf_imf_input_panel_init (void)
223 IMFCONTROLUIDBG("[%s]\n", __FUNCTION__);
225 if (_prop_change_handler) return;
227 _rootwin = ecore_x_window_root_first_get ();
228 ecore_x_event_mask_set (_rootwin, ECORE_X_EVENT_MASK_WINDOW_PROPERTY);
230 _prop_change_handler = ecore_event_handler_add (ECORE_X_EVENT_WINDOW_PROPERTY, _prop_change, NULL);
232 if (!prop_x_ext_keyboard_exist)
233 prop_x_ext_keyboard_exist = ecore_x_atom_get (PROP_X_EXT_KEYBOARD_EXIST);
235 if (!ecore_x_window_prop_card32_get (_rootwin, prop_x_ext_keyboard_exist, &hw_kbd_num, 1)) {
236 printf ("Error! cannot get hw_kbd_num\n");
241 EAPI void isf_imf_input_panel_shutdown (void)
243 IMFCONTROLUIDBG("[%s]\n", __FUNCTION__);
245 if (_prop_change_handler) {
246 ecore_event_handler_del (_prop_change_handler);
247 _prop_change_handler = NULL;
251 ecore_timer_del (hide_timer);
256 EAPI void isf_imf_context_input_panel_show (Ecore_IMF_Context* ctx)
260 Disable_Key_Item *dkey_item = NULL;
261 Private_Key_Item *pkey_item = NULL;
262 Eina_List *disable_key_list = NULL;
263 Eina_List *private_key_list = NULL;
265 void *list_data = NULL;
269 input_panel_ctx = ctx;
271 IMFCONTROLUIDBG("debug start --%s\n", __FUNCTION__);
273 if (hw_kbd_num != 0) {
274 printf ("H/W keyboard is existed.\n");
279 ecore_timer_del(hide_timer);
283 if (IfInitContext == false) {
284 _isf_imf_context_init ();
289 /* get input language */
290 iseContext.language = ecore_imf_context_input_panel_language_get (ctx);
291 IMFCONTROLUIDBG("[%s] language : %d\n", __func__, iseContext.language);
294 iseContext.layout = ecore_imf_context_input_panel_layout_get (ctx);
295 IMFCONTROLUIDBG("[%s] layout : %d\n", __func__, iseContext.layout);
298 iseContext.language = ecore_imf_context_input_panel_language_get (ctx);
299 IMFCONTROLUIDBG("[%s] language : %d\n", __func__, iseContext.language);
301 /* get disable key list */
302 disable_key_list = ecore_imf_context_input_panel_key_disabled_list_get (ctx);
303 iseContext.disabled_key_num = eina_list_count (disable_key_list);
304 IMFCONTROLUIDBG("disable key_num : %d\n", iseContext.disabled_key_num);
306 /* get private key list */
307 private_key_list = ecore_imf_context_input_panel_private_key_list_get (ctx);
308 iseContext.private_key_num = eina_list_count (private_key_list);
309 IMFCONTROLUIDBG("private key_num : %d\n", iseContext.private_key_num);
311 /* calculate packet size */
312 length = sizeof (iseContext);
313 length += iseContext.disabled_key_num * sizeof (Disable_Key_Item);
314 length += iseContext.private_key_num * sizeof (Private_Key_Item);
317 packet = calloc (1, length);
321 memcpy (packet, (void *)&iseContext, sizeof (iseContext));
324 offset = (void *)((unsigned int)packet + sizeof (iseContext));
325 EINA_LIST_FOREACH(disable_key_list, l, list_data) {
326 dkey_item = (Disable_Key_Item *)list_data;
328 memcpy ((void *)((unsigned int)offset+i*sizeof(Disable_Key_Item)), dkey_item, sizeof (Disable_Key_Item));
329 IMFCONTROLUIDBG("[Disable Key] layout : %d, key : %d, disable : %d\n", dkey_item->layout_idx, dkey_item->key_idx, dkey_item->disabled);
333 offset = (void *)((unsigned int)offset + iseContext.disabled_key_num * sizeof (Disable_Key_Item));
336 EINA_LIST_FOREACH(private_key_list, l, list_data) {
337 pkey_item = (Private_Key_Item *)list_data;
338 memcpy ((void *)((unsigned int)offset + i * sizeof (Private_Key_Item)), pkey_item, sizeof (Private_Key_Item));
339 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);
343 /* Set the current XID of the active window into the root window property */
344 _save_current_xid (ctx);
346 iseContext.state = ECORE_IMF_INPUT_PANEL_STATE_SHOW;
348 LOGD("input panel show. ctx : %p\n", ctx);
350 _isf_imf_context_input_panel_show (packet ,length);
353 send_caps_mode (ctx);
356 EAPI void isf_imf_context_input_panel_hide (Ecore_IMF_Context *ctx)
358 IMFCONTROLUIDBG("[%s]\n", __func__);
360 _input_panel_hide (ctx, EINA_FALSE);
363 EAPI void isf_imf_context_input_panel_instant_hide (Ecore_IMF_Context *ctx)
365 IMFCONTROLUIDBG("[%s]\n", __func__);
367 _input_panel_hide (ctx, EINA_TRUE);
370 EAPI void isf_imf_context_input_panel_language_set (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Lang language)
372 IMFCONTROLUIDBG("[%s] language : %d\n", __func__, language);
374 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get (ctx);
377 _isf_imf_context_init ();
378 iseContext.language = language;
380 if (context_scim == get_focused_ic ())
381 _isf_imf_context_input_panel_language_set (language);
384 EAPI Ecore_IMF_Input_Panel_Lang isf_imf_context_input_panel_language_get (Ecore_IMF_Context *ctx)
386 IMFCONTROLUIDBG("[%s] language : %d\n", __func__, iseContext.language);
387 if (!IfInitContext) _isf_imf_context_init();
388 return iseContext.language;
391 EAPI void isf_imf_context_input_panel_caps_mode_set (Ecore_IMF_Context *ctx, unsigned int mode)
393 IMFCONTROLUIDBG("[%s] shift mode : %d\n", __func__, mode);
396 _isf_imf_context_init ();
397 _isf_imf_context_input_panel_caps_mode_set (mode);
401 * Set up an ISE specific data
403 * @param[in] ctx a #Ecore_IMF_Context
404 * @param[in] data pointer of data to sets up to ISE
405 * @param[in] length length of data
407 EAPI void isf_imf_context_input_panel_imdata_set (Ecore_IMF_Context *ctx, const char* data, int length)
409 IMFCONTROLUIDBG("[%s] data : %s, len : %d\n", __func__, data, length);
414 _isf_imf_context_init ();
415 _isf_imf_context_input_panel_imdata_set (data, length);
419 * Get the ISE specific data from ISE
421 * @param[in] ctx a #Ecore_IMF_Context
422 * @param[out] data pointer of data to return
423 * @param[out] length length of data
425 EAPI void isf_imf_context_input_panel_imdata_get (Ecore_IMF_Context *ctx, char* data, int* length)
428 _isf_imf_context_init ();
429 _isf_imf_context_input_panel_imdata_get (data, length);
430 IMFCONTROLUIDBG("[%s] imdata : %s, len : %d\n", __func__, data, *length);
433 EAPI void isf_imf_context_input_panel_move (Ecore_IMF_Context *ctx, int x, int y)
435 IMFCONTROLUIDBG("[%s] x : %d, y : %d\n", __func__, x, y);
438 _isf_imf_context_init ();
439 iseContext.input_panel_x = x;
440 iseContext.input_panel_x = y;
444 * Get ISE's position and size, in screen coodinates of the ISE rectangle not the client area,
445 * the represents the size and location of the ISE
447 * @param[in] ctx a #Ecore_IMF_Context
448 * @param[out] x the x position of ISE window
449 * @param[out] y the y position of ISE window
450 * @param[out] w the width of ISE window
451 * @param[out] h the height of ISE window
453 EAPI void isf_imf_context_input_panel_geometry_get (Ecore_IMF_Context *ctx, int *x, int *y, int *w, int *h)
456 _isf_imf_context_init ();
457 _isf_imf_context_input_panel_geometry_get (x, y, w, h);
459 IMFCONTROLUIDBG("[%s] x : %d, y : %d, w : %d, h : %d\n", __func__, *x, *y, *w, *h);
463 * Sets up a private key in active ISE keyboard layout for own's application.
464 * In some case which does not support the private key will be ignored even
465 * through the application requested.
467 * @param[in] ctx a #Ecore_IMF_Context
468 * @param[in] layout_idx an index of layout page to be set
469 * @param[in] key_idx an index of key to be set
470 * @param[in] img_path the image file to be set
471 * @param[in] label a text label to be displayed on private key
472 * @param[in] value a value of key. If null, it will use original value of key
474 EAPI void isf_imf_context_input_panel_private_key_set (Ecore_IMF_Context *ctx,
477 const char *img_path,
481 IMFCONTROLUIDBG("[%s] layout : %d, key_index : %d, img_path : %s, label : %s, value : %s\n", __func__, layout_index, key_index, img_path, label, value);
483 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get (ctx);
486 _isf_imf_context_init ();
488 if (context_scim != get_focused_ic ())
492 _isf_imf_context_input_panel_private_key_set_by_image (layout_index, key_index, img_path, value);
494 _isf_imf_context_input_panel_private_key_set (layout_index, key_index, label, value);
499 * Make a key to be disabled in active ISE keyboard layout for own's application.
500 * In some case which does not support the disable key will be ignored
501 * even through the application requested.
503 * @param[in] ctx a #Ecore_IMF_Context
504 * @param[in] layout_idx an index of layout page to be set
505 * @param[in] key_idx an index of key to be set
506 * @param[in] disabled the state
508 EAPI void isf_imf_context_input_panel_key_disabled_set (Ecore_IMF_Context *ctx, int layout_index, int key_index, Eina_Bool disabled)
510 IMFCONTROLUIDBG("[%s] layout : %d, key_index : %d, value : %d\n", __func__, layout_index, key_index, disabled);
512 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get (ctx);
515 _isf_imf_context_init ();
517 if (context_scim == get_focused_ic())
518 _isf_imf_context_input_panel_key_disabled_set (layout_index, key_index, disabled);
522 * Sets up the layout infomation of active ISE
524 * @param[in] ctx a #Ecore_IMF_Context
525 * @param[in] layout sets a layout ID to be shown. The layout ID will define by the configuration of selected ISE.
528 isf_imf_context_input_panel_layout_set (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Layout layout)
530 IMFCONTROLUIDBG("[%s] layout : %d\n", __func__, layout);
532 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get (ctx);
535 _isf_imf_context_init ();
537 if (context_scim == get_focused_ic ())
538 _isf_imf_context_input_panel_layout_set (layout);
542 * Get current ISE layout
544 * @param[in] ctx a #Ecore_IMF_Context
546 * @return the layout of current ISE.
548 EAPI Ecore_IMF_Input_Panel_Layout isf_imf_context_input_panel_layout_get (Ecore_IMF_Context *ctx)
550 Ecore_IMF_Input_Panel_Layout layout;
552 _isf_imf_context_init ();
553 _isf_imf_context_input_panel_layout_get (&layout);
555 IMFCONTROLUIDBG("[%s] layout : %d\n", __func__, layout);
561 * Get current ISE state
563 * @param[in] ctx a #Ecore_IMF_Context
565 * @return the state of current ISE.
567 EAPI Ecore_IMF_Input_Panel_State isf_imf_context_input_panel_state_get (Ecore_IMF_Context *ctx)
569 IMFCONTROLUIDBG("[%s] state : %d\n", __func__, iseContext.state);
572 _isf_imf_context_init ();
573 return iseContext.state;
576 EAPI void isf_imf_context_input_panel_event_callback_add (Ecore_IMF_Context *ctx,
577 Ecore_IMF_Input_Panel_Event type,
578 void (*func) (void *data, Ecore_IMF_Context *ctx, int value),
581 EventCallbackNode *fn = NULL;
583 fn = (EventCallbackNode *)calloc (1, sizeof (EventCallbackNode));
587 IMFCONTROLUIDBG("[%s]\n", __func__);
592 fn->imf_context = ctx;
594 EventCallbackList = eina_list_append (EventCallbackList, fn);
597 EAPI void isf_imf_context_input_panel_event_callback_del (Ecore_IMF_Context *ctx,
598 Ecore_IMF_Input_Panel_Event type,
599 void (*func) (void *data, Ecore_IMF_Context *ctx, int value))
602 EventCallbackNode *fn = NULL;
604 IMFCONTROLUIDBG("[%s]\n", __func__);
606 for (l = EventCallbackList; l;) {
607 fn = (EventCallbackNode *)l->data;
609 if ((fn) && (fn->func == func) && (fn->type == type)) {
610 EventCallbackList = eina_list_remove (EventCallbackList, fn);
618 EAPI void isf_imf_context_input_panel_event_callback_clear (Ecore_IMF_Context *ctx)
621 EventCallbackNode *fn;
623 IMFCONTROLUIDBG("[%s]\n", __func__);
625 for (l = EventCallbackList; l;) {
626 fn = (EventCallbackNode *)l->data;
628 if ((fn) && (fn->imf_context == ctx)) {
629 EventCallbackList = eina_list_remove (EventCallbackList, fn);
637 * process command message, ISM_TRANS_CMD_ISE_PANEL_SHOWED of ecore_ise_process_event()
639 static bool _process_ise_panel_showed (void)
641 /* When the size of ISE gets changed, STATE_SHOW is be delivered again to letting applications know the change.
642 Later, an event type for notifying the size change of ISE needs to be added instead. */
643 iseContext.state = ECORE_IMF_INPUT_PANEL_STATE_SHOW;
645 /* Notify that ISE status has changed */
646 _event_callback_call (ECORE_IMF_INPUT_PANEL_STATE_EVENT, ECORE_IMF_INPUT_PANEL_STATE_SHOW);
652 * process command message, ISM_TRANS_CMD_ISE_PANEL_HIDED of ecore_ise_process_event()
654 static bool _process_ise_panel_hided (void)
656 if (iseContext.state == ECORE_IMF_INPUT_PANEL_STATE_HIDE) {
657 IMFCONTROLUIDBG("ISE is already hided (_process_ise_panel_hided)\n");
661 iseContext.state = ECORE_IMF_INPUT_PANEL_STATE_HIDE;
663 /* Notify that ISE status has changed */
664 _event_callback_call (ECORE_IMF_INPUT_PANEL_STATE_EVENT, ECORE_IMF_INPUT_PANEL_STATE_HIDE);
670 * process command message, ISM_TRANS_CMD_UPDATE_ISE_INPUT_CONTEXT of gtk_ise_process_event()
672 static bool _process_update_input_context (Transaction &trans)
677 if (!(trans.get_data (type) && trans.get_data (value)))
680 IMFCONTROLUIDBG("[%s] receive input context: [%d:%d]\n", __FUNCTION__, type, value);
682 if (type == (uint32)ECORE_IMF_INPUT_PANEL_STATE_EVENT && value == (uint32)ECORE_IMF_INPUT_PANEL_STATE_HIDE) {
683 _process_ise_panel_hided ();
687 if (type == (uint32)ECORE_IMF_INPUT_PANEL_STATE_EVENT && value == (uint32)ECORE_IMF_INPUT_PANEL_STATE_SHOW) {
688 _process_ise_panel_showed ();
692 _event_callback_call ((Ecore_IMF_Input_Panel_Event)type, (int)value);
698 * process ISE data of command message with ISF
700 * @param[in] trans packet data to be processed
701 * @param[in] cmd command ID that defines with ISF
703 void ecore_ise_process_data (Transaction &trans, int cmd)
706 case ISM_TRANS_CMD_ISE_PANEL_SHOWED : {
707 IMFCONTROLUIDBG ("cmd is ISM_TRANS_CMD_ISE_PANEL_SHOWED\n");
708 _process_ise_panel_showed ();
711 case ISM_TRANS_CMD_ISE_PANEL_HIDED : {
712 IMFCONTROLUIDBG ("cmd is ISM_TRANS_CMD_ISE_PANEL_HIDED\n");
713 _process_ise_panel_hided ();
716 case ISM_TRANS_CMD_UPDATE_ISE_INPUT_CONTEXT : {
717 IMFCONTROLUIDBG ("cmd is ISM_TRANS_CMD_UPDATE_ISE_INPUT_CONTEXT\n");
718 _process_update_input_context (trans);
722 IMFCONTROLUIDBG("unknown command");