1 /* Copyright (C) 2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
2  *
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation version 2.1
6  * of the License.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with this library; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
16  */
17 
18 #include "hime.h"
19 
20 #include "gst.h"
21 #include "gtab-buf.h"
22 #include "gtab.h"
23 #include "hime-conf.h"
24 #include "hime-endian.h"
25 #include "pho.h"
26 #include "tsin-parse.h"
27 #include "tsin.h"
28 #include "win-save-phrase.h"
29 
30 void disp_gbuf (), ClrIn (), clear_after_put ();
31 gboolean gtab_phrase_on ();
32 int page_len ();
33 void show_win_gtab ();
34 void disp_selection0 (gboolean phrase_selected, gboolean force_disp);
35 void disp_gtab_sel (char *s);
36 void add_cache (int start, int usecount, TSIN_PARSE *out, short match_phr_N, short no_match_ch_N, int tc_len);
37 int ch_pos_find (char *ch, int pos);
38 void inc_gtab_usecount (char *str), ClrSelArea ();
39 void lookup_gtabn (char *ch, char *out);
40 char *htmlspecialchars (char *s, char out[]);
41 void hide_gtab_pre_sel ();
42 gboolean gtab_vertical_select_on ();
43 
44 extern gboolean key_press_alt, key_press_ctrl;
45 
46 extern gboolean test_mode;
47 
48 GEDIT *gbuf;
49 extern char **seltab;
50 extern int ph_key_sz;
51 
extract_gtab_key(int start,int len,void * out)52 void extract_gtab_key (int start, int len, void *out) {
53     int i;
54 
55     char *p = (char *) out;
56     if (ph_key_sz == 4) {
57         for (i = 0; i < len; i++) {
58             u_int k = gbuf[i + start].keys[0];
59             memcpy (p, &k, sizeof (k));
60             p += sizeof (k);
61         }
62     } else {
63         for (i = 0; i < len; i++) {
64             memcpy (p, &gbuf[i + start].keys[0], sizeof (u_int64_t));
65             p += sizeof (u_int64_t);
66         }
67     }
68 }
69 
extract_gbuf_str(int start,int len,char * out)70 void extract_gbuf_str (int start, int len, char *out) {
71     int i;
72     out[0] = 0;
73     for (i = 0; i < len; i++)
74         strcat (out, gbuf[i + start].ch);
75 }
76 
gtab_cursor_end()77 gboolean gtab_cursor_end () {
78     return ggg.gbuf_cursor == ggg.gbufN;
79 }
80 
dump_gbuf()81 void dump_gbuf () {
82     int i;
83 
84     for (i = 0; i < ggg.gbufN; i++) {
85         int j;
86         for (j = 0; j < gbuf[i].selN; j++)
87             printf ("%d:%s ", j, gbuf[i].sel[j]);
88         puts ("");
89     }
90 }
91 
92 static unich_t latin_chars[] =
93     "ÀÁÂÃÄÅÆÆÇÈÉÊËÌÍÎÏÐÐÑÒÓÔÕÖØÙÚÛÜÝÞÞßàáâãäåææçèéêëìíîïððñòóôõöøùúûüýþþÿ"
94     "ĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJIJijijĴĵĶķĸĹĺĻļĽľĿŀŁł"
95     "ŃńŅņŇňʼnŊŋŌōŎŏŐőŒŒœœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽž";
96 
en_word_len(char * bf)97 int en_word_len (char *bf) {
98     char *s;
99 
100     for (s = bf; *s;) {
101         int sz = utf8_sz (s);
102         if (sz == 1) {
103             if (!((*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z') || strchr ("-_'", *s)))
104                 break;
105         } else if (sz == 2) {
106             char *p;
107             for (p = latin_chars; *p; p += 2)
108                 if (!memcmp (p, s, 2))
109                     break;
110             if (!(*p))
111                 break;
112         } else if (sz >= 3)
113             break;
114         s += sz;
115     }
116 
117     if (*s)
118         return 0;
119     return strlen (bf);
120 }
121 
gen_buf_str(int start,gboolean add_spc)122 static char *gen_buf_str (int start, gboolean add_spc) {
123     int i;
124     char *out = tmalloc (char, 1);
125     int outN = 0;
126 
127     gboolean last_en_word = FALSE;
128     for (i = start; i < ggg.gbufN; i++) {
129         char *t = gbuf[i].ch;
130         int len = strlen (t);
131 
132         if (add_spc && en_word_len (t) && !(gbuf[i].flag & FLAG_CHPHO_GTAB_BUF_EN_NO_SPC)) {
133             if (last_en_word) {
134                 out = trealloc (out, char, outN + 1);
135                 out[outN++] = ' ';
136             }
137             last_en_word = TRUE;
138         } else
139             last_en_word = FALSE;
140 
141         out = trealloc (out, char, outN + len + 1);
142         memcpy (out + outN, t, len);
143         outN += len;
144     }
145 
146     out[outN] = 0;
147     return out;
148 }
149 
150 extern gboolean last_cursor_off;
151 
gen_buf_str_disp()152 static char *gen_buf_str_disp () {
153     if (!ggg.gbufN) {
154         return strdup ("");
155     }
156 
157     int i;
158     char *out = tmalloc (char, 1);
159     int outN = 0;
160 
161     out[0] = 0;
162     gbuf[ggg.gbufN].ch = " ";
163 
164     gboolean last_is_en_word = FALSE;
165 
166     int N = last_cursor_off ? ggg.gbufN - 1 : ggg.gbufN;
167     for (i = 0; i <= N; i++) {
168         char addspc[MAX_CIN_PHR * 2 + 2];
169         char spec[MAX_CIN_PHR * 2 + 2];
170         int len = en_word_len (gbuf[i].ch);
171         //    dbg("i %d N:%d bufN:%d\n",i,N,ggg.gbufN);
172         if (gbuf[i].flag & FLAG_CHPHO_GTAB_BUF_EN_NO_SPC)
173             len = 0;
174         //    dbg("%d %d is_en:%d\n",i, len, last_is_en_word);
175 
176         if (len) {
177             if (last_is_en_word) {
178                 strcpy (addspc, " ");
179                 strcat (addspc, gbuf[i].ch);
180             } else
181                 strcpy (addspc, gbuf[i].ch);
182             last_is_en_word = TRUE;
183         } else {
184             last_is_en_word = FALSE;
185             strcpy (addspc, gbuf[i].ch);
186         }
187 
188         htmlspecialchars (addspc, spec);
189         //    dbg("addspc '%s'  spec:%s out:%s\n", addspc, spec, out);
190 
191         char www[MAX_CIN_PHR * 2 + 2];
192         char *t = spec;
193 
194         if (i == ggg.gbuf_cursor) {
195             if (hime_win_color_use)
196                 snprintf (www, sizeof (www), "<span foreground=\"white\" background=\"%s\">%s</span>", tsin_cursor_color, spec);
197             else
198                 snprintf (www, sizeof (www), "<span foreground=\"white\" background=\"" TSIN_CURSOR_COLOR_DEFAULT "\">%s</span>", spec);
199             t = www;
200         }
201 
202         len = strlen (t);
203         out = trealloc (out, char, outN + len + 1);
204         memcpy (out + outN, t, len);
205         outN += len;
206         out[outN] = 0;
207     }
208 
209     return out;
210 }
211 
212 void disp_label_edit (char *str);
213 
free_pgbuf(GEDIT * p)214 static void free_pgbuf (GEDIT *p) {
215     int i;
216     for (i = 0; i < p->selN; i++)
217         free (p->sel[i]);
218     free (p->sel);
219     p->ch = NULL;
220     p->sel = NULL;
221     p->flag = 0;
222 }
223 
free_gbuf(int idx)224 static void free_gbuf (int idx) {
225     free_pgbuf (&gbuf[idx]);
226 }
227 
clear_gtab_buf_all()228 static void clear_gtab_buf_all () {
229     int i;
230     for (i = 0; i < ggg.gbufN; i++)
231         free_gbuf (i);
232     ggg.gbuf_cursor = ggg.gbufN = 0;
233     ggg.gtab_buf_select = 0;
234     disp_gbuf ();
235 }
236 
disp_gbuf()237 void disp_gbuf () {
238     char *bf = gen_buf_str_disp ();
239     disp_label_edit (bf);
240 
241     if (ggg.gbufN && gtab_disp_key_codes)
242         lookup_gtabn (gbuf[ggg.gbufN - 1].ch, NULL);
243 
244     free (bf);
245 }
246 
clear_gbuf_sel()247 void clear_gbuf_sel () {
248     ggg.gtab_buf_select = 0;
249     ggg.total_matchN = 0;
250     ClrSelArea ();
251 }
252 
gbuf_cursor_left()253 int gbuf_cursor_left () {
254     hide_gtab_pre_sel ();
255     if (!ggg.gbuf_cursor)
256         return ggg.gbufN;
257     if (ggg.gtab_buf_select)
258         clear_gbuf_sel ();
259     ClrIn ();
260     ggg.gbuf_cursor--;
261     disp_gbuf ();
262     return 1;
263 }
264 
gbuf_cursor_right()265 int gbuf_cursor_right () {
266     hide_gtab_pre_sel ();
267     if (ggg.gbuf_cursor == ggg.gbufN)
268         return ggg.gbufN;
269     if (ggg.gtab_buf_select)
270         clear_gbuf_sel ();
271     ggg.gbuf_cursor++;
272     disp_gbuf ();
273     return 1;
274 }
275 
gbuf_cursor_home()276 int gbuf_cursor_home () {
277     hide_gtab_pre_sel ();
278     if (!ggg.gbufN)
279         return 0;
280     if (ggg.gtab_buf_select)
281         clear_gbuf_sel ();
282 
283     ggg.gbuf_cursor = 0;
284     disp_gbuf ();
285     return 1;
286 }
287 
gbuf_cursor_end()288 int gbuf_cursor_end () {
289     hide_gtab_pre_sel ();
290     if (!ggg.gbufN)
291         return 0;
292     if (ggg.gtab_buf_select)
293         clear_gbuf_sel ();
294 
295     ggg.gbuf_cursor = ggg.gbufN;
296     disp_gbuf ();
297     return 1;
298 }
299 
300 void inc_gtab_use_count (char *s);
301 void inc_dec_tsin_use_count (void *pho, char *ch, int N);
302 
output_gbuf()303 gboolean output_gbuf () {
304     hide_gtab_pre_sel ();
305 
306     if (!ggg.gbufN)
307         return FALSE;
308     char *bf = gen_buf_str (0, TRUE);
309 #if 0
310   printf("out %s\n", bf);
311 #endif
312 
313 #if 0
314   // single character
315   char *p;
316   for(p=bf; *p; p+=utf8_sz(p))
317     inc_gtab_use_count(p);
318 #endif
319 
320     send_text (bf);
321     free (bf);
322 
323     int i;
324     for (i = 0; i < ggg.gbufN;) {
325         char t[MAX_CIN_PHR + 1];
326         t[0] = 0;
327         inc_gtab_use_count (gbuf[i].ch);
328 
329         int j;
330         for (j = i; j < i + gbuf[i].plen; j++)
331             strcat (t, gbuf[j].ch);
332 
333         if (!gbuf[i].plen)
334             i++;
335         else {
336             u_int64_t kk[MAX_PHRASE_LEN];
337             extract_gtab_key (i, gbuf[i].plen, kk);
338             inc_dec_tsin_use_count (kk, t, gbuf[i].plen);
339             i += gbuf[i].plen;
340         }
341     }
342 
343     clear_gtab_buf_all ();
344     ClrIn ();
345     return TRUE;
346 }
347 
check_gtab_fixed_mismatch(int idx,char * mtch,int plen)348 gboolean check_gtab_fixed_mismatch (int idx, char *mtch, int plen) {
349     int j;
350     char *p = mtch;
351 
352     for (j = 0; j < plen; j++) {
353         int u8sz = utf8_sz (p);
354         if (!(gbuf[idx + j].flag & FLAG_CHPHO_FIXED))
355             continue;
356 
357         if (memcmp (gbuf[idx + j].ch, p, u8sz))
358             break;
359 
360         p += u8sz;
361     }
362 
363     if (j < plen)
364         return TRUE;
365 
366     return FALSE;
367 }
368 
set_gtab_user_head()369 void set_gtab_user_head () {
370     gbuf[ggg.gbuf_cursor].flag |= FLAG_CHPHO_PHRASE_USER_HEAD;
371 }
372 
373 #define DBG 0
374 
375 void free_cache ();
376 void init_tsin_table ();
377 void set_tsin_parse_len (int);
378 
gtab_parse()379 void gtab_parse () {
380     int i;
381     TSIN_PARSE out[MAX_PH_BF_EXT + 1];
382     memset (out, 0, sizeof (out));
383 
384     if (test_mode)
385         return;
386 
387     if (ggg.gbufN <= 1)
388         return;
389 
390     init_tsin_table ();
391 
392     init_cache (ggg.gbufN);
393 
394     set_tsin_parse_len (ggg.gbufN);
395 
396     short smatch_phr_N, sno_match_ch_N;
397     tsin_parse_recur (0, out, &smatch_phr_N, &sno_match_ch_N);
398 #if 0
399   puts("vvvvvvvvvvvvvvvv");
400   for(i=0;  i < out[i].len; i++) {
401     printf("%x %d:", out[i].str, out[i].len);
402     utf8_putcharn(out[i].str, out[i].len);
403   }
404   dbg("\n");
405 #endif
406 
407     for (i = 0; i < ggg.gbufN; i++)
408         gbuf[i].flag &= ~(FLAG_CHPHO_PHRASE_HEAD | FLAG_CHPHO_PHRASE_BODY);
409 
410     int ofsi;
411     for (ofsi = i = 0; out[i].len; i++) {
412         int j, ofsj;
413 
414         if (out[i].flag & FLAG_TSIN_PARSE_PHRASE) {
415             gbuf[ofsi].flag |= FLAG_CHPHO_PHRASE_HEAD;
416             gbuf[ofsi].plen = out[i].len;
417         }
418 
419         for (ofsj = j = 0; j < out[i].len; j++) {
420             char *w = (char *) &out[i].str[ofsj];
421             int wsz = utf8_sz (w);
422             ofsj += wsz;
423 
424             int k;
425             for (k = 0; k < gbuf[ofsi].selN; k++) {
426                 int sz = utf8_sz (gbuf[ofsi].sel[k]);
427                 if (wsz == sz && !memcmp (gbuf[ofsi].sel[k], w, sz))
428                     break;
429             }
430             if (k == gbuf[ofsi].selN) {
431 #if 0
432         dbg("qq ");
433         utf8_putchar(w);
434         p_err(" err 1 selN:%d ofsi:%d", gbuf[ofsi].selN, ofsi);
435 #endif
436                 k = 0;
437             }
438 
439             if (!(gbuf[ofsi].flag & FLAG_CHPHO_FIXED)) {
440                 gbuf[ofsi].ch = gbuf[ofsi].sel[k];
441                 gbuf[ofsi].c_sel = k;
442             }
443             gbuf[ofsi].flag |= FLAG_CHPHO_PHRASE_BODY;
444 
445             ofsi++;
446         }
447     }
448 
449 #if 0
450   puts("-----------------------------");
451   for(i=0;i<ggg.gbufN;i++)
452     puts(gbuf[i].ch);
453 #endif
454     free_cache ();
455 }
456 
cursor_gbuf()457 static GEDIT *cursor_gbuf () {
458     return ggg.gbuf_cursor == ggg.gbufN ? &gbuf[ggg.gbuf_cursor - 1] : &gbuf[ggg.gbuf_cursor];
459 }
460 
461 typedef struct {
462     char *s;
463     int usecount;
464     int org_seq;
465 } GITEM;
466 
467 int get_gtab_use_count (char *s);
468 
qcmp_gitem(const void * aa,const void * bb)469 int qcmp_gitem (const void *aa, const void *bb) {
470     int d = ((GITEM *) bb)->usecount - ((GITEM *) aa)->usecount;
471     if (d)
472         return d;
473 
474     return ((GITEM *) aa)->org_seq - ((GITEM *) bb)->org_seq;
475 }
476 
477 void hide_row2_if_necessary ();
478 
479 unich_t auto_end_punch[] = ", . ? : ; ! [ ] 「 」 , 。 ? ; : 、 ~ ! ( )";
insert_gbuf_cursor(char ** sel,int selN,u_int64_t key,gboolean b_gtab_en_no_spc)480 GEDIT *insert_gbuf_cursor (char **sel, int selN, u_int64_t key, gboolean b_gtab_en_no_spc) {
481     hide_row2_if_necessary ();
482 
483     if (!sel || !selN)
484         return NULL;
485     //  dbg("insert_gbuf_cursor %x\n", key);
486 
487     gbuf = trealloc (gbuf, GEDIT, ggg.gbufN + 2);
488 
489     GEDIT *pbuf = &gbuf[ggg.gbuf_cursor];
490 
491     if (ggg.gbuf_cursor < ggg.gbufN)
492         memmove (&gbuf[ggg.gbuf_cursor + 1], &gbuf[ggg.gbuf_cursor], sizeof (GEDIT) * (ggg.gbufN - ggg.gbuf_cursor));
493 
494     ggg.gbuf_cursor++;
495     ggg.gbufN++;
496 
497     memset (pbuf, 0, sizeof (GEDIT));
498     memset (gbuf + ggg.gbufN, 0, sizeof (GEDIT));
499 
500     GITEM *items = tmalloc (GITEM, selN);
501 
502     int i;
503     for (i = 0; i < selN; i++) {
504         items[i].s = sel[i];
505         items[i].org_seq = i;
506         items[i].usecount = get_gtab_use_count (sel[i]);
507     }
508     qsort (items, selN, sizeof (GITEM), qcmp_gitem);
509 
510     for (i = 0; i < selN; i++)
511         sel[i] = items[i].s;
512 
513     pbuf->ch = sel[0];
514     pbuf->sel = sel;
515     pbuf->selN = selN;
516     pbuf->c_sel = 0;
517     pbuf->keys[0] = key;
518     pbuf->keysN = 1;
519     pbuf->flag = b_gtab_en_no_spc ? FLAG_CHPHO_GTAB_BUF_EN_NO_SPC : 0;
520 
521     if (hime_punc_auto_send && ggg.gbufN == ggg.gbuf_cursor && selN == 1 && strstr (_ (auto_end_punch), sel[0])) {
522         char_play (pbuf->ch);
523         output_gbuf ();
524     } else {
525         gtab_parse ();
526         disp_gbuf ();
527         char_play (pbuf->ch);
528     }
529 
530     free (items);
531     return pbuf;
532 }
533 
set_gbuf_c_sel(int v)534 void set_gbuf_c_sel (int v) {
535     GEDIT *pbuf = cursor_gbuf ();
536 
537     pbuf->c_sel = v + ggg.pg_idx;
538     pbuf->ch = pbuf->sel[pbuf->c_sel];
539     //  dbg("zzzsel v:%d %d %s\n",v, pbuf->c_sel,pbuf->ch);
540     pbuf->flag |= FLAG_CHPHO_FIXED;
541     ggg.gtab_buf_select = 0;
542     ggg.more_pg = 0;
543     disp_gtab_sel ("");
544     gtab_parse ();
545     disp_gbuf ();
546     //  dbg("zzzsel v:%d\n", pbuf->c_sel);
547 }
548 
insert_gbuf_cursor1(char * s,u_int64_t key,gboolean b_gtab_en_no_spc)549 GEDIT *insert_gbuf_cursor1 (char *s, u_int64_t key, gboolean b_gtab_en_no_spc) {
550     if (!gtab_phrase_on ())
551         return NULL;
552 
553     //   dbg("insert_gbuf_cursor1 %s %x\n", s, key);
554     char **sel = tmalloc (char *, 1);
555     sel[0] = strdup (s);
556     GEDIT *e = insert_gbuf_cursor (sel, 1, key, b_gtab_en_no_spc);
557     clear_after_put ();
558     return e;
559 }
560 
insert_gbuf_cursor_phrase(char * s,void * key,int N)561 void insert_gbuf_cursor_phrase (char *s, void *key, int N) {
562     u_int *key32 = (u_int *) key;
563     u_int64_t *key64 = (u_int64_t *) key;
564 
565     int i;
566     for (i = 0; i < N; i++) {
567         char ch[CH_SZ + 1];
568         int n = utf8cpy (ch, s);
569         u_int64_t v = ph_key_sz == 4 ? key32[i] : key64[i];
570         GEDIT *e = insert_gbuf_cursor1 (ch, v, TRUE);
571         e->flag |= FLAG_CHPHO_FIXED;
572         s += n;
573     }
574 }
575 
key_N(u_int64_t k)576 static int key_N (u_int64_t k) {
577     int n = 0;
578     int mask = (1 << KeyBits) - 1;
579 
580     while (k) {
581         k >>= mask;
582         n++;
583     }
584 
585     return n;
586 }
587 
qcmp_key_N(const void * aa,const void * bb)588 static int qcmp_key_N (const void *aa, const void *bb) {
589     u_int64_t a = *((u_int64_t *) aa);
590     u_int64_t b = *((u_int64_t *) bb);
591 
592     return key_N (a) - key_N (b);
593 }
594 
insert_gbuf_nokey(char * s)595 void insert_gbuf_nokey (char *s) {
596     if (!gtab_phrase_on ())
597         return;
598 
599     //   dbg("insert_gbuf_nokey\n");
600 
601     int i;
602     u_int64_t keys[32];
603     int keysN = 0;
604     int sz = utf8_sz (s);
605 
606     keys[0] = 0;
607     if (cur_inmd->tbl64) {
608         for (i = 0; i < cur_inmd->DefChars; i++) {
609             if (!memcmp (cur_inmd->tbl64[i].ch, s, sz)) {
610                 u_int64_t t;
611                 memcpy (&t, cur_inmd->tbl64[i].key, sizeof (u_int64_t));
612                 keys[keysN++] = t;
613             }
614         }
615     } else if (cur_inmd->tbl) {
616         for (i = 0; i < cur_inmd->DefChars; i++) {
617             if (!memcmp (cur_inmd->tbl[i].ch, s, sz)) {
618                 u_int t;
619                 memcpy (&t, cur_inmd->tbl[i].key, sizeof (u_int));
620                 keys[keysN++] = t;
621             }
622         }
623     }
624 
625     qsort (keys, keysN, sizeof (u_int64_t), qcmp_key_N);
626 
627     GEDIT *e = insert_gbuf_cursor1 (s, keys[0], TRUE);
628     if (keysN > 8)
629         keysN = 8;
630 
631     memcpy (e->keys, keys, sizeof (u_int64_t) * keysN);
632     e->keysN = keysN;
633 }
634 
insert_gbuf_cursor1_cond(char * s,u_int64_t key,gboolean valid_key)635 void insert_gbuf_cursor1_cond (char *s, u_int64_t key, gboolean valid_key) {
636     if (valid_key)
637         insert_gbuf_cursor1 (s, key, FALSE);
638     else
639         insert_gbuf_nokey (s);
640 }
641 
insert_gbuf_cursor_char(char ch)642 void insert_gbuf_cursor_char (char ch) {
643     char t[2];
644     t[0] = ch;
645     t[1] = 0;
646     insert_gbuf_cursor1 (t, 0, TRUE);
647 }
648 
649 gboolean gtab_has_input ();
650 void hide_win_gtab ();
651 
gtab_buf_delete_ex(gboolean auto_hide)652 int gtab_buf_delete_ex (gboolean auto_hide) {
653     if (ggg.gbuf_cursor == ggg.gbufN)
654         return 0;
655 
656     if (test_mode)
657         return 1;
658 
659     if (ggg.gtab_buf_select)
660         clear_gbuf_sel ();
661 
662     free_gbuf (ggg.gbuf_cursor);
663     memmove (&gbuf[ggg.gbuf_cursor], &gbuf[ggg.gbuf_cursor + 1], sizeof (GEDIT) * (ggg.gbufN - ggg.gbuf_cursor - 1));
664     ggg.gbufN--;
665     disp_gbuf ();
666 
667     if (hime_pop_up_win && !gtab_has_input () && auto_hide)
668         hide_win_gtab ();
669 
670     return 1;
671 }
672 
gtab_buf_delete()673 int gtab_buf_delete () {
674     return gtab_buf_delete_ex (TRUE);
675 }
676 
677 gboolean gtab_has_input ();
678 void hide_win_gtab ();
679 
gtab_buf_backspace_ex(gboolean auto_hide)680 int gtab_buf_backspace_ex (gboolean auto_hide) {
681     if (!ggg.gbuf_cursor) {
682         return ggg.gbufN > 0;
683     }
684     ggg.gbuf_cursor--;
685     gtab_buf_delete_ex (auto_hide);
686 
687     if (hime_pop_up_win && !gtab_has_input () && auto_hide)
688         hide_win_gtab ();
689 
690     return 1;
691 }
692 
gtab_buf_backspace()693 int gtab_buf_backspace () {
694     return gtab_buf_backspace_ex (TRUE);
695 }
696 
gtab_buf_backspaceN(int n)697 void gtab_buf_backspaceN (int n) {
698     int i;
699     for (i = 0; i < n; i++)
700         gtab_buf_backspace_ex (FALSE);
701 }
702 
703 extern int more_pg;
704 
gtab_disp_sel()705 void gtab_disp_sel () {
706     int idx = ggg.gbuf_cursor == ggg.gbufN ? ggg.gbuf_cursor - 1 : ggg.gbuf_cursor;
707     GEDIT *pbuf = &gbuf[idx];
708 
709     int i;
710     for (i = 0; i < cur_inmd->M_DUP_SEL; i++) {
711         int v = i + ggg.pg_idx;
712         if (v >= pbuf->selN)
713             seltab[i][0] = 0;
714         else
715             strcpy (seltab[i], pbuf->sel[v]);
716     }
717 
718     if (pbuf->selN > page_len ())
719         ggg.more_pg = 1;
720     disp_selection0 (FALSE, TRUE);
721     show_win_gtab ();
722 }
723 
show_buf_select()724 int show_buf_select () {
725     if (!ggg.gbufN)
726         return 0;
727 
728     int idx = ggg.gbuf_cursor == ggg.gbufN ? ggg.gbuf_cursor - 1 : ggg.gbuf_cursor;
729     GEDIT *pbuf = &gbuf[idx];
730     ggg.gtab_buf_select = 1;
731     ggg.total_matchN = pbuf->selN;
732     ggg.pg_idx = 0;
733 
734     gtab_disp_sel ();
735     hide_gtab_pre_sel ();
736 
737     return 1;
738 }
739 
gbuf_prev_pg()740 void gbuf_prev_pg () {
741     ggg.pg_idx -= page_len ();
742     if (ggg.pg_idx < 0)
743         ggg.pg_idx = 0;
744 
745     gtab_disp_sel ();
746 }
747 
gbuf_next_pg()748 void gbuf_next_pg () {
749     ggg.pg_idx += page_len ();
750     if (ggg.pg_idx >= ggg.total_matchN)
751         ggg.pg_idx = 0;
752 
753     gtab_disp_sel ();
754 }
755 
756 #include "im-client/hime-im-client-attr.h"
757 
758 int get_DispInArea_str (char *out);
759 
gtab_get_preedit(char * str,HIME_PREEDIT_ATTR attr[],int * pcursor,int * sub_comp_len)760 int gtab_get_preedit (char *str, HIME_PREEDIT_ATTR attr[], int *pcursor, int *sub_comp_len) {
761     int i = 0;
762     int strN = 0;
763     int attrN = 0;
764     int ch_N = 0;
765 
766     //  dbg("gtab_get_preedit\n");
767     str[0] = 0;
768     *pcursor = 0;
769 
770     *sub_comp_len = ggg.ci > 0;
771 #if 1
772     if (ggg.gbufN && !hime_edit_display_ap_only ())
773         *sub_comp_len |= 4;
774 #endif
775     gboolean ap_only = hime_edit_display_ap_only ();
776 
777     if (gtab_phrase_on ()) {
778         attr[0].flag = HIME_PREEDIT_ATTR_FLAG_UNDERLINE;
779         attr[0].ofs0 = 0;
780 
781         if (ggg.gbufN)
782             attrN = 1;
783 
784         gboolean last_is_en_word = FALSE;
785         for (i = 0; i < ggg.gbufN; i++) {
786             char *s = gbuf[i].ch;
787             char tt[MAX_CIN_PHR + 2];
788 
789             if (en_word_len (s) && !(gbuf[i].flag & FLAG_CHPHO_GTAB_BUF_EN_NO_SPC)) {
790                 if (last_is_en_word) {
791                     strcpy (tt, " ");
792                     strcat (tt, s);
793                     s = tt;
794                 }
795                 last_is_en_word = TRUE;
796             } else {
797                 last_is_en_word = FALSE;
798             }
799 
800             int len = strlen (s);
801             int N = utf8_str_N (s);
802             ch_N += N;
803             if (i < ggg.gbuf_cursor)
804                 *pcursor += N;
805             if (ap_only && i == ggg.gbuf_cursor) {
806                 attr[1].ofs0 = *pcursor;
807                 attr[1].ofs1 = *pcursor + N;
808                 attr[1].flag = HIME_PREEDIT_ATTR_FLAG_REVERSE;
809                 attrN++;
810             }
811 
812             if (hime_display_on_the_spot_key () && i == ggg.gbuf_cursor)
813                 strN += get_DispInArea_str (str + strN);
814 
815             memcpy (str + strN, s, len);
816             strN += len;
817         }
818     }
819 
820     if (hime_display_on_the_spot_key () && i == ggg.gbuf_cursor)
821         strN += get_DispInArea_str (str + strN);
822 
823     str[strN] = 0;
824 
825     attr[0].ofs1 = ch_N;
826     return attrN;
827 }
828 
829 extern GtkWidget *gwin_gtab;
gtab_reset()830 void gtab_reset () {
831     if (!gwin_gtab)
832         return;
833     clear_gtab_buf_all ();
834     clear_gbuf_sel ();
835     ClrIn ();
836     return;
837 }
838 
839 int ch_to_gtab_keys (INMD *tinmd, char *ch, u_int64_t keys[]);
840 
save_gtab_buf_phrase_idx(int idx0,int len)841 void save_gtab_buf_phrase_idx (int idx0, int len) {
842     WSP_S wsp[MAX_PHRASE_LEN];
843 
844     memset (wsp, 0, sizeof (wsp));
845     int i;
846     for (i = 0; i < len; i++) {
847         u8cpy (wsp[i].ch, gbuf[idx0 + i].ch);
848         u_int64_t key = gbuf[idx0 + i].keys[0];
849 
850         if (!key) {
851             u_int64_t keys[64];
852             int keysN = ch_to_gtab_keys (cur_inmd, wsp[i].ch, keys);
853             if (keysN)
854                 key = keys[0];
855         }
856 
857         wsp[i].key = key;
858     }
859 
860     create_win_save_phrase (wsp, len);
861 }
862 
save_gtab_buf_phrase(KeySym key)863 void save_gtab_buf_phrase (KeySym key) {
864     int len = key - '0';
865     int idx0 = ggg.gbuf_cursor - len;
866     int idx1 = ggg.gbuf_cursor - 1;
867 
868     if (idx0 < 0 || idx0 > idx1)
869         return;
870 
871     save_gtab_buf_phrase_idx (idx0, len);
872 }
873 
save_gtab_buf_shift_enter()874 gboolean save_gtab_buf_shift_enter () {
875     if (!ggg.gbufN)
876         return 0;
877     int idx0 = 0;
878     if (ggg.gbufN != ggg.gbuf_cursor)
879         idx0 = ggg.gbuf_cursor;
880     int len = ggg.gbufN - idx0;
881     if (len > MAX_PHRASE_LEN)
882         return 0;
883 
884     save_gtab_buf_phrase_idx (idx0, len);
885     gbuf_cursor_end ();
886     return 1;
887 }
888 
889 void load_tsin_db0 (char *infname, gboolean is_gtab_i);
890 gboolean init_tsin_table_fname (INMD *p, char *fname);
891 
init_tsin_table()892 void init_tsin_table () {
893     char fname[256];
894     if (!current_CS)
895         return;
896 
897     init_tsin_table_fname (&inmd[current_CS->in_method], fname);
898     load_tsin_db0 (fname, TRUE);
899 }
900 
901 extern u_char scanphr_e (int chpho_idx, int plen, gboolean pho_incr, int *rselN);
902 void init_pre_sel ();
903 void clear_sele ();
904 void set_sele_text (int tN, int i, char *text, int len);
905 void get_win_gtab_geom ();
906 void disp_selections (int x, int y);
907 
908 gboolean use_tsin_sel_win ();
909 void init_tsin_selection_win ();
910 
911 static int gtab_pre_select_phrase_len;
912 
913 void disp_gtab_pre_sel (char *s);
914 extern GtkWidget *gwin1;
915 
gtab_scan_pre_select(gboolean b_incr)916 void gtab_scan_pre_select (gboolean b_incr) {
917     if (!gtab_phrase_pre_select)
918         return;
919     //  dbg("gtab_scan_pre_select\n");
920 
921     tss.pre_selN = 0;
922 
923     hide_gtab_pre_sel ();
924 
925     if (!gtab_cursor_end () || !ggg.gbufN)
926         return;
927 
928     init_tsin_table ();
929     init_pre_sel ();
930 
931     int Maxlen = ggg.gbufN;
932     if (Maxlen > MAX_PHRASE_LEN)
933         Maxlen = MAX_PHRASE_LEN;
934 
935     int len, selN, max_len = -1, max_selN;
936     for (len = 1; len <= Maxlen; len++) {
937         int idx = ggg.gbufN - len;
938         if (gbuf[idx].flag & FLAG_CHPHO_PHRASE_TAIL)
939             break;
940         int mlen = scanphr_e (ggg.gbufN - len, len, b_incr, &selN);
941         if (mlen) {
942             max_len = len;
943             max_selN = selN;
944         }
945     }
946 
947     //  dbg("max_len:%d  max_selN:%d\n", max_len, max_selN);
948 
949     if (max_len < 0 || max_selN >= strlen (cur_inmd->selkey) * 2) {
950         tss.pre_selN = 0;
951         return;
952     }
953 
954     gtab_pre_select_phrase_len = max_len;
955 
956     scanphr_e (ggg.gbufN - max_len, max_len, b_incr, &selN);
957 
958     //  dbg("selN:%d %d\n", selN, tss.pre_selN);
959 
960     if (selN == 1 && tss.pre_sel[0].len == max_len) {
961         char out[MAX_PHRASE_LEN * CH_SZ + 1];
962         extract_gbuf_str (ggg.gbufN - max_len, max_len, out);
963         if (!strcmp (out, tss.pre_sel[0].str))
964             return;
965     }
966 
967     //  dbg("selN %d %d\n",selN, tss.pre_selN);
968 
969     if (use_tsin_sel_win ()) {
970         if (gwin1)
971             clear_sele ();
972         else
973             init_tsin_selection_win ();
974 
975         int i;
976         for (i = 0; i < tss.pre_selN; i++)
977             set_sele_text (tss.pre_selN, i, tss.pre_sel[i].str, -1);
978         get_win_gtab_geom ();
979         disp_selections (-1, -1);
980         return;
981     }
982 
983     char tt[4096];
984     tt[0] = 0;
985     int i;
986 
987     for (i = 0; i < tss.pre_selN; i++) {
988         char ts[(MAX_PHRASE_LEN + 3) * CH_SZ + 1];
989         char *br = (i < tss.pre_selN - 1 && gtab_vertical_select_on ()) ? "\n" : "";
990         if (hime_win_color_use)
991             snprintf (ts, sizeof (ts), "<span foreground=\"%s\">%c</span>%s%s", hime_sel_key_color, cur_inmd->selkey[i], tss.pre_sel[i].str, br);
992         else
993             snprintf (ts, sizeof (ts), "<span foreground=\"" HIME_SEL_KEY_COLOR_DEFAULT "\">%c</span>%s%s", cur_inmd->selkey[i], tss.pre_sel[i].str, br);
994         strcat (tt, ts);
995         if (!gtab_vertical_select_on () && i < tss.pre_selN - 1)
996             strcat (tt, " ");
997     }
998 
999     //  dbg("tt %s\n", tt);
1000     disp_gtab_pre_sel (tt);
1001 }
1002 
1003 int shift_key_idx (char *s, KeySym xkey);
1004 
gtab_pre_select_idx(int c)1005 gboolean gtab_pre_select_idx (int c) {
1006     if (c < 0)
1007         return FALSE;
1008     if (c >= tss.pre_selN)
1009         return TRUE;
1010 
1011 #if 0
1012   dbg("c %d %s  ggg.gbuf_cursor:%d,%d\n", c, tss.pre_sel[c].str,
1013     ggg.gbuf_cursor, ggg.gbufN);
1014 #endif
1015 
1016     gtab_buf_backspaceN (gtab_pre_select_phrase_len);
1017     int len = tss.pre_sel[c].len;
1018     insert_gbuf_cursor_phrase (tss.pre_sel[c].str, tss.pre_sel[c].phkey, len);
1019     gbuf[ggg.gbufN - 1].flag |= FLAG_CHPHO_PHRASE_TAIL;
1020 
1021     hide_gtab_pre_sel ();
1022     if (hime_pop_up_win)
1023         hide_win_gtab ();
1024 
1025     return TRUE;
1026 }
1027 
gtab_pre_select_shift(KeySym key,int kbstate)1028 gboolean gtab_pre_select_shift (KeySym key, int kbstate) {
1029     //  dbg("gtab_pre_select_shift %c\n", key);
1030     if (!gtab_phrase_pre_select || !tss.pre_selN)
1031         return FALSE;
1032 
1033     int c = shift_key_idx (cur_inmd->selkey, key);
1034     return gtab_pre_select_idx (c);
1035 }
1036 
1037 void tsin_toggle_eng_ch ();
1038 
feedkey_gtab_release(KeySym xkey,int kbstate)1039 int feedkey_gtab_release (KeySym xkey, int kbstate) {
1040     switch (xkey) {
1041     case XK_Control_L:
1042     case XK_Control_R:
1043         if (key_press_ctrl && tss.pre_selN) {
1044             if (!test_mode) {
1045                 tss.ctrl_pre_sel = TRUE;
1046             }
1047             key_press_ctrl = FALSE;
1048             return 1;
1049         } else
1050             return 0;
1051 #if 1
1052     case XK_Shift_L:
1053     case XK_Shift_R:
1054         // dbg("release xkey %x\n", xkey);
1055         if (((tsin_chinese_english_toggle_key == TSIN_CHINESE_ENGLISH_TOGGLE_KEY_Shift) ||
1056              (tsin_chinese_english_toggle_key == TSIN_CHINESE_ENGLISH_TOGGLE_KEY_ShiftL && xkey == XK_Shift_L) ||
1057              (tsin_chinese_english_toggle_key == TSIN_CHINESE_ENGLISH_TOGGLE_KEY_ShiftR && xkey == XK_Shift_R)) &&
1058             key_press_alt) {
1059             if (!test_mode) {
1060                 tsin_toggle_eng_ch ();
1061             }
1062             key_press_alt = FALSE;
1063             return 1;
1064         } else
1065             return 0;
1066 #endif
1067     default:
1068         return 0;
1069     }
1070 }
1071 
1072 #include "win1.h"
1073 
gtab_set_win1_cb()1074 void gtab_set_win1_cb () {
1075     set_win1_cb ((cb_selec_by_idx_t) gtab_pre_select_idx, NULL, NULL);
1076 }
1077