1 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
2 /*
3  * nimf-anthy.c
4  * This file is part of Nimf.
5  *
6  * Copyright (C) 2016-2019 Hodong Kim <cogniti@gmail.com>
7  *
8  * Nimf is free software: you can redistribute it and/or modify it
9  * under the terms of the GNU Lesser General Public License as published
10  * by the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * Nimf is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  * See the GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program;  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <nimf.h>
23 #include <anthy/anthy.h>
24 #include <glib/gi18n.h>
25 
26 #define NIMF_TYPE_ANTHY             (nimf_anthy_get_type ())
27 #define NIMF_ANTHY(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), NIMF_TYPE_ANTHY, NimfAnthy))
28 #define NIMF_ANTHY_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), NIMF_TYPE_ANTHY, NimfAnthyClass))
29 #define NIMF_IS_ANTHY(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NIMF_TYPE_ANTHY))
30 #define NIMF_IS_ANTHY_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), NIMF_TYPE_ANTHY))
31 #define NIMF_ANTHY_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), NIMF_TYPE_ANTHY, NimfAnthyClass))
32 
33 #define NIMF_ANTHY_BUFFER_SIZE  256
34 
35 typedef struct _NimfAnthy      NimfAnthy;
36 typedef struct _NimfAnthyClass NimfAnthyClass;
37 
38 struct _NimfAnthy
39 {
40   NimfEngine parent_instance;
41 
42   NimfCandidatable  *candidatable;
43   GString           *preedit;
44   gint               preedit_offset; /* in bytes */
45   gint               preedit_dx;     /* in bytes */
46   NimfPreeditState   preedit_state;
47   NimfPreeditAttr  **preedit_attrs;
48   gchar             *id;
49   GSettings         *settings;
50   NimfKey          **hiragana_keys;
51   NimfKey          **katakana_keys;
52   gchar             *method;
53   gboolean           method_changed;
54   gint               n_input_mode;
55 
56   anthy_context_t  context;
57   gint             current_segment;
58   gchar            buffer[NIMF_ANTHY_BUFFER_SIZE];
59   gint             current_page;
60   gint             n_pages;
61   gint            *selections;
62 };
63 
64 struct _NimfAnthyClass
65 {
66   /*< private >*/
67   NimfEngineClass parent_class;
68 };
69 
70 typedef enum
71 {
72   COMMON,
73   EXPLICIT
74 } NInputMode;
75 
76 static gint        nimf_anthy_ref_count = 0;
77 static GHashTable *nimf_anthy_romaji = NULL;;
78 
79 typedef struct
80 {
81   gchar *key;
82   gchar *value;
83 } RomajiMap;
84 
85 static const RomajiMap romaji_map[] = {
86   {"a", "あ"},
87   {"b", ""}, /* dummy */
88   {"ba", "ば"},
89   {"be", "べ"},
90   {"bi", "び"},
91   {"bo", "ぼ"},
92   {"bu", "ぶ"},
93   {"by", ""}, /* dummy */
94   {"bya", "びゃ"},
95   {"bye", "びぇ"},
96   {"byi", "びぃ"},
97   {"byo", "びょ"},
98   {"byu", "びゅ"},
99   {"c", ""}, /* dummy */
100   {"ca", "か"},
101   {"ce", "せ"},
102   {"ch", ""}, /* dummy */
103   {"cha", "ちゃ"},
104   {"che", "ちぇ"},
105   {"chi", "ち"},
106   {"cho", "ちょ"},
107   {"chu", "ちゅ"},
108   {"ci", "し"},
109   {"co", "こ"},
110   {"cu", "く"},
111   {"cy", ""}, /* dummy */
112   {"cya", "ちゃ"},
113   {"cye", "ちぇ"},
114   {"cyi", "ちぃ"},
115   {"cyo", "ちょ"},
116   {"cyu", "ちゅ"},
117   {"d", ""}, /* dummy */
118   {"da", "だ"},
119   {"de", "で"},
120   {"dh", ""}, /* dummy */
121   {"dha", "でゃ"},
122   {"dhe", "でぇ"},
123   {"dhi", "でぃ"},
124   {"dho", "でょ"},
125   {"dhu", "でゅ"},
126   {"di", "ぢ"},
127   {"do", "ど"},
128   {"du", "づ"},
129   {"dw", ""}, /* dummy */
130   {"dwa", "どぁ"},
131   {"dwe", "どぇ"},
132   {"dwi", "どぃ"},
133   {"dwo", "どぉ"},
134   {"dwu", "どぅ"},
135   {"dy", ""}, /* dummy */
136   {"dya", "ぢゃ"},
137   {"dye", "ぢぇ"},
138   {"dyi", "ぢぃ"},
139   {"dyo", "ぢょ"},
140   {"dyu", "ぢゅ"},
141   {"e", "え"},
142   {"f", ""}, /* dummy */
143   {"fa", "ふぁ"},
144   {"fe", "ふぇ"},
145   {"fi", "ふぃ"},
146   {"fo", "ふぉ"},
147   {"fu", "ふ"},
148   {"fw", ""}, /* dummy */
149   {"fwa", "ふぁ"},
150   {"fwe", "ふぇ"},
151   {"fwi", "ふぃ"},
152   {"fwo", "ふぉ"},
153   {"fwu", "ふぅ"},
154   {"fy", ""}, /* dummy */
155   {"fya", "ふゃ"},
156   {"fye", "ふぇ"},
157   {"fyi", "ふぃ"},
158   {"fyo", "ふょ"},
159   {"fyu", "ふゅ"},
160   {"g", ""}, /* dummy */
161   {"ga", "が"},
162   {"ge", "げ"},
163   {"gi", "ぎ"},
164   {"go", "ご"},
165   {"gu", "ぐ"},
166   {"gw", ""}, /* dummy */
167   {"gwa", "ぐぁ"},
168   {"gwe", "ぐえ"},
169   {"gwi", "ぐぃ"},
170   {"gwo", "ぐぉ"},
171   {"gwu", "ぐぅ"},
172   {"gy", ""}, /* dummy */
173   {"gya", "ぎゃ"},
174   {"gye", "ぎぇ"},
175   {"gyi", "ぎぃ"},
176   {"gyo", "ぎょ"},
177   {"gyu", "ぎゅ"},
178   {"h", ""}, /* dummy */
179   {"ha", "は"},
180   {"he", "へ"},
181   {"hi", "ひ"},
182   {"ho", "ほ"},
183   {"hu", "ふ"},
184   {"hy", ""}, /* dummy */
185   {"hya", "ひゃ"},
186   {"hye", "ひぇ"},
187   {"hyi", "ひぃ"},
188   {"hyo", "ひょ"},
189   {"hyu", "ひゅ"},
190   {"i", "い"},
191   {"j", ""}, /* dummy */
192   {"ja", "じゃ"},
193   {"je", "じぇ"},
194   {"ji", "じ"},
195   {"jo", "じょ"},
196   {"ju", "じゅ"},
197   {"jy", ""}, /* dummy */
198   {"jya", "じゃ"},
199   {"jye", "じぇ"},
200   {"jyi", "じぃ"},
201   {"jyo", "じょ"},
202   {"jyu", "じゅ"},
203   {"k", ""}, /* dummy */
204   {"ka", "か"},
205   {"ke", "け"},
206   {"ki", "き"},
207   {"ko", "こ"},
208   {"ku", "く"},
209   {"kw", ""}, /* dummy */
210   {"kwa", "くぁ"},
211   {"ky", ""}, /* dummy */
212   {"kya", "きゃ"},
213   {"kye", "きぇ"},
214   {"kyi", "きぃ"},
215   {"kyo", "きょ"},
216   {"kyu", "きゅ"},
217   {"l", ""}, /* dummy */
218   {"la", "ぁ"},
219   {"le", "ぇ"},
220   {"li", "ぃ"},
221   {"lk", ""}, /* dummy */
222   {"lka", "ヵ"},
223   {"lke", "ヶ"},
224   {"lo", "ぉ"},
225   {"lt", ""}, /* dummy */
226   {"lts", ""}, /* dummy */
227   {"ltsu", "っ"},
228   {"ltu", "っ"},
229   {"lu", "ぅ"},
230   {"lw", ""}, /* dummy */
231   {"lwa", "ゎ"},
232   {"ly", ""}, /* dummy */
233   {"lya", "ゃ"},
234   {"lye", "ぇ"},
235   {"lyi", "ぃ"},
236   {"lyo", "ょ"},
237   {"lyu", "ゅ"},
238   {"m", ""}, /* dummy */
239   {"ma", "ま"},
240   {"me", "め"},
241   {"mi", "み"},
242   {"mo", "も"},
243   {"mu", "む"},
244   {"my", ""}, /* dummy */
245   {"mya", "みゃ"},
246   {"mye", "みぇ"},
247   {"myi", "みぃ"},
248   {"myo", "みょ"},
249   {"myu", "みゅ"},
250   {"n", ""}, /* dummy */
251   {"na", "な"},
252   {"ne", "ね"},
253   {"ni", "に"},
254   {"nn", "ん"},
255   {"no", "の"},
256   {"nu", "ぬ"},
257   {"ny", ""}, /* dummy */
258   {"nya", "にゃ"},
259   {"nye", "にぇ"},
260   {"nyi", "にぃ"},
261   {"nyo", "にょ"},
262   {"nyu", "にゅ"},
263   {"o", "お"},
264   {"p", ""}, /* dummy */
265   {"pa", "ぱ"},
266   {"pe", "ぺ"},
267   {"pi", "ぴ"},
268   {"po", "ぽ"},
269   {"pu", "ぷ"},
270   {"py", ""}, /* dummy */
271   {"pya", "ぴゃ"},
272   {"pye", "ぴぇ"},
273   {"pyi", "ぴぃ"},
274   {"pyo", "ぴょ"},
275   {"pyu", "ぴゅ"},
276   {"q", ""}, /* dummy */
277   {"qa", "くぁ"},
278   {"qe", "くぇ"},
279   {"qi", "くぃ"},
280   {"qo", "くぉ"},
281   {"qu", "く"},
282   {"qw", ""}, /* dummy */
283   {"qwa", "くぁ"},
284   {"qwe", "くぇ"},
285   {"qwi", "くぃ"},
286   {"qwo", "くぉ"},
287   {"qwu", "くぅ"},
288   {"qy", ""}, /* dummy */
289   {"qya", "くゃ"},
290   {"qye", "くぇ"},
291   {"qyi", "くぃ"},
292   {"qyo", "くょ"},
293   {"qyu", "くゅ"},
294   {"r", ""}, /* dummy */
295   {"ra", "ら"},
296   {"re", "れ"},
297   {"ri", "り"},
298   {"ro", "ろ"},
299   {"ru", "る"},
300   {"ry", ""}, /* dummy */
301   {"rya", "りゃ"},
302   {"rye", "りぇ"},
303   {"ryi", "りぃ"},
304   {"ryo", "りょ"},
305   {"ryu", "りゅ"},
306   {"s", ""}, /* dummy */
307   {"sa", "さ"},
308   {"se", "せ"},
309   {"sh", ""}, /* dummy */
310   {"sha", "しゃ"},
311   {"she", "しぇ"},
312   {"shi", "し"},
313   {"sho", "しょ"},
314   {"shu", "しゅ"},
315   {"si", "し"},
316   {"so", "そ"},
317   {"su", "す"},
318   {"sw", ""}, /* dummy */
319   {"swa", "すぁ"},
320   {"swe", "すぇ"},
321   {"swi", "すぃ"},
322   {"swo", "すぉ"},
323   {"swu", "すぅ"},
324   {"sy", ""}, /* dummy */
325   {"sya", "しゃ"},
326   {"sye", "しぇ"},
327   {"syi", "しぃ"},
328   {"syo", "しょ"},
329   {"syu", "しゅ"},
330   {"t", ""}, /* dummy */
331   {"ta", "た"},
332   {"te", "て"},
333   {"th", ""}, /* dummy */
334   {"tha", "てゃ"},
335   {"the", "てぇ"},
336   {"thi", "てぃ"},
337   {"tho", "てょ"},
338   {"thu", "てゅ"},
339   {"ti", "ち"},
340   {"to", "と"},
341   {"ts", ""}, /* dummy */
342   {"tsa", "つぁ"},
343   {"tse", "つぇ"},
344   {"tsi", "つぃ"},
345   {"tso", "つぉ"},
346   {"tsu", "つ"},
347   {"tu", "つ"},
348   {"tw", ""}, /* dummy */
349   {"twa", "とぁ"},
350   {"twe", "とぇ"},
351   {"twi", "とぃ"},
352   {"two", "とぉ"},
353   {"twu", "とぅ"},
354   {"ty", ""}, /* dummy */
355   {"tya", "ちゃ"},
356   {"tye", "ちぇ"},
357   {"tyi", "ちぃ"},
358   {"tyo", "ちょ"},
359   {"tyu", "ちゅ"},
360   {"u", "う"},
361   {"v", ""}, /* dummy */
362   {"va", "ヴぁ"},
363   {"ve", "ヴぇ"},
364   {"vi", "ヴぃ"},
365   {"vo", "ヴぉ"},
366   {"vu", "ヴ"},
367   {"vy", ""}, /* dummy */
368   {"vya", "ヴゃ"},
369   {"vye", "ヴぇ"},
370   {"vyi", "ヴぃ"},
371   {"vyo", "ヴょ"},
372   {"vyu", "ヴゅ"},
373   {"w", ""}, /* dummy */
374   {"wa", "わ"},
375   {"we", "うぇ"},
376   {"wh", ""}, /* dummy */
377   {"wha", "うぁ"},
378   {"whe", "うぇ"},
379   {"whi", "うぃ"},
380   {"who", "うぉ"},
381   {"whu", "う"},
382   {"wi", "うぃ"},
383   {"wo", "を"},
384   {"wu", "う"},
385   {"wy", ""}, /* dummy */
386   {"wye", "ゑ"},
387   {"wyi", "ゐ"},
388   {"x", ""}, /* dummy */
389   {"xa", "ぁ"},
390   {"xe", "ぇ"},
391   {"xi", "ぃ"},
392   {"xk", ""}, /* dummy */
393   {"xka", "ヵ"},
394   {"xke", "ヶ"},
395   {"xn", "ん"},
396   {"xo", "ぉ"},
397   {"xt", ""}, /* dummy */
398   {"xts", ""}, /* dummy */
399   {"xtsu", "っ"},
400   {"xtu", "っ"},
401   {"xu", "ぅ"},
402   {"xw", ""}, /* dummy */
403   {"xwa", "ゎ"},
404   {"xy", ""}, /* dummy */
405   {"xya", "ゃ"},
406   {"xye", "ぇ"},
407   {"xyi", "ぃ"},
408   {"xyo", "ょ"},
409   {"xyu", "ゅ"},
410   {"y", ""}, /* dummy */
411   {"ya", "や"},
412   {"ye", "いぇ"},
413   {"yi", "い"},
414   {"yo", "よ"},
415   {"yu", "ゆ"},
416   {"z", ""}, /* dummy */
417   {"za", "ざ"},
418   {"ze", "ぜ"},
419   {"zi", "じ"},
420   {"zo", "ぞ"},
421   {"zu", "ず"},
422   {"zy", ""}, /* dummy */
423   {"zya", "じゃ"},
424   {"zye", "じぇ"},
425   {"zyi", "じぃ"},
426   {"zyo", "じょ"},
427   {"zyu", "じゅ"},
428   {",", "、"},
429   {".", "。"},
430   {"-", "ー"}
431 };
432 
433 G_DEFINE_DYNAMIC_TYPE (NimfAnthy, nimf_anthy, NIMF_TYPE_ENGINE);
434 
435 static void
nimf_anthy_update_preedit_state(NimfEngine * engine,NimfServiceIC * target,const gchar * new_preedit,gint cursor_pos)436 nimf_anthy_update_preedit_state (NimfEngine    *engine,
437                                  NimfServiceIC *target,
438                                  const gchar   *new_preedit,
439                                  gint           cursor_pos)
440 {
441   g_debug (G_STRLOC ": %s", G_STRFUNC);
442 
443   NimfAnthy *anthy = NIMF_ANTHY (engine);
444 
445   if (anthy->preedit_state == NIMF_PREEDIT_STATE_END &&
446       anthy->preedit->len > 0)
447   {
448     anthy->preedit_state = NIMF_PREEDIT_STATE_START;
449     nimf_engine_emit_preedit_start (engine, target);
450   }
451 
452   nimf_engine_emit_preedit_changed (engine, target, new_preedit,
453                                     anthy->preedit_attrs, cursor_pos);
454 
455   if (!nimf_service_ic_get_use_preedit (target))
456     nimf_candidatable_set_auxiliary_text (anthy->candidatable,
457                                           anthy->preedit->str,
458                                           g_utf8_strlen (anthy->preedit->str,
459                                                          anthy->preedit_offset + anthy->preedit_dx));
460 
461   if (anthy->preedit_state == NIMF_PREEDIT_STATE_START &&
462       anthy->preedit->len == 0)
463   {
464     anthy->preedit_state = NIMF_PREEDIT_STATE_END;
465     nimf_engine_emit_preedit_end (engine, target);
466   }
467 }
468 
469 static void
nimf_anthy_emit_commit(NimfEngine * engine,NimfServiceIC * target)470 nimf_anthy_emit_commit (NimfEngine    *engine,
471                         NimfServiceIC *target)
472 {
473   g_debug (G_STRLOC ": %s", G_STRFUNC);
474 
475   NimfAnthy *anthy = NIMF_ANTHY (engine);
476   struct anthy_conv_stat conv_stat;
477   gint i;
478 
479   anthy_get_stat (anthy->context, &conv_stat);
480 
481   for (i = 0; i < conv_stat.nr_segment; i++)
482     anthy_commit_segment (anthy->context, i, anthy->selections[i]);
483 
484   if (anthy->preedit->len > 0)
485   {
486     nimf_engine_emit_commit (engine, target, anthy->preedit->str);
487     g_string_assign (anthy->preedit,  "");
488     anthy->preedit_offset = 0;
489     anthy->preedit_dx     = 0;
490     anthy->preedit_attrs[0]->start_index = 0;
491     anthy->preedit_attrs[0]->end_index   = 0;
492     anthy->preedit_attrs[1]->start_index = 0;
493     anthy->preedit_attrs[1]->end_index   = 0;
494     nimf_anthy_update_preedit_state (engine, target, "", 0);
495   }
496 }
497 
498 void
nimf_anthy_reset(NimfEngine * engine,NimfServiceIC * target)499 nimf_anthy_reset (NimfEngine    *engine,
500                   NimfServiceIC *target)
501 {
502   g_debug (G_STRLOC ": %s", G_STRFUNC);
503 
504   NimfAnthy *anthy = NIMF_ANTHY (engine);
505   struct anthy_conv_stat conv_stat;
506 
507   anthy_get_stat (anthy->context, &conv_stat);
508   nimf_candidatable_hide (anthy->candidatable);
509   nimf_anthy_emit_commit (engine, target);
510   memset (anthy->selections, 0, conv_stat.nr_segment * sizeof (gint));
511   anthy_reset_context (anthy->context);
512 }
513 
514 void
nimf_anthy_focus_in(NimfEngine * engine,NimfServiceIC * target)515 nimf_anthy_focus_in (NimfEngine    *engine,
516                      NimfServiceIC *target)
517 {
518   g_debug (G_STRLOC ": %s", G_STRFUNC);
519 }
520 
521 void
nimf_anthy_focus_out(NimfEngine * engine,NimfServiceIC * target)522 nimf_anthy_focus_out (NimfEngine    *engine,
523                       NimfServiceIC *target)
524 {
525   g_debug (G_STRLOC ": %s", G_STRFUNC);
526 
527   nimf_candidatable_hide (NIMF_ANTHY (engine)->candidatable);
528   nimf_anthy_reset (engine, target);
529 }
530 
531 static gint
nimf_anthy_get_current_page(NimfEngine * engine)532 nimf_anthy_get_current_page (NimfEngine *engine)
533 {
534   g_debug (G_STRLOC ": %s", G_STRFUNC);
535 
536   return NIMF_ANTHY (engine)->current_page;
537 }
538 
539 static void
nimf_anthy_convert_preedit_text(NimfEngine * engine,NimfServiceIC * target)540 nimf_anthy_convert_preedit_text (NimfEngine    *engine,
541                                  NimfServiceIC *target)
542 {
543   g_debug (G_STRLOC ": %s", G_STRFUNC);
544 
545   NimfAnthy *anthy = NIMF_ANTHY (engine);
546   struct anthy_conv_stat conv_stat;
547   gint i;
548   gint offset  = 0;
549   gint end_pos = 0;
550   gint len     = 0;
551   gint current_segment_len = 0;
552 
553   g_string_assign (anthy->preedit, "");
554   anthy_get_stat (anthy->context, &conv_stat);
555 
556   for (i = 0; i < conv_stat.nr_segment; i++)
557   {
558     anthy_get_segment (anthy->context, i, anthy->selections[i], anthy->buffer, NIMF_ANTHY_BUFFER_SIZE);
559     len = g_utf8_strlen (anthy->buffer, -1);
560     end_pos += len;
561 
562     if (i < anthy->current_segment)
563       offset += len;
564 
565     if (i == anthy->current_segment)
566       current_segment_len = len;
567 
568     g_string_append (anthy->preedit, anthy->buffer);
569   }
570 
571   anthy->preedit_attrs[0]->start_index = 0;
572   anthy->preedit_attrs[0]->end_index = end_pos;
573   anthy->preedit_attrs[1]->start_index = offset;
574   anthy->preedit_attrs[1]->end_index = offset + current_segment_len;
575   nimf_anthy_update_preedit_state (engine, target, anthy->preedit->str,
576                                    g_utf8_strlen (anthy->preedit->str, -1));
577 
578   anthy->preedit_offset = anthy->preedit->len;
579   anthy->preedit_dx     = 0;
580 }
581 
582 static void
nimf_anthy_update_preedit_text(NimfEngine * engine,NimfServiceIC * target)583 nimf_anthy_update_preedit_text (NimfEngine    *engine,
584                                 NimfServiceIC *target)
585 {
586   g_debug (G_STRLOC ": %s", G_STRFUNC);
587 
588   NimfAnthy *anthy = NIMF_ANTHY (engine);
589 
590   anthy->preedit_attrs[0]->start_index = 0;
591   anthy->preedit_attrs[0]->end_index   = g_utf8_strlen (anthy->preedit->str, -1);
592   anthy->preedit_attrs[1]->start_index = 0;
593   anthy->preedit_attrs[1]->end_index   = 0;
594   nimf_anthy_update_preedit_state (engine, target, anthy->preedit->str,
595     g_utf8_strlen (anthy->preedit->str,
596                    anthy->preedit_offset + anthy->preedit_dx));
597 }
598 
599 static void
nimf_anthy_update_page(NimfEngine * engine,NimfServiceIC * target)600 nimf_anthy_update_page (NimfEngine    *engine,
601                         NimfServiceIC *target)
602 {
603   g_debug (G_STRLOC ": %s", G_STRFUNC);
604 
605   NimfAnthy *anthy = NIMF_ANTHY (engine);
606   struct anthy_conv_stat    conv_stat;
607   struct anthy_segment_stat segment_stat;
608   gint i;
609 
610   anthy_get_stat (anthy->context, &conv_stat);
611   anthy_get_segment_stat (anthy->context, anthy->current_segment, &segment_stat);
612 
613   anthy->n_pages = (segment_stat.nr_candidate + 9) / 10;
614   nimf_candidatable_clear (anthy->candidatable, target);
615 
616   for (i = (anthy->current_page - 1) * 10;
617        i < MIN (anthy->current_page * 10, segment_stat.nr_candidate);
618        i++)
619   {
620     anthy_get_segment (anthy->context, anthy->current_segment, i,
621                        anthy->buffer, NIMF_ANTHY_BUFFER_SIZE);
622     nimf_candidatable_append (anthy->candidatable, anthy->buffer, NULL);
623   }
624 
625   nimf_candidatable_select_item_by_index_in_page
626     (anthy->candidatable, anthy->selections[anthy->current_segment]);
627   nimf_candidatable_set_page_values (anthy->candidatable, target,
628                                      anthy->current_page, anthy->n_pages, 10);
629 }
630 
631 static void
on_candidate_clicked(NimfEngine * engine,NimfServiceIC * target,gchar * text,gint index)632 on_candidate_clicked (NimfEngine    *engine,
633                       NimfServiceIC *target,
634                       gchar         *text,
635                       gint           index)
636 {
637   g_debug (G_STRLOC ": %s", G_STRFUNC);
638 
639   NimfAnthy *anthy = NIMF_ANTHY (engine);
640 
641   anthy->selections[anthy->current_segment] = (anthy->current_page -1) * 10 + index;
642   nimf_anthy_convert_preedit_text (engine, target);
643 }
644 
645 static void
nimf_anthy_page_end(NimfEngine * engine,NimfServiceIC * target)646 nimf_anthy_page_end (NimfEngine *engine, NimfServiceIC *target)
647 {
648   g_debug (G_STRLOC ": %s", G_STRFUNC);
649 
650   NimfAnthy *anthy = NIMF_ANTHY (engine);
651 
652   if (anthy->current_page == anthy->n_pages)
653   {
654     nimf_candidatable_select_last_item_in_page (anthy->candidatable);
655     return;
656   }
657 
658   anthy->current_page = anthy->n_pages;
659   nimf_anthy_update_page (engine, target);
660   nimf_candidatable_select_last_item_in_page (anthy->candidatable);
661 }
662 
663 static gboolean
nimf_anthy_page_up(NimfEngine * engine,NimfServiceIC * target)664 nimf_anthy_page_up (NimfEngine *engine, NimfServiceIC *target)
665 {
666   g_debug (G_STRLOC ": %s", G_STRFUNC);
667 
668   NimfAnthy *anthy = NIMF_ANTHY (engine);
669 
670   if (anthy->current_page <= 1)
671   {
672     nimf_anthy_page_end (engine, target);
673     return FALSE;
674   }
675 
676   anthy->current_page--;
677   nimf_anthy_update_page (engine, target);
678   nimf_candidatable_select_last_item_in_page (anthy->candidatable);
679 
680   return TRUE;
681 }
682 
683 static void
nimf_anthy_page_home(NimfEngine * engine,NimfServiceIC * target)684 nimf_anthy_page_home (NimfEngine *engine, NimfServiceIC *target)
685 {
686   g_debug (G_STRLOC ": %s", G_STRFUNC);
687 
688   NimfAnthy *anthy = NIMF_ANTHY (engine);
689 
690   if (anthy->current_page <= 1)
691   {
692     nimf_candidatable_select_first_item_in_page (anthy->candidatable);
693     return;
694   }
695 
696   anthy->current_page = 1;
697   nimf_anthy_update_page (engine, target);
698   nimf_candidatable_select_first_item_in_page (anthy->candidatable);
699 }
700 
701 static gboolean
nimf_anthy_page_down(NimfEngine * engine,NimfServiceIC * target)702 nimf_anthy_page_down (NimfEngine *engine, NimfServiceIC *target)
703 {
704   g_debug (G_STRLOC ": %s", G_STRFUNC);
705 
706   NimfAnthy *anthy = NIMF_ANTHY (engine);
707 
708   if (anthy->current_page == anthy->n_pages)
709   {
710     nimf_anthy_page_home (engine, target);
711     return FALSE;
712   }
713 
714   anthy->current_page++;
715   nimf_anthy_update_page (engine, target);
716   nimf_candidatable_select_first_item_in_page (anthy->candidatable);
717 
718   return TRUE;
719 }
720 
721 static void
on_candidate_scrolled(NimfEngine * engine,NimfServiceIC * target,gdouble value)722 on_candidate_scrolled (NimfEngine    *engine,
723                        NimfServiceIC *target,
724                        gdouble        value)
725 {
726   g_debug (G_STRLOC ": %s", G_STRFUNC);
727 
728   NimfAnthy *anthy = NIMF_ANTHY (engine);
729 
730   if ((gint) value == nimf_anthy_get_current_page (engine))
731     return;
732 
733   while (anthy->n_pages > 1)
734   {
735     gint d = (gint) value - nimf_anthy_get_current_page (engine);
736 
737     if (d > 0)
738       nimf_anthy_page_down (engine, target);
739     else if (d < 0)
740       nimf_anthy_page_up (engine, target);
741     else if (d == 0)
742       break;
743   }
744 }
745 
746 static void
nimf_anthy_update_candidate(NimfEngine * engine,NimfServiceIC * target)747 nimf_anthy_update_candidate (NimfEngine    *engine,
748                              NimfServiceIC *target)
749 {
750   g_debug (G_STRLOC ": %s", G_STRFUNC);
751 
752   NimfAnthy *anthy = NIMF_ANTHY (engine);
753   struct anthy_conv_stat conv_stat;
754 
755   anthy_get_stat (anthy->context, &conv_stat);
756 
757   if (conv_stat.nr_segment > 0)
758   {
759     anthy->current_page = 1;
760     nimf_anthy_update_page (engine, target);
761   }
762   else
763   {
764     if (anthy->n_pages > 0)
765     {
766       nimf_candidatable_hide (anthy->candidatable);
767       nimf_candidatable_clear (anthy->candidatable, target);
768       anthy->n_pages = 0;
769       anthy->current_page = 0;
770     }
771   }
772 }
773 
774 static gboolean
nimf_anthy_filter_event_romaji(NimfEngine * engine,NimfServiceIC * target,NimfEvent * event)775 nimf_anthy_filter_event_romaji (NimfEngine    *engine,
776                                 NimfServiceIC *target,
777                                 NimfEvent     *event)
778 {
779   g_debug (G_STRLOC ": %s", G_STRFUNC);
780 
781   NimfAnthy   *anthy = NIMF_ANTHY (engine);
782   const gchar *str;
783 
784   g_string_insert_c (anthy->preedit, anthy->preedit_offset + anthy->preedit_dx, event->key.keyval);
785   anthy->preedit_dx++;
786 
787   while (TRUE)
788   {
789     gchar *key;
790 
791     key = g_strndup (anthy->preedit->str + anthy->preedit_offset,
792                      anthy->preedit_dx);
793     str = g_hash_table_lookup (nimf_anthy_romaji, key);
794 
795     g_free (key);
796 
797     if (str)
798     {
799       if (str[0] != 0)
800       {
801         g_string_erase (anthy->preedit, anthy->preedit_offset,
802                         anthy->preedit_dx);
803         g_string_insert (anthy->preedit, anthy->preedit_offset, str);
804         anthy->preedit_offset += strlen (str);
805         anthy->preedit_dx = 0;
806       }
807 
808       break;
809     }
810     else
811     {
812       if (anthy->preedit_dx > 1)
813       {
814         char a = anthy->preedit->str[anthy->preedit_offset + anthy->preedit_dx - 2];
815         char b = anthy->preedit->str[anthy->preedit_offset + anthy->preedit_dx - 1];
816 
817         if (a != 'n' && a == b)
818         {
819           g_string_erase  (anthy->preedit, anthy->preedit_offset + anthy->preedit_dx - 2, 1);
820           g_string_insert (anthy->preedit, anthy->preedit_offset + anthy->preedit_dx - 2, "っ");
821           anthy->preedit_offset += strlen ("っ") - 1;
822         }
823         else if (anthy->n_input_mode == COMMON && a == 'n' &&
824                  !(b == 'a' || b == 'e' || b == 'i' || b == 'o' || b == 'u' || b == 'n'))
825         {
826           g_string_erase  (anthy->preedit, anthy->preedit_offset + anthy->preedit_dx - 2, 1);
827           g_string_insert (anthy->preedit, anthy->preedit_offset + anthy->preedit_dx - 2, "ん");
828           anthy->preedit_offset += strlen ("ん") - 1;
829         }
830 
831         anthy->preedit_offset += anthy->preedit_dx - 1;
832         anthy->preedit_dx = 1;
833       }
834       else
835       {
836         break;
837       }
838     }
839   }
840 
841   return TRUE;
842 }
843 
844 static void
nimf_anthy_preedit_insert(NimfAnthy * anthy,const gchar * val)845 nimf_anthy_preedit_insert (NimfAnthy   *anthy,
846                            const gchar *val)
847 {
848   g_debug (G_STRLOC ": %s", G_STRFUNC);
849 
850   g_string_insert (anthy->preedit, anthy->preedit_offset, val);
851   anthy->preedit_offset += strlen (val);
852 }
853 
854 static gboolean
nimf_anthy_preedit_offset_has_suffix(NimfAnthy * anthy,const gchar * suffix)855 nimf_anthy_preedit_offset_has_suffix (NimfAnthy *anthy, const gchar *suffix)
856 {
857   g_debug (G_STRLOC ": %s", G_STRFUNC);
858 
859   gint len = strlen (suffix);
860 
861   return !!g_strstr_len (anthy->preedit->str + anthy->preedit_offset - len,
862                          len, suffix);
863 }
864 
865 static gboolean
nimf_anthy_filter_event_pc104(NimfEngine * engine,NimfServiceIC * target,NimfEvent * event)866 nimf_anthy_filter_event_pc104 (NimfEngine    *engine,
867                                NimfServiceIC *target,
868                                NimfEvent     *event)
869 {
870   g_debug (G_STRLOC ": %s", G_STRFUNC);
871 
872   NimfAnthy *anthy = NIMF_ANTHY (engine);
873 
874   gboolean is_shift = event->key.state & NIMF_SHIFT_MASK;
875 
876   switch (event->key.hardware_keycode)
877   {
878     case 49: nimf_anthy_preedit_insert (anthy, "ろ"); break;
879     case 10: nimf_anthy_preedit_insert (anthy, "ぬ"); break;
880     case 11: nimf_anthy_preedit_insert (anthy, "ふ"); break;
881     case 12:
882       if (is_shift) nimf_anthy_preedit_insert (anthy, "ぁ");
883       else          nimf_anthy_preedit_insert (anthy, "あ");
884       break;
885     case 13:
886       if (is_shift) nimf_anthy_preedit_insert (anthy, "ぅ");
887       else          nimf_anthy_preedit_insert (anthy, "う");
888       break;
889     case 14:
890       if (is_shift) nimf_anthy_preedit_insert (anthy, "ぇ");
891       else          nimf_anthy_preedit_insert (anthy, "え");
892       break;
893     case 15:
894       if (is_shift) nimf_anthy_preedit_insert (anthy, "ぉ");
895       else          nimf_anthy_preedit_insert (anthy, "お");
896       break;
897     case 16:
898       if (is_shift) nimf_anthy_preedit_insert (anthy, "ゃ");
899       else          nimf_anthy_preedit_insert (anthy, "や");
900       break;
901     case 17:
902       if (is_shift) nimf_anthy_preedit_insert (anthy, "ゅ");
903       else          nimf_anthy_preedit_insert (anthy, "ゆ");
904       break;
905     case 18:
906       if (is_shift) nimf_anthy_preedit_insert (anthy, "ょ");
907       else          nimf_anthy_preedit_insert (anthy, "よ");
908       break;
909     case 19:
910       if (is_shift) nimf_anthy_preedit_insert (anthy, "を");
911       else          nimf_anthy_preedit_insert (anthy, "わ");
912       break;
913     case 20:
914       if (is_shift) nimf_anthy_preedit_insert (anthy, "ー");
915       else          nimf_anthy_preedit_insert (anthy, "ほ");
916       break;
917     case 21: nimf_anthy_preedit_insert (anthy, "へ"); break;
918     case 24: nimf_anthy_preedit_insert (anthy, "た"); break;
919     case 25: nimf_anthy_preedit_insert (anthy, "て"); break;
920     case 26:
921       if (is_shift) nimf_anthy_preedit_insert (anthy, "ぃ");
922       else          nimf_anthy_preedit_insert (anthy, "い");
923       break;
924     case 27: nimf_anthy_preedit_insert (anthy, "す"); break;
925     case 28: nimf_anthy_preedit_insert (anthy, "か"); break;
926     case 29: nimf_anthy_preedit_insert (anthy, "ん"); break;
927     case 30: nimf_anthy_preedit_insert (anthy, "な"); break;
928     case 31: nimf_anthy_preedit_insert (anthy, "に"); break;
929     case 32: nimf_anthy_preedit_insert (anthy, "ら"); break;
930     case 33: nimf_anthy_preedit_insert (anthy, "せ"); break;
931     case 34:
932       if (is_shift)
933       {
934         nimf_anthy_preedit_insert (anthy, "「");
935       }
936       else
937       {
938         if (anthy->preedit->len == 0)
939           break;
940 
941         if (nimf_anthy_preedit_offset_has_suffix (anthy, "か"))
942           g_string_overwrite (anthy->preedit,
943                               anthy->preedit_offset - strlen ("か"), "が");
944         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "き"))
945           g_string_overwrite (anthy->preedit,
946                               anthy->preedit_offset - strlen ("き"), "ぎ");
947         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "く"))
948           g_string_overwrite (anthy->preedit,
949                               anthy->preedit_offset - strlen ("く"), "ぐ");
950         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "け"))
951           g_string_overwrite (anthy->preedit,
952                               anthy->preedit_offset - strlen ("け"), "げ");
953         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "こ"))
954           g_string_overwrite (anthy->preedit,
955                               anthy->preedit_offset - strlen ("こ"), "ご");
956         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "さ"))
957           g_string_overwrite (anthy->preedit,
958                               anthy->preedit_offset - strlen ("さ"), "ざ");
959         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "し"))
960           g_string_overwrite (anthy->preedit,
961                               anthy->preedit_offset - strlen ("し"), "じ");
962         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "す"))
963           g_string_overwrite (anthy->preedit,
964                               anthy->preedit_offset - strlen ("す"), "ず");
965         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "せ"))
966           g_string_overwrite (anthy->preedit,
967                               anthy->preedit_offset - strlen ("せ"), "ぜ");
968         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "そ"))
969           g_string_overwrite (anthy->preedit,
970                               anthy->preedit_offset - strlen ("そ"), "ぞ");
971         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "た"))
972           g_string_overwrite (anthy->preedit,
973                               anthy->preedit_offset - strlen ("た"), "だ");
974         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "ち"))
975           g_string_overwrite (anthy->preedit,
976                               anthy->preedit_offset - strlen ("ち"), "ぢ");
977         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "つ"))
978           g_string_overwrite (anthy->preedit,
979                               anthy->preedit_offset - strlen ("つ"), "づ");
980         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "て"))
981           g_string_overwrite (anthy->preedit,
982                               anthy->preedit_offset - strlen ("て"), "で");
983         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "と"))
984           g_string_overwrite (anthy->preedit,
985                               anthy->preedit_offset - strlen ("と"), "ど");
986         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "は"))
987           g_string_overwrite (anthy->preedit,
988                               anthy->preedit_offset - strlen ("は"), "ば");
989         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "ひ"))
990           g_string_overwrite (anthy->preedit,
991                               anthy->preedit_offset - strlen ("ひ"), "び");
992         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "ふ"))
993           g_string_overwrite (anthy->preedit,
994                               anthy->preedit_offset - strlen ("ふ"), "ぶ");
995         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "へ"))
996           g_string_overwrite (anthy->preedit,
997                               anthy->preedit_offset - strlen ("へ"), "べ");
998         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "ほ"))
999           g_string_overwrite (anthy->preedit,
1000                               anthy->preedit_offset - strlen ("ほ"), "ぼ");
1001       }
1002       break;
1003     case 35:
1004       if (is_shift)
1005       {
1006         nimf_anthy_preedit_insert (anthy, "」");
1007       }
1008       else
1009       {
1010         if (anthy->preedit->len == 0)
1011           break;
1012 
1013         if (nimf_anthy_preedit_offset_has_suffix (anthy, "は"))
1014           g_string_overwrite (anthy->preedit,
1015                               anthy->preedit_offset - strlen ("は"), "ぱ");
1016         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "ひ"))
1017           g_string_overwrite (anthy->preedit,
1018                               anthy->preedit_offset - strlen ("ひ"), "ぴ");
1019         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "ふ"))
1020           g_string_overwrite (anthy->preedit,
1021                               anthy->preedit_offset - strlen ("ふ"), "ぷ");
1022         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "へ"))
1023           g_string_overwrite (anthy->preedit,
1024                               anthy->preedit_offset - strlen ("へ"), "ぺ");
1025         else if (nimf_anthy_preedit_offset_has_suffix (anthy, "ほ"))
1026           g_string_overwrite (anthy->preedit,
1027                               anthy->preedit_offset - strlen ("ほ"), "ぽ");
1028       }
1029       break;
1030     case 51: nimf_anthy_preedit_insert (anthy, "む"); break;
1031     case 38: nimf_anthy_preedit_insert (anthy, "ち"); break;
1032     case 39: nimf_anthy_preedit_insert (anthy, "と"); break;
1033     case 40: nimf_anthy_preedit_insert (anthy, "し"); break;
1034     case 41: nimf_anthy_preedit_insert (anthy, "は"); break;
1035     case 42: nimf_anthy_preedit_insert (anthy, "き"); break;
1036     case 43: nimf_anthy_preedit_insert (anthy, "く"); break;
1037     case 44: nimf_anthy_preedit_insert (anthy, "ま"); break;
1038     case 45: nimf_anthy_preedit_insert (anthy, "の"); break;
1039     case 46: nimf_anthy_preedit_insert (anthy, "り"); break;
1040     case 47: nimf_anthy_preedit_insert (anthy, "れ"); break;
1041     case 48: nimf_anthy_preedit_insert (anthy, "け"); break;
1042     case 52:
1043       if (is_shift) nimf_anthy_preedit_insert (anthy, "っ");
1044       else          nimf_anthy_preedit_insert (anthy, "つ");
1045       break;
1046     case 53: nimf_anthy_preedit_insert (anthy, "さ"); break;
1047     case 54: nimf_anthy_preedit_insert (anthy, "そ"); break;
1048     case 55: nimf_anthy_preedit_insert (anthy, "ひ"); break;
1049     case 56: nimf_anthy_preedit_insert (anthy, "こ"); break;
1050     case 57: nimf_anthy_preedit_insert (anthy, "み"); break;
1051     case 58: nimf_anthy_preedit_insert (anthy, "も"); break;
1052     case 59:
1053       if (is_shift) nimf_anthy_preedit_insert (anthy, "、");
1054       else          nimf_anthy_preedit_insert (anthy, "ね");
1055       break;
1056     case 60:
1057       if (is_shift) nimf_anthy_preedit_insert (anthy, "。");
1058       else          nimf_anthy_preedit_insert (anthy, "る");
1059       break;
1060     case 61:
1061       if (is_shift) nimf_anthy_preedit_insert (anthy, "・");
1062       else          nimf_anthy_preedit_insert (anthy, "め");
1063       break;
1064     default:
1065       return FALSE;
1066   }
1067 
1068   return TRUE;
1069 }
1070 
1071 static gchar *
nimf_anthy_convert_to(NimfAnthy * anthy,int candidate_type)1072 nimf_anthy_convert_to (NimfAnthy *anthy, int candidate_type)
1073 {
1074   g_debug (G_STRLOC ": %s", G_STRFUNC);
1075 
1076   struct   anthy_conv_stat conv_stat;
1077   GString *string;
1078   gint     i;
1079 
1080   anthy_set_string (anthy->context, anthy->preedit->str);
1081   anthy_get_stat (anthy->context, &conv_stat);
1082   string = g_string_new ("");
1083   memset (anthy->buffer, 0, NIMF_ANTHY_BUFFER_SIZE);
1084 
1085   for (i = 0; i < conv_stat.nr_segment; i++)
1086   {
1087     anthy_get_segment (anthy->context, i, candidate_type,
1088                        anthy->buffer, NIMF_ANTHY_BUFFER_SIZE);
1089     g_string_append (string, anthy->buffer);
1090   }
1091 
1092   anthy->preedit_offset = anthy->preedit->len;
1093   anthy->preedit_dx     = 0;
1094 
1095   return g_string_free (string, FALSE);
1096 }
1097 
1098 static void
nimf_anthy_replace_last_n(NimfAnthy * anthy)1099 nimf_anthy_replace_last_n (NimfAnthy *anthy)
1100 {
1101   g_debug (G_STRLOC ": %s", G_STRFUNC);
1102 
1103   if (g_str_has_suffix (anthy->preedit->str, "n"))
1104   {
1105     g_string_erase  (anthy->preedit, anthy->preedit->len - 1, 1);
1106     g_string_append (anthy->preedit, "ん");
1107   }
1108 }
1109 
1110 static gboolean
nimf_anthy_filter_event(NimfEngine * engine,NimfServiceIC * target,NimfEvent * event)1111 nimf_anthy_filter_event (NimfEngine    *engine,
1112                          NimfServiceIC *target,
1113                          NimfEvent     *event)
1114 {
1115   g_debug (G_STRLOC ": %s", G_STRFUNC);
1116 
1117   NimfAnthy *anthy = NIMF_ANTHY (engine);
1118   gboolean   retval;
1119 
1120   if (event->key.type == NIMF_EVENT_KEY_RELEASE)
1121     return FALSE;
1122 
1123   if (anthy->method_changed)
1124   {
1125     nimf_anthy_reset (engine, target);
1126     anthy->method_changed = FALSE;
1127   }
1128 
1129   if (nimf_candidatable_is_visible (anthy->candidatable))
1130   {
1131     switch (event->key.keyval)
1132     {
1133       case NIMF_KEY_Return:
1134       case NIMF_KEY_KP_Enter:
1135         nimf_candidatable_hide (anthy->candidatable);
1136         nimf_anthy_emit_commit (engine, target);
1137         return TRUE;
1138       case NIMF_KEY_Up:
1139       case NIMF_KEY_KP_Up:
1140         {
1141           nimf_candidatable_select_previous_item (anthy->candidatable);
1142           gint index = nimf_candidatable_get_selected_index (anthy->candidatable);
1143 
1144           if (G_LIKELY (index >= 0))
1145             on_candidate_clicked (engine, target, NULL, index);
1146         }
1147         return TRUE;
1148       case NIMF_KEY_Down:
1149       case NIMF_KEY_KP_Down:
1150       case NIMF_KEY_space:
1151         {
1152           nimf_candidatable_select_next_item (anthy->candidatable);
1153           gint index = nimf_candidatable_get_selected_index (anthy->candidatable);
1154 
1155           if (G_LIKELY (index >= 0))
1156             on_candidate_clicked (engine, target, NULL, index);
1157         }
1158         return TRUE;
1159       case NIMF_KEY_Left:
1160       case NIMF_KEY_KP_Left:
1161         if (anthy->current_segment > 0)
1162         {
1163           anthy->current_segment--;
1164         }
1165         else
1166         {
1167           struct anthy_conv_stat conv_stat;
1168 
1169           anthy_get_stat (anthy->context, &conv_stat);
1170           anthy->current_segment = conv_stat.nr_segment - 1;
1171         }
1172 
1173         nimf_anthy_convert_preedit_text (engine, target);
1174         nimf_anthy_update_candidate     (engine, target);
1175         return TRUE;
1176       case NIMF_KEY_Right:
1177       case NIMF_KEY_KP_Right:
1178         {
1179           struct anthy_conv_stat conv_stat;
1180 
1181           anthy_get_stat (anthy->context, &conv_stat);
1182 
1183           if (anthy->current_segment < conv_stat.nr_segment - 1)
1184             anthy->current_segment++;
1185           else
1186             anthy->current_segment = 0;
1187         }
1188 
1189         nimf_anthy_convert_preedit_text (engine, target);
1190         nimf_anthy_update_candidate     (engine, target);
1191         return TRUE;
1192       case NIMF_KEY_Page_Up:
1193       case NIMF_KEY_KP_Page_Up:
1194         nimf_anthy_page_up (engine, target);
1195         return TRUE;
1196       case NIMF_KEY_Page_Down:
1197       case NIMF_KEY_KP_Page_Down:
1198         nimf_anthy_page_down (engine, target);
1199         return TRUE;
1200       case NIMF_KEY_Home:
1201         nimf_anthy_page_home (engine, target);
1202         return TRUE;
1203       case NIMF_KEY_End:
1204         nimf_anthy_page_end (engine, target);
1205         return TRUE;
1206       case NIMF_KEY_0:
1207       case NIMF_KEY_1:
1208       case NIMF_KEY_2:
1209       case NIMF_KEY_3:
1210       case NIMF_KEY_4:
1211       case NIMF_KEY_5:
1212       case NIMF_KEY_6:
1213       case NIMF_KEY_7:
1214       case NIMF_KEY_8:
1215       case NIMF_KEY_9:
1216       case NIMF_KEY_KP_0:
1217       case NIMF_KEY_KP_1:
1218       case NIMF_KEY_KP_2:
1219       case NIMF_KEY_KP_3:
1220       case NIMF_KEY_KP_4:
1221       case NIMF_KEY_KP_5:
1222       case NIMF_KEY_KP_6:
1223       case NIMF_KEY_KP_7:
1224       case NIMF_KEY_KP_8:
1225       case NIMF_KEY_KP_9:
1226         {
1227           if (g_strcmp0 (anthy->method,"romaji"))
1228             break;
1229 
1230           if (anthy->current_page < 1)
1231             break;
1232 
1233           struct anthy_segment_stat segment_stat;
1234           gint i, n;
1235 
1236           if (event->key.keyval >= NIMF_KEY_0 &&
1237               event->key.keyval <= NIMF_KEY_9)
1238             n = (event->key.keyval - NIMF_KEY_0 + 9) % 10;
1239           else if (event->key.keyval >= NIMF_KEY_KP_0 &&
1240                    event->key.keyval <= NIMF_KEY_KP_9)
1241             n = (event->key.keyval - NIMF_KEY_KP_0 + 9) % 10;
1242           else
1243             break;
1244 
1245           i = (anthy->current_page - 1) * 10 + n;
1246 
1247           anthy_get_segment_stat (anthy->context, anthy->current_segment, &segment_stat);
1248 
1249           if (i < MIN (anthy->current_page * 10, segment_stat.nr_candidate))
1250           {
1251             on_candidate_clicked (engine, target, NULL, n);
1252             nimf_anthy_update_candidate (engine, target);
1253           }
1254         }
1255         return TRUE;
1256       case NIMF_KEY_Escape:
1257         nimf_candidatable_hide (anthy->candidatable);
1258         nimf_anthy_update_preedit_text (engine, target);
1259         return TRUE;
1260       default:
1261         nimf_candidatable_hide (anthy->candidatable);
1262         nimf_anthy_update_preedit_text (engine, target);
1263         break;
1264     }
1265   }
1266 
1267   if (anthy->preedit->len > 0)
1268   {
1269     if (G_UNLIKELY (nimf_event_matches (event, (const NimfKey **) anthy->hiragana_keys)))
1270     {
1271       gchar *converted;
1272 
1273       converted = nimf_anthy_convert_to (anthy, NTH_HIRAGANA_CANDIDATE);
1274 
1275       g_string_assign (anthy->preedit, converted);
1276       nimf_anthy_update_preedit_state (engine, target, anthy->preedit->str,
1277                                        g_utf8_strlen (anthy->preedit->str, -1));
1278       g_free (converted);
1279 
1280       return TRUE;
1281     }
1282     else if (G_UNLIKELY (nimf_event_matches (event, (const NimfKey **) anthy->katakana_keys)))
1283     {
1284       gchar *converted;
1285 
1286       converted = nimf_anthy_convert_to (anthy, NTH_KATAKANA_CANDIDATE);
1287 
1288       g_string_assign (anthy->preedit, converted);
1289       nimf_anthy_update_preedit_state (engine, target, anthy->preedit->str,
1290                                        g_utf8_strlen (anthy->preedit->str, -1));
1291       g_free (converted);
1292 
1293       return TRUE;
1294     }
1295   }
1296 
1297   if ((event->key.state & NIMF_MODIFIER_MASK) == NIMF_CONTROL_MASK ||
1298       (event->key.state & NIMF_MODIFIER_MASK) == (NIMF_CONTROL_MASK | NIMF_MOD2_MASK))
1299     return FALSE;
1300 
1301   if (event->key.keyval == NIMF_KEY_space)
1302   {
1303     if (anthy->preedit->len == 0)
1304     {
1305       nimf_candidatable_hide (anthy->candidatable);
1306       return FALSE;
1307     }
1308 
1309     anthy->current_segment = 0;
1310     struct anthy_conv_stat conv_stat;
1311 
1312     if (anthy->n_input_mode == COMMON)
1313       nimf_anthy_replace_last_n (anthy);
1314 
1315     anthy_set_string (anthy->context, anthy->preedit->str);
1316     anthy_get_stat (anthy->context, &conv_stat);
1317     anthy->current_segment = conv_stat.nr_segment - 1;
1318     anthy->selections = g_realloc_n (anthy->selections, conv_stat.nr_segment,
1319                                      sizeof (gint));
1320     memset (anthy->selections, 0, conv_stat.nr_segment * sizeof (gint));
1321 
1322     nimf_anthy_convert_preedit_text (engine, target);
1323 
1324     if (!nimf_candidatable_is_visible (anthy->candidatable))
1325       nimf_candidatable_show (anthy->candidatable, target,
1326                               !nimf_service_ic_get_use_preedit (target));
1327 
1328     anthy->current_segment = 0;
1329     nimf_anthy_convert_preedit_text (engine, target);
1330     nimf_anthy_update_candidate (engine, target);
1331 
1332     return TRUE;
1333   }
1334 
1335   if (event->key.keyval == NIMF_KEY_Return)
1336   {
1337     if (anthy->preedit->len > 0)
1338     {
1339       if (anthy->n_input_mode == COMMON)
1340         nimf_anthy_replace_last_n (anthy);
1341 
1342       nimf_anthy_reset (engine, target);
1343       retval = TRUE;
1344     }
1345 
1346     retval = FALSE;
1347   }
1348   else if (event->key.keyval == NIMF_KEY_BackSpace)
1349   {
1350     if (anthy->preedit_offset + anthy->preedit_dx > 0)
1351     {
1352       if (anthy->preedit_dx > 0)
1353       {
1354         g_string_erase (anthy->preedit, anthy->preedit_offset + anthy->preedit_dx - 1, 1);
1355         anthy->preedit_dx--;
1356       }
1357       else if (anthy->preedit_offset > 0)
1358       {
1359         const gchar *prev;
1360 
1361         prev = g_utf8_prev_char (anthy->preedit->str + anthy->preedit_offset);
1362         g_string_erase (anthy->preedit, prev - anthy->preedit->str,
1363                         anthy->preedit->str + anthy->preedit_offset - prev);
1364         anthy->preedit_offset = prev - anthy->preedit->str;
1365       }
1366 
1367       retval = TRUE;
1368     }
1369     else
1370     {
1371       retval = FALSE;
1372     }
1373   }
1374   else if (event->key.keyval == NIMF_KEY_Delete ||
1375            event->key.keyval == NIMF_KEY_KP_Delete)
1376   {
1377     if (anthy->preedit_offset + anthy->preedit_dx < anthy->preedit->len)
1378     {
1379       const gchar *next;
1380       gint         len;
1381 
1382       next = g_utf8_next_char (anthy->preedit->str + anthy->preedit_offset + anthy->preedit_dx);
1383       len = next - (anthy->preedit->str + anthy->preedit_offset + anthy->preedit_dx);
1384 
1385       g_string_erase (anthy->preedit, anthy->preedit_offset + anthy->preedit_dx, len);
1386 
1387       retval = TRUE;
1388     }
1389     else
1390     {
1391       retval = FALSE;
1392     }
1393   }
1394   else if (event->key.keyval == NIMF_KEY_Left ||
1395            event->key.keyval == NIMF_KEY_KP_Left)
1396   {
1397     if (anthy->preedit_dx > 0)
1398     {
1399       anthy->preedit_offset += anthy->preedit_dx - 1;
1400       anthy->preedit_dx = 0;
1401 
1402       retval = TRUE;
1403     }
1404     else if (anthy->preedit_offset > 0)
1405     {
1406       const gchar *prev;
1407 
1408       prev = g_utf8_prev_char (anthy->preedit->str + anthy->preedit_offset);
1409       anthy->preedit_offset = prev - anthy->preedit->str;
1410 
1411       retval = TRUE;
1412     }
1413     else
1414     {
1415       retval = FALSE;
1416     }
1417   }
1418   else if (event->key.keyval == NIMF_KEY_Right ||
1419            event->key.keyval == NIMF_KEY_KP_Right)
1420   {
1421     const gchar *next;
1422 
1423     if (anthy->preedit_offset + anthy->preedit_dx < anthy->preedit->len)
1424     {
1425       next = g_utf8_next_char (anthy->preedit->str + anthy->preedit_offset + anthy->preedit_dx);
1426       anthy->preedit_offset = next - anthy->preedit->str;
1427       anthy->preedit_dx = 0;
1428 
1429       retval = TRUE;
1430     }
1431     else
1432     {
1433       retval = FALSE;
1434     }
1435   }
1436   else if (event->key.keyval > 127)
1437     retval = FALSE;
1438   else if (g_strcmp0 (anthy->method, "romaji") == 0)
1439     retval = nimf_anthy_filter_event_romaji (engine, target, event);
1440   else
1441     retval = nimf_anthy_filter_event_pc104 (engine, target, event);
1442 
1443   if (retval == FALSE)
1444     return FALSE;
1445 
1446   nimf_anthy_update_preedit_text (engine, target);
1447 
1448   return TRUE;
1449 }
1450 
1451 static void
on_changed_keys(GSettings * settings,gchar * key,NimfAnthy * anthy)1452 on_changed_keys (GSettings *settings,
1453                  gchar     *key,
1454                  NimfAnthy *anthy)
1455 {
1456   g_debug (G_STRLOC ": %s", G_STRFUNC);
1457 
1458   gchar **keys = g_settings_get_strv (settings, key);
1459 
1460   if (g_strcmp0 (key, "hiragana-keys") == 0)
1461   {
1462     nimf_key_freev (anthy->hiragana_keys);
1463     anthy->hiragana_keys = nimf_key_newv ((const gchar **) keys);
1464   }
1465   else if (g_strcmp0 (key, "katakana-keys") == 0)
1466   {
1467     nimf_key_freev (anthy->katakana_keys);
1468     anthy->katakana_keys = nimf_key_newv ((const gchar **) keys);
1469   }
1470 
1471   g_strfreev (keys);
1472 }
1473 
1474 static void
on_changed_method(GSettings * settings,gchar * key,NimfAnthy * anthy)1475 on_changed_method (GSettings *settings,
1476                    gchar     *key,
1477                    NimfAnthy *anthy)
1478 {
1479   g_debug (G_STRLOC ": %s", G_STRFUNC);
1480 
1481   g_free (anthy->method);
1482   anthy->method = g_settings_get_string (settings, key);
1483   anthy->method_changed = TRUE;
1484 }
1485 
1486 static gint
nimf_anthy_get_n_input_mode(NimfAnthy * anthy)1487 nimf_anthy_get_n_input_mode (NimfAnthy *anthy)
1488 {
1489   g_debug (G_STRLOC ": %s", G_STRFUNC);
1490 
1491   gchar *mode;
1492   gint   retval;
1493 
1494   mode = g_settings_get_string (anthy->settings, "get-n-input-mode-list");
1495 
1496   if (g_strcmp0 (mode, "common") == 0)
1497     retval = COMMON;
1498   else
1499     retval = EXPLICIT;
1500 
1501   g_free (mode);
1502 
1503   return retval;
1504 }
1505 
1506 static void
on_changed_n_input_mode(GSettings * settings,gchar * key,NimfAnthy * anthy)1507 on_changed_n_input_mode (GSettings *settings,
1508                          gchar     *key,
1509                          NimfAnthy *anthy)
1510 {
1511   g_debug (G_STRLOC ": %s", G_STRFUNC);
1512 
1513   gchar *mode;
1514 
1515   mode = g_settings_get_string (settings, key);
1516 
1517   if (g_strcmp0 (mode, "common") == 0)
1518     anthy->n_input_mode = COMMON;
1519   else
1520     anthy->n_input_mode = EXPLICIT;
1521 
1522   g_free (mode);
1523 }
1524 
1525 static void
nimf_anthy_init(NimfAnthy * anthy)1526 nimf_anthy_init (NimfAnthy *anthy)
1527 {
1528   g_debug (G_STRLOC ": %s", G_STRFUNC);
1529 
1530   gchar **hiragana_keys;
1531   gchar **katakana_keys;
1532 
1533   anthy->id               = g_strdup ("nimf-anthy");
1534   anthy->preedit          = g_string_new ("");
1535   anthy->preedit_attrs    = g_malloc0_n (3, sizeof (NimfPreeditAttr *));
1536   anthy->preedit_attrs[0] = nimf_preedit_attr_new (NIMF_PREEDIT_ATTR_UNDERLINE, 0, 0);
1537   anthy->preedit_attrs[1] = nimf_preedit_attr_new (NIMF_PREEDIT_ATTR_HIGHLIGHT, 0, 0);
1538   anthy->preedit_attrs[2] = NULL;
1539   anthy->selections = g_malloc0_n (16, sizeof (gint));
1540 
1541   if (nimf_anthy_romaji)
1542   {
1543     g_hash_table_ref (nimf_anthy_romaji);
1544   }
1545   else
1546   {
1547     nimf_anthy_romaji = g_hash_table_new (g_str_hash, g_str_equal);
1548 
1549     gint i;
1550     for (i = 0; i < G_N_ELEMENTS (romaji_map); i++)
1551       g_hash_table_insert (nimf_anthy_romaji, romaji_map[i].key,
1552                                               romaji_map[i].value);
1553   }
1554 
1555   if (anthy_init () < 0)
1556     g_error (G_STRLOC ": %s: anthy is not initialized", G_STRFUNC);
1557 
1558   /* FIXME */
1559   /* anthy_set_personality () */
1560   anthy->context = anthy_create_context ();
1561   nimf_anthy_ref_count++;
1562   anthy_context_set_encoding (anthy->context, ANTHY_UTF8_ENCODING);
1563 
1564   anthy->settings = g_settings_new ("org.nimf.engines.nimf-anthy");
1565   anthy->method   = g_settings_get_string (anthy->settings, "get-method-infos");
1566   anthy->n_input_mode = nimf_anthy_get_n_input_mode (anthy);
1567   hiragana_keys = g_settings_get_strv   (anthy->settings, "hiragana-keys");
1568   katakana_keys = g_settings_get_strv   (anthy->settings, "katakana-keys");
1569   anthy->hiragana_keys = nimf_key_newv ((const gchar **) hiragana_keys);
1570   anthy->katakana_keys = nimf_key_newv ((const gchar **) katakana_keys);
1571 
1572   g_strfreev (hiragana_keys);
1573   g_strfreev (katakana_keys);
1574 
1575   g_signal_connect (anthy->settings, "changed::hiragana-keys",
1576                     G_CALLBACK (on_changed_keys), anthy);
1577   g_signal_connect (anthy->settings, "changed::katakana-keys",
1578                     G_CALLBACK (on_changed_keys), anthy);
1579   g_signal_connect (anthy->settings, "changed::get-method-infos",
1580                     G_CALLBACK (on_changed_method), anthy);
1581   g_signal_connect (anthy->settings, "changed::get-n-input-mode-list",
1582                     G_CALLBACK (on_changed_n_input_mode), anthy);
1583 }
1584 
1585 static void
nimf_anthy_finalize(GObject * object)1586 nimf_anthy_finalize (GObject *object)
1587 {
1588   g_debug (G_STRLOC ": %s", G_STRFUNC);
1589 
1590   NimfAnthy *anthy = NIMF_ANTHY (object);
1591 
1592   nimf_preedit_attr_freev (anthy->preedit_attrs);
1593   g_free (anthy->id);
1594   g_free (anthy->selections);
1595   g_hash_table_unref (nimf_anthy_romaji);
1596   g_string_free (anthy->preedit, TRUE);
1597   nimf_key_freev (anthy->hiragana_keys);
1598   nimf_key_freev (anthy->katakana_keys);
1599   g_free (anthy->method);
1600   g_object_unref (anthy->settings);
1601 
1602   if (--nimf_anthy_ref_count == 0)
1603   {
1604     nimf_anthy_romaji = NULL;
1605     anthy_release_context (anthy->context);
1606     anthy_quit ();
1607   }
1608 
1609   G_OBJECT_CLASS (nimf_anthy_parent_class)->finalize (object);
1610 }
1611 
1612 const gchar *
nimf_anthy_get_id(NimfEngine * engine)1613 nimf_anthy_get_id (NimfEngine *engine)
1614 {
1615   g_debug (G_STRLOC ": %s", G_STRFUNC);
1616 
1617   g_return_val_if_fail (NIMF_IS_ENGINE (engine), NULL);
1618 
1619   return NIMF_ANTHY (engine)->id;
1620 }
1621 
1622 const gchar *
nimf_anthy_get_icon_name(NimfEngine * engine)1623 nimf_anthy_get_icon_name (NimfEngine *engine)
1624 {
1625   g_debug (G_STRLOC ": %s", G_STRFUNC);
1626 
1627   g_return_val_if_fail (NIMF_IS_ENGINE (engine), NULL);
1628 
1629   return NIMF_ANTHY (engine)->id;
1630 }
1631 
1632 void
nimf_anthy_set_method(NimfEngine * engine,const gchar * method_id)1633 nimf_anthy_set_method (NimfEngine *engine, const gchar *method_id)
1634 {
1635   g_debug (G_STRLOC ": %s", G_STRFUNC);
1636 
1637   g_settings_set_string (NIMF_ANTHY (engine)->settings,
1638                          "get-method-infos", method_id);
1639 }
1640 
1641 static void
nimf_anthy_constructed(GObject * object)1642 nimf_anthy_constructed (GObject *object)
1643 {
1644   g_debug (G_STRLOC ": %s", G_STRFUNC);
1645 
1646   NimfAnthy *anthy = NIMF_ANTHY (object);
1647 
1648   anthy->candidatable = nimf_engine_get_candidatable (NIMF_ENGINE (anthy));
1649 }
1650 
1651 static void
nimf_anthy_class_init(NimfAnthyClass * class)1652 nimf_anthy_class_init (NimfAnthyClass *class)
1653 {
1654   g_debug (G_STRLOC ": %s", G_STRFUNC);
1655 
1656   GObjectClass *object_class = G_OBJECT_CLASS (class);
1657   NimfEngineClass *engine_class = NIMF_ENGINE_CLASS (class);
1658 
1659   engine_class->filter_event       = nimf_anthy_filter_event;
1660   engine_class->reset              = nimf_anthy_reset;
1661   engine_class->focus_in           = nimf_anthy_focus_in;
1662   engine_class->focus_out          = nimf_anthy_focus_out;
1663 
1664   engine_class->candidate_page_up   = nimf_anthy_page_up;
1665   engine_class->candidate_page_down = nimf_anthy_page_down;
1666   engine_class->candidate_clicked   = on_candidate_clicked;
1667   engine_class->candidate_scrolled  = on_candidate_scrolled;
1668 
1669   engine_class->get_id        = nimf_anthy_get_id;
1670   engine_class->get_icon_name = nimf_anthy_get_icon_name;
1671   engine_class->set_method    = nimf_anthy_set_method;
1672 
1673   object_class->constructed = nimf_anthy_constructed;
1674   object_class->finalize    = nimf_anthy_finalize;
1675 }
1676 
1677 static void
nimf_anthy_class_finalize(NimfAnthyClass * class)1678 nimf_anthy_class_finalize (NimfAnthyClass *class)
1679 {
1680   g_debug (G_STRLOC ": %s", G_STRFUNC);
1681 }
1682 
1683 typedef struct {
1684   const gchar *id;
1685   const gchar *name;
1686 } Method;
1687 
1688 static const Method methods[] = {
1689   {"romaji", N_("Romaji")},
1690   {"pc104",  N_("English Keyboard (pc104)")}
1691 };
1692 
1693 NimfMethodInfo **
nimf_anthy_get_method_infos()1694 nimf_anthy_get_method_infos ()
1695 {
1696   g_debug (G_STRLOC ": %s", G_STRFUNC);
1697 
1698   NimfMethodInfo **infos;
1699   gint             n_methods = G_N_ELEMENTS (methods);
1700   gint             i;
1701 
1702   infos = g_malloc (sizeof (NimfMethodInfo *) * n_methods + 1);
1703 
1704   for (i = 0; i < n_methods; i++)
1705   {
1706     infos[i] = nimf_method_info_new ();
1707     infos[i]->method_id = g_strdup (methods[i].id);
1708     infos[i]->label     = g_strdup (gettext (methods[i].name));
1709     infos[i]->group     = NULL;
1710   }
1711 
1712   infos[n_methods] = NULL;
1713 
1714   return infos;
1715 }
1716 
1717 static const Method modes[] = {
1718   {"common",   N_("Common practice")},
1719   {"explicit", N_("Explicitly type nn")}
1720 };
1721 
1722 NimfMethodInfo **
nimf_anthy_get_n_input_mode_list()1723 nimf_anthy_get_n_input_mode_list ()
1724 {
1725   g_debug (G_STRLOC ": %s", G_STRFUNC);
1726 
1727   NimfMethodInfo **infos;
1728   gint             n_methods = G_N_ELEMENTS (modes);
1729   gint             i;
1730 
1731   infos = g_malloc (sizeof (NimfMethodInfo *) * n_methods + 1);
1732 
1733   for (i = 0; i < n_methods; i++)
1734   {
1735     infos[i] = nimf_method_info_new ();
1736     infos[i]->method_id = g_strdup (modes[i].id);
1737     infos[i]->label     = g_strdup (gettext (modes[i].name));
1738     infos[i]->group     = NULL;
1739   }
1740 
1741   infos[n_methods] = NULL;
1742 
1743   return infos;
1744 }
1745 
1746 void
module_register_type(GTypeModule * type_module)1747 module_register_type (GTypeModule *type_module)
1748 {
1749   g_debug (G_STRLOC ": %s", G_STRFUNC);
1750 
1751   nimf_anthy_register_type (type_module);
1752 }
1753 
1754 GType
module_get_type()1755 module_get_type ()
1756 {
1757   g_debug (G_STRLOC ": %s", G_STRFUNC);
1758 
1759   return nimf_anthy_get_type ();
1760 }
1761