5 #define Uses_SCIM_DEBUG
6 #define Uses_SCIM_BACKEND
7 #define Uses_SCIM_IMENGINE_MODULE
8 #define Uses_SCIM_HOTKEY
9 #define Uses_SCIM_PANEL_CLIENT
11 #include <sys/types.h>
14 #include <sys/times.h>
17 #include <Ecore_Evas.h>
23 #include <X11/keysym.h>
24 #include <X11/Xutil.h>
27 #include "scim_imcontext.h"
31 struct _EcoreIMFContextISFImpl
33 EcoreIMFContextISF *parent;
34 IMEngineInstancePointer si;
35 Ecore_X_Window client_window;
37 Ecore_IMF_Input_Mode input_mode;
38 WideString preedit_string;
39 AttributeList preedit_attrlist;
40 Ecore_IMF_Autocapital_Type autocapital_type;
49 bool preedit_updating;
50 bool need_commit_preedit;
52 bool prediction_allow;
54 EcoreIMFContextISFImpl *next;
57 /* Input Context handling functions. */
58 static EcoreIMFContextISFImpl *new_ic_impl (EcoreIMFContextISF *parent);
59 static void delete_ic_impl (EcoreIMFContextISFImpl *impl);
60 static void delete_all_ic_impl (void);
62 static EcoreIMFContextISF *find_ic (int id);
65 /* private functions */
66 static void panel_slot_reload_config (int context);
67 static void panel_slot_exit (int context);
68 static void panel_slot_update_lookup_table_page_size(int context,
70 static void panel_slot_lookup_table_page_up (int context);
71 static void panel_slot_lookup_table_page_down (int context);
72 static void panel_slot_trigger_property (int context,
73 const String &property);
74 static void panel_slot_process_helper_event (int context,
75 const String &target_uuid,
76 const String &helper_uuid,
77 const Transaction &trans);
78 static void panel_slot_move_preedit_caret (int context,
80 static void panel_slot_select_candidate (int context,
82 static void panel_slot_process_key_event (int context,
84 static void panel_slot_commit_string (int context,
85 const WideString &wstr);
86 static void panel_slot_forward_key_event (int context,
88 static void panel_slot_request_help (int context);
89 static void panel_slot_request_factory_menu (int context);
90 static void panel_slot_change_factory (int context,
93 static void panel_req_focus_in (EcoreIMFContextISF *ic);
94 static void panel_req_update_factory_info (EcoreIMFContextISF *ic);
95 static void panel_req_update_spot_location (EcoreIMFContextISF *ic);
96 static void panel_req_show_help (EcoreIMFContextISF *ic);
97 static void panel_req_show_factory_menu (EcoreIMFContextISF *ic);
99 /* Panel iochannel handler*/
100 static bool panel_initialize (void);
101 static void panel_finalize (void);
102 static Eina_Bool panel_iochannel_handler (void *data,
103 Ecore_Fd_Handler *fd_handler);
105 /* utility functions */
106 static bool filter_hotkeys (EcoreIMFContextISF *ic,
107 const KeyEvent &key);
108 static void turn_on_ic (EcoreIMFContextISF *ic);
109 static void turn_off_ic (EcoreIMFContextISF *ic);
110 static void set_ic_capabilities (EcoreIMFContextISF *ic);
112 static void initialize (void);
113 static void finalize (void);
115 static void open_next_factory (EcoreIMFContextISF *ic);
116 static void open_previous_factory (EcoreIMFContextISF *ic);
117 static void open_specific_factory (EcoreIMFContextISF *ic,
119 static void initialize_modifier_bits (Display *display);
120 static unsigned int scim_x11_keymask_scim_to_x11 (Display *display, uint16 scimkeymask);
121 static XKeyEvent createKeyEvent (Display *display, Window &win,
122 Window &winRoot, bool press,
123 int keycode, int modifiers);
124 static void _x_send_key_event (const KeyEvent &key);
126 static void attach_instance (const IMEngineInstancePointer &si);
129 static void slot_show_preedit_string (IMEngineInstanceBase *si);
130 static void slot_show_aux_string (IMEngineInstanceBase *si);
131 static void slot_show_lookup_table (IMEngineInstanceBase *si);
133 static void slot_hide_preedit_string (IMEngineInstanceBase *si);
134 static void slot_hide_aux_string (IMEngineInstanceBase *si);
135 static void slot_hide_lookup_table (IMEngineInstanceBase *si);
137 static void slot_update_preedit_caret (IMEngineInstanceBase *si,
139 static void slot_update_preedit_string (IMEngineInstanceBase *si,
140 const WideString &str,
141 const AttributeList &attrs);
142 static void slot_update_aux_string (IMEngineInstanceBase *si,
143 const WideString &str,
144 const AttributeList &attrs);
145 static void slot_commit_string (IMEngineInstanceBase *si,
146 const WideString &str);
147 static void slot_forward_key_event (IMEngineInstanceBase *si,
148 const KeyEvent &key);
149 static void slot_update_lookup_table (IMEngineInstanceBase *si,
150 const LookupTable &table);
152 static void slot_register_properties (IMEngineInstanceBase *si,
153 const PropertyList &properties);
154 static void slot_update_property (IMEngineInstanceBase *si,
155 const Property &property);
156 static void slot_beep (IMEngineInstanceBase *si);
157 static void slot_start_helper (IMEngineInstanceBase *si,
158 const String &helper_uuid);
159 static void slot_stop_helper (IMEngineInstanceBase *si,
160 const String &helper_uuid);
161 static void slot_send_helper_event (IMEngineInstanceBase *si,
162 const String &helper_uuid,
163 const Transaction &trans);
164 static bool slot_get_surrounding_text (IMEngineInstanceBase *si,
169 static bool slot_delete_surrounding_text (IMEngineInstanceBase *si,
173 static void reload_config_callback (const ConfigPointer &config);
175 static void fallback_commit_string_cb (IMEngineInstanceBase *si,
176 const WideString &str);
178 static void caps_mode_check (Ecore_IMF_Context *ctx, Eina_Bool force);
180 /* Local variables declaration */
181 static String _language;
182 static EcoreIMFContextISFImpl *_used_ic_impl_list = 0;
183 static EcoreIMFContextISFImpl *_free_ic_impl_list = 0;
184 static EcoreIMFContextISF *_ic_list = 0;
186 static KeyboardLayout _keyboard_layout = SCIM_KEYBOARD_Default;
187 static int _valid_key_mask = SCIM_KEY_AllMasks;
189 static FrontEndHotkeyMatcher _frontend_hotkey_matcher;
190 static IMEngineHotkeyMatcher _imengine_hotkey_matcher;
192 static IMEngineInstancePointer _default_instance;
194 static ConfigModule *_config_module = 0;
195 static ConfigPointer _config;
196 static BackEndPointer _backend;
198 static EcoreIMFContextISF *_focused_ic = 0;
200 static bool _scim_initialized = false;
202 static int _instance_count = 0;
203 static int _context_count = 0;
205 static IMEngineFactoryPointer _fallback_factory;
206 static IMEngineInstancePointer _fallback_instance;
207 static PanelClient _panel_client;
209 static Ecore_Fd_Handler *_panel_iochannel_read_handler = 0;
210 static Ecore_Fd_Handler *_panel_iochannel_err_handler = 0;
212 static Ecore_X_Window _client_window = 0;
214 static bool _on_the_spot = true;
215 static bool _shared_input_method = false;
217 static Eina_Bool autocap_allow = EINA_FALSE;
219 static Display *__current_display = 0;
220 static int __current_alt_mask = Mod1Mask;
221 static int __current_meta_mask = 0;
222 static int __current_super_mask = 0;
223 static int __current_hyper_mask = 0;
224 static int __current_numlock_mask = Mod2Mask;
226 // A hack to shutdown the immodule cleanly even if im_module_exit() is not called when exiting.
227 class FinalizeHandler
232 SCIM_DEBUG_FRONTEND(1) << "FinalizeHandler::FinalizeHandler()\n";
236 SCIM_DEBUG_FRONTEND(1) << "FinalizeHandler::~FinalizeHandler()\n";
237 isf_imf_context_shutdown();
241 static FinalizeHandler _finalize_handler;
244 utf8_offset_to_index(const char *str, int offset)
248 for (i = 0; i < offset; i++)
250 eina_unicode_utf8_get_next(str, &index);
261 struct timezone tz; /* is not used since ages */
262 gettimeofday(&tv, &tz);
263 tint = tv.tv_sec * 1000;
264 tint = tint / 1000 * 1000;
265 tint = tint + tv.tv_usec / 1000;
269 /* Function Implementations */
270 static EcoreIMFContextISFImpl *
271 new_ic_impl(EcoreIMFContextISF *parent)
273 EcoreIMFContextISFImpl *impl = NULL;
275 if (_free_ic_impl_list != NULL)
277 impl = _free_ic_impl_list;
278 _free_ic_impl_list = _free_ic_impl_list->next;
282 impl = new EcoreIMFContextISFImpl;
287 impl->uppercase = false;
288 impl->autocapital_type = ECORE_IMF_AUTOCAPITAL_TYPE_NONE;
289 impl->next = _used_ic_impl_list;
290 _used_ic_impl_list = impl;
292 impl->parent = parent;
298 delete_ic_impl(EcoreIMFContextISFImpl *impl)
300 EcoreIMFContextISFImpl *rec = _used_ic_impl_list, *last = 0;
302 for (; rec != 0; last = rec, rec = rec->next)
307 last->next = rec->next;
309 _used_ic_impl_list = rec->next;
311 rec->next = _free_ic_impl_list;
312 _free_ic_impl_list = rec;
316 rec->client_window = 0;
317 rec->preedit_string = WideString();
318 rec->preedit_attrlist.clear();
326 delete_all_ic_impl(void)
328 EcoreIMFContextISFImpl *it = _used_ic_impl_list;
332 _used_ic_impl_list = it->next;
334 it = _used_ic_impl_list;
337 it = _free_ic_impl_list;
340 _free_ic_impl_list = it->next;
342 it = _free_ic_impl_list;
346 static EcoreIMFContextISF *
349 EcoreIMFContextISFImpl *rec = _used_ic_impl_list;
353 if (rec->parent && rec->parent->id == id)
362 analyze_surrounding_text(Ecore_IMF_Context *ctx)
364 char *plain_str = NULL;
365 char *markup_str = NULL;
366 const char *puncs[] = {". ", "! ", "? "};
367 Eina_Bool ret = EINA_FALSE;
370 Eina_Unicode *tail = NULL;
371 Eina_Unicode *ustr = NULL;
372 const int punc_num = sizeof(puncs) / sizeof(puncs[0]);
373 Eina_Unicode *uni_puncs[punc_num];
374 EcoreIMFContextISF *context_scim;
376 if (!ctx) return EINA_FALSE;
377 context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
378 if (!context_scim || !context_scim->impl) return EINA_FALSE;
380 switch (context_scim->impl->autocapital_type)
382 case ECORE_IMF_AUTOCAPITAL_TYPE_NONE:
384 case ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER:
390 for (i = 0; i < punc_num; i++)
391 uni_puncs[i] = eina_unicode_utf8_to_unicode(puncs[i], NULL);
393 ecore_imf_context_surrounding_get(ctx, &markup_str, &cursor_pos);
394 if (!markup_str) goto done;
402 // Convert into plain string
403 plain_str = evas_textblock_text_markup_to_utf8(NULL, markup_str);
404 if (!plain_str) goto done;
406 // Convert string from UTF-8 to unicode
407 ustr = eina_unicode_utf8_to_unicode(plain_str, NULL);
408 if (!ustr) goto done;
412 if (context_scim->impl->autocapital_type == ECORE_IMF_AUTOCAPITAL_TYPE_WORD)
414 if (ustr[cursor_pos-1] == ' ')
421 // Check paragraph separator <PS> and carriage return <br>
422 if ((ustr[cursor_pos-1] == 0x2029) || (ustr[cursor_pos-1] == '\n'))
432 tail = eina_unicode_strndup(ustr+cursor_pos-2, 2);
436 for (i = 0; i < punc_num; i++)
438 if (!eina_unicode_strcmp(tail, uni_puncs[i]))
450 if (ustr) free(ustr);
451 if (markup_str) free(markup_str);
452 if (plain_str) free(plain_str);
454 for (i = 0; i < punc_num; i++)
455 if (uni_puncs[i]) free(uni_puncs[i]);
461 caps_mode_check(Ecore_IMF_Context *ctx, Eina_Bool force)
464 EcoreIMFContextISF *context_scim;
467 context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
469 if (autocap_allow == EINA_FALSE)
472 // Check autocapital type
473 if (!context_scim || !context_scim->impl)
476 if (analyze_surrounding_text(ctx))
477 uppercase = EINA_TRUE;
479 uppercase = EINA_FALSE;
482 context_scim->impl->uppercase = uppercase;
484 if (context_scim->impl->uppercase != uppercase)
485 context_scim->impl->uppercase = uppercase;
489 feed_key_event(Evas *evas, const char *str, Eina_Bool fake)
491 char key_string[128] = {0};
492 unsigned int timestamp = 0;
495 timestamp = get_time();
497 if (strncmp(str, "KeyRelease+", 11) == 0)
499 strncpy(key_string, str + 11, strlen(str)-11);
500 evas_event_feed_key_up(evas, key_string, key_string, NULL, NULL, timestamp, NULL);
501 SCIM_DEBUG_FRONTEND(1) << " evas_event_feed_key_up()...\n";
505 strncpy(key_string, str, strlen(str));
506 evas_event_feed_key_down(evas, key_string, key_string, NULL, NULL, timestamp, NULL);
507 SCIM_DEBUG_FRONTEND(1) << " evas_event_feed_key_down()...\n";
512 window_to_screen_geometry_get(Ecore_X_Window client_win, int *x, int *y)
514 Ecore_X_Window root_window, win;
516 int sum_x = 0, sum_y = 0;
518 root_window = ecore_x_window_root_get(client_win);
521 while (root_window != win)
523 ecore_x_window_geometry_get(win, &win_x, &win_y, NULL, NULL);
526 win = ecore_x_window_parent_get(win);
535 /* Public functions */
537 * isf_imf_context_new
539 * This function will be called by Ecore IMF.
540 * Create a instance of type EcoreIMFContextISF.
542 * Return value: A pointer to the newly created EcoreIMFContextISF instance
544 EAPI EcoreIMFContextISF *
545 isf_imf_context_new(void)
547 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
550 EcoreIMFContextISF *context_scim = new EcoreIMFContextISF;
551 if (context_scim == NULL)
553 std::cerr << "memory allocation failed in " << __FUNCTION__ << "\n";
557 context_scim->id = _context_count++;
559 if (!_scim_initialized)
562 _scim_initialized = true;
565 env = getenv("ECORE_IMF_AUTOCAPITAL_ALLOW");
567 autocap_allow = !!atoi(env);
573 * isf_imf_context_shutdown
575 * It will be called when the scim im module is unloaded by ecore. It will do some
579 isf_imf_context_shutdown(void)
581 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
583 if (_scim_initialized)
585 _scim_initialized = false;
591 isf_imf_context_add(Ecore_IMF_Context *ctx)
593 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
595 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
597 if (!context_scim) return;
599 context_scim->impl = NULL;
604 IMEngineInstancePointer si;
606 // Use the default instance if "shared input method" mode is enabled.
607 if (_shared_input_method && !_default_instance.null())
609 si = _default_instance;
610 SCIM_DEBUG_FRONTEND(2) << "use default instance: " << si->get_id() << " " << si->get_factory_uuid() << "\n";
613 // Not in "shared input method" mode, or no default instance, create an instance.
616 IMEngineFactoryPointer factory = _backend->get_default_factory(_language, "UTF-8");
617 if (factory.null()) return;
618 si = factory->create_instance("UTF-8", _instance_count++);
619 if (si.null()) return;
621 SCIM_DEBUG_FRONTEND(2) << "create new instance: " << si->get_id() << " " << si->get_factory_uuid() << "\n";
624 // If "shared input method" mode is enabled, and there is no default instance,
625 // then store this instance as default one.
626 if (_shared_input_method && _default_instance.null())
628 SCIM_DEBUG_FRONTEND(2) << "update default instance.\n";
629 _default_instance = si;
632 context_scim->ctx = ctx;
633 context_scim->impl = new_ic_impl(context_scim);
634 if (context_scim->impl == NULL)
636 std::cerr << "memory allocation failed in " << __FUNCTION__ << "\n";
640 context_scim->impl->si = si;
641 context_scim->impl->client_window = 0;
642 context_scim->impl->client_canvas = NULL;
643 context_scim->impl->preedit_caret = 0;
644 context_scim->impl->cursor_x = 0;
645 context_scim->impl->cursor_y = 0;
646 context_scim->impl->cursor_pos = -1;
647 context_scim->impl->is_on = false;
648 context_scim->impl->shared_si = _shared_input_method;
649 context_scim->impl->use_preedit = _on_the_spot;
650 context_scim->impl->preedit_started = false;
651 context_scim->impl->preedit_updating = false;
652 context_scim->impl->need_commit_preedit = false;
655 context_scim->next = NULL;
657 context_scim->next = _ic_list;
658 _ic_list = context_scim;
660 if (_shared_input_method)
661 context_scim->impl->is_on = _config->read(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), context_scim->impl->is_on);
663 _panel_client.prepare(context_scim->id);
664 _panel_client.register_input_context(context_scim->id, si->get_factory_uuid());
665 set_ic_capabilities(context_scim);
666 _panel_client.send();
668 SCIM_DEBUG_FRONTEND(2) << "input context created: id = " << context_scim->id << "\n";
672 isf_imf_context_del(Ecore_IMF_Context *ctx)
674 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
676 if (!_ic_list) return;
678 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
682 if (context_scim->id != _ic_list->id)
684 EcoreIMFContextISF * pre = _ic_list;
685 EcoreIMFContextISF * cur = _ic_list->next;
688 if (cur->id == context_scim->id)
690 pre->next = cur->next;
698 _ic_list = _ic_list->next;
701 if (context_scim && context_scim->impl)
703 _panel_client.prepare(context_scim->id);
705 if (context_scim == _focused_ic)
706 context_scim->impl->si->focus_out();
708 // Delete the instance.
709 EcoreIMFContextISF *old_focused = _focused_ic;
710 _focused_ic = context_scim;
711 context_scim->impl->si.reset();
712 _focused_ic = old_focused;
714 if (context_scim == _focused_ic)
716 _panel_client.turn_off(context_scim->id);
717 _panel_client.focus_out(context_scim->id);
720 _panel_client.remove_input_context(context_scim->id);
721 _panel_client.send();
723 if (context_scim->impl->client_window)
724 isf_imf_context_client_window_set(ctx, NULL);
726 if (context_scim->impl)
728 delete_ic_impl(context_scim->impl);
729 context_scim->impl = 0;
733 if (context_scim == _focused_ic)
744 * isf_imf_context_client_canvas_set
745 * @ctx: a #Ecore_IMF_Context
746 * @canvas: the client canvas
748 * This function will be called by Ecore IMF.
750 * Set the client canvas for the Input Method Context; this is the canvas
751 * in which the input appears.
753 * The canvas type can be determined by using the context canvas type.
754 * Actually only canvas with type "evas" (Evas *) is supported. This canvas
755 * may be used in order to correctly position status windows, and may also
756 * be used for purposes internal to the Input Method Context.
759 isf_imf_context_client_canvas_set(Ecore_IMF_Context *ctx, void *canvas)
761 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
763 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
765 if (context_scim && context_scim->impl && context_scim->impl->client_canvas != (Evas*) canvas)
766 context_scim->impl->client_canvas = (Evas*)canvas;
770 * isf_imf_context_client_window_set
771 * @ctx: a #Ecore_IMF_Context
772 * @window: the client window
774 * This function will be called by Ecore IMF.
776 * Set the client window for the Input Method Context; this is the Ecore_X_Window
777 * when using X11, Ecore_Win32_Window when using Win32, etc.
779 * This window is used in order to correctly position status windows,
780 * and may also be used for purposes internal to the Input Method Context.
783 isf_imf_context_client_window_set(Ecore_IMF_Context *ctx, void *window)
785 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
787 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
789 if (context_scim && context_scim->impl && context_scim->impl->client_window != (Ecore_X_Window)((Ecore_Window)window))
791 context_scim->impl->client_window = (Ecore_X_Window)((Ecore_Window)window);
793 if ((context_scim->impl->client_window != 0) &&
794 (context_scim->impl->client_window != _client_window))
795 _client_window = context_scim->impl->client_window;
800 * isf_imf_context_reset
801 * @ctx: a #Ecore_IMF_Context
803 * This function will be called by Ecore IMF.
805 * Notify the Input Method Context that a change such as a change in cursor
806 * position has been made. This will typically cause the Input Method Context
807 * to clear the preedit state.
810 isf_imf_context_reset(Ecore_IMF_Context *ctx)
812 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
814 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
816 if (context_scim && context_scim->impl && context_scim == _focused_ic)
818 WideString wstr = context_scim->impl->preedit_string;
820 _panel_client.prepare(context_scim->id);
821 context_scim->impl->si->reset();
822 _panel_client.send();
824 if (context_scim->impl->need_commit_preedit)
828 ecore_imf_context_commit_event_add(context_scim->ctx, utf8_wcstombs(wstr).c_str());
829 ecore_imf_context_event_callback_call(context_scim->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(wstr).c_str());
831 _panel_client.prepare(context_scim->id);
832 _panel_client.send();
838 * isf_imf_context_focus_in
839 * @ctx: a #Ecore_IMF_Context
841 * This function will be called by Ecore IMF.
843 * Notify the Input Method Context that the widget to which its correspond has gained focus.
846 isf_imf_context_focus_in(Ecore_IMF_Context *ctx)
848 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
853 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__<< "(" << context_scim->id << ")...\n";
857 if (_focused_ic == context_scim)
859 SCIM_DEBUG_FRONTEND(1) << "It's already focused.\n";
862 SCIM_DEBUG_FRONTEND(1) << "Focus out previous IC first: " << _focused_ic->id << "\n";
863 if (_focused_ic->ctx)
864 isf_imf_context_focus_out(_focused_ic->ctx);
867 bool need_cap = false;
868 bool need_reset = false;
869 bool need_reg = false;
871 if (context_scim && context_scim->impl)
873 _focused_ic = context_scim;
874 _panel_client.prepare(context_scim->id);
876 // Handle the "Shared Input Method" mode.
877 if (_shared_input_method)
879 SCIM_DEBUG_FRONTEND(2) << "shared input method.\n";
880 IMEngineFactoryPointer factory = _backend->get_default_factory(_language, "UTF-8");
883 if (_default_instance.null() || _default_instance->get_factory_uuid() != factory->get_uuid())
885 _default_instance = factory->create_instance("UTF-8", _default_instance.null() ? _instance_count++ : _default_instance->get_id());
886 attach_instance(_default_instance);
887 SCIM_DEBUG_FRONTEND(2) << "create new default instance: " << _default_instance->get_id() << " " << _default_instance->get_factory_uuid() << "\n";
890 context_scim->impl->shared_si = true;
891 context_scim->impl->si = _default_instance;
893 context_scim->impl->is_on = _config->read(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), context_scim->impl->is_on);
894 context_scim->impl->preedit_string.clear();
895 context_scim->impl->preedit_attrlist.clear();
896 context_scim->impl->preedit_caret = 0;
897 context_scim->impl->preedit_started = false;
903 else if (context_scim->impl->shared_si)
905 SCIM_DEBUG_FRONTEND(2) << "exit shared input method.\n";
906 IMEngineFactoryPointer factory = _backend->get_default_factory(_language, "UTF-8");
909 context_scim->impl->si = factory->create_instance("UTF-8", _instance_count++);
910 context_scim->impl->preedit_string.clear();
911 context_scim->impl->preedit_attrlist.clear();
912 context_scim->impl->preedit_caret = 0;
913 context_scim->impl->preedit_started = false;
914 attach_instance(context_scim->impl->si);
917 context_scim->impl->shared_si = false;
918 SCIM_DEBUG_FRONTEND(2) << "create new instance: " << context_scim->impl->si->get_id() << " " << context_scim->impl->si->get_factory_uuid() << "\n";
922 context_scim->impl->si->set_frontend_data(static_cast <void*>(context_scim));
924 if (need_reg) _panel_client.register_input_context(context_scim->id, context_scim->impl->si->get_factory_uuid());
925 if (need_cap) set_ic_capabilities(context_scim);
926 if (need_reset) context_scim->impl->si->reset();
928 panel_req_focus_in(context_scim);
929 panel_req_update_spot_location(context_scim);
930 panel_req_update_factory_info(context_scim);
932 if (context_scim->impl->is_on)
934 _panel_client.turn_on(context_scim->id);
935 _panel_client.hide_preedit_string(context_scim->id);
936 _panel_client.hide_aux_string(context_scim->id);
937 _panel_client.hide_lookup_table(context_scim->id);
938 context_scim->impl->si->focus_in();
942 _panel_client.turn_off(context_scim->id);
945 _panel_client.send();
948 if (ecore_imf_context_input_panel_enabled_get(ctx))
949 ecore_imf_context_input_panel_show(ctx);
953 * isf_imf_context_focus_out
954 * @ctx: a #Ecore_IMF_Context
956 * This function will be called by Ecore IMF.
958 * Notify the Input Method Context that the widget to which its correspond has lost focus.
961 isf_imf_context_focus_out(Ecore_IMF_Context *ctx)
963 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
965 if (!context_scim) return;
967 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "(" << context_scim->id << ")...\n";
969 if (context_scim && context_scim->impl && context_scim == _focused_ic)
971 WideString wstr = context_scim->impl->preedit_string;
973 if (context_scim->impl->need_commit_preedit)
977 ecore_imf_context_commit_event_add(context_scim->ctx, utf8_wcstombs(wstr).c_str());
978 ecore_imf_context_event_callback_call(context_scim->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(wstr).c_str());
980 _panel_client.prepare(context_scim->id);
981 _panel_client.send();
984 _panel_client.prepare(context_scim->id);
985 context_scim->impl->si->focus_out();
986 context_scim->impl->si->reset();
987 _panel_client.turn_off(context_scim->id);
988 _panel_client.focus_out(context_scim->id);
989 _panel_client.send();
993 if (ecore_imf_context_input_panel_enabled_get(ctx))
994 ecore_imf_context_input_panel_hide(ctx);
998 * isf_imf_context_cursor_location_set
999 * @ctx: a #Ecore_IMF_Context
1000 * @x: x position of New cursor.
1001 * @y: y position of New cursor.
1002 * @w: the width of New cursor.
1003 * @h: the height of New cursor.
1005 * This function will be called by Ecore IMF.
1007 * Notify the Input Method Context that a change in the cursor location has been made.
1010 isf_imf_context_cursor_location_set(Ecore_IMF_Context *ctx, int cx, int cy, int cw, int ch)
1012 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1014 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
1016 int canvas_x, canvas_y;
1017 int new_cursor_x, new_cursor_y;
1019 if (cw == 0 && ch == 0)
1022 if (context_scim && context_scim->impl && context_scim == _focused_ic)
1024 if (context_scim->impl->client_canvas)
1026 ee = ecore_evas_ecore_evas_get(context_scim->impl->client_canvas);
1029 ecore_evas_geometry_get(ee, &canvas_x, &canvas_y, NULL, NULL);
1033 if (context_scim->impl->client_window)
1034 window_to_screen_geometry_get(context_scim->impl->client_window, &canvas_x, &canvas_y);
1039 new_cursor_x = canvas_x + cx;
1040 new_cursor_y = canvas_y + cy + ch;
1042 // Don't update spot location while updating preedit string.
1043 if (context_scim->impl->preedit_updating && (context_scim->impl->cursor_y == new_cursor_y))
1046 if (context_scim->impl->cursor_x != new_cursor_x || context_scim->impl->cursor_y != new_cursor_y)
1048 context_scim->impl->cursor_x = new_cursor_x;
1049 context_scim->impl->cursor_y = new_cursor_y;
1050 _panel_client.prepare(context_scim->id);
1051 panel_req_update_spot_location(context_scim);
1052 _panel_client.send();
1053 SCIM_DEBUG_FRONTEND(2) << "new cursor location = " << context_scim->impl->cursor_x << "," << context_scim->impl->cursor_y << "\n";
1059 * isf_imf_context_use_preedit_set
1060 * @ctx: a #Ecore_IMF_Context
1061 * @use_preedit: Whether the IM context should use the preedit string.
1063 * This function will be called by Ecore IMF.
1065 * Set whether the IM context should use the preedit string to display feedback.
1066 * If is 0 (default is 1), then the IM context may use some other method to
1067 * display feedback, such as displaying it in a child of the root window.
1070 isf_imf_context_use_preedit_set(Ecore_IMF_Context* ctx, Eina_Bool use_preedit)
1072 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " = " << (use_preedit ? "true" : "false") << "...\n";
1074 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1076 if (!_on_the_spot) return;
1078 if (context_scim && context_scim->impl)
1080 bool old = context_scim->impl->use_preedit;
1081 context_scim->impl->use_preedit = use_preedit;
1082 if (context_scim == _focused_ic)
1084 _panel_client.prepare(context_scim->id);
1086 if (old != use_preedit)
1087 set_ic_capabilities(context_scim);
1089 if (context_scim->impl->preedit_string.length())
1090 slot_show_preedit_string(context_scim->impl->si);
1092 _panel_client.send();
1098 isf_imf_context_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx, char** str, Eina_List **attrs, int *cursor_pos)
1100 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1102 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1104 if (context_scim && context_scim->impl && context_scim->impl->is_on)
1106 String mbs = utf8_wcstombs(context_scim->impl->preedit_string);
1111 *str = strdup(mbs.c_str());
1118 *cursor_pos = context_scim->impl->preedit_caret;
1125 int start_index, end_index;
1126 int wlen = context_scim->impl->preedit_string.length();
1128 Ecore_IMF_Preedit_Attr *attr = NULL;
1129 AttributeList::const_iterator i;
1130 bool *attrs_flag = new bool [mbs.length()];
1131 memset(attrs_flag, 0, mbs.length() *sizeof(bool));
1133 for (i = context_scim->impl->preedit_attrlist.begin();
1134 i != context_scim->impl->preedit_attrlist.end(); ++i)
1136 start_index = i->get_start();
1137 end_index = i->get_end();
1139 if (end_index <= wlen && start_index < end_index && i->get_type() != SCIM_ATTR_DECORATE_NONE)
1141 start_index = utf8_offset_to_index(mbs.c_str(), i->get_start());
1142 end_index = utf8_offset_to_index(mbs.c_str(), i->get_end());
1144 if (i->get_type() == SCIM_ATTR_DECORATE)
1146 attr = (Ecore_IMF_Preedit_Attr *)calloc(1, sizeof(Ecore_IMF_Preedit_Attr));
1149 attr->start_index = start_index;
1150 attr->end_index = end_index;
1152 if (i->get_value() == SCIM_ATTR_DECORATE_UNDERLINE)
1154 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1;
1155 *attrs = eina_list_append(*attrs, (void *)attr);
1157 else if (i->get_value() == SCIM_ATTR_DECORATE_REVERSE)
1159 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2;
1160 *attrs = eina_list_append(*attrs, (void *)attr);
1162 else if (i->get_value() == SCIM_ATTR_DECORATE_HIGHLIGHT)
1164 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB3;
1165 *attrs = eina_list_append(*attrs, (void *)attr);
1172 switch(i->get_value())
1174 case SCIM_ATTR_DECORATE_UNDERLINE:
1175 case SCIM_ATTR_DECORATE_REVERSE:
1176 case SCIM_ATTR_DECORATE_HIGHLIGHT:
1177 // Record which character has attribute.
1178 for (int pos = start_index; pos < end_index; ++pos)
1179 attrs_flag [pos] = 1;
1185 else if (i->get_type() == SCIM_ATTR_FOREGROUND)
1187 SCIM_DEBUG_FRONTEND(4) << "SCIM_ATTR_FOREGROUND\n";
1189 else if (i->get_type() == SCIM_ATTR_BACKGROUND)
1191 SCIM_DEBUG_FRONTEND(4) << "SCIM_ATTR_BACKGROUND\n";
1196 // Add underline for all characters which don't have attribute.
1197 for (unsigned int pos = 0; pos < mbs.length(); ++pos)
1199 if (!attrs_flag [pos])
1201 int begin_pos = pos;
1203 while (pos < mbs.length() && !attrs_flag[pos])
1206 // use REVERSE style as default
1207 attr = (Ecore_IMF_Preedit_Attr *)calloc(1, sizeof(Ecore_IMF_Preedit_Attr));
1210 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2;
1211 attr->start_index = begin_pos;
1212 attr->end_index = pos;
1213 *attrs = eina_list_append(*attrs, (void *)attr);
1217 delete [] attrs_flag;
1235 * isf_imf_context_preedit_string_get
1236 * @ctx: a #Ecore_IMF_Context
1237 * @str: the preedit string
1238 * @cursor_pos: the cursor position
1240 * This function will be called by Ecore IMF.
1242 * To get the preedit string of the input method.
1245 isf_imf_context_preedit_string_get(Ecore_IMF_Context *ctx, char** str, int *cursor_pos)
1247 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1249 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1251 if (context_scim && context_scim->impl && context_scim->impl->is_on)
1253 String mbs = utf8_wcstombs(context_scim->impl->preedit_string);
1258 *str = strdup(mbs.c_str());
1264 *cursor_pos = context_scim->impl->preedit_caret;
1277 * isf_imf_context_cursor_position_set
1278 * @ctx: a #Ecore_IMF_Context
1279 * @cursor_pos: New cursor position in characters.
1281 * This function will be called by Ecore IMF.
1283 * Notify the Input Method Context that a change in the cursor position has been made.
1286 isf_imf_context_cursor_position_set(Ecore_IMF_Context *ctx, int cursor_pos)
1288 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1290 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
1292 if (context_scim && context_scim->impl && context_scim == _focused_ic)
1294 // Don't update spot location while updating preedit string.
1295 if (context_scim->impl->preedit_updating)
1298 if (context_scim->impl->cursor_pos != cursor_pos)
1300 context_scim->impl->cursor_pos = cursor_pos;
1301 caps_mode_check(ctx, EINA_FALSE);
1307 * isf_imf_context_input_mode_set
1308 * @ctx: a #Ecore_IMF_Context
1309 * @input_mode: the input mode
1311 * This function will be called by Ecore IMF.
1313 * To set the input mode of input method. The definition of Ecore_IMF_Input_Mode
1314 * is in Ecore_IMF.h.
1317 isf_imf_context_input_mode_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Mode input_mode)
1319 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1321 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1322 if (context_scim && context_scim->impl)
1323 context_scim->impl->input_mode = input_mode;
1327 * isf_imf_context_prediction_allow_set
1328 * @ctx: a #Ecore_IMF_Context
1329 * @use_prediction: Whether the IM context should use the prediction.
1331 * This function will be called by Ecore IMF.
1333 * Set whether the IM context should use the prediction.
1336 isf_imf_context_prediction_allow_set(Ecore_IMF_Context* ctx, Eina_Bool prediction)
1338 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " = " << (prediction ? "true" : "false") << "...\n";
1340 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
1342 if (context_scim && context_scim->impl && context_scim->impl->prediction_allow != prediction)
1343 context_scim->impl->prediction_allow = prediction;
1347 isf_imf_context_autocapital_type_set(Ecore_IMF_Context* ctx, Ecore_IMF_Autocapital_Type autocapital_type)
1349 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " = " << autocapital_type << "...\n";
1351 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
1353 if (context_scim && context_scim->impl && context_scim->impl->autocapital_type != autocapital_type)
1354 context_scim->impl->autocapital_type = autocapital_type;
1358 * isf_imf_context_filter_event
1359 * @ctx: a #Ecore_IMF_Context
1360 * @type: The type of event defined by Ecore_IMF_Event_Type.
1361 * @event: The event itself.
1362 * Return value: %TRUE if the input method handled the key event.
1364 * This function will be called by Ecore IMF.
1366 * Allow an Ecore Input Context to internally handle an event. If this function
1367 * returns 1, then no further processing should be done for this event. Input
1368 * methods must be able to accept all types of events (simply returning 0 if
1369 * the event was not handled), but there is no obligation of any events to be
1370 * submitted to this function.
1373 isf_imf_context_filter_event(Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event)
1375 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1377 EcoreIMFContextISF *ic = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1378 Eina_Bool ret = EINA_FALSE;
1380 if (ic == NULL || ic->impl == NULL)
1385 if (type == ECORE_IMF_EVENT_KEY_DOWN)
1387 Ecore_IMF_Event_Key_Down *ev = (Ecore_IMF_Event_Key_Down *)event;
1388 scim_string_to_key(key, ev->key);
1389 if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT) key.mask |=SCIM_KEY_ShiftMask;
1390 if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_CTRL) key.mask |=SCIM_KEY_ControlMask;
1391 if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALT) key.mask |=SCIM_KEY_AltMask;
1392 if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALTGR) key.mask |=SCIM_KEY_Mod5Mask;
1393 if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_CAPS) key.mask |=SCIM_KEY_CapsLockMask;
1394 if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_NUM) key.mask |=SCIM_KEY_NumLockMask;
1396 else if (type == ECORE_IMF_EVENT_KEY_UP)
1398 Ecore_IMF_Event_Key_Up *ev = (Ecore_IMF_Event_Key_Up *)event;
1399 scim_string_to_key(key, ev->key);
1400 key.mask = SCIM_KEY_ReleaseMask;
1401 if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT) key.mask |=SCIM_KEY_ShiftMask;
1402 if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_CTRL) key.mask |=SCIM_KEY_ControlMask;
1403 if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALT) key.mask |=SCIM_KEY_AltMask;
1404 if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALTGR) key.mask |=SCIM_KEY_Mod5Mask;
1405 if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_CAPS) key.mask |=SCIM_KEY_CapsLockMask;
1406 if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_NUM) key.mask |=SCIM_KEY_NumLockMask;
1413 key.mask &= _valid_key_mask;
1415 _panel_client.prepare(ic->id);
1418 if (!filter_hotkeys(ic, key))
1420 if (!_focused_ic || !_focused_ic->impl->is_on ||
1421 !_focused_ic->impl->si->process_key_event(key))
1425 _panel_client.send();
1431 isf_imf_context_input_panel_show(Ecore_IMF_Context *ctx)
1433 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1435 EcoreIMFContextISF *ic = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1436 if (ic == NULL || ic->impl == NULL)
1439 ecore_x_e_virtual_keyboard_state_set
1440 (ic->impl->client_window, ECORE_X_VIRTUAL_KEYBOARD_STATE_ON);
1444 isf_imf_context_input_panel_hide(Ecore_IMF_Context *ctx)
1446 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1448 EcoreIMFContextISF *ic = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1449 if (ic == NULL || ic->impl == NULL)
1452 ecore_x_e_virtual_keyboard_state_set
1453 (ic->impl->client_window, ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF);
1456 /* Panel Slot functions */
1458 panel_slot_reload_config(int context __UNUSED__)
1460 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1465 panel_slot_exit(int /* context */)
1467 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1473 panel_slot_update_lookup_table_page_size(int context, int page_size)
1475 EcoreIMFContextISF *ic = find_ic(context);
1476 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " page_size=" << page_size << " ic=" << ic << "\n";
1479 _panel_client.prepare(ic->id);
1480 ic->impl->si->update_lookup_table_page_size(page_size);
1481 _panel_client.send();
1486 panel_slot_lookup_table_page_up(int context)
1488 EcoreIMFContextISF *ic = find_ic(context);
1489 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n";
1492 _panel_client.prepare(ic->id);
1493 ic->impl->si->lookup_table_page_up();
1494 _panel_client.send();
1499 panel_slot_lookup_table_page_down(int context)
1501 EcoreIMFContextISF *ic = find_ic(context);
1502 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n";
1505 _panel_client.prepare(ic->id);
1506 ic->impl->si->lookup_table_page_down();
1507 _panel_client.send();
1512 panel_slot_trigger_property(int context, const String &property)
1514 EcoreIMFContextISF *ic = find_ic(context);
1515 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " property=" << property << " ic=" << ic << "\n";
1518 _panel_client.prepare(ic->id);
1519 ic->impl->si->trigger_property(property);
1520 _panel_client.send();
1525 panel_slot_process_helper_event(int context, const String &target_uuid, const String &helper_uuid, const Transaction &trans)
1527 EcoreIMFContextISF *ic = find_ic(context);
1528 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " target=" << target_uuid
1529 << " helper=" << helper_uuid << " ic=" << ic << " ic->impl=" << (ic ? ic->impl : 0) << " ic-uuid="
1530 << ((ic && ic->impl) ? ic->impl->si->get_factory_uuid() : "" ) << "\n";
1531 if (ic && ic->impl && ic->impl->si->get_factory_uuid() == target_uuid)
1533 _panel_client.prepare(ic->id);
1534 SCIM_DEBUG_FRONTEND(2) << "call process_helper_event\n";
1535 ic->impl->si->process_helper_event(helper_uuid, trans);
1536 _panel_client.send();
1541 panel_slot_move_preedit_caret(int context, int caret_pos)
1543 EcoreIMFContextISF *ic = find_ic(context);
1544 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " caret=" << caret_pos << " ic=" << ic << "\n";
1547 _panel_client.prepare(ic->id);
1548 ic->impl->si->move_preedit_caret(caret_pos);
1549 _panel_client.send();
1554 panel_slot_select_candidate(int context, int cand_index)
1556 EcoreIMFContextISF *ic = find_ic(context);
1557 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " candidate=" << cand_index << " ic=" << ic << "\n";
1560 _panel_client.prepare(ic->id);
1561 ic->impl->si->select_candidate(cand_index);
1562 _panel_client.send();
1567 panel_slot_process_key_event(int context, const KeyEvent &key)
1569 EcoreIMFContextISF *ic = find_ic(context);
1570 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " key=" << key.get_key_string() << " ic=" << ic << "\n";
1572 if (key.is_key_press())
1573 ecore_x_test_fake_key_press(key.get_key_string().c_str());
1577 panel_slot_commit_string(int context, const WideString &wstr)
1579 EcoreIMFContextISF *ic = find_ic(context);
1580 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " str=" << utf8_wcstombs(wstr) << " ic=" << ic << "\n";
1584 if (_focused_ic != ic)
1587 ecore_imf_context_commit_event_add(ic->ctx, utf8_wcstombs(wstr).c_str());
1588 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(wstr).c_str());
1593 panel_slot_forward_key_event(int context, const KeyEvent &key)
1595 EcoreIMFContextISF *ic = find_ic(context);
1596 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " key=" << key.get_key_string() << " ic=" << ic << "\n";
1598 if (ic && ic->impl && ic->impl->client_canvas)
1599 feed_key_event(ic->impl->client_canvas, key.get_key_string().c_str(), EINA_TRUE);
1603 panel_slot_request_help(int context)
1605 EcoreIMFContextISF *ic = find_ic(context);
1606 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n";
1610 _panel_client.prepare(ic->id);
1611 panel_req_show_help(ic);
1612 _panel_client.send();
1617 panel_slot_request_factory_menu(int context)
1619 EcoreIMFContextISF *ic = find_ic(context);
1620 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n";
1624 _panel_client.prepare(ic->id);
1625 panel_req_show_factory_menu(ic);
1626 _panel_client.send();
1631 panel_slot_change_factory(int context, const String &uuid)
1633 EcoreIMFContextISF *ic = find_ic(context);
1634 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " factory=" << uuid << " ic=" << ic << "\n";
1638 ic->impl->si->reset();
1639 _panel_client.prepare(ic->id);
1640 open_specific_factory(ic, uuid);
1641 _panel_client.send();
1645 /* Panel Requestion functions. */
1647 panel_req_show_help(EcoreIMFContextISF *ic)
1649 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1653 help = String("Smart Common Input Method platform ") +
1654 //String(SCIM_VERSION) +
1655 String("\n(C) 2002-2005 James Su <suzhe@tsinghua.org.cn>\n\n");
1659 IMEngineFactoryPointer sf = _backend->get_factory(ic->impl->si->get_factory_uuid());
1662 help += utf8_wcstombs(sf->get_name());
1663 help += String(":\n\n");
1665 help += utf8_wcstombs(sf->get_help());
1666 help += String("\n\n");
1668 help += utf8_wcstombs(sf->get_credits());
1670 _panel_client.show_help(ic->id, help);
1675 panel_req_show_factory_menu(EcoreIMFContextISF *ic)
1677 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1679 std::vector<IMEngineFactoryPointer> factories;
1680 std::vector <PanelFactoryInfo> menu;
1682 _backend->get_factories_for_encoding(factories, "UTF-8");
1684 for (size_t i = 0; i < factories.size(); ++ i)
1686 menu.push_back(PanelFactoryInfo(
1687 factories [i]->get_uuid(),
1688 utf8_wcstombs(factories [i]->get_name()),
1689 factories [i]->get_language(),
1690 factories [i]->get_icon_file()));
1694 _panel_client.show_factory_menu(ic->id, menu);
1698 panel_req_update_factory_info(EcoreIMFContextISF *ic)
1700 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1702 if (ic && ic->impl && ic == _focused_ic)
1704 PanelFactoryInfo info;
1705 if (ic->impl->is_on)
1707 IMEngineFactoryPointer sf = _backend->get_factory(ic->impl->si->get_factory_uuid());
1709 info = PanelFactoryInfo(sf->get_uuid(), utf8_wcstombs(sf->get_name()), sf->get_language(), sf->get_icon_file());
1713 info = PanelFactoryInfo(String(""), String("English/Keyboard"), String("C"), "");
1715 _panel_client.update_factory_info(ic->id, info);
1720 panel_req_focus_in(EcoreIMFContextISF *ic)
1722 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1724 _panel_client.focus_in(ic->id, ic->impl->si->get_factory_uuid());
1728 panel_req_update_spot_location(EcoreIMFContextISF *ic)
1730 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1732 _panel_client.update_spot_location(ic->id, ic->impl->cursor_x, ic->impl->cursor_y);
1736 filter_hotkeys(EcoreIMFContextISF *ic, const KeyEvent &key)
1738 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1742 _frontend_hotkey_matcher.push_key_event(key);
1743 _imengine_hotkey_matcher.push_key_event(key);
1745 FrontEndHotkeyAction hotkey_action = _frontend_hotkey_matcher.get_match_result();
1747 if (hotkey_action == SCIM_FRONTEND_HOTKEY_TRIGGER)
1749 if (!ic->impl->is_on)
1755 else if (hotkey_action == SCIM_FRONTEND_HOTKEY_ON)
1757 if (!ic->impl->is_on)
1761 else if (hotkey_action == SCIM_FRONTEND_HOTKEY_OFF)
1763 if (ic->impl->is_on)
1767 else if (hotkey_action == SCIM_FRONTEND_HOTKEY_NEXT_FACTORY)
1769 open_next_factory(ic);
1772 else if (hotkey_action == SCIM_FRONTEND_HOTKEY_PREVIOUS_FACTORY)
1774 open_previous_factory(ic);
1777 else if (hotkey_action == SCIM_FRONTEND_HOTKEY_SHOW_FACTORY_MENU)
1779 panel_req_show_factory_menu(ic);
1782 else if (_imengine_hotkey_matcher.is_matched())
1784 String sfid = _imengine_hotkey_matcher.get_match_result();
1785 open_specific_factory(ic, sfid);
1792 panel_initialize(void)
1794 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1796 String display_name;
1798 const char *p = getenv("DISPLAY");
1799 if (p) display_name = String(p);
1802 if (_panel_client.open_connection(_config->get_name(), display_name) >= 0)
1804 int fd = _panel_client.get_connection_number();
1806 _panel_iochannel_read_handler = ecore_main_fd_handler_add(fd, ECORE_FD_READ, panel_iochannel_handler, NULL, NULL, NULL);
1808 SCIM_DEBUG_FRONTEND(2) << " Panel FD= " << fd << "\n";
1812 std::cerr << "panel_initialize() failed!!!\n";
1817 panel_finalize(void)
1819 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1821 _panel_client.close_connection();
1823 if (_panel_iochannel_read_handler)
1825 ecore_main_fd_handler_del(_panel_iochannel_read_handler);
1826 _panel_iochannel_read_handler = 0;
1829 if (_panel_iochannel_err_handler)
1831 ecore_main_fd_handler_del(_panel_iochannel_err_handler);
1832 _panel_iochannel_err_handler = 0;
1837 panel_iochannel_handler(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler)
1839 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1841 if (fd_handler == _panel_iochannel_read_handler)
1843 if (!_panel_client.filter_event())
1847 return ECORE_CALLBACK_CANCEL;
1850 else if (fd_handler == _panel_iochannel_err_handler)
1854 return ECORE_CALLBACK_CANCEL;
1856 return ECORE_CALLBACK_RENEW;
1860 turn_on_ic(EcoreIMFContextISF *ic)
1862 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1864 if (ic && ic->impl && !ic->impl->is_on)
1866 ic->impl->is_on = true;
1868 if (ic == _focused_ic)
1870 panel_req_focus_in(ic);
1871 panel_req_update_spot_location(ic);
1872 panel_req_update_factory_info(ic);
1873 _panel_client.turn_on(ic->id);
1874 _panel_client.hide_preedit_string(ic->id);
1875 _panel_client.hide_aux_string(ic->id);
1876 _panel_client.hide_lookup_table(ic->id);
1877 ic->impl->si->focus_in();
1880 //Record the IC on/off status
1881 if (_shared_input_method)
1882 _config->write(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), true);
1884 if (ic->impl->use_preedit && ic->impl->preedit_string.length())
1886 ecore_imf_context_preedit_start_event_add(ic->ctx);
1887 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
1888 ecore_imf_context_preedit_changed_event_add(ic->ctx);
1889 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1890 ic->impl->preedit_started = true;
1896 turn_off_ic(EcoreIMFContextISF *ic)
1898 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1900 if (ic && ic->impl && ic->impl->is_on)
1902 ic->impl->is_on = false;
1904 if (ic == _focused_ic)
1906 ic->impl->si->focus_out();
1908 panel_req_update_factory_info(ic);
1909 _panel_client.turn_off(ic->id);
1912 //Record the IC on/off status
1913 if (_shared_input_method)
1914 _config->write(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), false);
1916 if (ic->impl->use_preedit && ic->impl->preedit_string.length())
1918 ecore_imf_context_preedit_changed_event_add(ic->ctx);
1919 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1920 ecore_imf_context_preedit_end_event_add(ic->ctx);
1921 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
1922 ic->impl->preedit_started = false;
1928 set_ic_capabilities(EcoreIMFContextISF *ic)
1930 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1934 unsigned int cap = SCIM_CLIENT_CAP_ALL_CAPABILITIES;
1936 if (!_on_the_spot || !ic->impl->use_preedit)
1937 cap -= SCIM_CLIENT_CAP_ONTHESPOT_PREEDIT;
1939 ic->impl->si->update_client_capabilities(cap);
1944 check_socket_frontend(void)
1946 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1948 SocketAddress address;
1949 SocketClient client;
1953 address.set_address(scim_get_default_socket_frontend_address());
1955 if (!client.connect(address))
1958 if (!scim_socket_open_connection(magic,
1959 String("ConnectionTester"),
1960 String("SocketFrontEnd"),
1971 std::vector<String> config_list;
1972 std::vector<String> engine_list;
1973 std::vector<String> load_engine_list;
1975 std::vector<String>::iterator it;
1977 bool manual = false;
1981 String config_module_name = "simple";
1983 printf("Initializing Ecore SCIM IMModule...\n");
1985 SCIM_DEBUG_FRONTEND(1) << "Initializing Ecore SCIM IMModule...\n";
1987 // Get system language.
1988 _language = scim_get_locale_language(scim_get_current_locale());
1992 // If no Socket FrontEnd is running, then launch one.
1993 // And set manual to false.
1994 bool check_result = check_socket_frontend();
1997 std::cerr << "Launching a SCIM daemon with Socket FrontEnd...\n";
1999 scim_get_imengine_module_list(engine_list);
2001 for (it = engine_list.begin(); it != engine_list.end(); it++)
2003 if (*it != "socket")
2004 load_engine_list.push_back(*it);
2007 const char *new_argv [] = { "--no-stay", 0 };
2010 (load_engine_list.size() ? scim_combine_string_list(load_engine_list, ',') : "none"),
2016 // If there is one Socket FrontEnd running and it's not manual mode,
2017 // then just use this Socket Frontend.
2020 for (int i = 0; i < 200; ++i)
2024 config_module_name = "socket";
2025 load_engine_list.clear();
2026 load_engine_list.push_back("socket");
2030 check_result = check_socket_frontend();
2035 if (config_module_name != "dummy")
2037 //load config module
2038 SCIM_DEBUG_FRONTEND(1) << "Loading Config module: " << config_module_name << "...\n";
2039 _config_module = new ConfigModule(config_module_name);
2041 //create config instance
2042 if (_config_module != NULL && _config_module->valid())
2043 _config = _config_module->create_config();
2048 SCIM_DEBUG_FRONTEND(1) << "Config module cannot be loaded, using dummy Config.\n";
2050 if (_config_module) delete _config_module;
2051 _config_module = NULL;
2053 _config = new DummyConfig();
2054 config_module_name = "dummy";
2057 reload_config_callback(_config);
2058 _config->signal_connect_reload(slot(reload_config_callback));
2061 _backend = new CommonBackEnd(_config, load_engine_list.size() ? load_engine_list : engine_list);
2063 if (_backend.null())
2064 std::cerr << "Cannot create BackEnd Object!\n";
2066 _fallback_factory = _backend->get_factory(SCIM_COMPOSE_KEY_FACTORY_UUID);
2068 if (_fallback_factory.null())
2069 _fallback_factory = new DummyIMEngineFactory();
2071 _fallback_instance = _fallback_factory->create_instance(String("UTF-8"), 0);
2072 _fallback_instance->signal_connect_commit_string(slot(fallback_commit_string_cb));
2074 // Attach Panel Client signal.
2075 _panel_client.signal_connect_reload_config (slot(panel_slot_reload_config));
2076 _panel_client.signal_connect_exit (slot(panel_slot_exit));
2077 _panel_client.signal_connect_update_lookup_table_page_size(slot(panel_slot_update_lookup_table_page_size));
2078 _panel_client.signal_connect_lookup_table_page_up (slot(panel_slot_lookup_table_page_up));
2079 _panel_client.signal_connect_lookup_table_page_down (slot(panel_slot_lookup_table_page_down));
2080 _panel_client.signal_connect_trigger_property (slot(panel_slot_trigger_property));
2081 _panel_client.signal_connect_process_helper_event (slot(panel_slot_process_helper_event));
2082 _panel_client.signal_connect_move_preedit_caret (slot(panel_slot_move_preedit_caret));
2083 _panel_client.signal_connect_select_candidate (slot(panel_slot_select_candidate));
2084 _panel_client.signal_connect_process_key_event (slot(panel_slot_process_key_event));
2085 _panel_client.signal_connect_commit_string (slot(panel_slot_commit_string));
2086 _panel_client.signal_connect_forward_key_event (slot(panel_slot_forward_key_event));
2087 _panel_client.signal_connect_request_help (slot(panel_slot_request_help));
2088 _panel_client.signal_connect_request_factory_menu (slot(panel_slot_request_factory_menu));
2089 _panel_client.signal_connect_change_factory (slot(panel_slot_change_factory));
2091 if (!panel_initialize())
2092 std::cerr << "Ecore IM Module: Cannot connect to Panel!\n";
2098 SCIM_DEBUG_FRONTEND(1) << "Finalizing Ecore ISF IMModule...\n";
2100 // Reset this first so that the shared instance could be released correctly afterwards.
2101 _default_instance.reset();
2103 SCIM_DEBUG_FRONTEND(2) << "Finalize all IC partially.\n";
2104 while (_used_ic_impl_list)
2106 // In case in "shared input method" mode,
2107 // all contexts share only one instance,
2108 // so we need point the reference pointer correctly before finalizing.
2109 _used_ic_impl_list->si->set_frontend_data(static_cast <void*>(_used_ic_impl_list->parent));
2110 isf_imf_context_del(_used_ic_impl_list->parent->ctx);
2113 delete_all_ic_impl();
2115 _fallback_instance.reset();
2116 _fallback_factory.reset();
2118 SCIM_DEBUG_FRONTEND(2) << " Releasing BackEnd...\n";
2121 SCIM_DEBUG_FRONTEND(2) << " Releasing Config...\n";
2126 SCIM_DEBUG_FRONTEND(2) << " Deleting _config_module...\n";
2127 delete _config_module;
2134 _scim_initialized = false;
2140 open_next_factory(EcoreIMFContextISF *ic)
2142 SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n";
2143 IMEngineFactoryPointer sf = _backend->get_next_factory("", "UTF-8", ic->impl->si->get_factory_uuid());
2148 ic->impl->si = sf->create_instance("UTF-8", ic->impl->si->get_id());
2149 ic->impl->si->set_frontend_data(static_cast <void*>(ic));
2150 ic->impl->preedit_string = WideString();
2151 ic->impl->preedit_caret = 0;
2152 attach_instance(ic->impl->si);
2153 _backend->set_default_factory(_language, sf->get_uuid());
2154 _panel_client.register_input_context(ic->id, sf->get_uuid());
2155 set_ic_capabilities(ic);
2158 if (_shared_input_method)
2160 _default_instance = ic->impl->si;
2161 ic->impl->shared_si = true;
2167 open_previous_factory(EcoreIMFContextISF *ic)
2172 SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n";
2173 IMEngineFactoryPointer sf = _backend->get_previous_factory("", "UTF-8", ic->impl->si->get_factory_uuid());
2178 ic->impl->si = sf->create_instance("UTF-8", ic->impl->si->get_id());
2179 ic->impl->si->set_frontend_data(static_cast <void*>(ic));
2180 ic->impl->preedit_string = WideString();
2181 ic->impl->preedit_caret = 0;
2182 attach_instance(ic->impl->si);
2183 _backend->set_default_factory(_language, sf->get_uuid());
2184 _panel_client.register_input_context(ic->id, sf->get_uuid());
2185 set_ic_capabilities(ic);
2188 if (_shared_input_method)
2190 _default_instance = ic->impl->si;
2191 ic->impl->shared_si = true;
2197 open_specific_factory(EcoreIMFContextISF *ic,
2203 SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n";
2205 // The same input method is selected, just turn on the IC.
2206 if (ic->impl->si->get_factory_uuid() == uuid)
2212 IMEngineFactoryPointer sf = _backend->get_factory(uuid);
2214 if (uuid.length() && !sf.null())
2217 ic->impl->si = sf->create_instance("UTF-8", ic->impl->si->get_id());
2218 ic->impl->si->set_frontend_data(static_cast <void*>(ic));
2219 ic->impl->preedit_string = WideString();
2220 ic->impl->preedit_caret = 0;
2221 attach_instance(ic->impl->si);
2222 _backend->set_default_factory(_language, sf->get_uuid());
2223 _panel_client.register_input_context(ic->id, sf->get_uuid());
2224 set_ic_capabilities(ic);
2227 if (_shared_input_method)
2229 _default_instance = ic->impl->si;
2230 ic->impl->shared_si = true;
2235 // turn_off_ic comment out panel_req_update_factory_info()
2237 if (ic && ic->impl->is_on)
2239 ic->impl->is_on = false;
2241 if (ic == _focused_ic)
2243 ic->impl->si->focus_out();
2245 panel_req_update_factory_info(ic);
2246 _panel_client.turn_off(ic->id);
2249 //Record the IC on/off status
2250 if (_shared_input_method)
2251 _config->write(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), false);
2253 if (ic->impl->use_preedit && ic->impl->preedit_string.length())
2255 ecore_imf_context_preedit_changed_event_add(ic->ctx);
2256 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
2257 ecore_imf_context_preedit_end_event_add(ic->ctx);
2258 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
2259 ic->impl->preedit_started = false;
2265 static void initialize_modifier_bits(Display *display)
2267 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2269 if (__current_display == display)
2272 __current_display = display;
2276 __current_alt_mask = Mod1Mask;
2277 __current_meta_mask = ShiftMask | Mod1Mask;
2278 __current_super_mask = 0;
2279 __current_hyper_mask = 0;
2280 __current_numlock_mask = Mod2Mask;
2284 XModifierKeymap *mods = NULL;
2286 ::KeyCode ctrl_l = XKeysymToKeycode(display, XK_Control_L);
2287 ::KeyCode ctrl_r = XKeysymToKeycode(display, XK_Control_R);
2288 ::KeyCode meta_l = XKeysymToKeycode(display, XK_Meta_L);
2289 ::KeyCode meta_r = XKeysymToKeycode(display, XK_Meta_R);
2290 ::KeyCode alt_l = XKeysymToKeycode(display, XK_Alt_L);
2291 ::KeyCode alt_r = XKeysymToKeycode(display, XK_Alt_R);
2292 ::KeyCode super_l = XKeysymToKeycode(display, XK_Super_L);
2293 ::KeyCode super_r = XKeysymToKeycode(display, XK_Super_R);
2294 ::KeyCode hyper_l = XKeysymToKeycode(display, XK_Hyper_L);
2295 ::KeyCode hyper_r = XKeysymToKeycode(display, XK_Hyper_R);
2296 ::KeyCode numlock = XKeysymToKeycode(display, XK_Num_Lock);
2300 mods = XGetModifierMapping(display);
2304 __current_alt_mask = 0;
2305 __current_meta_mask = 0;
2306 __current_super_mask = 0;
2307 __current_hyper_mask = 0;
2308 __current_numlock_mask = 0;
2310 /* We skip the first three sets for Shift, Lock, and Control. The
2311 remaining sets are for Mod1, Mod2, Mod3, Mod4, and Mod5. */
2312 for (i = 3; i < 8; i++)
2314 for (j = 0; j < mods->max_keypermod; j++)
2316 ::KeyCode code = mods->modifiermap [i * mods->max_keypermod + j];
2317 if (! code) continue;
2318 if (code == alt_l || code == alt_r)
2319 __current_alt_mask |= (1 << i);
2320 else if (code == meta_l || code == meta_r)
2321 __current_meta_mask |= (1 << i);
2322 else if (code == super_l || code == super_r)
2323 __current_super_mask |= (1 << i);
2324 else if (code == hyper_l || code == hyper_r)
2325 __current_hyper_mask |= (1 << i);
2326 else if (code == numlock)
2327 __current_numlock_mask |= (1 << i);
2331 /* Check whether there is a combine keys mapped to Meta */
2332 if (__current_meta_mask == 0)
2336 KeySym keysym_l, keysym_r;
2338 xkey.type = KeyPress;
2339 xkey.display = display;
2341 xkey.send_event = False;
2342 xkey.x = xkey.y = xkey.x_root = xkey.y_root = 0;
2344 xkey.same_screen = False;
2345 xkey.subwindow = None;
2347 xkey.root = DefaultRootWindow(display);
2348 xkey.state = ShiftMask;
2350 xkey.keycode = meta_l;
2351 XLookupString(&xkey, buf, 32, &keysym_l, 0);
2352 xkey.keycode = meta_r;
2353 XLookupString(&xkey, buf, 32, &keysym_r, 0);
2355 if ((meta_l == alt_l && keysym_l == XK_Meta_L) || (meta_r == alt_r && keysym_r == XK_Meta_R))
2356 __current_meta_mask = ShiftMask + __current_alt_mask;
2357 else if ((meta_l == ctrl_l && keysym_l == XK_Meta_L) || (meta_r == ctrl_r && keysym_r == XK_Meta_R))
2358 __current_meta_mask = ShiftMask + ControlMask;
2361 XFreeModifiermap(mods);
2364 static unsigned int scim_x11_keymask_scim_to_x11(Display *display, uint16 scimkeymask)
2366 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2368 unsigned int state = 0;
2370 initialize_modifier_bits(display);
2372 if (scimkeymask & SCIM_KEY_ShiftMask) state |= ShiftMask;
2373 if (scimkeymask & SCIM_KEY_CapsLockMask) state |= LockMask;
2374 if (scimkeymask & SCIM_KEY_ControlMask) state |= ControlMask;
2375 if (scimkeymask & SCIM_KEY_AltMask) state |= __current_alt_mask;
2376 if (scimkeymask & SCIM_KEY_MetaMask) state |= __current_meta_mask;
2377 if (scimkeymask & SCIM_KEY_SuperMask) state |= __current_super_mask;
2378 if (scimkeymask & SCIM_KEY_HyperMask) state |= __current_hyper_mask;
2379 if (scimkeymask & SCIM_KEY_NumLockMask) state |= __current_numlock_mask;
2384 static XKeyEvent createKeyEvent(Display *display, Window &win,
2385 Window &winRoot, bool press,
2386 int keycode, int modifiers)
2388 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2392 event.display = display;
2394 event.root = winRoot;
2395 event.subwindow = None;
2396 event.time = CurrentTime;
2401 event.same_screen = EINA_TRUE;
2402 event.state = modifiers;
2403 event.keycode = XKeysymToKeycode(display, keycode);
2405 event.type = KeyPress;
2407 event.type = KeyRelease;
2408 event.send_event = EINA_FALSE;
2414 static void _x_send_key_event(const KeyEvent &key)
2416 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2418 // Obtain the X11 display.
2419 Display *display = XOpenDisplay(NULL);
2420 if (display == NULL)
2422 std::cerr << "XOpenDisplay failed\n";
2426 // Get the root window for the current display.
2429 // Find the window which has the current keyboard focus.
2430 Window winFocus = 0;
2431 int revert = RevertToParent;
2433 XGetInputFocus(display, &winFocus, &revert);
2435 // Send a fake key press event to the window.
2436 XSelectInput(display, winFocus, FocusChangeMask|KeyPressMask|KeyReleaseMask);
2437 XMapWindow(display, winFocus);
2439 unsigned int modifier = scim_x11_keymask_scim_to_x11(display, key.mask);
2441 if (key.is_key_press())
2443 event = createKeyEvent(display, winFocus, winRoot, true, key.code, modifier);
2444 XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event);
2448 event = createKeyEvent(display, winFocus, winRoot, false, key.code, modifier);
2449 XSendEvent(event.display, event.window, True, KeyReleaseMask, (XEvent *)&event);
2452 XCloseDisplay(display);
2456 attach_instance(const IMEngineInstancePointer &si)
2458 si->signal_connect_show_preedit_string(
2459 slot(slot_show_preedit_string));
2460 si->signal_connect_show_aux_string(
2461 slot(slot_show_aux_string));
2462 si->signal_connect_show_lookup_table(
2463 slot(slot_show_lookup_table));
2465 si->signal_connect_hide_preedit_string(
2466 slot(slot_hide_preedit_string));
2467 si->signal_connect_hide_aux_string(
2468 slot(slot_hide_aux_string));
2469 si->signal_connect_hide_lookup_table(
2470 slot(slot_hide_lookup_table));
2472 si->signal_connect_update_preedit_caret(
2473 slot(slot_update_preedit_caret));
2474 si->signal_connect_update_preedit_string(
2475 slot(slot_update_preedit_string));
2476 si->signal_connect_update_aux_string(
2477 slot(slot_update_aux_string));
2478 si->signal_connect_update_lookup_table(
2479 slot(slot_update_lookup_table));
2481 si->signal_connect_commit_string(
2482 slot(slot_commit_string));
2484 si->signal_connect_forward_key_event(
2485 slot(slot_forward_key_event));
2487 si->signal_connect_register_properties(
2488 slot(slot_register_properties));
2490 si->signal_connect_update_property(
2491 slot(slot_update_property));
2493 si->signal_connect_beep(
2496 si->signal_connect_start_helper(
2497 slot(slot_start_helper));
2499 si->signal_connect_stop_helper(
2500 slot(slot_stop_helper));
2502 si->signal_connect_send_helper_event(
2503 slot(slot_send_helper_event));
2505 si->signal_connect_get_surrounding_text(
2506 slot(slot_get_surrounding_text));
2508 si->signal_connect_delete_surrounding_text(
2509 slot(slot_delete_surrounding_text));
2512 // Implementation of slot functions
2514 slot_show_preedit_string(IMEngineInstanceBase *si)
2516 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2518 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2520 if (ic && ic->impl && _focused_ic == ic)
2522 if (ic->impl->use_preedit)
2524 if (!ic->impl->preedit_started)
2526 ecore_imf_context_preedit_start_event_add(_focused_ic->ctx);
2527 ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
2528 ic->impl->preedit_started = true;
2532 _panel_client.show_preedit_string(ic->id);
2537 slot_show_aux_string(IMEngineInstanceBase *si)
2539 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2541 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2543 if (ic && ic->impl && _focused_ic == ic)
2544 _panel_client.show_aux_string(ic->id);
2548 slot_show_lookup_table(IMEngineInstanceBase *si)
2550 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2552 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2554 if (ic && ic->impl && _focused_ic == ic)
2555 _panel_client.show_lookup_table(ic->id);
2559 slot_hide_preedit_string(IMEngineInstanceBase *si)
2561 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2563 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2565 if (ic && ic->impl && _focused_ic == ic)
2568 if (ic->impl->preedit_string.length())
2570 ic->impl->preedit_string = WideString();
2571 ic->impl->preedit_caret = 0;
2572 ic->impl->preedit_attrlist.clear();
2575 if (ic->impl->use_preedit)
2579 ecore_imf_context_preedit_changed_event_add(ic->ctx);
2580 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
2582 if (ic->impl->preedit_started)
2584 ecore_imf_context_preedit_end_event_add(ic->ctx);
2585 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
2586 ic->impl->preedit_started = false;
2590 _panel_client.hide_preedit_string(ic->id);
2595 slot_hide_aux_string(IMEngineInstanceBase *si)
2597 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2599 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2601 if (ic && ic->impl && _focused_ic == ic)
2602 _panel_client.hide_aux_string(ic->id);
2606 slot_hide_lookup_table(IMEngineInstanceBase *si)
2608 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2610 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2612 if (ic && ic->impl && _focused_ic == ic)
2613 _panel_client.hide_lookup_table(ic->id);
2617 slot_update_preedit_caret(IMEngineInstanceBase *si, int caret)
2619 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2621 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2623 if (ic && ic->impl && _focused_ic == ic && ic->impl->preedit_caret != caret)
2625 ic->impl->preedit_caret = caret;
2626 if (ic->impl->use_preedit)
2628 if (!ic->impl->preedit_started)
2630 ecore_imf_context_preedit_start_event_add(ic->ctx);
2631 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
2632 ic->impl->preedit_started = true;
2634 ecore_imf_context_preedit_changed_event_add(ic->ctx);
2635 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
2638 _panel_client.update_preedit_caret(ic->id, caret);
2643 slot_update_preedit_string(IMEngineInstanceBase *si,
2644 const WideString & str,
2645 const AttributeList & attrs)
2647 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2649 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2651 if (ic && ic->impl && _focused_ic == ic && (ic->impl->preedit_string != str || str.length()))
2653 ic->impl->preedit_string = str;
2654 ic->impl->preedit_attrlist = attrs;
2655 if (ic->impl->use_preedit)
2657 if (!ic->impl->preedit_started)
2659 ecore_imf_context_preedit_start_event_add(_focused_ic->ctx);
2660 ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
2661 ic->impl->preedit_started = true;
2663 ic->impl->preedit_caret = str.length();
2664 ic->impl->preedit_updating = true;
2665 ecore_imf_context_preedit_changed_event_add(ic->ctx);
2666 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
2667 ic->impl->preedit_updating = false;
2671 _panel_client.update_preedit_string(ic->id, str, attrs);
2677 slot_update_aux_string(IMEngineInstanceBase *si,
2678 const WideString & str,
2679 const AttributeList & attrs)
2681 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2683 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2685 if (ic && ic->impl && _focused_ic == ic)
2686 _panel_client.update_aux_string(ic->id, str, attrs);
2690 slot_commit_string(IMEngineInstanceBase *si,
2691 const WideString & str)
2693 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2695 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2699 ecore_imf_context_commit_event_add(ic->ctx, utf8_wcstombs(str).c_str());
2700 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(str).c_str());
2705 slot_forward_key_event(IMEngineInstanceBase *si,
2706 const KeyEvent & key)
2708 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2710 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2712 if (ic && _focused_ic == ic)
2714 if (!_fallback_instance->process_key_event(key))
2715 _x_send_key_event(key);
2720 slot_update_lookup_table(IMEngineInstanceBase *si,
2721 const LookupTable & table)
2723 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2725 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2727 if (ic && ic->impl && _focused_ic == ic)
2728 _panel_client.update_lookup_table(ic->id, table);
2732 slot_register_properties(IMEngineInstanceBase *si,
2733 const PropertyList & properties)
2735 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2737 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2739 if (ic && ic->impl && _focused_ic == ic)
2740 _panel_client.register_properties(ic->id, properties);
2744 slot_update_property(IMEngineInstanceBase *si,
2745 const Property & property)
2747 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2749 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2751 if (ic && ic->impl && _focused_ic == ic)
2752 _panel_client.update_property(ic->id, property);
2756 slot_beep(IMEngineInstanceBase *si __UNUSED__)
2758 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2762 slot_start_helper(IMEngineInstanceBase *si,
2763 const String &helper_uuid)
2765 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2767 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context="
2768 << (ic ? ic->id : -1) << " ic=" << ic
2769 << " ic-uuid=" << ((ic ) ? ic->impl->si->get_factory_uuid() : "") << "...\n";
2772 _panel_client.start_helper(ic->id, helper_uuid);
2776 slot_stop_helper(IMEngineInstanceBase *si,
2777 const String &helper_uuid)
2779 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2781 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context=" << (ic ? ic->id : -1) << " ic=" << ic << "...\n";
2784 _panel_client.stop_helper(ic->id, helper_uuid);
2788 slot_send_helper_event(IMEngineInstanceBase *si,
2789 const String &helper_uuid,
2790 const Transaction &trans)
2792 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2794 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context="
2795 << (ic ? ic->id : -1) << " ic=" << ic
2796 << " ic-uuid=" << ((ic) ? ic->impl->si->get_factory_uuid() : "") << "...\n";
2799 _panel_client.send_helper_event(ic->id, helper_uuid, trans);
2803 slot_get_surrounding_text(IMEngineInstanceBase *si,
2809 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2811 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2813 if (ic && ic->impl && _focused_ic == ic)
2815 char *surrounding = NULL;
2817 if (ecore_imf_context_surrounding_get(_focused_ic->ctx, &surrounding, &cursor_index))
2819 SCIM_DEBUG_FRONTEND(2) << "Surrounding text: " << surrounding <<"\n";
2820 SCIM_DEBUG_FRONTEND(2) << "Cursor Index : " << cursor_index <<"\n";
2821 WideString before(utf8_mbstowcs(String(surrounding, surrounding + cursor_index)));
2822 WideString after(utf8_mbstowcs(String(surrounding + cursor_index)));
2823 if (maxlen_before > 0 && ((unsigned int)maxlen_before) < before.length())
2824 before = WideString(before.begin() + (before.length() - maxlen_before), before.end());
2825 else if (maxlen_before == 0) before = WideString();
2826 if (maxlen_after > 0 && ((unsigned int)maxlen_after) < after.length())
2827 after = WideString(after.begin(), after.begin() + maxlen_after);
2828 else if (maxlen_after == 0) after = WideString();
2829 text = before + after;
2830 cursor = before.length();
2838 slot_delete_surrounding_text(IMEngineInstanceBase *si,
2842 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2844 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2846 if (ic && ic->impl && _focused_ic == ic)
2848 Ecore_IMF_Event_Delete_Surrounding ev;
2849 ev.ctx = _focused_ic->ctx;
2852 ecore_imf_context_delete_surrounding_event_add(_focused_ic->ctx, offset, len);
2853 ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, &ev);
2860 reload_config_callback(const ConfigPointer &config)
2862 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2864 _frontend_hotkey_matcher.load_hotkeys(config);
2865 _imengine_hotkey_matcher.load_hotkeys(config);
2869 scim_string_to_key(key,
2870 config->read(String(SCIM_CONFIG_HOTKEYS_FRONTEND_VALID_KEY_MASK),
2871 String("Shift+Control+Alt+Lock")));
2873 _valid_key_mask = (key.mask > 0)?(key.mask):0xFFFF;
2874 _valid_key_mask |= SCIM_KEY_ReleaseMask;
2875 // Special treatment for two backslash keys on jp106 keyboard.
2876 _valid_key_mask |= SCIM_KEY_QuirkKanaRoMask;
2878 _on_the_spot = config->read(String(SCIM_CONFIG_FRONTEND_ON_THE_SPOT), _on_the_spot);
2879 _shared_input_method = config->read(String(SCIM_CONFIG_FRONTEND_SHARED_INPUT_METHOD), _shared_input_method);
2881 // Get keyboard layout setting
2882 // Flush the global config first, in order to load the new configs from disk.
2883 scim_global_config_flush();
2885 _keyboard_layout = scim_get_default_keyboard_layout();
2889 fallback_commit_string_cb(IMEngineInstanceBase *si __UNUSED__,
2890 const WideString &str)
2892 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2894 if (_focused_ic && _focused_ic->impl)
2896 ecore_imf_context_commit_event_add(_focused_ic->ctx, utf8_wcstombs(str).c_str());
2897 ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(str).c_str());