2 * Ecore example illustrating how to use ecore imf.
5 * gcc -o ecore_imf_example ecore_imf_example.c `pkg-config --cflags --libs ecore evas ecore-evas ecore-imf ecore-imf-evas`
10 #include <Ecore_Evas.h>
11 #include <Ecore_IMF.h>
12 #include <Ecore_IMF_Evas.h>
16 typedef struct _Entry Entry;
22 Evas_Textblock_Style *txt_style;
23 Evas_Textblock_Cursor *cursor;
24 Evas_Textblock_Cursor *preedit_start;
25 Evas_Textblock_Cursor *preedit_end;
26 Ecore_IMF_Context *imf_context;
27 Eina_Bool have_preedit : 1;
30 static void _mouse_up_cb(void *data, Evas *e, Evas_Object *o, void *event_info)
35 evas_object_focus_set(en->rect, EINA_TRUE);
38 static void _entry_focus_in_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
44 ecore_imf_context_focus_in(en->imf_context);
47 static void _entry_focus_out_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
54 ecore_imf_context_reset(en->imf_context);
55 ecore_imf_context_focus_out(en->imf_context);
60 _canvas_focus_in_cb(void *data, Evas *e, void *event_info)
62 Evas_Object *obj = evas_focus_get(e);
64 _entry_focus_in_cb(obj, NULL, NULL, NULL);
68 _canvas_focus_out_cb(void *data, Evas *e, void *event_info)
70 Evas_Object *obj = evas_focus_get(e);
72 _entry_focus_out_cb(obj, NULL, NULL, NULL);
76 _imf_cursor_info_set(Entry *en)
78 Evas_Coord x, y, w, h;
79 Evas_Coord cx, cy, cw, ch; // cursor geometry
80 int cursor_pos; // cursor position in chars (Not bytes)
84 // Get cursor geometry
85 evas_object_geometry_get(en->txt_obj, &x, &y, &w, &h);
86 evas_textblock_cursor_geometry_get(en->cursor, &cx, &cy, &cw, &ch, NULL, EVAS_TEXTBLOCK_CURSOR_BEFORE);
88 // Get cursor position
89 cursor_pos = evas_textblock_cursor_pos_get(en->cursor);
91 ecore_imf_context_cursor_position_set(en->imf_context, cursor_pos);
92 ecore_imf_context_cursor_location_set(en->imf_context, x+cx, y+cy, cw, ch);
95 static void _preedit_del(Entry *en)
97 if (!en || !en->have_preedit) return;
98 if (!en->preedit_start || !en->preedit_end) return;
99 if (!evas_textblock_cursor_compare(en->preedit_start, en->preedit_end)) return;
101 /* delete the preedit characters */
102 evas_textblock_cursor_range_delete(en->preedit_start, en->preedit_end);
106 _preedit_clear(Entry *en)
108 if (en->preedit_start)
110 evas_textblock_cursor_free(en->preedit_start);
111 en->preedit_start = NULL;
116 evas_textblock_cursor_free(en->preedit_end);
117 en->preedit_end = NULL;
120 en->have_preedit = EINA_FALSE;
124 _ecore_imf_retrieve_surrounding_cb(void *data, Ecore_IMF_Context *ctx, char **text, int *cursor_pos)
126 /* This callback will be called when the Input Method Context module requests the surrounding context. */
132 str = evas_object_textblock_text_markup_get(en->txt_obj);
133 *text = str ? strdup(str) : strdup("");
135 /* Get the current position of cursor */
137 *cursor_pos = evas_textblock_cursor_pos_get(en->cursor);
143 _ecore_imf_event_delete_surrounding_cb(void *data, Ecore_IMF_Context *ctx, void *event_info)
145 /* called when the input method needs to delete all or part of the context surrounding the cursor */
147 Ecore_IMF_Event_Delete_Surrounding *ev = event_info;
148 Evas_Textblock_Cursor *del_start, *del_end;
153 cursor_pos = evas_textblock_cursor_pos_get(en->cursor);
155 del_start = evas_object_textblock_cursor_new(en->txt_obj);
156 evas_textblock_cursor_pos_set(del_start, cursor_pos + ev->offset);
158 del_end = evas_object_textblock_cursor_new(en->txt_obj);
159 evas_textblock_cursor_pos_set(del_end, cursor_pos + ev->offset + ev->n_chars);
161 /* implement function to delete character(s) from 'cursor_pos+ev->offset' cursor position to 'cursor_pos + ev->offset + ev->n_chars' */
162 evas_textblock_cursor_range_delete(del_start, del_end);
164 evas_textblock_cursor_free(del_start);
165 evas_textblock_cursor_free(del_end);
168 static void _ecore_imf_event_commit_cb (void *data, Ecore_IMF_Context *ctx, void *event_info)
171 char *commit_str = (char *)event_info;
174 /* Delete preedit string */
178 printf ("commit string : %s\n", commit_str);
180 evas_object_textblock_text_markup_prepend(en->cursor, commit_str);
182 /* Notify cursor information */
183 _imf_cursor_info_set(en);
188 static void _ecore_imf_event_preedit_changed_cb(void *data, Ecore_IMF_Context *ctx, void *event_info)
190 /* example how to get preedit string */
192 char *preedit_string;
194 Eina_List *attrs = NULL;
196 Ecore_IMF_Preedit_Attr *attr;
197 Ecore_IMF_Context * imf_context = ctx;
198 int preedit_start_pos, preedit_end_pos;
200 Eina_Bool preedit_end_state = EINA_FALSE;
204 /* Get preedit string, attributes */
205 ecore_imf_context_preedit_string_with_attributes_get(imf_context, &preedit_string, &attrs, &cursor_pos);
206 printf("preedit string : %s\n", preedit_string);
208 if (!strcmp(preedit_string, ""))
209 preedit_end_state = EINA_TRUE;
214 preedit_start_pos = evas_textblock_cursor_pos_get(en->cursor);
216 /* insert preedit character(s) */
217 if (strlen(preedit_string) > 0)
221 EINA_LIST_FOREACH(attrs, l, attr)
223 if (attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB1) // style type
225 /* apply appropriate style such as underline */
227 else if (attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB2 || attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB3)
229 /* apply appropriate style such as underline */
233 /* insert code to display preedit string in your editor */
234 evas_object_textblock_text_markup_prepend(en->cursor, preedit_string);
238 if (!preedit_end_state)
240 /* set preedit start cursor */
241 if (!en->preedit_start)
242 en->preedit_start = evas_object_textblock_cursor_new(en->txt_obj);
243 evas_textblock_cursor_copy(en->cursor, en->preedit_start);
245 /* set preedit end cursor */
246 if (!en->preedit_end)
247 en->preedit_end = evas_object_textblock_cursor_new(en->txt_obj);
248 evas_textblock_cursor_copy(en->cursor, en->preedit_end);
250 preedit_end_pos = evas_textblock_cursor_pos_get(en->cursor);
252 for (i = 0; i < (preedit_end_pos - preedit_start_pos); i++)
254 evas_textblock_cursor_char_prev(en->preedit_start);
257 en->have_preedit = EINA_TRUE;
259 /* set cursor position */
260 evas_textblock_cursor_pos_set(en->cursor, preedit_start_pos + cursor_pos);
263 /* Notify cursor information */
264 _imf_cursor_info_set(en);
266 EINA_LIST_FREE(attrs, attr) free(attr);
268 free(preedit_string);
272 _key_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
275 Evas_Event_Key_Down *ev = event_info;
276 Eina_Bool control, alt, shift;
278 Eina_Bool cursor_changed;
280 if (!ev->key) return;
284 Ecore_IMF_Event_Key_Down ecore_ev;
285 ecore_imf_evas_event_key_down_wrap(ev, &ecore_ev);
286 if (ecore_imf_context_filter_event(en->imf_context,
287 ECORE_IMF_EVENT_KEY_DOWN,
288 (Ecore_IMF_Event *)&ecore_ev))
292 control = evas_key_modifier_is_set(ev->modifiers, "Control");
293 alt = evas_key_modifier_is_set(ev->modifiers, "Alt");
294 shift = evas_key_modifier_is_set(ev->modifiers, "Shift");
296 if ((!strcmp(ev->keyname, "Escape")) ||
297 (!strcmp(ev->keyname, "Return")) || (!strcmp(ev->keyname, "KP_Enter")))
298 ecore_imf_context_reset(en->imf_context);
300 if (!strcmp(ev->key, "BackSpace"))
302 if (evas_textblock_cursor_char_prev(en->cursor))
303 evas_textblock_cursor_char_delete(en->cursor);
307 else if (!strcmp(ev->key, "Delete") ||
308 (!strcmp(ev->key, "KP_Delete") && !ev->string))
312 else if ((control) && (!strcmp(ev->key, "v")))
317 else if ((control) && (!strcmp(ev->key, "a")))
322 else if ((control) && (!strcmp(ev->key, "A")))
327 else if ((control) && ((!strcmp(ev->key, "c") || (!strcmp(ev->key, "Insert")))))
332 else if ((control) && ((!strcmp(ev->key, "x") || (!strcmp(ev->key, "m")))))
337 else if ((control) && (!strcmp(ev->key, "z")))
342 else if ((control) && (!strcmp(ev->key, "y")))
347 else if ((!strcmp(ev->key, "Return")) || (!strcmp(ev->key, "KP_Enter")))
354 printf("key down string : %s\n", ev->string);
355 evas_object_textblock_text_markup_prepend(en->cursor, ev->string);
359 /* Notify cursor information */
360 _imf_cursor_info_set(en);
364 _key_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
367 Evas_Event_Key_Up *ev = event_info;
373 Ecore_IMF_Event_Key_Up ecore_ev;
375 ecore_imf_evas_event_key_up_wrap(ev, &ecore_ev);
376 if (ecore_imf_context_filter_event(en->imf_context,
377 ECORE_IMF_EVENT_KEY_UP,
378 (Ecore_IMF_Event *)&ecore_ev))
384 create_input_field(Evas *evas, Entry *en, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
388 /* Create background for text input field */
389 en->rect = evas_object_rectangle_add(evas);
390 evas_object_color_set(en->rect, 150, 150, 150, 255); /* gray */
391 evas_object_move(en->rect, x, y);
392 evas_object_resize(en->rect, w, h);
393 evas_object_show(en->rect);
395 /* Create text object for displaying text */
396 en->txt_obj = evas_object_textblock_add(evas);
397 evas_object_color_set(en->txt_obj, 0, 0, 0, 255);
398 evas_object_pass_events_set(en->txt_obj, EINA_TRUE);
399 evas_object_move(en->txt_obj, x, y);
400 evas_object_resize(en->txt_obj, w, h);
401 evas_object_show(en->txt_obj);
403 /* Set style on textblock */
404 static const char *style_buf =
405 "DEFAULT='font=Sans font_size=30 color=#000 text_class=entry'"
407 "b='+ font=Sans:style=bold'";
408 en->txt_style = evas_textblock_style_new();
409 evas_textblock_style_set(en->txt_style, style_buf);
410 evas_object_textblock_style_set(en->txt_obj, en->txt_style);
413 en->cursor = evas_object_textblock_cursor_new(en->txt_obj);
415 /* Create input context */
416 const char* default_id = ecore_imf_context_default_id_get();
420 en->imf_context = ecore_imf_context_add(default_id);
421 ecore_imf_context_client_window_set(en->imf_context, (void *)ecore_evas_window_get(ecore_evas_ecore_evas_get(evas)));
422 ecore_imf_context_client_canvas_set(en->imf_context, evas);
424 evas_object_event_callback_add(en->rect, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, en);
425 evas_object_event_callback_add(en->rect, EVAS_CALLBACK_KEY_UP, _key_up_cb, en);
426 evas_object_event_callback_add(en->rect, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, en);
427 evas_object_event_callback_add(en->rect, EVAS_CALLBACK_FOCUS_IN, _entry_focus_in_cb, en);
428 evas_object_event_callback_add(en->rect, EVAS_CALLBACK_FOCUS_OUT, _entry_focus_out_cb, en);
430 en->have_preedit = EINA_FALSE;
431 en->preedit_start = NULL;
432 en->preedit_end = NULL;
434 /* register retrieve surrounding callback */
435 ecore_imf_context_retrieve_surrounding_callback_set(en->imf_context, _ecore_imf_retrieve_surrounding_cb, en);
437 /* register commit event callback */
438 ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_COMMIT, _ecore_imf_event_commit_cb, en);
440 /* register preedit changed event handler */
441 ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, _ecore_imf_event_preedit_changed_cb, en);
443 /* register surrounding delete event callback */
444 ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, _ecore_imf_event_delete_surrounding_cb, en);
448 delete_input_field(Entry *en)
454 evas_object_del(en->rect);
460 evas_textblock_cursor_free(en->cursor);
464 if (en->preedit_start)
466 evas_textblock_cursor_free(en->preedit_start);
467 en->preedit_start = NULL;
472 evas_textblock_cursor_free(en->preedit_end);
473 en->preedit_end = NULL;
478 evas_object_del(en->txt_obj);
484 evas_textblock_style_free(en->txt_style);
485 en->txt_style = NULL;
490 ecore_imf_context_del(en->imf_context);
491 en->imf_context = NULL;
495 int main(int argc, char *argv[])
501 if (!ecore_evas_init()) {
502 fprintf(stderr, "failed to call ecore_evas_init()\n");
507 // Create a new window, with size=480x800 and default engine
508 ee = ecore_evas_new(NULL, 0, 0, 480, 800, NULL);
511 fprintf(stderr, "failed to call ecore_evas_new\n");
517 // Get the canvas off just-created window
518 evas = ecore_evas_get(ee);
520 fprintf(stderr, "failed to ccall ecore_evas_get\n");
524 // Create input field rectangle
525 Evas_Object* bg = evas_object_rectangle_add(evas);
526 evas_object_move(bg, 0, 0);
527 evas_object_resize(bg, 480, 800);
528 evas_object_color_set(bg, 255, 255, 255, 255);
529 evas_object_show(bg);
531 evas_event_callback_add(evas, EVAS_CALLBACK_CANVAS_FOCUS_IN, _canvas_focus_in_cb, NULL);
532 evas_event_callback_add(evas, EVAS_CALLBACK_CANVAS_FOCUS_OUT, _canvas_focus_out_cb, NULL);
534 // create input field 1
535 create_input_field(evas, &en1, 40, 60, 400, 80);
537 // create input field 2
538 create_input_field(evas, &en2, 40, 180, 400, 80);
540 // Give focus to input field 1
541 evas_object_focus_set(en1.rect, EINA_TRUE);
543 ecore_main_loop_begin(); // begin mainloop
545 delete_input_field(&en1); // delete input field 1
546 delete_input_field(&en2); // delete input field 2
548 evas_event_callback_del_full(evas, EVAS_CALLBACK_CANVAS_FOCUS_IN, _canvas_focus_in_cb, NULL);
549 evas_event_callback_del_full(evas, EVAS_CALLBACK_CANVAS_FOCUS_OUT, _canvas_focus_out_cb, NULL);
553 ecore_imf_shutdown();
554 ecore_evas_shutdown();