1 #include <stdlib.h>
2 #include <ctype.h>
3 #include "IBusChewingUtil.h"
4 #include "IBusChewingProperties.h"
5 #include "IBusChewingPreEdit.h"
6 #include "IBusChewingPreEdit-private.h"
7
8 /**************************************
9 * Methods
10 */
11
ibus_chewing_pre_edit_new(MkdgBackend * backend)12 IBusChewingPreEdit *ibus_chewing_pre_edit_new(MkdgBackend * backend)
13 {
14 IBusChewingPreEdit *self = g_new0(IBusChewingPreEdit, 1);
15 self->iProperties = ibus_chewing_properties_new(backend, self, NULL);
16 self->preEdit = g_string_sized_new(IBUS_CHEWING_MAX_BYTES);
17 self->outgoing = g_string_sized_new(IBUS_CHEWING_MAX_BYTES);
18 self->keyLast = 0;
19 self->bpmfLen = 0;
20 self->wordLen = 0;
21 self->engine = NULL;
22
23 /* Create chewing context */
24 gchar buf[100];
25 g_snprintf(buf, 100, "%s/.chewing", getenv("HOME"));
26 #if !CHEWING_CHECK_VERSION(0,4,0)
27 gint ret = chewing_Init(QUOTE_ME(CHEWING_DATADIR_REAL), buf);
28 if (ret) {
29 IBUS_CHEWING_LOG(ERROR,
30 "ibus_chewing_pre_edit_new() chewing_Init(%s,%s)",
31 QUOTE_ME(CHEWING_DATADIR_REAL), buf);
32 }
33 #endif
34 self->context = chewing_new();
35 chewing_set_ChiEngMode(self->context, CHINESE_MODE);
36
37 self->iTable =
38 g_object_ref_sink(ibus_chewing_lookup_table_new
39 (self->iProperties, self->context));
40 return self;
41 }
42
ibus_chewing_pre_edit_free(IBusChewingPreEdit * self)43 void ibus_chewing_pre_edit_free(IBusChewingPreEdit * self)
44 {
45 /* properties need not be freed here */
46 chewing_delete(self->context);
47 g_string_free(self->preEdit, TRUE);
48 g_string_free(self->outgoing, TRUE);
49 ibus_lookup_table_clear(self->iTable);
50 g_object_unref(self->iTable);
51 g_free(self);
52 }
53
ibus_chewing_pre_edit_get_bopomofo_string(IBusChewingPreEdit * self)54 gchar *ibus_chewing_pre_edit_get_bopomofo_string(IBusChewingPreEdit * self)
55 {
56 #if CHEWING_CHECK_VERSION(0,4,0)
57 const gchar *buf = chewing_bopomofo_String_static(self->context);
58 self->bpmfLen = (gint) g_utf8_strlen(buf, 0);
59 return g_strdup(buf);
60 #else
61 return chewing_zuin_String(self->context, &(self->bpmfLen));
62 #endif
63 }
64
ibus_chewing_pre_edit_use_all_configure(IBusChewingPreEdit * self)65 void ibus_chewing_pre_edit_use_all_configure(IBusChewingPreEdit * self)
66 {
67 mkdg_properties_use_all(self->iProperties->properties, NULL);
68 }
69
ibus_chewing_pre_edit_update_outgoing(IBusChewingPreEdit * self)70 void ibus_chewing_pre_edit_update_outgoing(IBusChewingPreEdit * self)
71 {
72 if (ibus_chewing_pre_edit_has_flag(self, FLAG_UPDATED_OUTGOING)) {
73 /* Commit already sent to outgoing, no need to update again */
74 return;
75 }
76 if (chewing_commit_Check(self->context)) {
77 /* commit_Check=1 means new commit available */
78 gchar *commitStr = chewing_commit_String(self->context);
79 IBUS_CHEWING_LOG(INFO, "commitStr=|%s|\n", commitStr);
80 g_string_append(self->outgoing, commitStr);
81 g_free(commitStr);
82 ibus_chewing_pre_edit_set_flag(self, FLAG_UPDATED_OUTGOING);
83 }
84 IBUS_CHEWING_LOG(INFO, "outgoing=|%s|\n", self->outgoing->str);
85 IBUS_CHEWING_LOG(DEBUG,
86 "ibus_chewing_pre_edit_update_outgoing(-): return: outgoing=|%s|",
87 self->outgoing->str);
88 }
89
ibus_chewing_pre_edit_update(IBusChewingPreEdit * self)90 void ibus_chewing_pre_edit_update(IBusChewingPreEdit * self)
91 {
92 IBUS_CHEWING_LOG(DEBUG, "* ibus_chewing_pre_edit_update(-)");
93
94 /* Make preEdit */
95 gchar *bufferStr = chewing_buffer_String(self->context);
96 gchar *bpmfStr = ibus_chewing_pre_edit_get_bopomofo_string(self);
97 g_string_assign(self->preEdit, "");
98 gint i;
99 gchar *cP = bufferStr;
100 gunichar uniCh;
101 IBUS_CHEWING_LOG(INFO,
102 "* ibus_chewing_pre_edit_update(-) bufferStr=|%s|, bpmfStr=|%s| bpmfLen=%d cursor=%d",
103 bufferStr, bpmfStr, self->bpmfLen, cursor_current);
104 for (i = 0; i < chewing_buffer_Len(self->context) && cP != NULL; i++) {
105 if (i == cursor_current) {
106 /* Insert bopomofo string */
107 g_string_append(self->preEdit, bpmfStr);
108 }
109 uniCh = g_utf8_get_char(cP);
110 g_string_append_unichar(self->preEdit, uniCh);
111 cP = g_utf8_next_char(cP);
112 }
113 if (chewing_buffer_Len(self->context) <= cursor_current) {
114 g_string_append(self->preEdit, bpmfStr);
115 }
116 self->wordLen = i + self->bpmfLen;
117 g_free(bufferStr);
118 g_free(bpmfStr);
119
120 ibus_chewing_pre_edit_update_outgoing(self);
121
122 }
123
ibus_chewing_pre_edit_length(IBusChewingPreEdit * self)124 guint ibus_chewing_pre_edit_length(IBusChewingPreEdit * self)
125 {
126 return self->preEdit->len;
127 }
128
ibus_chewing_pre_edit_word_length(IBusChewingPreEdit * self)129 guint ibus_chewing_pre_edit_word_length(IBusChewingPreEdit * self)
130 {
131 return self->wordLen;
132 }
133
ibus_chewing_pre_edit_word_limit(IBusChewingPreEdit * self)134 guint ibus_chewing_pre_edit_word_limit(IBusChewingPreEdit * self)
135 {
136 return chewing_get_maxChiSymbolLen(self->context);
137 }
138
ibus_chewing_pre_edit_get_pre_edit(IBusChewingPreEdit * self)139 gchar *ibus_chewing_pre_edit_get_pre_edit(IBusChewingPreEdit * self)
140 {
141 return self->preEdit->str;
142 }
143
ibus_chewing_pre_edit_get_outgoing(IBusChewingPreEdit * self)144 gchar *ibus_chewing_pre_edit_get_outgoing(IBusChewingPreEdit * self)
145 {
146 return self->outgoing->str;
147 }
148
149 /* force_commit is run when receiving IGNORE event */
ibus_chewing_pre_edit_force_commit(IBusChewingPreEdit * self)150 void ibus_chewing_pre_edit_force_commit(IBusChewingPreEdit * self)
151 {
152 IBUS_CHEWING_LOG(INFO,
153 "ibus_chewing_pre_edit_force_commit(-) bpmf_check=%d buffer_check=%d",
154 bpmf_check, chewing_buffer_Check(self->context));
155
156 /* Ignore the context and
157 * Commit whatever in preedit buffer
158 */
159 g_string_append(self->outgoing, self->preEdit->str);
160
161 ibus_chewing_pre_edit_clear_pre_edit(self);
162 ibus_chewing_pre_edit_update(self);
163
164 }
165
ibus_chewing_pre_edit_clear(IBusChewingPreEdit * self)166 void ibus_chewing_pre_edit_clear(IBusChewingPreEdit * self)
167 {
168 IBUS_CHEWING_LOG(INFO, "ibus_chewing_pre_edit_clear(-)");
169
170 ibus_chewing_pre_edit_clear_pre_edit(self);
171 ibus_chewing_pre_edit_clear_outgoing(self);
172 ibus_chewing_pre_edit_update(self);
173 }
174
ibus_chewing_pre_edit_clear_bopomofo(IBusChewingPreEdit * self)175 void ibus_chewing_pre_edit_clear_bopomofo(IBusChewingPreEdit * self)
176 {
177 IBUS_CHEWING_LOG(DEBUG, "ibus_chewing_pre_edit_clear_bopomofo(-)");
178
179 /* Esc key can close candidate list, clear bopomofo, and clear
180 * the whole pre-edit buffer. Make sure it acts as we expected.
181 */
182 if (table_is_showing) {
183 chewing_handle_Esc(self->context);
184 }
185
186 if (bpmf_check) {
187 chewing_handle_Esc(self->context);
188 }
189
190 ibus_chewing_pre_edit_update(self);
191 }
192
ibus_chewing_pre_edit_clear_pre_edit(IBusChewingPreEdit * self)193 void ibus_chewing_pre_edit_clear_pre_edit(IBusChewingPreEdit * self)
194 {
195 IBUS_CHEWING_LOG(DEBUG, "ibus_chewing_pre_edit_clear_pre_edit(-)");
196
197 ibus_chewing_pre_edit_clear_bopomofo(self);
198
199 /* Save the orig Esc clean buffer state */
200 gint origState = chewing_get_escCleanAllBuf(self->context);
201 chewing_set_escCleanAllBuf(self->context, TRUE);
202
203 chewing_handle_Esc(self->context);
204
205 chewing_set_escCleanAllBuf(self->context, origState);
206 ibus_chewing_pre_edit_update(self);
207 }
208
ibus_chewing_pre_edit_clear_outgoing(IBusChewingPreEdit * self)209 void ibus_chewing_pre_edit_clear_outgoing(IBusChewingPreEdit * self)
210 {
211 IBUS_CHEWING_LOG(DEBUG, "ibus_chewing_pre_edit_clear_outgoing(-)");
212 g_string_assign(self->outgoing, "");
213
214 }
215
216 #define is_chinese ibus_chewing_pre_edit_get_chi_eng_mode(self)
217 #define is_full_shape ibus_chewing_pre_edit_get_full_half_mode(self)
ibus_chewing_pre_edit_get_chi_eng_mode(IBusChewingPreEdit * self)218 gboolean ibus_chewing_pre_edit_get_chi_eng_mode(IBusChewingPreEdit * self)
219 {
220 return chewing_get_ChiEngMode(self->context) != 0;
221 }
222
ibus_chewing_pre_edit_get_full_half_mode(IBusChewingPreEdit * self)223 gboolean ibus_chewing_pre_edit_get_full_half_mode(IBusChewingPreEdit *
224 self)
225 {
226 return chewing_get_ShapeMode(self->context) != 0;
227 }
228
ibus_chewing_pre_edit_set_chi_eng_mode(IBusChewingPreEdit * self,gboolean chineseMode)229 void ibus_chewing_pre_edit_set_chi_eng_mode(IBusChewingPreEdit * self,
230 gboolean chineseMode)
231 {
232 /* Clear bopomofo when toggling Chi-Eng Mode */
233 if (!chineseMode && is_chinese && bpmf_check) {
234 ibus_chewing_pre_edit_clear_bopomofo(self);
235 }
236 chewing_set_ChiEngMode(self->context, (chineseMode) ? 1 : 0);
237 }
238
ibus_chewing_pre_edit_set_full_half_mode(IBusChewingPreEdit * self,gboolean fullShapeMode)239 void ibus_chewing_pre_edit_set_full_half_mode(IBusChewingPreEdit * self,
240 gboolean fullShapeMode)
241 {
242 if (is_chinese && bpmf_check) {
243 /* Clear bopomofo when toggling Full-Half Mode */
244 ibus_chewing_pre_edit_clear_bopomofo(self);
245 }
246 chewing_set_ShapeMode(self->context, (fullShapeMode) ? 1 : 0);
247 }
248
249 /**************************************
250 * ibus_chewing_pre_edit key processing
251 */
self_key_sym_fix(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)252 KSym self_key_sym_fix(IBusChewingPreEdit * self, KSym kSym,
253 KeyModifiers unmaskedMod)
254 {
255 gchar caseConversionMode = default_english_case_short;
256 if (!ibus_chewing_pre_edit_get_property_boolean(self,
257 "capslock-toggle-chinese"))
258 {
259 caseConversionMode = 'n';
260 }
261 if (is_chinese) {
262 /*
263 * Ignore the status of CapsLock, thus
264 */
265 if (is_shift) {
266 return toupper(kSym);
267 }
268 return tolower(kSym);
269 } else {
270 /* May need to change case if Caps Lock toggle chinese */
271 switch (caseConversionMode) {
272 case 'l':
273 if (is_shift) {
274 /* Uppercase */
275 return toupper(kSym);
276 }
277 /* Lowercase */
278 return tolower(kSym);
279 case 'u':
280 if (is_shift) {
281 /* Lowercase */
282 return tolower(kSym);
283 }
284 /* Uppercase */
285 return toupper(kSym);
286 default:
287 break;
288 }
289 }
290 return kSym;
291 }
292
self_handle_key_sym_default(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)293 EventResponse self_handle_key_sym_default(IBusChewingPreEdit * self,
294 KSym kSym,
295 KeyModifiers unmaskedMod)
296 {
297 filter_modifiers(IBUS_SHIFT_MASK);
298 handle_log("key_sym_default");
299
300 /* Seem like we need to disable easy symbol temporarily
301 * otherwise the key won't process
302 */
303 gint easySymbolInput = chewing_get_easySymbolInput(self->context);
304 if (maskedMod != IBUS_SHIFT_MASK) {
305 chewing_set_easySymbolInput(self->context, 0);
306 }
307 EventResponse response = EVENT_RESPONSE_UNDECIDED;
308 KSym fixedKSym = self_key_sym_fix(self, kSym, unmaskedMod);
309 IBUS_CHEWING_LOG(DEBUG,
310 "* self_handle_key_sym_default(): new kSym %x(%s), %x(%s)",
311 fixedKSym, key_sym_get_name(fixedKSym), unmaskedMod,
312 modifiers_to_string(unmaskedMod));
313 gint ret = chewing_handle_Default(self->context, fixedKSym);
314 /* Handle quick commit */
315 ibus_chewing_pre_edit_clear_flag(self, FLAG_UPDATED_OUTGOING);
316 ibus_chewing_pre_edit_update_outgoing(self);
317
318 switch (ret) {
319 case 0:
320 case KEYSTROKE_COMMIT:
321 response = EVENT_RESPONSE_PROCESS;
322 break;
323 case KEYSTROKE_ABSORB:
324 response = EVENT_RESPONSE_ABSORB;
325 break;
326 case KEYSTROKE_IGNORE:
327 response = EVENT_RESPONSE_IGNORE;
328 break;
329 default:
330 break;
331 }
332
333 IBUS_CHEWING_LOG(DEBUG,
334 "self_handle_key_sym_default() ret=%d response=%d",
335 ret, response);
336 /* Restore easySymbolInput */
337 chewing_set_easySymbolInput(self->context, easySymbolInput);
338 return response;
339 }
340
341 /* Return FALSE if the key should not be processed with input method */
self_handle_num(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)342 EventResponse self_handle_num(IBusChewingPreEdit * self, KSym kSym,
343 KeyModifiers unmaskedMod)
344 {
345 filter_modifiers(IBUS_SHIFT_MASK | IBUS_CONTROL_MASK);
346 absorb_when_release;
347 handle_log("num");
348
349 if (is_ctrl_only) {
350 return
351 event_process_or_ignore(!chewing_handle_CtrlNum
352 (self->context, kSym));
353 }
354 /* maskedMod= 0 */
355 return self_handle_key_sym_default(self, kSym, unmaskedMod);
356 }
357
self_handle_num_keypad(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)358 EventResponse self_handle_num_keypad(IBusChewingPreEdit * self,
359 KSym kSym, KeyModifiers unmaskedMod)
360 {
361 filter_modifiers(IBUS_SHIFT_MASK | IBUS_CONTROL_MASK);
362 absorb_when_release;
363 handle_log("num_keypad");
364
365 KSym kSymEquiv = key_sym_KP_to_normal(kSym);
366
367 if ((maskedMod != 0) && (!is_shift_only) && (!is_ctrl_only)) {
368 return EVENT_RESPONSE_IGNORE;
369 }
370
371 if (is_ctrl_only) {
372 return
373 event_process_or_ignore(!chewing_handle_CtrlNum
374 (self->context, kSymEquiv));
375 }
376
377 if (bpmf_check) {
378 return EVENT_RESPONSE_IGNORE;
379 }
380
381 if (!buffer_is_empty && table_is_showing) {
382 return EVENT_RESPONSE_IGNORE;
383 }
384
385 /* maskedMod= 0 */
386 gint origChiEngMode = chewing_get_ChiEngMode(self->context);
387 ibus_chewing_pre_edit_set_chi_eng_mode(self, FALSE);
388
389 return self_handle_key_sym_default(self, kSymEquiv, unmaskedMod);
390 ibus_chewing_pre_edit_set_chi_eng_mode(self, origChiEngMode);
391 }
392
self_handle_caps_lock(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)393 EventResponse self_handle_caps_lock(IBusChewingPreEdit * self, KSym kSym,
394 KeyModifiers unmaskedMod)
395 {
396 filter_modifiers(0);
397
398 if (!ibus_chewing_pre_edit_get_property_boolean(self,
399 "capslock-toggle-chinese")) {
400 /* Ignore the Caps Lock event when it does not toggle Chinese */
401 return EVENT_RESPONSE_IGNORE;
402 }
403
404 absorb_when_release;
405 handle_log("caps_lock");
406
407 /* Clear bopomofo when toggling Chi-Eng Mode */
408 if (is_chinese && bpmf_check) {
409 ibus_chewing_pre_edit_clear_bopomofo(self);
410 }
411
412 return
413 event_process_or_ignore(!chewing_handle_Capslock(self->context));
414 }
415
self_handle_shift(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)416 EventResponse self_handle_shift(IBusChewingPreEdit * self, KSym kSym,
417 KeyModifiers unmaskedMod)
418 {
419 filter_modifiers(IBUS_SHIFT_MASK);
420 handle_log("shift");
421
422 gboolean shiftIsToggleChinese =
423 ibus_chewing_pre_edit_get_property_boolean(self,
424 "shift-toggle-chinese");
425
426 if (!shiftIsToggleChinese) {
427 return EVENT_RESPONSE_IGNORE;
428 }
429
430 if (!event_is_released(unmaskedMod)) {
431 return EVENT_RESPONSE_ABSORB;
432 }
433
434 /* keyLast != Shift means Shift is just part of combination,
435 * thus should not be recognized as single Shift key
436 */
437 if (self->keyLast != IBUS_KEY_Shift_L
438 && self->keyLast != IBUS_KEY_Shift_R) {
439 return EVENT_RESPONSE_ABSORB;
440 }
441
442 ibus_chewing_pre_edit_toggle_chi_eng_mode(self);
443 return EVENT_RESPONSE_ABSORB;
444 }
445
self_handle_space(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)446 EventResponse self_handle_space(IBusChewingPreEdit * self, KSym kSym,
447 KeyModifiers unmaskedMod)
448 {
449 filter_modifiers(IBUS_SHIFT_MASK | IBUS_CONTROL_MASK);
450 absorb_when_release;
451 handle_log("space");
452
453 if (is_shift_only) {
454 ibus_chewing_pre_edit_toggle_full_half_mode(self);
455 return EVENT_RESPONSE_PROCESS;
456 }
457
458 /* Bug of libchewing:
459 * when "space to select" is enabled, chewing_handle_Space() will
460 * ignore the first space. Therefore, use chewing_handle_Space()
461 * only if the buffer is not empty and we want to select.
462 */
463 gboolean spaceAsSelection =
464 ibus_chewing_pre_edit_get_property_boolean(self,
465 "space-as-selection");
466
467 if (is_chinese && !buffer_is_empty && !bpmf_check && spaceAsSelection) {
468 return event_process_or_ignore(!chewing_handle_Space(self->context));
469 } else {
470 return self_handle_key_sym_default(self, kSym, unmaskedMod);
471 }
472 }
473
self_handle_return(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)474 EventResponse self_handle_return(IBusChewingPreEdit * self, KSym kSym,
475 KeyModifiers unmaskedMod)
476 {
477 filter_modifiers(0);
478 absorb_when_release;
479 ignore_when_buffer_is_empty;
480 handle_log("return");
481
482 EventResponse response =
483 event_process_or_ignore(!chewing_handle_Enter(self->context));
484
485 /* Handle quick commit */
486 ibus_chewing_pre_edit_clear_flag(self, FLAG_UPDATED_OUTGOING);
487 ibus_chewing_pre_edit_update_outgoing(self);
488
489 return response;
490 }
491
self_handle_backspace(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)492 EventResponse self_handle_backspace(IBusChewingPreEdit * self, KSym kSym,
493 KeyModifiers unmaskedMod)
494 {
495 filter_modifiers(0);
496 absorb_when_release;
497
498 if (buffer_is_empty && !table_is_showing) {
499 return EVENT_RESPONSE_IGNORE;
500 }
501
502 handle_log("backspace");
503
504 #if !CHEWING_CHECK_VERSION(0,4,0)
505 if (table_is_showing) {
506 return event_process_or_ignore(!chewing_handle_Esc(self->context));
507 }
508 #endif
509
510 return
511 event_process_or_ignore(!chewing_handle_Backspace(self->context));
512 }
513
self_handle_delete(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)514 EventResponse self_handle_delete(IBusChewingPreEdit * self, KSym kSym,
515 KeyModifiers unmaskedMod)
516 {
517 filter_modifiers(0);
518 absorb_when_release;
519 ignore_when_buffer_is_empty;
520 handle_log("delete");
521
522 return event_process_or_ignore(!chewing_handle_Del(self->context));
523 }
524
self_handle_escape(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)525 EventResponse self_handle_escape(IBusChewingPreEdit * self, KSym kSym,
526 KeyModifiers unmaskedMod)
527 {
528 filter_modifiers(0);
529 absorb_when_release;
530
531 if (buffer_is_empty && !table_is_showing) {
532 return EVENT_RESPONSE_IGNORE;
533 }
534
535 handle_log("escape");
536
537 return event_process_or_ignore(!chewing_handle_Esc(self->context));
538 }
539
self_handle_left(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)540 EventResponse self_handle_left(IBusChewingPreEdit * self, KSym kSym,
541 KeyModifiers unmaskedMod)
542 {
543 filter_modifiers(IBUS_SHIFT_MASK);
544 absorb_when_release;
545
546 if (buffer_is_empty && !table_is_showing) {
547 return EVENT_RESPONSE_IGNORE;
548 }
549
550 handle_log("left");
551
552 if (is_shift_only) {
553 return
554 event_process_or_ignore(!chewing_handle_ShiftLeft
555 (self->context));
556 }
557
558 return event_process_or_ignore(!chewing_handle_Left(self->context));
559 }
560
self_handle_up(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)561 EventResponse self_handle_up(IBusChewingPreEdit * self, KSym kSym,
562 KeyModifiers unmaskedMod)
563 {
564 filter_modifiers(0);
565 absorb_when_release;
566
567 if (buffer_is_empty && !table_is_showing) {
568 return EVENT_RESPONSE_IGNORE;
569 }
570
571 handle_log("up");
572
573 return event_process_or_ignore(!chewing_handle_Up(self->context));
574 }
575
self_handle_right(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)576 EventResponse self_handle_right(IBusChewingPreEdit * self, KSym kSym,
577 KeyModifiers unmaskedMod)
578 {
579 filter_modifiers(IBUS_SHIFT_MASK);
580 absorb_when_release;
581
582 if (buffer_is_empty && !table_is_showing) {
583 return EVENT_RESPONSE_IGNORE;
584 }
585
586 handle_log("right");
587
588 if (is_shift_only) {
589 return
590 event_process_or_ignore(!chewing_handle_ShiftRight
591 (self->context));
592 }
593
594 return event_process_or_ignore(!chewing_handle_Right(self->context));
595 }
596
self_handle_down(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)597 EventResponse self_handle_down(IBusChewingPreEdit * self, KSym kSym,
598 KeyModifiers unmaskedMod)
599 {
600 filter_modifiers(0);
601 absorb_when_release;
602
603 if (buffer_is_empty && !table_is_showing) {
604 return EVENT_RESPONSE_IGNORE;
605 }
606
607 handle_log("down");
608
609 return event_process_or_ignore(!chewing_handle_Down(self->context));
610 }
611
self_handle_page_up(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)612 EventResponse self_handle_page_up(IBusChewingPreEdit * self, KSym kSym,
613 KeyModifiers unmaskedMod)
614 {
615 filter_modifiers(0);
616 absorb_when_release;
617
618 if (buffer_is_empty && !table_is_showing) {
619 return EVENT_RESPONSE_IGNORE;
620 }
621
622 handle_log("page_up");
623
624 #if !CHEWING_CHECK_VERSION(0,4,0)
625 if (table_is_showing) {
626 return event_process_or_ignore(!chewing_handle_Left(self->context));
627 }
628 #endif
629
630 return event_process_or_ignore(!chewing_handle_PageUp(self->context));
631 }
632
self_handle_page_down(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)633 EventResponse self_handle_page_down(IBusChewingPreEdit * self, KSym kSym,
634 KeyModifiers unmaskedMod)
635 {
636 filter_modifiers(0);
637 absorb_when_release;
638
639 if (buffer_is_empty && !table_is_showing) {
640 return EVENT_RESPONSE_IGNORE;
641 }
642
643 handle_log("page_down");
644
645 #if !CHEWING_CHECK_VERSION(0,4,0)
646 if (table_is_showing) {
647 return event_process_or_ignore(!chewing_handle_Right(self->context));
648 }
649 #endif
650
651 return
652 event_process_or_ignore(!chewing_handle_PageDown(self->context));
653 }
654
self_handle_tab(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)655 EventResponse self_handle_tab(IBusChewingPreEdit * self, KSym kSym,
656 KeyModifiers unmaskedMod)
657 {
658 filter_modifiers(0);
659 absorb_when_release;
660 ignore_when_buffer_is_empty;
661 handle_log("tab");
662
663 return event_process_or_ignore(!chewing_handle_Tab(self->context));
664 }
665
self_handle_home(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)666 EventResponse self_handle_home(IBusChewingPreEdit * self, KSym kSym,
667 KeyModifiers unmaskedMod)
668 {
669 filter_modifiers(0);
670 absorb_when_release;
671 ignore_when_buffer_is_empty;
672 handle_log("home");
673
674 return event_process_or_ignore(!chewing_handle_Home(self->context));
675 }
676
self_handle_end(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)677 EventResponse self_handle_end(IBusChewingPreEdit * self, KSym kSym,
678 KeyModifiers unmaskedMod)
679 {
680 filter_modifiers(0);
681 absorb_when_release;
682 ignore_when_buffer_is_empty;
683 handle_log("end");
684
685 return event_process_or_ignore(!chewing_handle_End(self->context));
686 }
687
self_handle_special(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)688 EventResponse self_handle_special(IBusChewingPreEdit * self, KSym kSym,
689 KeyModifiers unmaskedMod)
690 {
691 /* KSym >=128 is special key, which IM ignore. */
692 return EVENT_RESPONSE_IGNORE;
693 }
694
self_handle_default(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)695 EventResponse self_handle_default(IBusChewingPreEdit * self, KSym kSym,
696 KeyModifiers unmaskedMod)
697 {
698 filter_modifiers(IBUS_SHIFT_MASK);
699 absorb_when_release;
700 handle_log("default");
701
702 return self_handle_key_sym_default(self, kSym, unmaskedMod);
703 }
704
705 KeyHandlingRule keyHandlingRules[] = {
706 {
707 IBUS_KEY_0, IBUS_KEY_9, self_handle_num}
708 , {
709 IBUS_KEY_KP_0, IBUS_KEY_KP_9, self_handle_num_keypad}
710 , {
711 IBUS_KEY_Caps_Lock, IBUS_KEY_Caps_Lock, self_handle_caps_lock}
712 , {
713 IBUS_KEY_Shift_L, IBUS_KEY_Shift_R, self_handle_shift}
714 , {
715 IBUS_KEY_space, IBUS_KEY_space, self_handle_space}
716 , {
717 IBUS_KEY_Return, IBUS_KEY_Return, self_handle_return}
718 , {
719 IBUS_KEY_KP_Enter, IBUS_KEY_KP_Enter, self_handle_return}
720 , {
721 IBUS_KEY_BackSpace, IBUS_KEY_BackSpace, self_handle_backspace}
722 , {
723 IBUS_KEY_Delete, IBUS_KEY_Delete, self_handle_delete}
724 , {
725 IBUS_KEY_KP_Delete, IBUS_KEY_KP_Delete, self_handle_delete}
726 , {
727 IBUS_KEY_Escape, IBUS_KEY_Escape, self_handle_escape}
728 , {
729 IBUS_KEY_Left, IBUS_KEY_Left, self_handle_left}
730 , {
731 IBUS_KEY_KP_Left, IBUS_KEY_KP_Left, self_handle_left}
732 , {
733 IBUS_KEY_Up, IBUS_KEY_Up, self_handle_up}
734 , {
735 IBUS_KEY_KP_Up, IBUS_KEY_KP_Up, self_handle_up}
736 , {
737 IBUS_KEY_Right, IBUS_KEY_Right, self_handle_right}
738 , {
739 IBUS_KEY_KP_Right, IBUS_KEY_KP_Right, self_handle_right}
740 , {
741 IBUS_KEY_Down, IBUS_KEY_Down, self_handle_down}
742 , {
743 IBUS_KEY_KP_Down, IBUS_KEY_KP_Down, self_handle_down}
744 , {
745 IBUS_KEY_Page_Up, IBUS_KEY_Page_Up, self_handle_page_up}
746 , {
747 IBUS_KEY_KP_Page_Up, IBUS_KEY_KP_Page_Up, self_handle_page_up}
748 , {
749 IBUS_KEY_Page_Down, IBUS_KEY_Page_Down, self_handle_page_down}
750 , {
751 IBUS_KEY_KP_Page_Down, IBUS_KEY_KP_Page_Down, self_handle_page_down}
752 , {
753 IBUS_KEY_Tab, IBUS_KEY_Tab, self_handle_tab}
754 , {
755 IBUS_KEY_Home, IBUS_KEY_Home, self_handle_home}
756 , {
757 IBUS_KEY_KP_Home, IBUS_KEY_KP_Home, self_handle_home}
758 , {
759 IBUS_KEY_End, IBUS_KEY_End, self_handle_end}
760 , {
761 IBUS_KEY_KP_End, IBUS_KEY_KP_End, self_handle_end}
762 , {
763 128, G_MAXUINT, self_handle_special}
764 , {
765 0, 0, self_handle_default}
766 ,
767 };
768
self_key_sym_find_key_handling_rule(KSym kSym)769 static KeyHandlingRule *self_key_sym_find_key_handling_rule(KSym kSym)
770 {
771 gint i;
772 for (i = 0; keyHandlingRules[i].kSymLower != 0; i++) {
773 if ((keyHandlingRules[i].kSymLower <= kSym) &&
774 (kSym <= keyHandlingRules[i].kSymUpper)) {
775 return &(keyHandlingRules[i]);
776 }
777 }
778 return &(keyHandlingRules[i]);
779 }
780
781 #define handle_key(kSym, unmaskedMod) (self_key_sym_find_key_handling_rule(kSym))->keyFunc(self, kSym, unmaskedMod)
782
783 #define process_key_debug(prompt) IBUS_CHEWING_LOG(DEBUG, "ibus_chewing_pre_edit_process_key(): %s flags=%x buff_check=%d bpmf_check=%d cursor=%d total_choice=%d is_chinese=%d is_full_shape=%d is_plain_zhuyin=%d" ,\
784 prompt, self->flags, chewing_buffer_Check(self->context),\
785 bpmf_check, cursor_current, total_choice, is_chinese, is_full_shape, is_plain_zhuyin)
786
787
788 /* keyCode should be converted to kSym already */
ibus_chewing_pre_edit_process_key(IBusChewingPreEdit * self,KSym kSym,KeyModifiers unmaskedMod)789 gboolean ibus_chewing_pre_edit_process_key
790 (IBusChewingPreEdit * self, KSym kSym, KeyModifiers unmaskedMod) {
791 IBUS_CHEWING_LOG(INFO,
792 "***** ibus_chewing_pre_edit_process_key(-,%x(%s),%x(%s))",
793 kSym, key_sym_get_name(kSym),
794 unmaskedMod, modifiers_to_string(unmaskedMod));
795 process_key_debug("Before response");
796
797 /* Find corresponding rule */
798 EventResponse response;
799 response = handle_key(kSym, unmaskedMod);
800
801 IBUS_CHEWING_LOG(DEBUG,
802 "ibus_chewing_pre_edit_process_key() response=%x",
803 response);
804 process_key_debug("After response");
805 self->keyLast = kSym;
806 switch (response) {
807 case EVENT_RESPONSE_ABSORB:
808 return TRUE;
809 case EVENT_RESPONSE_IGNORE:
810 return FALSE;
811 default:
812 break;
813 }
814
815 /**
816 *Plain zhuyin mode
817 */
818 if (is_plain_zhuyin && !bpmf_check) {
819 /* libchewing functions are used here to skip the check
820 * that handle_key functions perform.
821 */
822 if (kSym == IBUS_KEY_Escape) {
823 ibus_chewing_pre_edit_clear_pre_edit(self);
824 } else if (kSym == IBUS_KEY_Return && table_is_showing) {
825 /* Use Enter to select the last chosen */
826 chewing_handle_Up(self->context);
827 chewing_handle_Enter(self->context);
828 } else if (is_chinese && !table_is_showing) {
829 /* Character completed, and lookup table is not show */
830 /* Then open lookup table */
831
832 if (is_shift) {
833 /* For Chinese symbols */
834 chewing_handle_Left(self->context);
835 }
836 chewing_handle_Down(self->context);
837 } else if (total_choice == 0) {
838 /* lookup table is shown */
839 /* but selection is done */
840 chewing_handle_Enter(self->context);
841 }
842 }
843 process_key_debug("After plain-zhuyin handling");
844
845 ibus_chewing_pre_edit_update(self);
846
847 guint candidateCount =
848 ibus_chewing_lookup_table_update(self->iTable, self->iProperties,
849 self->context);
850 IBUS_CHEWING_LOG(INFO,
851 "ibus_chewing_pre_edit_process_key() candidateCount=%d",
852 candidateCount);
853
854 if (candidateCount) {
855 ibus_chewing_pre_edit_set_flag(self, FLAG_TABLE_SHOW);
856 } else {
857 ibus_chewing_pre_edit_clear_flag(self, FLAG_TABLE_SHOW);
858 }
859 return TRUE;
860 }
861
ibus_chewing_pre_edit_key_code_to_key_sym(IBusChewingPreEdit * self,KSym keySym,guint keyCode,KeyModifiers unmaskedMod)862 KSym ibus_chewing_pre_edit_key_code_to_key_sym
863 (IBusChewingPreEdit * self, KSym keySym,
864 guint keyCode, KeyModifiers unmaskedMod) {
865 KSym kSym = keySym;
866 if (!is_chinese) {
867 /* English mode, pass as-is */
868 return kSym;
869 }
870
871 if (!ibus_chewing_pre_edit_is_system_keyboard_layout(self)) {
872 /* Use en_US keyboard layout */
873 /* ibus_keymap_lookup_key_sym treats keycode >= 256 */
874 /* as IBUS_VoidSymbol */
875 kSym =
876 ibus_keymap_lookup_keysym(ibus_keymap_get
877 ("us"), keyCode, unmaskedMod);
878 if (kSym == IBUS_VoidSymbol) {
879 /* Restore key_sym */
880 kSym = keySym;
881 }
882 }
883
884 return kSym;
885 }
886