1 #include "gcin.h"
2 #include "gtab.h"
3 #include "gcin-conf.h"
4 #include "gcin-endian.h"
5 #include "pho.h"
6 #include "tsin.h"
7 #include "tsin-parse.h"
8 #include "win-save-phrase.h"
9 #include "gtab-buf.h"
10 #include "gst.h"
11 #if WIN32
12 #include <io.h>
13 #endif
14 
15 void disp_gbuf(), ClrIn(), clear_after_put();
16 gboolean gtab_phrase_on();
17 int page_len();
18 void show_win_gtab();
19 void disp_selection0(gboolean phrase_selected, gboolean force_disp);
20 void disp_gtab_sel(char *s);
21 void add_cache(int start, int usecount, TSIN_PARSE *out, short match_phr_N, short no_match_ch_N, int tc_len);
22 int ch_pos_find(char *ch, int pos);
23 void inc_gtab_usecount(char *str), ClrSelArea();
24 void lookup_gtabn(char *ch, char *out);
25 char *htmlspecialchars(char *s, char out[]);
26 void hide_gtab_pre_sel();
27 gboolean gtab_vertical_select_on();
28 
29 extern gint64 key_press_time, key_press_time_ctrl;
30 
31 extern gboolean test_mode;
32 
33 GEDIT *gbuf;
34 extern char **seltab;
35 extern int ph_key_sz;
36 
extract_gtab_key(gboolean is_en,int start,int len,void * out)37 void extract_gtab_key(gboolean is_en, int start, int len, void *out)
38 {
39   int i;
40   char *p=(char *)out;
41 
42   if (is_en) {
43     for(i=0; i < len; i++) {
44       *(p++)  = gbuf[i+start].ch[0];
45     }
46   } else
47   if (tsin_hand.ph_key_sz==4) {
48     for(i=0; i < len; i++) {
49       u_int k = gbuf[i+start].keys[0];
50       memcpy(p, &k, sizeof(k));
51       p+=sizeof(k);
52     }
53   } else
54   if (tsin_hand.ph_key_sz==8){
55     for(i=0; i < len; i++) {
56       memcpy(p, &gbuf[i+start].keys[0], sizeof(u_int64_t));
57       p+=sizeof(u_int64_t);
58     }
59   }
60 }
61 
extract_gbuf_str(int start,int len,char * out)62 void extract_gbuf_str(int start, int len, char *out)
63 {
64   int i;
65   out[0]=0;
66   for(i=0;i<len;i++)
67     strcat(out, gbuf[i+start].ch);
68 }
69 
70 
gtab_cursor_end()71 gboolean gtab_cursor_end()
72 {
73   return ggg.gbuf_cursor==ggg.gbufN;
74 }
75 
dump_gbuf()76 void dump_gbuf()
77 {
78   int i;
79 
80   for(i=0; i<ggg.gbufN; i++) {
81     int j;
82     for(j=0;j < gbuf[i].selN; j++)
83       printf("%d:%s ", j, gbuf[i].sel[j]);
84     puts("");
85   }
86 }
87 
88 #if 0
89 static char latin_chars[]=
90 "ÀÁÂÃÄÅÆÆÇÈÉÊËÌÍÎÏÐÐÑÒÓÔÕÖØÙÚÛÜÝÞÞßàáâãäåææçèéêëìíîïððñòóôõöøùúûüýþþÿ"
91 "ĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJIJijijĴĵĶķĸĹĺĻļĽľĿŀŁł"
92 "ŃńŅņŇňʼnŊŋŌōŎŏŐőŒŒœœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽž";
93 
94 int en_word_len(char *bf)
95 {
96   char *s;
97 
98   for(s=bf;*s;) {
99     int sz = utf8_sz(s);
100     if (sz==1) {
101       if (!(*s >= 'A' && *s<='Z' || *s >= 'a' && *s<='z' || strchr("-_'", *s)))
102         break;
103     } else
104     if (sz==2) {
105       char *p;
106       for (p=latin_chars; *p; p+=2)
107         if (!memcmp(p, s, 2))
108           break;
109       if (!(*p))
110         break;
111     } else
112     if (sz>=3)
113       break;
114     s+=sz;
115   }
116 
117   if (*s)
118     return 0;
119   return strlen(bf);
120 }
121 #endif
122 
gen_buf_str(int start,gboolean add_spc)123 static char *gen_buf_str(int start, gboolean add_spc)
124 {
125   int i;
126   char *out = tmalloc(char, 1);
127   int outN=0;
128 
129   gboolean last_en_word = FALSE;
130   for(i=start;i<ggg.gbufN;i++) {
131     char *t = gbuf[i].ch;
132     int len = strlen(t);
133 
134 #if 0
135     if (add_spc && en_word_len(t) && !(gbuf[i].flag & FLAG_CHPHO_GTAB_BUF_EN_NO_SPC)) {
136       if (last_en_word) {
137         out = trealloc(out, char, outN+1);
138         out[outN++]=' ';
139       }
140       last_en_word = TRUE;
141     } else
142       last_en_word = FALSE;
143 #endif
144 
145     out = trealloc(out, char, outN+len+1);
146     memcpy(out + outN, t, len);
147     outN+=len;
148   }
149 
150   out[outN] = 0;
151   return out;
152 }
153 
154 extern gboolean last_cursor_off;
155 
gen_buf_str_disp()156 static char *gen_buf_str_disp()
157 {
158 #if 0
159   if (!ggg.gbufN) {
160     return strdup("");
161   }
162 #endif
163 
164   int i;
165   char *out = tmalloc(char, 1);
166   int outN=0;
167 
168   out[0]=0;
169 //  gbuf[ggg.gbufN].ch = " ";
170 
171 //  gboolean last_is_en_word = FALSE;
172 
173 #if 0
174   int N = last_cursor_off ? ggg.gbufN-1:ggg.gbufN;
175 #else
176   int N = ggg.gbufN;
177 #endif
178   for(i=0;i <= N;i++) {
179     char addspc[MAX_CIN_PHR * 2 + 2];
180     char spec[MAX_CIN_PHR * 2 + 2];
181     int len = i<N?strlen(gbuf[i].ch):0;
182 //    dbg("i %d N:%d bufN:%d\n",i,N,ggg.gbufN);
183 #if 0
184     if (gbuf[i].flag & FLAG_CHPHO_GTAB_BUF_EN_NO_SPC)
185       len = 0;
186 #endif
187 //    dbg("%d %d is_en:%d\n",i, len, last_is_en_word);
188 
189     if (len) {
190 #if 0
191       if (last_is_en_word) {
192         strcpy(addspc, " ");
193         strcat(addspc, gbuf[i].ch);
194       } else
195 #endif
196         strcpy(addspc, gbuf[i].ch);
197 //      last_is_en_word = TRUE;
198     } else {
199 //      last_is_en_word = FALSE;
200       strcpy(addspc, " ");
201     }
202 
203     htmlspecialchars(addspc, spec);
204 //    dbg("addspc '%s'  spec:%s out:%s\n", addspc, spec, out);
205 
206     char www[MAX_CIN_PHR * 2 + 2];
207     char *t = spec;
208 
209     if (i==ggg.gbuf_cursor) {
210       sprintf(www, "<span background=\"%s\">%s</span>", tsin_pho_mode()?tsin_cursor_color:"green", spec);
211       t = www;
212     }
213 
214     len = strlen(t);
215     out = trealloc(out, char, outN+len+1);
216     memcpy(out + outN, t, len);
217     outN+=len;
218     out[outN] = 0;
219   }
220 
221   return out;
222 }
223 
224 
225 void disp_label_edit(char *str);
226 
free_pgbuf(GEDIT * p)227 static void free_pgbuf(GEDIT *p) {
228   if (p->sel) {
229       int i;
230       for (i = 0; i < p->selN; i++) {
231           free(p->sel[i]);
232           p->sel[i] = NULL;
233       }
234       free(p->sel);
235       p->sel = NULL;
236   }
237 
238   p->ch = NULL;
239   p->selN = 0;
240   p->flag = 0;
241 }
242 
free_gbuf(int idx)243 static void free_gbuf(int idx)
244 {
245     if (!gbuf || idx >= ggg.gbufN || idx < 0)
246         return;
247     free_pgbuf(&gbuf[idx]);
248 }
249 
clear_gtab_buf_all()250 void clear_gtab_buf_all()
251 {
252   int i;
253   for(i=0;i<ggg.gbufN;i++)
254     free_gbuf(i);
255   ggg.gbuf_cursor = ggg.gbufN=0;
256   ggg.gtab_buf_select = 0;
257   disp_gbuf();
258 }
259 
260 
261 void minimize_win_gtab();
disp_gbuf()262 void disp_gbuf()
263 {
264 #if WIN32
265   if (test_mode)
266     return;
267 #endif
268   char *bf=gen_buf_str_disp();
269   disp_label_edit(bf);
270 
271   if (ggg.gbufN && gtab_disp_key_codes)
272     lookup_gtabn(gbuf[ggg.gbufN-1].ch, NULL);
273 
274   free(bf);
275 
276   minimize_win_gtab();
277 }
278 
clear_gbuf_sel()279 void clear_gbuf_sel()
280 {
281 #if WIN32
282   if (test_mode)
283     return;
284 #endif
285   ggg.gtab_buf_select = 0;
286   ggg.total_matchN = 0;
287   ggg.pg_idx = 0;
288   ClrSelArea();
289 }
290 
gbuf_cursor_left()291 int gbuf_cursor_left()
292 {
293   hide_gtab_pre_sel();
294   if (!ggg.gbuf_cursor)
295     return ggg.gbufN;
296 #if WIN32
297   if (test_mode)
298     return 1;
299 #endif
300   if (ggg.gtab_buf_select)
301     clear_gbuf_sel();
302   ClrIn();
303   ggg.gbuf_cursor--;
304   disp_gbuf();
305   return 1;
306 }
307 
308 
gbuf_cursor_right()309 int gbuf_cursor_right()
310 {
311   hide_gtab_pre_sel();
312   if (ggg.gbuf_cursor==ggg.gbufN)
313     return ggg.gbufN;
314 #if WIN32
315   if (test_mode)
316     return 1;
317 #endif
318   if (ggg.gtab_buf_select)
319     clear_gbuf_sel();
320   ggg.gbuf_cursor++;
321   disp_gbuf();
322   return 1;
323 }
324 
gbuf_cursor_home()325 int gbuf_cursor_home()
326 {
327   hide_gtab_pre_sel();
328   if (!ggg.gbufN)
329     return 0;
330 #if WIN32
331   if (test_mode)
332     return 1;
333 #endif
334   if (ggg.gtab_buf_select)
335     clear_gbuf_sel();
336 
337   ggg.gbuf_cursor = 0;
338   disp_gbuf();
339   return 1;
340 }
341 
342 
gbuf_cursor_end()343 int gbuf_cursor_end()
344 {
345   hide_gtab_pre_sel();
346   if (!ggg.gbufN)
347     return 0;
348 #if WIN32
349   if (test_mode)
350     return 1;
351 #endif
352   if (ggg.gtab_buf_select)
353     clear_gbuf_sel();
354 
355   ggg.gbuf_cursor = ggg.gbufN;
356   disp_gbuf();
357   return 1;
358 }
359 
360 void inc_gtab_use_count(char *s);
361 gboolean inc_tsin_use_count(TSIN_HANDLE *th, void *pho, char *ch, int N);
362 gboolean inc_tsin_use_count_en(char *s, int len);
363 gboolean is_legal_en_char(char *ch);
364 void strtolower(char *u8, int len), hide_win_gtab();
365 gboolean gtab_has_input();
366 
output_gbuf_()367 gboolean output_gbuf_()
368 {
369   hide_gtab_pre_sel();
370 //  ClrIn();
371 
372   if (!ggg.gbufN)
373     return FALSE;
374 #if WIN32
375   if (test_mode)
376     return TRUE;
377 #endif
378   char *bf=gen_buf_str(0, TRUE);
379 #if 1
380   dbg("oggg.gbufN:%d ut %s\n", ggg.gbufN, bf);
381 #endif
382 
383   send_text(bf);
384   free(bf);
385 
386   int i;
387   for(i=0; i < ggg.gbufN;) {
388     char t[MAX_CIN_PHR+1];
389     t[0]=0;
390     inc_gtab_use_count(gbuf[i].ch);
391 
392     int j;
393     gboolean is_en = TRUE;
394     for(j=i; j < ggg.gbufN && j < i+gbuf[i].plen; j++) {
395       strcat(t, gbuf[j].ch);
396       if (!is_legal_en_char(gbuf[j].ch))
397         is_en = FALSE;
398     }
399 
400     int plen = gbuf[i].plen;
401     if (!plen) {
402       dbg("plen zero\n");
403       i++;
404     } else {
405 	  if (is_en) {
406 		dbg("is_en %s\n", t);
407 		inc_tsin_use_count_en(t, plen);
408       } else {
409         u_int64_t kk[MAX_PHRASE_LEN];
410 	    extract_gtab_key(FALSE, i, plen, kk);
411 	    inc_tsin_use_count(&tsin_hand, kk, t, plen);
412 	  }
413 
414       i+=plen;
415     }
416   }
417 
418   clear_gtab_buf_all();
419 
420   if (gcin_pop_up_win && !gtab_has_input()) {
421     hide_win_gtab();
422   }
423   return TRUE;
424 }
425 
output_gbuf()426 gboolean output_gbuf() {
427   ClrIn();
428   return output_gbuf_();
429 }
430 
431 
check_gtab_fixed_mismatch(int idx,char * mtch,int plen)432 gboolean check_gtab_fixed_mismatch(int idx, char *mtch, int plen)
433 {
434   int j;
435   char *p = mtch;
436 
437   for(j=0; j < plen; j++) {
438     int u8sz = utf8_sz(p);
439     if (!(gbuf[idx+j].flag & FLAG_CHPHO_FIXED))
440       continue;
441 
442     if (memcmp(gbuf[idx+j].ch, p, u8sz))
443       break;
444 
445     p+= u8sz;
446   }
447 
448   if (j < plen)
449     return TRUE;
450 
451   return FALSE;
452 }
453 
set_gtab_user_head()454 void set_gtab_user_head()
455 {
456 #if WIN32
457   if (test_mode)
458     return;
459 #endif
460   gbuf[ggg.gbuf_cursor].flag |= FLAG_CHPHO_PHRASE_USER_HEAD;
461 }
462 
463 
464 CACHE *cache_lookup(int start);
465 
466 #define DBG 0
467 
468 void init_cache();
469 void free_cache();
470 void init_tsin_table();
471 void set_tsin_parse_len(int);
472 
gtab_parse()473 void gtab_parse()
474 {
475   int i;
476   TSIN_PARSE out[MAX_PH_BF_EXT+1];
477   bzero(out, sizeof(out));
478 
479   if (test_mode)
480     return;
481 
482   if (ggg.gbufN <= 1)
483     return;
484 
485   init_tsin_table();
486 
487   init_cache(ggg.gbufN);
488 
489   set_tsin_parse_len(ggg.gbufN);
490 
491   short smatch_phr_N, sno_match_ch_N;
492   tsin_parse_recur(0, out, &smatch_phr_N, &sno_match_ch_N);
493 #if 0
494   puts("vvvvvvvvvvvvvvvv");
495   for(i=0;  i < out[i].len; i++) {
496     printf("%x %d:", out[i].str, out[i].len);
497     utf8_putcharn(out[i].str, out[i].len);
498   }
499   dbg("\n");
500 #endif
501 
502   for(i=0; i < ggg.gbufN; i++)
503     gbuf[i].flag &= ~(FLAG_CHPHO_PHRASE_HEAD|FLAG_CHPHO_PHRASE_BODY);
504 
505   int ofsi;
506   for(ofsi=i=0; out[i].len; i++) {
507     int j, ofsj;
508 
509     if (out[i].flag & FLAG_TSIN_PARSE_PHRASE) {
510       gbuf[ofsi].flag |= FLAG_CHPHO_PHRASE_HEAD;
511       gbuf[ofsi].plen = out[i].len;
512     }
513 
514     for(ofsj=j=0; j < out[i].len; j++) {
515       char *w = (char *)&out[i].str[ofsj];
516       int wsz = utf8_sz(w);
517       ofsj += wsz;
518 
519       int k;
520       for(k=0;k<gbuf[ofsi].selN; k++) {
521         int sz = utf8_sz(gbuf[ofsi].sel[k]);
522         if (wsz == sz && !memcmp(gbuf[ofsi].sel[k], w, sz))
523           break;
524       }
525       if (k==gbuf[ofsi].selN) {
526 #if 0
527         dbg("qq ");
528         utf8_putchar(w);
529         p_err(" err 1 selN:%d ofsi:%d", gbuf[ofsi].selN, ofsi);
530 #endif
531         k=0;
532       }
533 
534       if (!(gbuf[ofsi].flag & FLAG_CHPHO_FIXED)) {
535         gbuf[ofsi].ch = gbuf[ofsi].sel[k];
536         gbuf[ofsi].c_sel = k;
537       }
538       gbuf[ofsi].flag |= FLAG_CHPHO_PHRASE_BODY;
539 
540       ofsi++;
541     }
542   }
543 
544 #if 0
545   puts("-----------------------------");
546   for(i=0;i<ggg.gbufN;i++)
547     puts(gbuf[i].ch);
548 #endif
549   free_cache();
550 }
551 
cursor_gbuf()552 static GEDIT *cursor_gbuf()
553 {
554   return ggg.gbuf_cursor == ggg.gbufN ? &gbuf[ggg.gbuf_cursor-1] : &gbuf[ggg.gbuf_cursor];
555 }
556 
557 typedef struct {
558   char *s;
559   int usecount;
560   int org_seq;
561 } GITEM;
562 
563 int get_gtab_use_count(char *s);
564 
qcmp_gitem(const void * aa,const void * bb)565 int qcmp_gitem(const void *aa, const void *bb)
566 {
567   int d = ((GITEM *)bb)->usecount - ((GITEM *)aa)->usecount;
568   if (d)
569     return d;
570 
571   return ((GITEM *)aa)->org_seq - ((GITEM *)bb)->org_seq;
572 }
573 
574 void hide_row2_if_necessary();
575 
576 char auto_end_punch[]=", . ? : ; ! [ ] 「 」 , 。 ? ; : 、 ~ ! ( )";
insert_gbuf_cursor(char ** sel,int selN,u_int64_t key,gboolean b_gtab_en_no_spc)577 GEDIT *insert_gbuf_cursor(char **sel, int selN, u_int64_t key, gboolean b_gtab_en_no_spc)
578 {
579 #if WIN32
580   if (test_mode)
581 	  return NULL;
582 #endif
583   dbg("insert_gbuf_cursor test_mode:%d\n", test_mode);
584   hide_row2_if_necessary();
585 
586   if (!sel || !selN)
587     return NULL;
588 //  dbg("insert_gbuf_cursor %x\n", key);
589 
590   gbuf=trealloc(gbuf, GEDIT, ggg.gbufN+2);
591 
592   GEDIT *pbuf = &gbuf[ggg.gbuf_cursor];
593 
594   if (ggg.gbuf_cursor < ggg.gbufN)
595     memmove(&gbuf[ggg.gbuf_cursor+1], &gbuf[ggg.gbuf_cursor], sizeof(GEDIT) * (ggg.gbufN - ggg.gbuf_cursor));
596 
597   ggg.gbuf_cursor++;
598   ggg.gbufN++;
599 
600   bzero(pbuf, sizeof(GEDIT));
601   bzero(gbuf+ggg.gbufN, sizeof(GEDIT));
602 
603   GITEM *items = tmalloc(GITEM, selN);
604 
605   int i;
606   for(i=0; i < selN; i++) {
607     items[i].s = sel[i];
608     items[i].org_seq = i;
609     items[i].usecount = get_gtab_use_count(sel[i]);
610   }
611   qsort(items, selN, sizeof(GITEM), qcmp_gitem);
612 
613   for(i=0; i < selN; i++)
614     sel[i] = items[i].s;
615 
616   pbuf->ch = sel[0];
617   pbuf->sel = sel;
618   pbuf->selN = selN;
619   pbuf->c_sel = 0;
620   pbuf->keys[0] = key;
621   pbuf->keysN=1;
622 //  dbg("insert_gbuf_cursor %s %d\n", sel[0],b_gtab_en_no_spc);
623   pbuf->flag = b_gtab_en_no_spc ? FLAG_CHPHO_GTAB_BUF_EN_NO_SPC:0;
624 
625 
626   if (!tsin_pho_mode()) {
627     if (ggg.gbufN==ggg.gbuf_cursor && selN==1 && (strstr(",.?/:", sel[0]) /* || (sel[0][0]==' ' && ggg.gbufN==1) */ ) ) {
628       output_gbuf();
629     } else {
630       disp_gbuf();
631     }
632   } else
633   if (gcin_punc_auto_send && ggg.gbufN==ggg.gbuf_cursor && selN==1 && strstr(auto_end_punch, sel[0])) {
634     char_play(pbuf->ch);
635     output_gbuf();
636   } else {
637     gtab_parse();
638     disp_gbuf();
639     char_play(pbuf->ch);
640   }
641 
642   free(items);
643   return pbuf;
644 }
645 
646 
set_gbuf_c_sel(int v)647 void set_gbuf_c_sel(int v)
648 {
649   GEDIT *pbuf = cursor_gbuf();
650 
651   pbuf->c_sel = v + ggg.pg_idx;
652   pbuf->ch = pbuf->sel[pbuf->c_sel];
653 //  dbg("zzzsel v:%d %d %s\n",v, pbuf->c_sel,pbuf->ch);
654   pbuf->flag |= FLAG_CHPHO_FIXED;
655   ggg.gtab_buf_select = 0;
656   ggg.more_pg = 0;
657   disp_gtab_sel("");
658   gtab_parse();
659   disp_gbuf();
660 
661   if (gcin_buffer_select_char_auto_right) {
662       gbuf_cursor_right();
663   }
664 //  dbg("zzzsel v:%d\n", pbuf->c_sel);
665 }
666 
insert_gbuf_cursor1(char * s,u_int64_t key,gboolean b_gtab_en_no_spc)667 GEDIT *insert_gbuf_cursor1(char *s, u_int64_t key, gboolean b_gtab_en_no_spc)
668 {
669 #if WIN32
670    if (test_mode)
671 	   return NULL;
672 #endif
673    if (!gtab_phrase_on())
674      return NULL;
675 
676    char **sel = tmalloc(char *, 1);
677    sel[0] = strdup(s);
678 //   dbg("insert_gbuf_cursor1 %s %llx %d\n", s, key, b_gtab_en_no_spc);
679    GEDIT *e = insert_gbuf_cursor(sel, 1, key, b_gtab_en_no_spc);
680    clear_after_put();
681    return e;
682 }
683 
insert_gbuf_cursor_phrase(char * s,void * key,int N)684 void insert_gbuf_cursor_phrase(char *s, void *key, int N)
685 {
686   u_int *key32 = (u_int *)key;
687   u_int64_t *key64 = (u_int64_t *)key;
688 
689 //  dbg("insert_gbuf_cursor_phrase\n");
690 
691   int i;
692   for(i=0; i < N; i++) {
693     char ch[CH_SZ+1];
694     int n = utf8cpy(ch, s);
695     u_int64_t v = tsin_hand.ph_key_sz==4?key32[i]:key64[i];
696     GEDIT *e = insert_gbuf_cursor1(ch, v, TRUE);
697     e->flag |= FLAG_CHPHO_FIXED;
698     s+=n;
699     if (i==0)
700       e->plen = N;
701   }
702 }
703 
key_N(u_int64_t k)704 static int key_N(u_int64_t k)
705 {
706   int n=0;
707   int mask = (1 << KeyBits) - 1;
708 
709   while (k) {
710     k>>=mask;
711     n++;
712   }
713 
714   return n;
715 }
716 
qcmp_key_N(const void * aa,const void * bb)717 static int qcmp_key_N(const void *aa, const void *bb)
718 {
719   u_int64_t a = *((u_int64_t *)aa);
720   u_int64_t b = *((u_int64_t *)bb);
721 
722   return key_N(a) - key_N(b);
723 }
724 
725 
insert_gbuf_nokey(char * s)726 void insert_gbuf_nokey(char *s)
727 {
728 #if WIN32
729    if (test_mode)
730      return;
731 #endif
732    if (!gtab_phrase_on())
733      return;
734 
735    dbg("insert_gbuf_nokey %s\n", s);
736 
737    int i;
738 #define MKEY 32
739    u_int64_t keys[MKEY];
740    int keysN=0;
741    int sz = utf8_sz(s);
742 
743    keys[0]=0;
744    if (cur_inmd->tbl64) {
745      for(i=0; i < cur_inmd->DefChars; i++) {
746        if (!memcmp(cur_inmd->tbl64[i].ch, s, sz)) {
747          u_int64_t t;
748          memcpy(&t, cur_inmd->tbl64[i].key, sizeof(u_int64_t));
749          keys[keysN++] = t;
750          if (keysN >= MKEY)
751            break;
752        }
753      }
754    } else
755    if (cur_inmd->tbl) {
756      for(i=0; i < cur_inmd->DefChars; i++) {
757        if (!memcmp(cur_inmd->tbl[i].ch, s, sz)) {
758          u_int t;
759          memcpy(&t, cur_inmd->tbl[i].key, sizeof(u_int));
760          keys[keysN++] = t;
761          if (keysN >= MKEY)
762             break;
763        }
764      }
765    }
766 
767    qsort(keys, keysN, sizeof(u_int64_t), qcmp_key_N);
768 
769    GEDIT *e = insert_gbuf_cursor1(s, keys[0], FALSE /* TRUE */);
770    if (keysN > 8)
771      keysN = 8;
772 
773    memcpy(e->keys, keys, sizeof(u_int64_t) * keysN);
774    e->keysN = keysN;
775 }
776 
insert_gbuf_cursor1_cond(char * s,u_int64_t key,gboolean valid_key)777 void insert_gbuf_cursor1_cond(char *s, u_int64_t key, gboolean valid_key)
778 {
779 #if WIN32
780   if (test_mode)
781     return;
782 #endif
783   dbg("insert_gbuf_cursor1_cond %s\n", s);
784   if (valid_key)
785     insert_gbuf_cursor1(s, key, FALSE);
786   else
787     insert_gbuf_nokey(s);
788 }
789 
insert_gbuf_cursor_char(char ch)790 void insert_gbuf_cursor_char(char ch)
791 {
792 #if WIN32
793   if (test_mode)
794     return;
795 #endif
796   char t[2];
797   t[0]=ch;
798   t[1]=0;
799   insert_gbuf_cursor1(t, 0, TRUE);
800 }
801 
802 gboolean gtab_has_input();
803 void hide_win_gtab();
804 
gtab_buf_delete_ex(gboolean auto_hide)805 int gtab_buf_delete_ex(gboolean auto_hide)
806 {
807   if (ggg.gbuf_cursor==ggg.gbufN)
808     return 0;
809 #if WIN32
810   if (test_mode)
811     return 1;
812 #endif
813   if (ggg.gtab_buf_select)
814     clear_gbuf_sel();
815 
816   free_gbuf(ggg.gbuf_cursor);
817   memmove(&gbuf[ggg.gbuf_cursor], &gbuf[ggg.gbuf_cursor+1], sizeof(GEDIT) * (ggg.gbufN - ggg.gbuf_cursor -1));
818   ggg.gbufN--;
819   disp_gbuf();
820 
821   if (gcin_pop_up_win && !gtab_has_input() && auto_hide)
822     hide_win_gtab();
823 
824   return 1;
825 }
826 
gtab_buf_delete()827 int gtab_buf_delete()
828 {
829   return gtab_buf_delete_ex(TRUE);
830 }
831 
832 
833 gboolean gtab_has_input();
834 void hide_win_gtab();
835 
gtab_buf_backspace_ex(gboolean auto_hide)836 int gtab_buf_backspace_ex(gboolean auto_hide)
837 {
838   if (!ggg.gbuf_cursor) {
839     return ggg.gbufN>0;
840   }
841 
842 #if WIN32
843   if (test_mode)
844     return 1;
845 #endif
846 
847   ggg.gbuf_cursor--;
848   gtab_buf_delete_ex(auto_hide);
849 
850   if (gcin_pop_up_win && !gtab_has_input() && auto_hide)
851     hide_win_gtab();
852 
853   return 1;
854 }
855 
gtab_buf_backspace()856 int gtab_buf_backspace()
857 {
858   return gtab_buf_backspace_ex(TRUE);
859 }
860 
861 
gtab_buf_backspaceN(int n)862 void gtab_buf_backspaceN(int n)
863 {
864   int i;
865   for(i=0; i < n; i++)
866     gtab_buf_backspace_ex(FALSE);
867 }
868 
869 extern int more_pg;
870 
gtab_disp_sel()871 void gtab_disp_sel()
872 {
873   int idx = ggg.gbuf_cursor==ggg.gbufN ? ggg.gbuf_cursor-1:ggg.gbuf_cursor;
874   GEDIT *pbuf=&gbuf[idx];
875 
876   int i;
877   for(i=0; i < cur_inmd->M_DUP_SEL; i++) {
878     int v = i + ggg.pg_idx;
879     if (v >= pbuf->selN)
880       seltab[i][0]=0;
881     else
882       strcpy(seltab[i], pbuf->sel[v]);
883   }
884 
885   if (pbuf->selN > page_len())
886     ggg.more_pg = 1;
887 #if WIN32
888   show_win_gtab();
889   disp_selection0(FALSE, TRUE);
890 #else
891   disp_selection0(FALSE, TRUE);
892   show_win_gtab();
893 #endif
894 }
895 
896 
show_buf_select()897 int show_buf_select()
898 {
899   if (!ggg.gbufN)
900     return 0;
901 #if WIN32
902   if (test_mode)
903 	  return 1;
904 #endif
905   int idx = ggg.gbuf_cursor==ggg.gbufN ? ggg.gbuf_cursor-1:ggg.gbuf_cursor;
906   GEDIT *pbuf=&gbuf[idx];
907   ggg.gtab_buf_select = 1;
908   ggg.total_matchN = pbuf->selN;
909   ggg.pg_idx = 0;
910 
911   gtab_disp_sel();
912   hide_gtab_pre_sel();
913 
914   return 1;
915 }
916 
gbuf_prev_pg()917 void gbuf_prev_pg()
918 {
919   ggg.pg_idx -= page_len();
920   if (ggg.pg_idx < 0)
921     ggg.pg_idx = 0;
922 
923   gtab_disp_sel();
924 }
925 
gbuf_next_pg()926 void gbuf_next_pg()
927 {
928 #if WIN32
929   if (test_mode)
930 	  return;
931 #endif
932   ggg.pg_idx += page_len();
933   if (ggg.pg_idx >= ggg.total_matchN)
934     ggg.pg_idx = 0;
935 
936   gtab_disp_sel();
937 }
938 
939 #include "im-client/gcin-im-client-attr.h"
940 
941 int get_DispInArea_str(char *out);
942 
gtab_get_preedit(char * str,GCIN_PREEDIT_ATTR attr[],int * pcursor,int * sub_comp_len)943 int gtab_get_preedit(char *str, GCIN_PREEDIT_ATTR attr[], int *pcursor, int *sub_comp_len)
944 {
945   int i=0;
946   int strN=0;
947   int attrN=0;
948   int ch_N=0;
949 
950 //  dbg("gtab_get_preedit\n");
951   str[0]=0;
952   *pcursor=0;
953 
954 #if WIN32 || 1
955   *sub_comp_len = ggg.ci > 0;
956 #if 1
957   if (ggg.gbufN && !gcin_edit_display_ap_only())
958 	*sub_comp_len|=4;
959 #endif
960 #endif
961   gboolean ap_only = gcin_edit_display_ap_only();
962 
963   if (gtab_phrase_on()) {
964     attr[0].flag=GCIN_PREEDIT_ATTR_FLAG_UNDERLINE;
965     attr[0].ofs0=0;
966 
967     if (ggg.gbufN)
968       attrN=1;
969 
970 //    gboolean last_is_en_word = FALSE;
971     for(i=0; i < ggg.gbufN; i++) {
972       char *s = gbuf[i].ch;
973       char tt[MAX_CIN_PHR+2];
974 #if 0
975       if (en_word_len(s) && !(gbuf[i].flag & FLAG_CHPHO_GTAB_BUF_EN_NO_SPC)) {
976         if (last_is_en_word) {
977           strcpy(tt, " ");
978           strcat(tt, s);
979           s = tt;
980         }
981         last_is_en_word = TRUE;
982       } else {
983         last_is_en_word = FALSE;
984       }
985 #endif
986       int len = strlen(s);
987       int N = utf8_str_N(s);
988       ch_N+=N;
989       if (i < ggg.gbuf_cursor)
990         *pcursor+=N;
991       if (ap_only && i==ggg.gbuf_cursor) {
992         attr[1].ofs0=*pcursor;
993         attr[1].ofs1=*pcursor+N;
994         attr[1].flag=GCIN_PREEDIT_ATTR_FLAG_REVERSE;
995         attrN++;
996       }
997 
998       if (gcin_display_on_the_spot_key() && i==ggg.gbuf_cursor)
999         strN += get_DispInArea_str(str+strN);
1000 
1001       memcpy(str+strN, s, len);
1002       strN+=len;
1003     }
1004   }
1005 
1006 
1007   if (gcin_display_on_the_spot_key() && i==ggg.gbuf_cursor)
1008     strN += get_DispInArea_str(str+strN);
1009 
1010   str[strN]=0;
1011 
1012   attr[0].ofs1 = ch_N;
1013   return attrN;
1014 }
1015 
1016 extern GtkWidget *gwin_gtab;
gtab_reset()1017 void gtab_reset()
1018 {
1019 #if UNIX
1020   if (!gwin_gtab)
1021     return;
1022 #endif
1023 #if WIN32
1024   if (test_mode)
1025 	  return;
1026 #endif
1027   clear_gtab_buf_all();
1028   clear_gbuf_sel();
1029   ClrIn();
1030   if (gcin_pop_up_win)
1031     hide_win_gtab();
1032   return;
1033 }
1034 
1035 int ch_to_gtab_keys(INMD *tinmd, char *ch, u_int64_t keys[]);
1036 
save_gtab_buf_phrase_idx(int idx0,int len)1037 void save_gtab_buf_phrase_idx(int idx0, int len)
1038 {
1039   if (len > MAX_PHRASE_LEN)
1040     return;
1041   WSP_S wsp[MAX_PHRASE_LEN];
1042 
1043   bzero(wsp, sizeof(wsp));
1044   int i;
1045   for(i=0; i < len; i++) {
1046     u8cpy(wsp[i].ch, gbuf[idx0 + i].ch);
1047     u_int64_t key = gbuf[idx0 + i].keys[0];
1048 
1049     if (!key) {
1050       u_int64_t keys[64];
1051       int keysN = ch_to_gtab_keys(cur_inmd, wsp[i].ch, keys);
1052       if (keysN)
1053         key = keys[0];
1054     }
1055 
1056     wsp[i].key = key;
1057   }
1058 
1059   create_win_save_phrase(wsp, len);
1060 }
1061 
save_gtab_buf_phrase(KeySym key)1062 void save_gtab_buf_phrase(KeySym key)
1063 {
1064   int len = key - '0';
1065   int idx0 = ggg.gbuf_cursor - len;
1066   int idx1 = ggg.gbuf_cursor - 1;
1067 
1068   if (idx0 < 0 || idx0 > idx1)
1069     return;
1070 
1071   save_gtab_buf_phrase_idx(idx0, len);
1072 }
1073 
save_gtab_buf_shift_enter()1074 gboolean save_gtab_buf_shift_enter()
1075 {
1076 	int start = ggg.gbufN == ggg.gbuf_cursor ? 0:ggg.gbuf_cursor;
1077 	int N = ggg.gbufN - start;
1078 	if (!N || N > MAX_CIN_PHR_N)
1079 		return 0;
1080 #if WIN32
1081 	if (test_mode)
1082 		return TRUE;
1083 #endif
1084 	save_gtab_buf_phrase_idx(start, N);
1085 	gbuf_cursor_end();
1086 	return 1;
1087 }
1088 
1089 
1090 void load_tsin_db0(char *infname, gboolean is_gtab_i);
1091 gboolean init_tsin_table_fname(INMD *p, char *fname);
1092 
init_tsin_table()1093 void init_tsin_table()
1094 {
1095   char fname[256];
1096   if (!current_CS)
1097     return;
1098 
1099   init_tsin_table_fname(&inmd[current_CS->in_method], fname);
1100   load_tsin_db0(fname, TRUE);
1101 }
1102 
1103 u_char scanphr_e(TSIN_HANDLE *th, gboolean is_gtab, int chpho_idx, int plen, gboolean pho_incr, int *rselN);
1104 void init_pre_sel();
1105 void clear_sele();
1106 void set_sele_text(int i, char *text, int len);
1107 void get_win_gtab_geom();
1108 void disp_selections(int x, int y);
1109 
1110 gboolean use_tsin_sel_win();
1111 void init_tsin_selection_win();
1112 
1113 static int gtab_pre_select_phrase_len;
1114 
1115 void disp_gtab_pre_sel(char *s);
1116 extern GtkWidget *gwin1;
1117 
gtab_scan_pre_select(gboolean b_incr)1118 void gtab_scan_pre_select(gboolean b_incr)
1119 {
1120 #if WIN32
1121   if (test_mode)
1122     return;
1123 #endif
1124 
1125   if (!gtab_phrase_pre_select)
1126     return;
1127 //  dbg("gtab_scan_pre_select\n");
1128 
1129   tss.pre_selN = 0;
1130 
1131   hide_gtab_pre_sel();
1132 
1133   if (!gtab_cursor_end() || !ggg.gbufN)
1134     return;
1135 
1136   init_tsin_table();
1137   init_pre_sel();
1138 
1139   int Maxlen = ggg.gbufN;
1140   if (Maxlen > MAX_PHRASE_LEN)
1141     Maxlen = MAX_PHRASE_LEN;
1142 
1143   int len, selN, max_len=-1, max_selN;
1144   for(len=1; len <= Maxlen; len++) {
1145     int idx = ggg.gbufN - len;
1146     if (gbuf[idx].flag & FLAG_CHPHO_PHRASE_TAIL)
1147       break;
1148     int mlen = scanphr_e(&tsin_hand, TRUE, ggg.gbufN - len, len, b_incr, &selN);
1149     if (mlen) {
1150       max_len = len;
1151       max_selN = selN;
1152     }
1153   }
1154 
1155 //  dbg("max_len:%d  max_selN:%d\n", max_len, max_selN);
1156 
1157   if (max_len < 0 || max_selN >= strlen(cur_inmd->selkey) * 2) {
1158     tss.pre_selN = 0;
1159     return;
1160   }
1161 
1162   gtab_pre_select_phrase_len = max_len;
1163 
1164   scanphr_e(&tsin_hand, TRUE, ggg.gbufN - max_len, max_len, b_incr, &selN);
1165 
1166 //  dbg("selN:%d %d\n", selN, tss.pre_selN);
1167 
1168   if (selN==1 && tss.pre_sel[0].len==max_len) {
1169     char out[MAX_PHRASE_LEN * CH_SZ + 1];
1170     extract_gbuf_str(ggg.gbufN - max_len, max_len, out);
1171     if (!strcmp(out, tss.pre_sel[0].str))
1172       return;
1173   }
1174 
1175 //  dbg("selN %d %d\n",selN, tss.pre_selN);
1176 
1177   if (use_tsin_sel_win()) {
1178 	if (gwin1)
1179       clear_sele();
1180 	else
1181       init_tsin_selection_win();
1182 
1183     int i;
1184     for(i=0;i<tss.pre_selN; i++)
1185        set_sele_text(i,tss.pre_sel[i].str, -1);
1186     get_win_gtab_geom();
1187     disp_selections(-1, -1);
1188     return;
1189   }
1190 
1191   char tt[4096];
1192   tt[0]=0;
1193   int i;
1194 
1195   for(i=0;i<tss.pre_selN; i++) {
1196     char ts[(MAX_PHRASE_LEN+3) * CH_SZ + 1];
1197     char *br= (i < tss.pre_selN-1 && gtab_vertical_select_on())?"\n":"";
1198 
1199     sprintf(ts, "<span foreground=\"%s\">%c</span>%s%s", gcin_sel_key_color,
1200       cur_inmd->selkey[i], tss.pre_sel[i].str, br);
1201     strcat(tt, ts);
1202     if (!gtab_vertical_select_on() && i < tss.pre_selN-1)
1203       strcat(tt, " ");
1204   }
1205 
1206 //  dbg("tt %s\n", tt);
1207   disp_gtab_pre_sel(tt);
1208 }
1209 
1210 
1211 int shift_key_idx(char *s, KeySym xkey);
1212 
gtab_pre_select_idx(int c)1213 gboolean gtab_pre_select_idx(int c)
1214 {
1215   if (c < 0)
1216     return FALSE;
1217   if (c >= tss.pre_selN)
1218     return TRUE;
1219 
1220 #if 0
1221   dbg("c %d %s  ggg.gbuf_cursor:%d,%d\n", c, tss.pre_sel[c].str,
1222     ggg.gbuf_cursor, ggg.gbufN);
1223 #endif
1224 #if WIN32
1225   if (!test_mode)
1226 #endif
1227   {
1228 	  gtab_buf_backspaceN(gtab_pre_select_phrase_len);
1229 	  int len = tss.pre_sel[c].len;
1230 
1231 	  if (!tsin_pho_mode()) {
1232 		len = utf8_str_N(tss.pre_sel[c].str);
1233 	  }
1234 
1235 	  insert_gbuf_cursor_phrase(tss.pre_sel[c].str, tss.pre_sel[c].phkey, len);
1236 	  gbuf[ggg.gbufN-1].flag |= FLAG_CHPHO_PHRASE_TAIL;
1237 
1238 	  hide_gtab_pre_sel();
1239 	  if (gcin_edit_display_ap_only() && gcin_on_the_spot_key)
1240 		hide_win_gtab();
1241   }
1242   return TRUE;
1243 }
1244 
1245 extern char noshi_sele[], shift_sele[];
1246 
gtab_pre_select_shift(KeySym key,int kbstate)1247 gboolean gtab_pre_select_shift(KeySym key, int kbstate)
1248 {
1249   dbg("gtab_pre_select_shift %c\n", key);
1250   if (!gtab_phrase_pre_select || !tss.pre_selN)
1251     return FALSE;
1252 
1253   // If the key(123) is not defined as gtab keys, the shift keys(!@#) should be used for punc, not preselect
1254   int c;
1255   char *p;
1256   if ((p=strchr(cur_inmd->selkey, key))) {
1257     c = p - cur_inmd->selkey;
1258     return gtab_pre_select_idx(c);
1259   } else
1260     c = shift_key_idx(cur_inmd->selkey, key);
1261 
1262   if (c < 0)
1263     return FALSE;
1264   p = strchr(shift_sele, key);
1265   if (!p)
1266     return FALSE;
1267   int idx = p - shift_sele;
1268   char noshi = noshi_sele[idx];
1269   if (!cur_inmd->keymap[noshi])
1270     return FALSE;
1271 
1272   return gtab_pre_select_idx(c);
1273 }
1274 
1275 void tsin_toggle_eng_ch();
1276 void set_key_codes_label(char *s, int better);
1277 
feedkey_gtab_release(KeySym xkey,int kbstate)1278 int feedkey_gtab_release(KeySym xkey, int kbstate)
1279 {
1280   gint64 kpt;
1281 
1282   switch (xkey) {
1283      case XK_Control_L:
1284      case XK_Control_R:
1285        kpt = key_press_time_ctrl;
1286 	   if (!test_mode)
1287 		   key_press_time_ctrl = 0;
1288 
1289         if (current_time() - kpt < 300000 && tss.pre_selN) {
1290           if (!test_mode) {
1291             tss.ctrl_pre_sel = TRUE;
1292           }
1293           return 1;
1294         } else
1295           return 0;
1296 #if 1
1297      case XK_Shift_L:
1298      case XK_Shift_R:
1299        kpt = key_press_time;
1300 	   if (!test_mode)
1301 		  key_press_time = 0;
1302 
1303 // dbg("release xkey %x\n", xkey);
1304         if (
1305 (  (tsin_chinese_english_toggle_key == TSIN_CHINESE_ENGLISH_TOGGLE_KEY_Shift) ||
1306    (tsin_chinese_english_toggle_key == TSIN_CHINESE_ENGLISH_TOGGLE_KEY_ShiftL
1307      && xkey == XK_Shift_L) ||
1308    (tsin_chinese_english_toggle_key == TSIN_CHINESE_ENGLISH_TOGGLE_KEY_ShiftR
1309      && xkey == XK_Shift_R))
1310           &&  current_time() - kpt < 300000) {
1311           if (!test_mode) {
1312             tsin_toggle_eng_ch();
1313             if (!tsin_pho_mode())
1314               set_key_codes_label(NULL, FALSE);
1315 			ClrIn();
1316             disp_gbuf();
1317           }
1318           return 1;
1319         } else
1320           return 0;
1321 #endif
1322      default:
1323         return 0;
1324   }
1325 }
1326 
1327 #include "win1.h"
1328 
gtab_set_win1_cb()1329 void gtab_set_win1_cb()
1330 {
1331   set_win1_cb((cb_selec_by_idx_t)gtab_pre_select_idx, NULL, NULL);
1332 }
1333 
1334 void load_en_db();
1335 u_char scanphr_en(TSIN_HANDLE *th, gboolean is_gtab, int chpho_idx, int plen,  int *rselN);
1336 gboolean misalpha(char c);
1337 void disp_pre_sel_page();
1338 extern char *wselkey;
1339 void get_en_miss_cand(FILE *fp, char *s, int slen, char best[][MAX_PHRASE_LEN]);
1340 
disp_gtab_pre()1341 void disp_gtab_pre() {
1342  if (use_tsin_sel_win()) {
1343 	if (gwin1)
1344       clear_sele();
1345 	else
1346       init_tsin_selection_win();
1347 
1348 	dbg("-------------> tss.pre_selN:%d\n", tss.pre_selN);
1349     int i;
1350     for(i=0;i<tss.pre_selN; i++)
1351        set_sele_text(i,tss.pre_sel[i].str, -1);
1352     get_win_gtab_geom();
1353     disp_selections(-1, -1);
1354     return;
1355   }
1356 
1357   char tt[4096];
1358   tt[0]=0;
1359   int i;
1360 
1361   for(i=0;i<tss.pre_selN; i++) {
1362     char ts[(MAX_PHRASE_LEN+3) * CH_SZ + 1];
1363     char *br= (i < tss.pre_selN-1 && gtab_vertical_select_on())?"\n":"";
1364 
1365     sprintf(ts, "<span foreground=\"%s\">%c</span>%s%s", gcin_sel_key_color,
1366       wselkey[i], tss.pre_sel[i].str, br);
1367     strcat(tt, ts);
1368     if (!gtab_vertical_select_on() && i < tss.pre_selN-1)
1369       strcat(tt, " ");
1370   }
1371 
1372   dbg("tt %s\n", tt);
1373   disp_gtab_pre_sel(tt);
1374 }
1375 
gtab_en_scan_pre_select()1376 void gtab_en_scan_pre_select()
1377 {
1378   dbg("gtab_en_scan_pre_select\n");
1379 
1380   if (!en_hand.fph)
1381     load_en_db();
1382 
1383   dbg("gtab_en_scan_pre_select %d th->ph_key_sz:%d\n", tss.c_len, en_hand.ph_key_sz);
1384 
1385   tss.pre_selN = 0;
1386 
1387   hide_gtab_pre_sel();
1388 
1389   if (!ggg.gbuf_cursor || !ggg.gbufN)
1390     return;
1391 
1392   init_pre_sel();
1393 
1394   int Maxlen = ggg.gbufN;
1395   if (Maxlen > MAX_PHRASE_LEN)
1396     Maxlen = MAX_PHRASE_LEN;
1397 
1398   int len, selN, max_len=-1, max_selN=-1;
1399   for(len=2; len <= Maxlen; len++) {
1400     int idx = ggg.gbufN - len;
1401     if (gbuf[idx].flag & FLAG_CHPHO_PHRASE_TAIL) {
1402 //      dbg("phrase tail %d\n", idx);
1403       break;
1404     }
1405 
1406     char c = gbuf[idx].ch[0];
1407     char c1 = idx==0?0:gbuf[idx-1].ch[0];
1408     char c2 = idx<=1?0:gbuf[idx-2].ch[0];
1409 
1410     if (c & 0x80)
1411       break;
1412 
1413 	if (misalpha(c1))
1414 	  continue;
1415 	if (misalpha(c) && c1=='\'' && misalpha(c2))
1416 	  continue;
1417 
1418     int mlen = scanphr_en(&en_hand, TRUE, ggg.gbufN - len, len, &selN);
1419 	dbg("mlen %d len:%d\n", mlen, len);
1420 
1421     if (mlen) {
1422       max_len = len;
1423       max_selN = selN;
1424     }
1425   }
1426 
1427   dbg("max_len:%d  max_selN:%d\n", max_len, max_selN);
1428 
1429   if (max_len < 0 || max_selN > 50) { // will ctrl press/release + keys as select keys
1430     dbg("too many or no %d\n", max_len);
1431     tss.pre_selN=0;
1432 
1433 #if 1
1434 		int i;
1435 		for(i=ggg.gbufN;i>0;i--) {
1436 			char c = gbuf[i-1].ch[0];
1437 			if (!((c>='A' && c<='Z') || (c>='a' && c<='z')))
1438 				break;
1439 		}
1440 
1441 		dbg("i %d\n", i);
1442 
1443 		if (ggg.gbufN - i > 2) {
1444 			int len = ggg.gbufN-i;
1445 			char en[128];
1446 			for(int j=0;j<len;j++)
1447 				en[j]=gbuf[i+j].ch[0];
1448 			en[len]=0;
1449 			dbg("pp8 '%s'\n", en);
1450 			char best[10][MAX_PHRASE_LEN];
1451 			get_en_miss_cand(en_hand.fph, en, len, best);
1452 			int n=0;
1453 			for(int i=0;i<10;i++) {
1454 				if (best[i][0]) {
1455 					dbg("best %d %s", i, best[i]);
1456 					bzero(tss.pre_sel[i].phkey, sizeof(tss.pre_sel[i].phkey));
1457 					tss.pre_sel[i].len = strlen(best[i]);
1458 					strcpy(tss.pre_sel[i].str, best[i]);
1459 					n++;
1460 				}
1461 			}
1462 
1463 			dbg("\nn %d\n", n);
1464 
1465 			tss.pre_selN = n;
1466 			if (n > 0) {
1467 				gtab_pre_select_phrase_len = len;
1468 				disp_gtab_pre();
1469 			}
1470 
1471 			return;
1472 		}
1473 #endif
1474     return;
1475   }
1476 
1477   gtab_pre_select_phrase_len = max_len;
1478   scanphr_en(&en_hand, TRUE, ggg.gbufN - max_len, max_len, &selN);
1479 
1480   if (selN==1 && tss.pre_sel[0].len==max_len) {
1481     char out[MAX_PHRASE_LEN * CH_SZ + 1];
1482     extract_gbuf_str(ggg.gbufN - max_len, max_len, out);
1483     if (!strcmp(out, tss.pre_sel[0].str))
1484       return;
1485   }
1486 
1487   disp_gtab_pre();
1488 }
1489 
1490