1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2
3 #include <stdio.h>
4
5 #include <pobl/bl_mem.h> /* malloc/alloca/free */
6 #include <pobl/bl_str.h> /* strdup/bl_str_sep/bl_snprintf */
7 #include <pobl/bl_util.h> /* DIGIT_STR_LEN */
8
9 #include <ui_im.h>
10
11 #include "../im_common.h"
12 #include "../im_info.h"
13 #include "wnnlib.h"
14
15 #if 0
16 #define IM_WNN_DEBUG 1
17 #endif
18
19 /* Don't forget to modify digit_to_wstr() if MAX_DIGIT_NUM is changed. */
20 #define MAX_DIGIT_NUM 3 /* 999 */
21 #define CAND_WINDOW_ROWS 5
22
23 typedef struct im_wnn {
24 /* input method common object */
25 ui_im_t im;
26
27 char buf[1024];
28 int is_enabled;
29 int is_cand;
30
31 vt_char_encoding_t term_encoding;
32
33 char *encoding_name; /* encoding of conversion engine */
34
35 /* conv is NULL if term_encoding == wnn encoding */
36 ef_parser_t *parser_term; /* for term encoding */
37 ef_conv_t *conv; /* for term encoding */
38
39 jcConvBuf *convbuf;
40 int dan;
41
42 } im_wnn_t;
43
44 /* --- static variables --- */
45
46 static int ref_count = 0;
47 static ui_im_export_syms_t *syms = NULL; /* mlterm internal symbols */
48 static ef_parser_t *parser_wchar = NULL;
49
50 /* --- static functions --- */
51
digit_to_wstr(wchar * dst,int digit)52 static wchar *digit_to_wstr(wchar *dst, int digit) {
53 int num;
54
55 if (digit >= 1000) {
56 /* Ignore it because MAX_DIGIT_NUM is 3 (=999). */
57 digit -= (digit / 1000) * 1000;
58 }
59
60 if (digit >= 100) {
61 num = digit / 100;
62 *(dst++) = num + 0x30;
63 digit -= num * 100;
64 } else if (((digit - 1) / CAND_WINDOW_ROWS + 1) * CAND_WINDOW_ROWS >= 100) {
65 *(dst++) = ' ';
66 }
67
68 if (digit >= 10) {
69 num = digit / 10;
70 *(dst++) = num + 0x30;
71 digit -= num * 10;
72 } else if (((digit - 1) / CAND_WINDOW_ROWS + 1) * CAND_WINDOW_ROWS >= 10) {
73 *(dst++) = ' ';
74 }
75
76 *(dst++) = digit + 0x30;
77
78 return dst;
79 }
80
wchar_parser_set_str(ef_parser_t * parser,u_char * str,size_t size)81 static void wchar_parser_set_str(ef_parser_t *parser, u_char *str, size_t size) {
82 parser->str = str;
83 parser->left = size;
84 parser->marked_left = 0;
85 parser->is_eos = 0;
86 }
87
wchar_parser_destroy(ef_parser_t * parser)88 static void wchar_parser_destroy(ef_parser_t *parser) { free(parser); }
89
wchar_parser_next_char(ef_parser_t * parser,ef_char_t * ch)90 static int wchar_parser_next_char(ef_parser_t *parser, ef_char_t *ch) {
91 wchar wch;
92
93 if (parser->is_eos) {
94 return 0;
95 }
96
97 ef_parser_mark(parser);
98
99 wch = ((wchar*)parser->str)[0];
100
101 if (wch < 0x100) {
102 ch->size = 1;
103
104 if (wch < 0x80) {
105 ch->ch[0] = wch;
106 ch->cs = US_ASCII;
107 } else {
108 ch->ch[0] = (wch & 0x7f);
109 ch->cs = JISX0201_KATA;
110 }
111 } else if ((wch & 0x8080) == 0x8080) {
112 ef_int_to_bytes(ch->ch, 2, wch & ~0x8080);
113 ch->size = 2;
114 ch->cs = JISX0208_1983;
115 } else {
116 ef_parser_reset(parser);
117
118 return 0;
119 }
120
121 ef_parser_n_increment(parser, 2);
122 ch->property = 0;
123
124 return 1;
125 }
126
wchar_parser_new(void)127 static ef_parser_t *wchar_parser_new(void) {
128 ef_parser_t *parser;
129
130 if ((parser = malloc(sizeof(ef_parser_t))) == NULL) {
131 return NULL;
132 }
133
134 ef_parser_init(parser);
135
136 parser->init = ef_parser_init;
137 parser->set_str = wchar_parser_set_str;
138 parser->destroy = wchar_parser_destroy;
139 parser->next_char = wchar_parser_next_char;
140
141 return parser;
142 }
143
preedit(im_wnn_t * wnn,char * preedit,size_t preedit_len,int rev_pos,int rev_len,char * candidateword,size_t candidateword_len,char * pos)144 static void preedit(im_wnn_t *wnn, char *preedit, /* wchar */
145 size_t preedit_len, int rev_pos, int rev_len, char *candidateword, /* wchar */
146 size_t candidateword_len, char *pos) {
147 int x;
148 int y;
149
150 if (preedit == NULL) {
151 goto candidate;
152 } else if (preedit_len == 0) {
153 if (wnn->im.preedit.filled_len > 0) {
154 /* Stop preediting. */
155 wnn->im.preedit.filled_len = 0;
156 }
157 } else {
158 ef_char_t ch;
159 vt_char_t *p;
160 u_int num_chars;
161 u_int len;
162 u_char *tmp = NULL;
163 size_t pos_len;
164
165 wnn->im.preedit.cursor_offset = rev_pos;
166
167 num_chars = 0;
168 (*parser_wchar->init)(parser_wchar);
169 (*parser_wchar->set_str)(parser_wchar, preedit, preedit_len);
170 while ((*parser_wchar->next_char)(parser_wchar, &ch)) {
171 num_chars++;
172 }
173
174 pos_len = strlen(pos);
175
176 if ((p = realloc(wnn->im.preedit.chars, sizeof(vt_char_t) * (num_chars + pos_len))) ==
177 NULL) {
178 return;
179 }
180
181 if ((len = im_convert_encoding(parser_wchar, wnn->conv, preedit, &tmp, preedit_len))) {
182 preedit = tmp;
183 preedit_len = len;
184 }
185
186 (*syms->vt_str_init)(wnn->im.preedit.chars = p,
187 wnn->im.preedit.num_chars = (num_chars + pos_len));
188 wnn->im.preedit.filled_len = 0;
189
190 (*wnn->parser_term->init)(wnn->parser_term);
191 (*wnn->parser_term->set_str)(wnn->parser_term, preedit, preedit_len);
192 while ((*wnn->parser_term->next_char)(wnn->parser_term, &ch)) {
193 int is_fullwidth;
194 int is_comb;
195
196 if ((*syms->vt_convert_to_internal_ch)(wnn->im.vtparser, &ch) <= 0) {
197 continue;
198 }
199
200 if (ch.property & EF_FULLWIDTH) {
201 is_fullwidth = 1;
202 } else if (ch.property & EF_AWIDTH) {
203 /* TODO: check col_size_of_width_a */
204 is_fullwidth = 1;
205 } else {
206 is_fullwidth = IS_FULLWIDTH_CS(ch.cs);
207 }
208
209 if (ch.property & EF_COMBINING) {
210 is_comb = 1;
211
212 if ((*syms->vt_char_combine)(p - 1, ef_char_to_int(&ch), ch.cs, is_fullwidth,
213 (ch.property & EF_AWIDTH) ? 1 : 0, is_comb,
214 VT_FG_COLOR, VT_BG_COLOR, 0, 0, LS_UNDERLINE_SINGLE, 0, 0)) {
215 continue;
216 }
217
218 /*
219 * if combining failed , char is normally appended.
220 */
221 } else {
222 is_comb = 0;
223 }
224
225 if (wnn->im.preedit.cursor_offset <= wnn->im.preedit.filled_len &&
226 wnn->im.preedit.filled_len < wnn->im.preedit.cursor_offset + rev_len) {
227 (*syms->vt_char_set)(p, ef_char_to_int(&ch), ch.cs, is_fullwidth,
228 (ch.property & EF_AWIDTH) ? 1 : 0, is_comb, VT_BG_COLOR,
229 VT_FG_COLOR, 0, 0, LS_UNDERLINE_SINGLE, 0, 0);
230 } else {
231 (*syms->vt_char_set)(p, ef_char_to_int(&ch), ch.cs, is_fullwidth,
232 (ch.property & EF_AWIDTH) ? 1 : 0, is_comb, VT_FG_COLOR,
233 VT_BG_COLOR, 0, 0, LS_UNDERLINE_SINGLE, 0, 0);
234 }
235
236 p++;
237 wnn->im.preedit.filled_len++;
238 }
239
240 for (; pos_len > 0; pos_len--) {
241 (*syms->vt_char_set)(p++, *(pos++), US_ASCII, 0, 0, 0, VT_FG_COLOR, VT_BG_COLOR, 0, 0,
242 LS_UNDERLINE_SINGLE, 0, 0);
243 wnn->im.preedit.filled_len++;
244 }
245
246 if (tmp) {
247 free(tmp);
248 }
249 }
250
251 (*wnn->im.listener->draw_preedit_str)(wnn->im.listener->self, wnn->im.preedit.chars,
252 wnn->im.preedit.filled_len, wnn->im.preedit.cursor_offset);
253
254 candidate:
255 if (candidateword == NULL) {
256 return;
257 } else if (candidateword_len == 0) {
258 if (wnn->im.stat_screen) {
259 (*wnn->im.stat_screen->destroy)(wnn->im.stat_screen);
260 wnn->im.stat_screen = NULL;
261 }
262 } else {
263 u_char *tmp = NULL;
264
265 (*wnn->im.listener->get_spot)(wnn->im.listener->self, wnn->im.preedit.chars,
266 wnn->im.preedit.segment_offset, &x, &y);
267
268 if (wnn->im.stat_screen == NULL) {
269 if (!(wnn->im.stat_screen = (*syms->ui_im_status_screen_new)(
270 wnn->im.disp, wnn->im.font_man, wnn->im.color_man, wnn->im.vtparser,
271 (*wnn->im.listener->is_vertical)(wnn->im.listener->self),
272 (*wnn->im.listener->get_line_height)(wnn->im.listener->self), x, y))) {
273 #ifdef DEBUG
274 bl_warn_printf(BL_DEBUG_TAG " ui_im_status_screen_new() failed.\n");
275 #endif
276
277 return;
278 }
279 } else {
280 (*wnn->im.stat_screen->show)(wnn->im.stat_screen);
281 (*wnn->im.stat_screen->set_spot)(wnn->im.stat_screen, x, y);
282 }
283
284 (*parser_wchar->init)(parser_wchar);
285 if (im_convert_encoding(parser_wchar, wnn->conv, candidateword, &tmp, candidateword_len)) {
286 candidateword = tmp;
287 }
288
289 (*wnn->im.stat_screen->set)(wnn->im.stat_screen, wnn->parser_term, candidateword);
290
291 if (tmp) {
292 free(tmp);
293 }
294 }
295 }
296
commit(im_wnn_t * wnn,const char * str,size_t len)297 static void commit(im_wnn_t *wnn, const char *str, size_t len) {
298 (*wnn->im.listener->write_to_term)(wnn->im.listener->self, str, len, parser_wchar);
299 }
300
insert_char(im_wnn_t * wnn,u_char key_char)301 static int insert_char(im_wnn_t *wnn, u_char key_char) {
302 static struct {
303 wchar a;
304 wchar i;
305 wchar u;
306 wchar e;
307 wchar o;
308
309 } kana_table[] = {
310 /* a */ /* i */ /* u */ /* e */ /* o */
311 {0xa4a2, 0xa4a4, 0xa4a6, 0xa4a8, 0xa4aa},
312 {0xa4d0, 0xa4d3, 0xa4d6, 0xa4d9, 0xa4dc}, /* b */
313 {0xa4ab, 0xa4ad, 0xa4af, 0xa4b1, 0xa4b3}, /* c */
314 {0xa4c0, 0xa4c2, 0xa4c5, 0xa4c7, 0xa4c9}, /* d */
315 {0xa4e3, 0xa4a3, 0xa4e5, 0xa4a7, 0xa4e7}, /* xy */
316 {0, 0, 0xa4d5, 0, 0,}, /* f */
317 {0xa4ac, 0xa4ae, 0xa4b0, 0xa4b2, 0xa4b4}, /* g */
318 {0xa4cf, 0xa4d2, 0xa4d5, 0xa4d8, 0xa4db}, /* h */
319 {0xa4e3, 0, 0xa4e5, 0xa4a7, 0xa4e7}, /* ch/sh */
320 {0, 0xa4b8, 0, 0, 0,}, /* j */
321 {0xa4ab, 0xa4ad, 0xa4af, 0xa4b1, 0xa4b3}, /* k */
322 {0xa4a1, 0xa4a3, 0xa4a5, 0xa4a7, 0xa4a9}, /* l */
323 {0xa4de, 0xa4df, 0xa4e0, 0xa4e1, 0xa4e2}, /* m */
324 {0xa4ca, 0xa4cb, 0xa4cc, 0xa4cd, 0xa4ce}, /* n */
325 {0, 0, 0, 0, 0,},
326 {0xa4d1, 0xa4d4, 0xa4d7, 0xa4da, 0xa4dd}, /* p */
327 {0, 0, 0, 0, 0,},
328 {0xa4e9, 0xa4ea, 0xa4eb, 0xa4ec, 0xa4ed}, /* r */
329 {0xa4b5, 0xa4b7, 0xa4b9, 0xa4bb, 0xa4bd}, /* s */
330 {0xa4bf, 0xa4c1, 0xa4c4, 0xa4c6, 0xa4c8}, /* t */
331 {0, 0, 0, 0, 0,},
332 {0, 0, 0, 0, 0,},
333 {0xa4ef, 0xa4f0, 0, 0xa4f1, 0xa4f2}, /* w */
334 {0xa4a1, 0xa4a3, 0xa4a5, 0xa4a7, 0xa4a9}, /* x */
335 {0xa4e4, 0, 0xa4e6, 0, 0xa4e8}, /* y */
336 {0xa4b6, 0xa4b8, 0xa4ba, 0xa4bc, 0xa4be}, /* z */
337 };
338 static wchar sign_table1[] = {
339 0xa1aa, 0xa1c9, 0xa1f4, 0xa1f0, 0xa1f3, 0xa1f5, 0xa1c7, 0xa1ca, 0xa1cb, 0xa1f6, 0xa1dc,
340 0xa1a4, 0xa1bc, 0xa1a3, 0xa1bf, 0xa3b0, 0xa3b1, 0xa3b2, 0xa3b3, 0xa3b4, 0xa3b5, 0xa3b6,
341 0xa3b7, 0xa3b8, 0xa3b9, 0xa1a7, 0xa1a8, 0xa1e3, 0xa1e1, 0xa1e4, 0xa1a9, 0xa1f7,
342 };
343 static wchar sign_table2[] = {
344 0xa1ce, 0xa1ef, 0xa1cf, 0xa1b0, 0xa1b2,
345 };
346 static wchar sign_table3[] = {
347 0xa1d0, 0xa1c3, 0xa1d1, 0xa1c1,
348 };
349 wchar wch;
350
351 if (wnn->dan) {
352 jcDeleteChar(wnn->convbuf, 1);
353 }
354
355 if (key_char == 'a' || key_char == 'i' || key_char == 'u' || key_char == 'e' || key_char == 'o') {
356 if (wnn->dan == 'f' - 'a') {
357 if (key_char != 'u') {
358 jcInsertChar(wnn->convbuf, 0xa4d5); /* hu */
359 wnn->dan = 'x' - 'a';
360 }
361 } else if (wnn->dan == 'j' - 'a') {
362 if (key_char != 'i') {
363 jcInsertChar(wnn->convbuf, 0xa4b8); /* zi */
364 wnn->dan = 'e' - 'a';
365 }
366 }
367
368 if (key_char == 'a') {
369 wch = kana_table[wnn->dan].a;
370 wnn->dan = 0;
371 } else if (key_char == 'i') {
372 if (wnn->dan == 'i' - 'a') {
373 wnn->dan = 0;
374
375 return 0; /* shi/chi */
376 }
377
378 wch = kana_table[wnn->dan].i;
379 wnn->dan = 0;
380 } else if (key_char == 'u') {
381 if (wnn->dan == 'j' - 'a') {
382 jcInsertChar(wnn->convbuf, 0xa4b8); /* zi */
383 wnn->dan = 'e' - 'a';
384 }
385 wch = kana_table[wnn->dan].u;
386 wnn->dan = 0;
387 } else if (key_char == 'e') {
388 if (wnn->dan == 'f' - 'a') {
389 jcInsertChar(wnn->convbuf, 0xa4d5); /* hu */
390 wnn->dan = 'x' - 'a';
391 } else if (wnn->dan == 'j' - 'a') {
392 jcInsertChar(wnn->convbuf, 0xa4b8); /* zi */
393 wnn->dan = 'x' - 'a';
394 }
395 wch = kana_table[wnn->dan].e;
396 wnn->dan = 0;
397 } else /* if( key_char == 'o') */
398 {
399 if (wnn->dan == 'f' - 'a') {
400 jcInsertChar(wnn->convbuf, 0xa4d5); /* hu */
401 wnn->dan = 'x' - 'a';
402 } else if (wnn->dan == 'j' - 'a') {
403 jcInsertChar(wnn->convbuf, 0xa4b8); /* zi */
404 wnn->dan = 'e' - 'a';
405 }
406 wch = kana_table[wnn->dan].o;
407 wnn->dan = 0;
408 }
409 } else if (('!' <= key_char && key_char <= '@') || ('[' <= key_char && key_char <= '_') ||
410 ('{' <= key_char && key_char <= '~')) {
411 if (wnn->dan) {
412 jcInsertChar(wnn->convbuf, wnn->dan + 'a');
413 wnn->dan = 0;
414 }
415
416 if (key_char <= '@') {
417 wch = sign_table1[key_char - '!'];
418 } else if (key_char <= '_') {
419 wch = sign_table2[key_char - '['];
420 } else {
421 wch = sign_table3[key_char - '{'];
422 }
423 } else {
424 if (wnn->dan == 'n' - 'a' && key_char != 'a' && key_char != 'i' && key_char != 'u' &&
425 key_char != 'e' && key_char != 'o' && key_char != 'y') {
426 if (key_char == 'n') {
427 wch = 0xa4f3; /* n */
428 wnn->dan = 0;
429 } else {
430 jcInsertChar(wnn->convbuf, 0xa4f3);
431 wch = key_char;
432 wnn->dan = key_char - 'a';
433 }
434 } else if (key_char == wnn->dan + 'a') {
435 jcInsertChar(wnn->convbuf, 0xa4c3);
436 wch = key_char;
437 } else if (key_char == 'y') {
438 if (wnn->dan == 'k' - 'a') {
439 jcInsertChar(wnn->convbuf, 0xa4ad); /* ki */
440 wnn->dan = 'x' - 'a';
441 } else if (wnn->dan == 'g' - 'a') {
442 jcInsertChar(wnn->convbuf, 0xa4ae); /* gi */
443 wnn->dan = 'x' - 'a';
444 } else if (wnn->dan == 's' - 'a') {
445 jcInsertChar(wnn->convbuf, 0xa4b7); /* si */
446 wnn->dan = 'x' - 'a';
447 } else if (wnn->dan == 'z' - 'a') {
448 jcInsertChar(wnn->convbuf, 0xa4b8); /* zi */
449 wnn->dan = 'x' - 'a';
450 } else if (wnn->dan == 't' - 'a' || wnn->dan == 'c' - 'a') {
451 jcInsertChar(wnn->convbuf, 0xa4c1); /* ti */
452 wnn->dan = 'x' - 'a';
453 } else if (wnn->dan == 'd' - 'a') {
454 jcInsertChar(wnn->convbuf, 0xa4c2); /* di */
455 wnn->dan = 'x' - 'a';
456 } else if (wnn->dan == 'n' - 'a') {
457 jcInsertChar(wnn->convbuf, 0xa4cb); /* ni */
458 wnn->dan = 'x' - 'a';
459 } else if (wnn->dan == 'h' - 'a') {
460 jcInsertChar(wnn->convbuf, 0xa4d2); /* hi */
461 wnn->dan = 'x' - 'a';
462 } else if (wnn->dan == 'b' - 'a') {
463 jcInsertChar(wnn->convbuf, 0xa4d3); /* bi */
464 wnn->dan = 'x' - 'a';
465 } else if (wnn->dan == 'p' - 'a') {
466 jcInsertChar(wnn->convbuf, 0xa4d4); /* pi */
467 wnn->dan = 'x' - 'a';
468 } else if (wnn->dan == 'm' - 'a') {
469 jcInsertChar(wnn->convbuf, 0xa4df); /* mi */
470 wnn->dan = 'x' - 'a';
471 } else if (wnn->dan == 'r' - 'a') {
472 jcInsertChar(wnn->convbuf, 0xa4ea); /* ri */
473 wnn->dan = 'x' - 'a';
474 }
475
476 if (wnn->dan == 'x' - 'a') {
477 wnn->dan = 'e' - 'a';
478 wch = 'y';
479 } else if (wnn->dan == 'v' - 'a') {
480 if (key_char == 'u') {
481 wch = 0xa5f4;
482 wnn->dan = 0;
483 } else {
484 jcInsertChar(wnn->convbuf, 0xa5f4); /* v */
485 wnn->dan = 'x' - 'a';
486
487 return insert_char(wnn, key_char);
488 }
489 } else {
490 goto normal;
491 }
492 } else if (key_char == 'h') {
493 if (wnn->dan == 'c' - 'a') {
494 jcInsertChar(wnn->convbuf, 0xa4c1); /* ti */
495 wnn->dan = 'i' - 'a';
496 } else if (wnn->dan == 's' - 'a') {
497 jcInsertChar(wnn->convbuf, 0xa4b7); /* si */
498 wnn->dan = 'i' - 'a';
499 } else if (wnn->dan == 'd' - 'a') {
500 jcInsertChar(wnn->convbuf, 0xa4c7); /* di */
501 wnn->dan = 'e' - 'a';
502 } else {
503 goto normal;
504 }
505
506 wch = 'h';
507 } else {
508 normal:
509 if (wnn->dan) {
510 jcInsertChar(wnn->convbuf, wnn->dan + 'a');
511 }
512
513 wch = key_char;
514
515 if ('a' <= key_char && key_char <= 'z') {
516 wnn->dan = key_char - 'a';
517 } else {
518 wnn->dan = 0;
519 }
520 }
521 }
522
523 if (wch == 0) {
524 return 1;
525 }
526
527 if (jcInsertChar(wnn->convbuf, wch) != 0) {
528 #ifdef DEBUG
529 bl_debug_printf(BL_DEBUG_TAG " InsertChar failed.\n");
530 #endif
531 }
532
533 return 0;
534 }
535
fix(im_wnn_t * wnn)536 static int fix(im_wnn_t *wnn) {
537 if (wnn->convbuf->displayEnd > wnn->convbuf->displayBuf) {
538 wnn->dan = 0;
539 wnn->is_cand = 0;
540 preedit(wnn, "", 0, 0, 0, "", 0, "");
541 commit(wnn, wnn->convbuf->displayBuf,
542 (wnn->convbuf->displayEnd - wnn->convbuf->displayBuf) * 2);
543 jcFix(wnn->convbuf);
544 jcClear(wnn->convbuf);
545
546 return 0;
547 } else {
548 return 1;
549 }
550 }
551
552 /*
553 * methods of ui_im_t
554 */
555
destroy(ui_im_t * im)556 static void destroy(ui_im_t *im) {
557 im_wnn_t *wnn;
558 struct wnn_buf *buf;
559
560 wnn = (im_wnn_t*)im;
561
562 (*wnn->parser_term->destroy)(wnn->parser_term);
563
564 if (wnn->conv) {
565 (*wnn->conv->destroy)(wnn->conv);
566 }
567
568 buf = wnn->convbuf->wnn;
569 jcDestroyBuffer(wnn->convbuf, 1);
570 jcClose(buf);
571
572 free(wnn);
573
574 ref_count--;
575
576 #ifdef IM_WNN_DEBUG
577 bl_debug_printf(BL_DEBUG_TAG " An object was destroyed. ref_count: %d\n", ref_count);
578 #endif
579
580 if (ref_count == 0) {
581 (*parser_wchar->destroy)(parser_wchar);
582 parser_wchar = NULL;
583 }
584 }
585
switch_mode(ui_im_t * im)586 static int switch_mode(ui_im_t *im) {
587 im_wnn_t *wnn;
588
589 wnn = (im_wnn_t*)im;
590
591 if ((wnn->is_enabled = (!wnn->is_enabled))) {
592 preedit(wnn, NULL, 0, 0, 0, NULL, 0, "");
593 } else {
594 jcClear(wnn->convbuf);
595 preedit(wnn, "", 0, 0, 0, "", 0, "");
596 }
597
598 return 1;
599 }
600
key_event(ui_im_t * im,u_char key_char,KeySym ksym,XKeyEvent * event)601 static int key_event(ui_im_t *im, u_char key_char, KeySym ksym, XKeyEvent *event) {
602 wchar kana[2] = {0xa4ab, 0xa4ca};
603 im_wnn_t *wnn;
604 wchar *cand = NULL;
605 size_t cand_len = 0;
606 int ret = 0;
607 char *pos = "";
608
609 wnn = (im_wnn_t*)im;
610
611 if (key_char == ' ' && (event->state & ShiftMask)) {
612 switch_mode(im);
613
614 if (!wnn->is_enabled) {
615 return 0;
616 }
617 } else if (!wnn->is_enabled) {
618 return 1;
619 } else if (key_char == '\r' || key_char == '\n') {
620 ret = fix(wnn);
621 } else if (ksym == XK_BackSpace || ksym == XK_Delete || key_char == 0x08 /* Ctrl+h */) {
622 if (wnn->im.preedit.filled_len > 0) {
623 wnn->dan = 0;
624 wnn->is_cand = 0;
625
626 if (jcIsConverted(wnn->convbuf, 0)) {
627 jcCancel(wnn->convbuf);
628 jcBottom(wnn->convbuf);
629 } else {
630 jcDeleteChar(wnn->convbuf, 1);
631 }
632 } else {
633 ret = 1;
634 }
635 } else if (key_char != ' ' && key_char != '\0') {
636 if (wnn->im.preedit.filled_len > 0 && jcIsConverted(wnn->convbuf, 0)) {
637 if (key_char < ' ') {
638 if (key_char == 0x03 || key_char == 0x07) /* Ctrl+c, Ctrl+g */
639 {
640 jcCancel(wnn->convbuf);
641 jcBottom(wnn->convbuf);
642 }
643
644 ret = 1;
645 } else {
646 fix(wnn);
647 }
648 } else if (key_char < ' ') {
649 ret = 1;
650 } else {
651 wnn->is_cand = 0;
652 }
653
654 if (ret == 0 && insert_char(wnn, key_char) != 0) {
655 ret = 1;
656 }
657 } else {
658 if (key_char == ' ' && wnn->im.preedit.filled_len == 0) {
659 ret = 1;
660 }
661
662 if (key_char == ' ' || ksym == XK_Up || ksym == XK_Down) {
663 if (!jcIsConverted(wnn->convbuf, 0)) {
664 wchar kanji[2] = {0xb4c1, 0xbbfa};
665
666 if (key_char != ' ') {
667 ret = 1;
668 }
669
670 if (jcConvert(wnn->convbuf, 0, 0, 0) != 0) {
671 #ifdef DEBUG
672 bl_debug_printf(BL_DEBUG_TAG " jcConvert failed.\n");
673 #endif
674 }
675
676 cand = kanji;
677 cand_len = 2;
678
679 wnn->dan = 0;
680 wnn->is_cand = 0;
681 } else {
682 int ncand;
683 int curcand;
684
685 if (jcNext(wnn->convbuf, 0, ksym == XK_Up ? JC_PREV : JC_NEXT) != 0) {
686 #ifdef DEBUG
687 bl_debug_printf(BL_DEBUG_TAG " jcNext failed.\n");
688 #endif
689 }
690
691 if (jcCandidateInfo(wnn->convbuf, 0, &ncand, &curcand) == 0 &&
692 (!wnn->is_cand ||
693 (ksym == XK_Up
694 ? (curcand % CAND_WINDOW_ROWS == CAND_WINDOW_ROWS - 1 || curcand == ncand - 1)
695 : (curcand % CAND_WINDOW_ROWS == 0)))) {
696 wchar tmp[1024];
697 wchar *src;
698 wchar *dst;
699 int count;
700 int beg = curcand - curcand % CAND_WINDOW_ROWS;
701
702 wnn->is_cand = 1;
703
704 for (count = 0; count < CAND_WINDOW_ROWS; count++) {
705 if (jcGetCandidate(wnn->convbuf, beg + count, tmp, sizeof(tmp)) == 0) {
706 cand_len += (MAX_DIGIT_NUM + 1);
707 for (src = tmp; *src; src++) {
708 cand_len++;
709 }
710
711 if (count < CAND_WINDOW_ROWS - 1 && beg + count < ncand - 1) {
712 cand_len++; /* '\n' */
713 }
714 }
715 }
716
717 if ((cand = alloca(cand_len * sizeof(wchar)))) {
718 dst = cand;
719
720 for (count = 0; count < CAND_WINDOW_ROWS; count++) {
721 if (jcGetCandidate(wnn->convbuf, beg + count, tmp, sizeof(tmp)) == 0) {
722 dst = digit_to_wstr(dst, beg + count + 1);
723 *(dst++) = ' ';
724
725 for (src = tmp; *src; src++) {
726 *(dst++) = *src;
727 }
728
729 if (count < CAND_WINDOW_ROWS - 1 && beg + count < ncand - 1) {
730 *(dst++) = '\n';
731 }
732 }
733 }
734 }
735
736 cand_len = dst - cand;
737 }
738
739 if ((pos = alloca(4 + DIGIT_STR_LEN(int)*2 + 1))) {
740 sprintf(pos, " [%d/%d]", curcand + 1, ncand);
741 }
742 }
743 } else if (ksym == XK_Right) {
744 if (event->state & ShiftMask) {
745 jcExpand(wnn->convbuf, 0, jcIsConverted(wnn->convbuf, 0));
746 } else {
747 jcMove(wnn->convbuf, 0, JC_FORWARD);
748 }
749
750 wnn->dan = 0;
751 wnn->is_cand = 0;
752 } else if (ksym == XK_Left) {
753 if (event->state & ShiftMask) {
754 jcShrink(wnn->convbuf, 0, jcIsConverted(wnn->convbuf, 0));
755 } else {
756 jcMove(wnn->convbuf, 0, JC_BACKWARD);
757 }
758
759 wnn->dan = 0;
760 wnn->is_cand = 0;
761 } else {
762 ret = 1;
763 }
764 }
765
766 if (jcIsConverted(wnn->convbuf, 0)) {
767 preedit(wnn, wnn->convbuf->displayBuf,
768 (wnn->convbuf->displayEnd - wnn->convbuf->displayBuf) * 2,
769 wnn->convbuf->clauseInfo[wnn->convbuf->curLCStart].dispp - wnn->convbuf->displayBuf,
770 wnn->convbuf->clauseInfo[wnn->convbuf->curLCEnd].dispp -
771 wnn->convbuf->clauseInfo[wnn->convbuf->curLCStart].dispp,
772 cand, cand_len * sizeof(wchar), pos);
773 } else {
774 preedit(wnn, wnn->convbuf->displayBuf,
775 (wnn->convbuf->displayEnd - wnn->convbuf->displayBuf) * 2, jcDotOffset(wnn->convbuf), 0,
776 (char*)kana, sizeof(kana), pos);
777 }
778
779 return ret;
780 }
781
is_active(ui_im_t * im)782 static int is_active(ui_im_t *im) { return ((im_wnn_t*)im)->is_enabled; }
783
focused(ui_im_t * im)784 static void focused(ui_im_t *im) {
785 im_wnn_t *wnn;
786
787 wnn = (im_wnn_t*)im;
788
789 if (wnn->im.cand_screen) {
790 (*wnn->im.cand_screen->show)(wnn->im.cand_screen);
791 }
792 }
793
unfocused(ui_im_t * im)794 static void unfocused(ui_im_t *im) {
795 im_wnn_t *wnn;
796
797 wnn = (im_wnn_t*)im;
798
799 if (wnn->im.cand_screen) {
800 (*wnn->im.cand_screen->hide)(wnn->im.cand_screen);
801 }
802 }
803
804 /* --- global functions --- */
805
im_wnn_new(u_int64_t magic,vt_char_encoding_t term_encoding,ui_im_export_syms_t * export_syms,char * server,u_int mod_ignore_mask)806 ui_im_t *im_wnn_new(u_int64_t magic, vt_char_encoding_t term_encoding,
807 ui_im_export_syms_t *export_syms, char *server, u_int mod_ignore_mask) {
808 im_wnn_t *wnn;
809 struct wnn_buf *buf;
810
811 if (magic != (u_int64_t)IM_API_COMPAT_CHECK_MAGIC) {
812 bl_error_printf("Incompatible input method API.\n");
813
814 return NULL;
815 }
816
817 if (ref_count == 0) {
818 syms = export_syms;
819 parser_wchar = wchar_parser_new();
820 }
821
822 if (!(wnn = calloc(1, sizeof(im_wnn_t)))) {
823 #ifdef DEBUG
824 bl_warn_printf(BL_DEBUG_TAG " malloc failed.\n");
825 #endif
826
827 goto error;
828 }
829
830 wnn->term_encoding = term_encoding;
831 wnn->encoding_name = (*syms->vt_get_char_encoding_name)(term_encoding);
832
833 if (!(wnn->conv = (*syms->vt_char_encoding_conv_new)(term_encoding))) {
834 goto error;
835 }
836
837 if (!(wnn->parser_term = (*syms->vt_char_encoding_parser_new)(term_encoding))) {
838 goto error;
839 }
840
841 if (!(buf = jcOpen(server, "", 0, "", bl_msg_printf, bl_msg_printf, 0))) {
842 #ifdef DEBUG
843 bl_debug_printf(BL_DEBUG_TAG " jcOpen failed.\n");
844 #endif
845
846 goto error;
847 }
848
849 wnn->convbuf = jcCreateBuffer(buf, 0, 0);
850
851 /*
852 * set methods of ui_im_t
853 */
854 wnn->im.destroy = destroy;
855 wnn->im.key_event = key_event;
856 wnn->im.switch_mode = switch_mode;
857 wnn->im.is_active = is_active;
858 wnn->im.focused = focused;
859 wnn->im.unfocused = unfocused;
860
861 ref_count++;
862
863 #ifdef IM_WNN_DEBUG
864 bl_debug_printf("New object was created. ref_count is %d.\n", ref_count);
865 #endif
866
867 return (ui_im_t*)wnn;
868
869 error:
870 if (ref_count == 0) {
871 if (parser_wchar) {
872 (*parser_wchar->destroy)(parser_wchar);
873 parser_wchar = NULL;
874 }
875 }
876
877 if (wnn) {
878 if (wnn->parser_term) {
879 (*wnn->parser_term->destroy)(wnn->parser_term);
880 }
881
882 if (wnn->conv) {
883 (*wnn->conv->destroy)(wnn->conv);
884 }
885
886 buf = wnn->convbuf->wnn;
887 jcDestroyBuffer(wnn->convbuf, 1);
888 jcClose(buf);
889
890 free(wnn);
891 }
892
893 return NULL;
894 }
895
896 /* --- API for external tools --- */
897
im_wnn_get_info(char * locale,char * encoding)898 im_info_t *im_wnn_get_info(char *locale, char *encoding) {
899 im_info_t *result;
900
901 if ((result = malloc(sizeof(im_info_t)))) {
902 result->id = strdup("wnn");
903 result->name = strdup("Wnn");
904 result->num_args = 0;
905 result->args = NULL;
906 result->readable_args = NULL;
907 }
908
909 return result;
910 }
911