Let's ignore shift keys:
[platform/upstream/ibus-hangul.git] / src / engine.c
1 /* vim:set et sts=4: */
2
3 #include <ibus.h>
4 #include <hangul.h>
5 #include <string.h>
6 #include "engine.h"
7
8 typedef struct _IBusHangulEngine IBusHangulEngine;
9 typedef struct _IBusHangulEngineClass IBusHangulEngineClass;
10
11 struct _IBusHangulEngine {
12         IBusEngine parent;
13
14     /* members */
15     HangulInputContext *context;
16     gboolean hangul_mode;
17
18     IBusLookupTable *table;
19     IBusProperty    *hangul_mode_prop;
20     IBusPropList    *prop_list;
21 };
22
23 struct _IBusHangulEngineClass {
24         IBusEngineClass parent;
25 };
26
27 /* functions prototype */
28 static void     ibus_hangul_engine_class_init   (IBusHangulEngineClass  *klass);
29 static void     ibus_hangul_engine_init             (IBusHangulEngine           *hangul);
30 static GObject*
31             ibus_hangul_engine_constructor  (GType                   type,
32                                              guint                   n_construct_params,
33                                              GObjectConstructParam  *construct_params);
34 static void     ibus_hangul_engine_destroy              (IBusHangulEngine               *hangul);
35 static gboolean
36                         ibus_hangul_engine_process_key_event
37                                             (IBusEngine             *engine,
38                                              guint                       keyval,
39                                              guint                       modifiers);
40 static void ibus_hangul_engine_focus_in     (IBusEngine             *engine);
41 static void ibus_hangul_engine_focus_out    (IBusEngine             *engine);
42 static void ibus_hangul_engine_reset        (IBusEngine             *engine);
43 static void ibus_hangul_engine_enable       (IBusEngine             *engine);
44 static void ibus_hangul_engine_disable      (IBusEngine             *engine);
45 #if 0
46 static void ibus_engine_set_cursor_location (IBusEngine             *engine,
47                                              gint                    x,
48                                              gint                    y,
49                                              gint                    w,
50                                              gint                    h);
51 static void ibus_hangul_engine_set_capabilities
52                                             (IBusEngine             *engine,
53                                              guint                   caps);
54 #endif
55 static void ibus_hangul_engine_page_up      (IBusEngine             *engine);
56 static void ibus_hangul_engine_page_down    (IBusEngine             *engine);
57 static void ibus_hangul_engine_cursor_up    (IBusEngine             *engine);
58 static void ibus_hangul_engine_cursor_down  (IBusEngine             *engine);
59 static void ibus_hangul_engine_toggle_hangul_mode
60                                             (IBusHangulEngine       *hangul);
61 #if 0
62 static void ibus_hangul_property_activate   (IBusEngine             *engine,
63                                              const gchar            *prop_name,
64                                              gint                    prop_state);
65 static void ibus_hangul_engine_property_show
66                                                                                         (IBusEngine             *engine,
67                                              const gchar            *prop_name);
68 static void ibus_hangul_engine_property_hide
69                                                                                         (IBusEngine             *engine,
70                                              const gchar            *prop_name);
71 #endif
72
73 static void ibus_hangul_engine_flush        (IBusHangulEngine       *hangul);
74 static void ibus_hangul_engine_update_preedit_text
75                                             (IBusHangulEngine       *hangul);
76
77 static IBusEngineClass *parent_class = NULL;
78
79 GType
80 ibus_hangul_engine_get_type (void)
81 {
82         static GType type = 0;
83
84         static const GTypeInfo type_info = {
85                 sizeof (IBusHangulEngineClass),
86                 (GBaseInitFunc)         NULL,
87                 (GBaseFinalizeFunc) NULL,
88                 (GClassInitFunc)        ibus_hangul_engine_class_init,
89                 NULL,
90                 NULL,
91                 sizeof (IBusHangulEngine),
92                 0,
93                 (GInstanceInitFunc)     ibus_hangul_engine_init,
94         };
95
96         if (type == 0) {
97                 type = g_type_register_static (IBUS_TYPE_ENGINE,
98                                                                            "IBusHangulEngine",
99                                                                            &type_info,
100                                                                            (GTypeFlags) 0);
101         }
102
103         return type;
104 }
105
106 static void
107 ibus_hangul_engine_class_init (IBusHangulEngineClass *klass)
108 {
109     GObjectClass *object_class = G_OBJECT_CLASS (klass);
110         IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
111         IBusEngineClass *engine_class = IBUS_ENGINE_CLASS (klass);
112
113         parent_class = (IBusEngineClass *) g_type_class_peek_parent (klass);
114
115     object_class->constructor = ibus_hangul_engine_constructor;
116         ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_hangul_engine_destroy;
117
118     engine_class->process_key_event = ibus_hangul_engine_process_key_event;
119
120     engine_class->reset = ibus_hangul_engine_reset;
121     engine_class->enable = ibus_hangul_engine_enable;
122     engine_class->disable = ibus_hangul_engine_disable;
123
124     engine_class->focus_in = ibus_hangul_engine_focus_in;
125     engine_class->focus_out = ibus_hangul_engine_focus_out;
126
127     engine_class->page_up = ibus_hangul_engine_page_up;
128     engine_class->page_down = ibus_hangul_engine_page_down;
129
130     engine_class->cursor_up = ibus_hangul_engine_cursor_up;
131     engine_class->cursor_down = ibus_hangul_engine_cursor_down;
132 }
133
134 static void
135 ibus_hangul_engine_init (IBusHangulEngine *hangul)
136 {
137     hangul->context = hangul_ic_new ("2");
138     hangul->hangul_mode = TRUE;
139     hangul->hangul_mode_prop = ibus_property_new ("hangul_mode_prop",
140                                            PROP_TYPE_NORMAL,
141                                            NULL,
142                                            NULL,
143                                            NULL,
144                                            TRUE,
145                                            FALSE,
146                                            0,
147                                            NULL);
148
149     hangul->prop_list = ibus_prop_list_new ();
150     ibus_prop_list_append (hangul->prop_list,  hangul->hangul_mode_prop);
151
152     hangul->table = ibus_lookup_table_new (9, 0, TRUE, TRUE);
153 }
154
155 static GObject*
156 ibus_hangul_engine_constructor (GType                   type,
157                                 guint                   n_construct_params,
158                                 GObjectConstructParam  *construct_params)
159 {
160     IBusHangulEngine *hangul;
161
162     hangul = (IBusHangulEngine *) G_OBJECT_CLASS (parent_class)->constructor (type,
163                                                        n_construct_params,
164                                                        construct_params);
165
166     return (GObject *)hangul;
167 }
168
169
170 static void
171 ibus_hangul_engine_destroy (IBusHangulEngine *hangul)
172 {
173     if (hangul->prop_list) {
174         g_object_unref (hangul->prop_list);
175         hangul->prop_list = NULL;
176     }
177
178     if (hangul->hangul_mode_prop) {
179         g_object_unref (hangul->hangul_mode_prop);
180         hangul->hangul_mode_prop = NULL;
181     }
182
183     if (hangul->table) {
184         g_object_unref (hangul->table);
185         hangul->table = NULL;
186     }
187
188     if (hangul->context) {
189         hangul_ic_delete (hangul->context);
190         hangul->context = NULL;
191     }
192
193         IBUS_OBJECT_CLASS (parent_class)->destroy ((IBusObject *)hangul);
194 }
195
196 static void
197 ibus_hangul_engine_update_preedit_text (IBusHangulEngine *hangul)
198 {
199     const gunichar *str;
200     IBusText *text;
201
202     str = hangul_ic_get_preedit_string (hangul->context);
203
204     if (str != NULL && str[0] != 0) {
205         text = ibus_text_new_from_ucs4 (str);
206         ibus_text_append_attribute (text, IBUS_ATTR_TYPE_FOREGROUND, 0x00ffffff, 0, -1);
207         ibus_text_append_attribute (text, IBUS_ATTR_TYPE_BACKGROUND, 0x00000000, 0, -1);
208         ibus_engine_update_preedit_text ((IBusEngine *)hangul,
209                                          text,
210                                          ibus_text_get_length (text),
211                                          TRUE);
212         g_object_unref (text);
213     }
214     else {
215         text = ibus_text_new_from_static_string ("");
216         ibus_engine_update_preedit_text ((IBusEngine *)hangul, text, 0, FALSE);
217         g_object_unref (text);
218     }
219 }
220
221 static gboolean
222 ibus_hangul_engine_process_key_event (IBusEngine     *engine,
223                                       guint           keyval,
224                                       guint           modifiers)
225 {
226     IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
227
228     gboolean retval;
229     const gunichar *str;
230
231     if (modifiers & IBUS_RELEASE_MASK)
232         return FALSE;
233
234     if (modifiers & (IBUS_CONTROL_MASK | IBUS_MOD1_MASK))
235         return FALSE;
236
237     // if we don't ignore shift keys, shift key will make flush the preedit 
238     // string. So you cannot input shift+key.
239     // Let's think about these examples:
240     //   dlTek (2 set)
241     //   qhRdmaqkq (2 set)
242     if (keyval == IBUS_Shift_L || keyval == IBUS_Shift_R)
243         return FALSE;
244
245     if (keyval == IBUS_BackSpace) {
246         retval = hangul_ic_backspace (hangul->context);
247     } else {
248         retval = hangul_ic_process (hangul->context, keyval);
249     }
250
251     str = hangul_ic_get_commit_string (hangul->context);
252     if (str != NULL && str[0] != 0) {
253         IBusText *text = ibus_text_new_from_ucs4 (str);
254         ibus_engine_commit_text ((IBusEngine *)hangul, text);
255         g_object_unref (text);
256     }
257
258     ibus_hangul_engine_update_preedit_text (hangul);
259
260     if (!retval)
261         ibus_hangul_engine_flush (hangul);
262
263     return retval;
264 }
265
266 static void
267 ibus_hangul_engine_flush (IBusHangulEngine *hangul)
268 {
269     const gunichar *str;
270     IBusText *text;
271
272     str = hangul_ic_flush (hangul->context);
273
274     if (str == NULL || str[0] == 0)
275         return;
276
277     text = ibus_text_new_from_ucs4 (str);
278
279     ibus_engine_hide_preedit_text ((IBusEngine *) hangul);
280     ibus_engine_commit_text ((IBusEngine *) hangul, text);
281
282     g_object_unref (text);
283 }
284
285 static void
286 ibus_hangul_engine_toggle_hangul_mode (IBusHangulEngine *hangul)
287 {
288     IBusText *text;
289     hangul->hangul_mode = ! hangul->hangul_mode;
290
291     ibus_hangul_engine_flush (hangul);
292
293     if (hangul->hangul_mode) {
294         text = ibus_text_new_from_static_string ("한");
295     }
296     else {
297         text = ibus_text_new_from_static_string ("A");
298     }
299
300     ibus_property_set_label (hangul->hangul_mode_prop, text);
301     ibus_engine_update_property ((IBusEngine *)hangul, hangul->hangul_mode_prop);
302     g_object_unref (text);
303 }
304
305 static void
306 ibus_hangul_engine_focus_in (IBusEngine *engine)
307 {
308     IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
309
310     ibus_engine_register_properties (engine, hangul->prop_list);
311
312     parent_class->focus_in (engine);
313 }
314
315 static void
316 ibus_hangul_engine_focus_out (IBusEngine *engine)
317 {
318     IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
319
320     ibus_hangul_engine_flush (hangul);
321
322     parent_class->focus_out ((IBusEngine *) hangul);
323 }
324
325 static void
326 ibus_hangul_engine_reset (IBusEngine *engine)
327 {
328     IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
329
330     ibus_hangul_engine_flush (hangul);
331     parent_class->reset (engine);
332 }
333
334 static void
335 ibus_hangul_engine_enable (IBusEngine *engine)
336 {
337     parent_class->enable (engine);
338 }
339
340 static void
341 ibus_hangul_engine_disable (IBusEngine *engine)
342 {
343     ibus_hangul_engine_focus_out (engine);
344     parent_class->disable (engine);
345 }
346
347 static void
348 ibus_hangul_engine_page_up (IBusEngine *engine)
349 {
350     parent_class->page_up (engine);
351 }
352
353 static void
354 ibus_hangul_engine_page_down (IBusEngine *engine)
355 {
356     parent_class->page_down (engine);
357 }
358
359 static void
360 ibus_hangul_engine_cursor_up (IBusEngine *engine)
361 {
362     parent_class->cursor_up (engine);
363 }
364
365 static void
366 ibus_hangul_engine_cursor_down (IBusEngine *engine)
367 {
368     parent_class->cursor_down (engine);
369 }
370