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 eina ecore-evas ecore-imf ecore-imf-evas`
10
#include <Ecore_Evas.h>
12
#include <Ecore_IMF_Evas.h>
19
typedef struct _Entry Entry;
25
Evas_Textblock_Style *txt_style;
26
Evas_Textblock_Cursor *cursor;
27
Evas_Textblock_Cursor *preedit_start;
28
Evas_Textblock_Cursor *preedit_end;
29
Ecore_IMF_Context *imf_context;
30
Eina_Bool have_preedit : 1;
33
static void _imf_cursor_info_set(Entry *en);
36
_mouse_down_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *o EINA_UNUSED, void *event_info)
39
Evas_Event_Mouse_Down *ev = event_info;
44
Ecore_IMF_Event_Mouse_Down ecore_ev;
45
ecore_imf_evas_event_mouse_down_wrap(ev, &ecore_ev);
46
if (ecore_imf_context_filter_event(en->imf_context,
47
ECORE_IMF_EVENT_MOUSE_DOWN,
48
(Ecore_IMF_Event *)&ecore_ev))
51
// ecore_imf_context_reset should be called before calculating new cursor position
52
ecore_imf_context_reset(en->imf_context);
55
// calculate new cursor position
59
_mouse_up_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *o EINA_UNUSED, void *event_info)
62
Evas_Event_Mouse_Up *ev = event_info;
65
if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
67
_imf_cursor_info_set(en);
73
Ecore_IMF_Event_Mouse_Up ecore_ev;
74
ecore_imf_evas_event_mouse_up_wrap(ev, &ecore_ev);
75
if (ecore_imf_context_filter_event(en->imf_context,
76
ECORE_IMF_EVENT_MOUSE_UP,
77
(Ecore_IMF_Event *)&ecore_ev))
83
if (evas_object_focus_get(en->rect))
85
// notify cursor information
86
_imf_cursor_info_set(en);
89
evas_object_focus_set(en->rect, EINA_TRUE);
94
_entry_focus_in_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *o EINA_UNUSED, void *event_info EINA_UNUSED)
100
ecore_imf_context_focus_in(en->imf_context);
102
// notify the cursor information
103
_imf_cursor_info_set(en);
107
_entry_focus_out_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *o EINA_UNUSED, void *event_info EINA_UNUSED)
114
// ecore_imf_context_reset should be called for flushing the preedit string in focus-out event handler
115
ecore_imf_context_reset(en->imf_context);
116
ecore_imf_context_focus_out(en->imf_context);
121
_canvas_focus_in_cb(void *data EINA_UNUSED, Evas *e, void *event_info EINA_UNUSED)
124
Evas_Object *obj = evas_focus_get(e);
127
en = evas_object_data_get(obj, "Entry");
129
_entry_focus_in_cb(en, NULL, NULL, NULL);
133
_canvas_focus_out_cb(void *data EINA_UNUSED, Evas *e, void *event_info EINA_UNUSED)
136
Evas_Object *obj = evas_focus_get(e);
139
en = evas_object_data_get(obj, "Entry");
141
_entry_focus_out_cb(en, NULL, NULL, NULL);
145
_imf_cursor_info_set(Entry *en)
147
Evas_Coord x, y, w, h;
148
Evas_Coord cx, cy, cw, ch; // cursor geometry
149
int cursor_pos; // cursor position in chars (Not bytes)
150
Evas_BiDi_Direction dir;
154
// get cursor geometry
156
evas_object_geometry_get(en->txt_obj, &x, &y, &w, &h);
158
if (en->cursor && en->imf_context)
160
evas_textblock_cursor_geometry_get(en->cursor, &cx, &cy, &cw, &ch, &dir, EVAS_TEXTBLOCK_CURSOR_BEFORE);
162
// get cursor position
163
cursor_pos = evas_textblock_cursor_pos_get(en->cursor);
165
ecore_imf_context_cursor_position_set(en->imf_context, cursor_pos);
166
ecore_imf_context_cursor_location_set(en->imf_context, x + cx, y + cy, cw, ch);
167
ecore_imf_context_bidi_direction_set(en->imf_context, (Ecore_IMF_BiDi_Direction)dir);
172
_preedit_del(Entry *en)
174
if (!en || !en->have_preedit) return;
175
if (!en->preedit_start || !en->preedit_end) return;
176
if (!evas_textblock_cursor_compare(en->preedit_start, en->preedit_end)) return;
178
// delete the preedit characters
179
evas_textblock_cursor_range_delete(en->preedit_start, en->preedit_end);
183
_preedit_clear(Entry *en)
185
if (en->preedit_start)
187
evas_textblock_cursor_free(en->preedit_start);
188
en->preedit_start = NULL;
193
evas_textblock_cursor_free(en->preedit_end);
194
en->preedit_end = NULL;
197
en->have_preedit = EINA_FALSE;
201
_ecore_imf_retrieve_surrounding_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, char **text, int *cursor_pos)
203
// This callback will be called when the Input Method Context module requests the surrounding context.
207
if (!en) return EINA_FALSE;
209
str = evas_object_textblock_text_markup_get(en->txt_obj);
212
*text = str ? strdup(str) : strdup("");
214
// get the current position of cursor
215
if (cursor_pos && en->cursor)
216
*cursor_pos = evas_textblock_cursor_pos_get(en->cursor);
222
_ecore_imf_event_delete_surrounding_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, void *event_info)
224
// called when the input method needs to delete all or part of the context surrounding the cursor
226
Ecore_IMF_Event_Delete_Surrounding *ev = event_info;
227
Evas_Textblock_Cursor *del_start, *del_end;
230
if ((!en) || (!ev) || (!en->cursor)) return;
232
// get the current cursor position
233
cursor_pos = evas_textblock_cursor_pos_get(en->cursor);
235
// start cursor position to be deleted
236
del_start = evas_object_textblock_cursor_new(en->txt_obj);
237
evas_textblock_cursor_pos_set(del_start, cursor_pos + ev->offset);
239
// end cursor position to be deleted
240
del_end = evas_object_textblock_cursor_new(en->txt_obj);
241
evas_textblock_cursor_pos_set(del_end, cursor_pos + ev->offset + ev->n_chars);
243
// implement function to delete character(s) from 'cursor_pos+ev->offset' cursor position to 'cursor_pos + ev->offset + ev->n_chars'
244
evas_textblock_cursor_range_delete(del_start, del_end);
246
evas_textblock_cursor_free(del_start);
247
evas_textblock_cursor_free(del_end);
251
_ecore_imf_event_commit_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, void *event_info)
254
char *commit_str = (char *)event_info;
257
// delete preedit string
261
printf("commit string : %s\n", commit_str);
263
// insert the commit string in the editor
264
if (en->cursor && commit_str)
265
evas_object_textblock_text_markup_prepend(en->cursor, commit_str);
267
// notify the cursor information
268
_imf_cursor_info_set(en);
274
_ecore_imf_event_preedit_changed_cb(void *data, Ecore_IMF_Context *ctx, void *event_info EINA_UNUSED)
276
// example how to get preedit string
278
char *preedit_string;
280
Eina_List *attrs = NULL;
282
Ecore_IMF_Preedit_Attr *attr;
283
Ecore_IMF_Context *imf_context = ctx;
284
int preedit_start_pos, preedit_end_pos;
286
Eina_Bool preedit_end_state = EINA_FALSE;
288
if (!en || !en->cursor) return;
290
// get preedit string and attributes
291
ecore_imf_context_preedit_string_with_attributes_get(imf_context, &preedit_string, &attrs, &cursor_pos);
292
printf("preedit string : %s\n", preedit_string);
294
if (!strcmp(preedit_string, ""))
295
preedit_end_state = EINA_TRUE;
300
preedit_start_pos = evas_textblock_cursor_pos_get(en->cursor);
302
// insert preedit character(s)
303
if (strlen(preedit_string) > 0)
307
EINA_LIST_FOREACH(attrs, l, attr)
309
if (attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB1) // style type
311
// apply appropriate style such as underline
313
else if (attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB2 || attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB3)
315
// apply appropriate style such as underline
319
// insert code to display preedit string in your editor
320
evas_object_textblock_text_markup_prepend(en->cursor, preedit_string);
324
if (!preedit_end_state)
326
// set preedit start cursor
327
if (!en->preedit_start)
328
en->preedit_start = evas_object_textblock_cursor_new(en->txt_obj);
329
evas_textblock_cursor_copy(en->cursor, en->preedit_start);
331
// set preedit end cursor
332
if (!en->preedit_end)
333
en->preedit_end = evas_object_textblock_cursor_new(en->txt_obj);
334
evas_textblock_cursor_copy(en->cursor, en->preedit_end);
336
preedit_end_pos = evas_textblock_cursor_pos_get(en->cursor);
338
for (i = 0; i < (preedit_end_pos - preedit_start_pos); i++)
340
evas_textblock_cursor_char_prev(en->preedit_start);
343
en->have_preedit = EINA_TRUE;
345
// set cursor position
346
evas_textblock_cursor_pos_set(en->cursor, preedit_start_pos + cursor_pos);
349
// notify the cursor information
350
_imf_cursor_info_set(en);
352
EINA_LIST_FREE(attrs, attr)
355
free(preedit_string);
359
_key_down_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *o EINA_UNUSED, void *event_info)
362
Evas_Event_Key_Down *ev = event_info;
363
Eina_Bool control, alt, shift;
364
if ((!en) || (!ev->key) || (!en->cursor)) return;
368
Ecore_IMF_Event_Key_Down ecore_ev;
369
ecore_imf_evas_event_key_down_wrap(ev, &ecore_ev);
370
if (ecore_imf_context_filter_event(en->imf_context,
371
ECORE_IMF_EVENT_KEY_DOWN,
372
(Ecore_IMF_Event *)&ecore_ev))
376
control = evas_key_modifier_is_set(ev->modifiers, "Control");
377
alt = evas_key_modifier_is_set(ev->modifiers, "Alt");
378
shift = evas_key_modifier_is_set(ev->modifiers, "Shift");
382
if (!strcmp(ev->key, "BackSpace"))
384
if (evas_textblock_cursor_char_prev(en->cursor))
386
evas_textblock_cursor_char_delete(en->cursor);
387
// notify the cursor information
388
_imf_cursor_info_set(en);
392
else if (!strcmp(ev->key, "Delete") ||
393
(!strcmp(ev->key, "KP_Delete") && !ev->string))
397
else if ((control) && (!strcmp(ev->key, "v")))
402
else if ((control) && (!strcmp(ev->key, "a")))
407
else if ((control) && (!strcmp(ev->key, "A")))
412
else if ((control) && ((!strcmp(ev->key, "c") || (!strcmp(ev->key, "Insert")))))
417
else if ((control) && ((!strcmp(ev->key, "x") || (!strcmp(ev->key, "m")))))
422
else if ((control) && (!strcmp(ev->key, "z")))
427
else if ((control) && (!strcmp(ev->key, "y")))
432
else if ((!strcmp(ev->key, "Return")) || (!strcmp(ev->key, "KP_Enter")))
440
printf("key down string : %s\n", ev->string);
441
evas_object_textblock_text_markup_prepend(en->cursor, ev->string);
445
// notify the cursor information
446
_imf_cursor_info_set(en);
450
_key_up_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *o EINA_UNUSED, void *event_info)
453
Evas_Event_Key_Up *ev = event_info;
459
Ecore_IMF_Event_Key_Up ecore_ev;
461
ecore_imf_evas_event_key_up_wrap(ev, &ecore_ev);
462
if (ecore_imf_context_filter_event(en->imf_context,
463
ECORE_IMF_EVENT_KEY_UP,
464
(Ecore_IMF_Event *)&ecore_ev))
470
create_input_field(Evas *evas, Entry *en, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
474
en->have_preedit = EINA_FALSE;
475
en->preedit_start = NULL;
476
en->preedit_end = NULL;
478
// create the background for text input field
479
en->rect = evas_object_rectangle_add(evas);
480
evas_object_color_set(en->rect, 150, 150, 150, 255); // gray color
481
evas_object_move(en->rect, x, y);
482
evas_object_resize(en->rect, w, h);
483
evas_object_show(en->rect);
484
evas_object_data_set(en->rect, "Entry", en);
486
// create text object for displaying text
487
en->txt_obj = evas_object_textblock_add(evas);
488
evas_object_color_set(en->txt_obj, 0, 0, 0, 255);
489
evas_object_pass_events_set(en->txt_obj, EINA_TRUE);
490
evas_object_move(en->txt_obj, x, y);
491
evas_object_resize(en->txt_obj, w, h);
492
evas_object_show(en->txt_obj);
494
// set style on textblock
495
static const char *style_buf =
496
"DEFAULT='font=Sans font_size=30 color=#000 text_class=entry'"
498
"b='+ font=Sans:style=bold'";
499
en->txt_style = evas_textblock_style_new();
500
evas_textblock_style_set(en->txt_style, style_buf);
501
evas_object_textblock_style_set(en->txt_obj, en->txt_style);
504
en->cursor = evas_object_textblock_cursor_new(en->txt_obj);
506
// create input context
507
const char *default_id = ecore_imf_context_default_id_get();
510
fprintf(stderr, "Can't create ecore_imf_context\n");
514
en->imf_context = ecore_imf_context_add(default_id);
515
ecore_imf_context_client_canvas_set(en->imf_context, evas);
517
// register key event handler
518
evas_object_event_callback_add(en->rect, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, en);
519
evas_object_event_callback_add(en->rect, EVAS_CALLBACK_KEY_UP, _key_up_cb, en);
521
// register mouse event handler
522
evas_object_event_callback_add(en->rect, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, en);
523
evas_object_event_callback_add(en->rect, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, en);
525
// register focus event handler
526
evas_object_event_callback_add(en->rect, EVAS_CALLBACK_FOCUS_IN, _entry_focus_in_cb, en);
527
evas_object_event_callback_add(en->rect, EVAS_CALLBACK_FOCUS_OUT, _entry_focus_out_cb, en);
529
// register retrieve surrounding callback
530
ecore_imf_context_retrieve_surrounding_callback_set(en->imf_context, _ecore_imf_retrieve_surrounding_cb, en);
532
// register commit event callback
533
ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_COMMIT, _ecore_imf_event_commit_cb, en);
535
// register preedit changed event handler
536
ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, _ecore_imf_event_preedit_changed_cb, en);
538
// register surrounding delete event callback
539
ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, _ecore_imf_event_delete_surrounding_cb, en);
543
delete_input_field(Entry *en)
549
evas_object_del(en->rect);
555
evas_textblock_cursor_free(en->cursor);
559
if (en->preedit_start)
561
evas_textblock_cursor_free(en->preedit_start);
562
en->preedit_start = NULL;
567
evas_textblock_cursor_free(en->preedit_end);
568
en->preedit_end = NULL;
573
evas_object_del(en->txt_obj);
579
evas_textblock_style_free(en->txt_style);
580
en->txt_style = NULL;
585
ecore_imf_context_del(en->imf_context);
586
en->imf_context = NULL;
597
if (!ecore_evas_init())
599
fprintf(stderr, "failed to call ecore_evas_init()\n");
605
// create a new window, with size=WIDTHxHEIGHT and default engine
606
ee = ecore_evas_new(NULL, 0, 0, WIDTH, HEIGHT, NULL);
610
fprintf(stderr, "failed to call ecore_evas_new\n");
616
// get the canvas off just-created window
617
evas = ecore_evas_get(ee);
620
fprintf(stderr, "failed to call ecore_evas_get\n");
624
// create input field rectangle
625
Evas_Object *bg = evas_object_rectangle_add(evas);
626
evas_object_move(bg, 0, 0);
627
evas_object_resize(bg, WIDTH, HEIGHT);
628
evas_object_color_set(bg, 255, 255, 255, 255);
629
evas_object_show(bg);
631
// register canvas focus in/out event handler
632
evas_event_callback_add(evas, EVAS_CALLBACK_CANVAS_FOCUS_IN, _canvas_focus_in_cb, NULL);
633
evas_event_callback_add(evas, EVAS_CALLBACK_CANVAS_FOCUS_OUT, _canvas_focus_out_cb, NULL);
635
memset(&en1, 0, sizeof(en1));
636
memset(&en2, 0, sizeof(en2));
638
// create input field 1
639
create_input_field(evas, &en1, 40, 60, 400, 80);
641
// create input field 2
642
create_input_field(evas, &en2, 40, 180, 400, 80);
644
// give focus to input field 1
645
evas_object_focus_set(en1.rect, EINA_TRUE);
647
ecore_main_loop_begin(); // begin mainloop
649
delete_input_field(&en1); // delete input field 1
650
delete_input_field(&en2); // delete input field 2
652
evas_event_callback_del_full(evas, EVAS_CALLBACK_CANVAS_FOCUS_IN, _canvas_focus_in_cb, NULL);
653
evas_event_callback_del_full(evas, EVAS_CALLBACK_CANVAS_FOCUS_OUT, _canvas_focus_out_cb, NULL);
657
ecore_imf_shutdown();
658
ecore_evas_shutdown();