1 /*
2 	Copyright (C) 1995-2008	Edward Der-Hua Liu, Hsin-Chu, Taiwan
3 */
4 
5 #include "gcin.h"
6 #include "pho.h"
7 #include "tsin.h"
8 #include "gtab.h"
9 #include "gst.h"
10 
qcmp_pre_sel_usecount(const void * aa,const void * bb)11 static int qcmp_pre_sel_usecount(const void *aa, const void *bb)
12 {
13   PRE_SEL *a = (PRE_SEL *) aa;
14   PRE_SEL *b = (PRE_SEL *) bb;
15 
16   int d = b->usecount - a->usecount;
17 
18   if (d != 0)
19     return d;
20 
21   return a->len - b->len; // shorter first
22 }
23 
qcmp_pre_sel_str(const void * aa,const void * bb)24 static int qcmp_pre_sel_str(const void *aa, const void *bb)
25 {
26   PRE_SEL *a = (PRE_SEL *) aa;
27   PRE_SEL *b = (PRE_SEL *) bb;
28 
29   return strcmp(a->str, b->str);
30 }
31 
32 void extract_gtab_key(gboolean is_en, int start, int len, void *out);
33 gboolean tsin_seek_ex(TSIN_HANDLE *th, void *pho, int plen, int *r_sti, int *r_edi, char *tone_mask);
34 void load_tsin_entry_ex(TSIN_HANDLE *ptsin_hand, int idx, char *len, usecount_t *usecount, void *pho, u_char *ch);
35 gboolean check_gtab_fixed_mismatch(int idx, char *mtch, int plen);
36 void mask_tone(phokey_t *pho, int plen, char *tone_off);
37 void init_pre_sel();
38 void mask_key_typ_pho(phokey_t *key);
39 extern u_int64_t vmaskci;
40 
ph_key_length(TSIN_HANDLE * th,u_int64_t k)41 int ph_key_length(TSIN_HANDLE *th, u_int64_t k)
42 {
43   int klen=0;
44   if (th->ph_key_sz==2) {
45     int k1,k2,k3,k4;
46     phokey_t kk = (phokey_t) k;
47     k4=(kk&7);
48     kk>>=3;
49     k3=(kk&15);
50     kk>>=4;
51     k2=(kk&3);
52     kk>>=2;
53     k1=(kk&31);
54     if (k1)
55       klen++;
56     if (k2)
57       klen++;
58     if (k3)
59       klen++;
60     if (k4)
61       klen++;
62   } else {
63     klen = 3; // temporary fix
64   }
65 
66 //  dbg("ph_key_length %d\n", klen);
67   return klen;
68 }
69 
70 extern char typ_pho_len[];
71 void mask_pho_ref(phokey_t *pho, phokey_t *refpho, int plen, char *tone_mask);
72 
scanphr_e(TSIN_HANDLE * th,gboolean is_gtab,int chpho_idx,int plen,gboolean pho_incr,int * rselN)73 u_char scanphr_e(TSIN_HANDLE *th, gboolean is_gtab, int chpho_idx, int plen, gboolean pho_incr, int *rselN)
74 {
75   gboolean is_pho = th->ph_key_sz==2;
76   if (plen >= MAX_PHRASE_LEN)
77     goto empty;
78   if (chpho_idx < 0)
79     goto empty;
80 
81   phokey_t tailpho, tailpho0head=0;
82 
83   if (pho_incr) {
84     if (is_pho) {
85       tailpho = pho2key(poo.typ_pho);
86       if (!tailpho)
87         pho_incr = FALSE;
88 
89 	  // If user input ㄣ, then ㄅㄧㄣ should not be selected
90 	  int i;
91 	  for(i=0;i<4;i++)
92         if (poo.typ_pho[i])
93           break;
94 	  if (i>0 && i < 4) {
95 		tailpho0head |= (1 << typ_pho_len[0]) - 1;
96 	    int j;
97 	    for(j=1;j<4;j++) {
98 		  tailpho0head <<= typ_pho_len[j];
99 		  if (j < i)
100 		    tailpho0head |= ((1 << typ_pho_len[j]) - 1);
101 	    }
102 	  }
103 
104 //	  dbg("i:%d tailpho0head %x\n",i, tailpho0head);
105     } else {
106       if (!ggg.kval)
107         pho_incr = FALSE;
108     }
109   }
110 
111   u_int64_t pp64[MAX_PHRASE_LEN + 1];
112   phokey_t *pp = (phokey_t*)pp64;
113   char *pp8 = (char *)pp64;
114   int *pp32 = (int *)pp64;
115 
116   if (!is_gtab) {
117 	extract_pho(FALSE, chpho_idx, plen, pp);
118   } else {
119     extract_gtab_key(FALSE, chpho_idx, plen, pp64);
120   }
121 
122 #if 0
123   dbg("scanphr %d\n", plen);
124 
125   int t;
126   for(t=0; t < plen; t++) {
127 	dbg("pp%d] %x ",t, pp[t]);
128     prph(pp[t]);
129   }
130   dbg("\n");
131 #endif
132 
133   char pinyin_set[MAX_PH_BF_EXT];
134   char *t_pinyin_set = NULL;
135   gboolean is_pin_juyin = is_pho && (pin_juyin || pho_no_tone);
136 #define selNMax 50
137   PRE_SEL sel[selNMax], sel_nu[selNMax];
138   int selN = 0, sel_nuN=0;
139   tss.pre_selN = 0;
140   int maxlen=0;
141 
142   if (is_pin_juyin) {
143     get_chpho_pinyin_set(pinyin_set);
144     t_pinyin_set = pinyin_set + chpho_idx;
145     mask_tone(pp, plen, t_pinyin_set);
146   }
147 
148   int sti, edi;
149   if (!tsin_seek_ex(th, pp, plen, &sti, &edi, t_pinyin_set)) {
150 empty:
151     if (rselN)
152       *rselN = 0;
153     return 0;
154   }
155 //  dbg("plen:%d sti:%d edi:%d\n", plen, sti, edi);
156 
157   u_int64_t mtk64[MAX_PHRASE_LEN+1];
158   phokey_t *mtk = (phokey_t*) mtk64, mtko[MAX_PHRASE_LEN+1];
159   u_int *mtk32 = (u_int *)mtk64;
160   u_char *mtk8 = (u_char *)mtk64;
161   void *mtk_src = is_pin_juyin?(void*)mtko:(void*)mtk64;
162 
163   while (sti < edi && selN < selNMax) {
164     u_char mtch[MAX_PHRASE_LEN*CH_SZ+1];
165     char match_len;
166     usecount_t usecount;
167 
168 	mtk[plen] = 0;
169     load_tsin_entry_ex(th, sti, &match_len, &usecount, mtk, mtch);
170 //	dbg("mtch %s\n", mtch);
171 
172     sti++;
173     if (plen > match_len || (pho_incr && plen==match_len)) {
174       continue;
175     }
176 
177     if (is_pho) {
178 #if 0
179       mask_tone(mtk, plen, t_pinyin_set);
180 #else
181 	  if (is_pin_juyin) {
182 		memcpy(mtko, mtk, sizeof(phokey_t)*match_len);
183 	    mask_pho_ref(mtk, pp, plen, t_pinyin_set);
184 	  }
185 #endif
186 	}
187 
188     int i;
189 
190     if (is_pho) {
191       for(i=0; i < plen; i++) {
192         if (mtk[i]!=pp[i])
193           break;
194       }
195     } else {
196 	  if (th->ph_key_sz==4) {
197         for(i=0; i < plen; i++) {
198           if (mtk32[i]!=pp32[i])
199             break;
200         }
201 	  } else {
202         for(i=0; i < plen; i++) {
203           if (mtk64[i]!=pp64[i])
204             break;
205         }
206       }
207     }
208 
209     if (i < plen) {
210       continue;
211     }
212 
213 #if 1
214     if (pho_incr) {
215 	  // en doesn't need this
216       if (is_pho) {
217         phokey_t last_m = mtk[plen];
218 #if 1
219 		if (last_m & tailpho0head) {
220 //		  dbg("%x ", last_m); prph(last_m); dbg("\n");
221           continue;
222 		}
223 #endif
224         mask_key_typ_pho(&last_m);
225         if (last_m != tailpho)
226           continue;
227       } else {
228         u_int64_t v = th->ph_key_sz==4?mtk32[plen]:mtk64[plen];
229         if (ggg.kval != (v&vmaskci))
230           continue;
231       }
232     }
233 #endif
234 
235 #if 0
236     dbg("nnn ");
237     nputs(mtch, match_len);
238     dbg("\n");
239 #endif
240 
241     if (!is_gtab) {
242       if (check_fixed_mismatch(chpho_idx, (char *)mtch, plen))
243         continue;
244     } else {
245       if (check_gtab_fixed_mismatch(chpho_idx, (char *)mtch, plen))
246         continue;
247     }
248 
249     if (maxlen < match_len)
250       maxlen = match_len;
251 
252 	if (usecount>0) {
253 		bzero(sel[selN].phkey, sizeof(sel[selN].phkey));
254 		memcpy(sel[selN].phkey, mtk_src, match_len*th->ph_key_sz);
255 		sel[selN].len = match_len;
256 		sel[selN].usecount = usecount;
257 		utf8cpyN(sel[selN].str, (char *)mtch, match_len);
258 		selN++;
259 	} else {
260 		if (sel_nuN < selNMax) {
261 		  bzero(sel_nu[sel_nuN].phkey, sizeof(sel_nu[sel_nuN].phkey));
262 		  memcpy(sel_nu[sel_nuN].phkey, mtk_src, match_len*th->ph_key_sz);
263 		  sel_nu[sel_nuN].len = match_len;
264 		  sel_nu[sel_nuN].usecount = usecount;
265 		  utf8cpyN(sel_nu[sel_nuN].str, (char *)mtch, match_len);
266 		  sel_nuN++;
267 		}
268 	}
269   }
270 
271 //  dbg("SelN:%d  maxlen:%d\n", selN, maxlen);
272 
273   if (selN < selNMax && sel_nuN) {
274 	  int d = selNMax - selN;
275 	  if (d > sel_nuN)
276 	    d = sel_nuN;
277 	  for(int i=0;i<d;i++)
278 	    sel[selN++]=sel_nu[i];
279   }
280 
281   if (selN > 1) {
282     qsort(sel, selN, sizeof(PRE_SEL), qcmp_pre_sel_str);
283     int nselN = 0;
284     int i;
285     for(i=0;i<selN;i++)
286       if (sel[i].len>1 && (!i || strcmp(sel[i].str, sel[i-1].str)))
287         sel[nselN++]=sel[i];
288     selN = nselN;
289   }
290 
291 #if 1
292   if (selN==1) {
293 //    if (sel[0].len==1 || (sel[0].len==2 && ph_key_length(th, sel[0].phkey[1])<2))
294     if (sel[0].len==1)
295       goto empty;
296   }
297 #endif
298 
299   qsort(sel, selN, sizeof(PRE_SEL), qcmp_pre_sel_usecount);
300 
301 //  dbg("selN:%d\n", selN);
302   if (!is_gtab)
303     tss.pre_selN = Min(selN, phkbm.selkeyN);
304   else
305     tss.pre_selN = Min(selN, (int)strlen(cur_inmd->selkey));
306 
307 //  dbg("tss.pre_selN %d\n", tss.pre_selN);
308   memcpy(tss.pre_sel, sel, sizeof(PRE_SEL) * tss.pre_selN);
309 
310   if (rselN)
311     *rselN = selN;
312 
313   return maxlen;
314 }
315 
316 
317 
318 void hide_pre_sel();
319 void chpho_get_str(int idx, int len, char *ch);
320 void disp_pre_sel_page();
321 gboolean tsin_seek_ex(TSIN_HANDLE *th, void *pho, int plen, int *r_sti, int *r_edi, char *tone_mask);
322 int tsin_sele_by_idx(int c);
323 
tsin_scan_pre_select(gboolean b_incr)324 void tsin_scan_pre_select(gboolean b_incr)
325 {
326   if (!tsin_phrase_pre_select)
327     return;
328 //  dbg("tsin_scan_pre_select %d\n", b_incr);
329 
330   tss.pre_selN = 0;
331 
332   hide_pre_sel();
333 
334   if (!tss.c_idx || !tss.c_len)
335     return;
336 
337   init_pre_sel();
338 
339   int Maxlen = tss.c_idx;
340   if (Maxlen > MAX_PHRASE_LEN)
341     Maxlen = MAX_PHRASE_LEN;
342 
343   int len, selN, max_len=-1, max_selN=-1;
344   for(len=1; len <= Maxlen; len++) {
345     int idx = tss.c_idx - len;
346     if ((tss.chpho[idx].flag & FLAG_CHPHO_PHRASE_TAIL) || !(tss.chpho[idx].cha[0]&0x80)) {
347 //      dbg("phrase tail %d\n", idx);
348       break;
349     }
350 #if 0
351     int mlen = scanphr_e(&tsin_hand, FALSE, tss.c_len - len, len, b_incr, &selN);
352 #else
353 	int mlen = scanphr_e(&tsin_hand, FALSE, tss.c_idx - len, len, b_incr, &selN);
354 #endif
355 //	dbg("mlen %d len:%d\n", mlen, len);
356 
357     if (mlen) {
358       max_len = len;
359       max_selN = selN;
360     }
361   }
362 
363 //  dbg("max_len:%d  max_selN:%d\n", max_len, max_selN);
364 
365   if (max_len < 0 /* || max_selN >= strlen(pho_selkey) * 2 */ ) {
366     tss.pre_selN=0;
367     return;
368   }
369 
370 #if 0
371   scanphr_e(&tsin_hand, FALSE, tss.c_len - max_len, max_len, b_incr, &selN);
372 #else
373   scanphr_e(&tsin_hand, FALSE, tss.c_idx - max_len, max_len, b_incr, &selN);
374 #endif
375 
376 //  dbg("selN:%d %d\n", selN, tss.pre_selN);
377 
378 //  dbg("selN %d %d\n",selN, tss.pre_selN);
379 #if 0
380   tss.ph_sta = tss.c_len - max_len;
381 #else
382   tss.ph_sta = tss.c_idx - max_len;
383 #endif
384 
385   if (selN==1 && tss.pre_sel[0].len==max_len) {
386     char out[MAX_PHRASE_LEN * CH_SZ + 1];
387     chpho_get_str(tss.c_len - max_len, max_len, out);
388     if (!strcmp(out, tss.pre_sel[0].str)) {
389 //	  tsin_sele_by_idx(0);
390       return;
391     }
392   }
393 
394   disp_pre_sel_page();
395 }
396 
397 char *ch_mode_selkey(gboolean is_gtab);
398 
en_sel_keys(gboolean is_gtab)399 char *en_sel_keys(gboolean is_gtab)
400 {
401   char *s = ch_mode_selkey(is_gtab);
402   static char *sel = "1234567890";
403 
404   if (!s)
405     return sel;
406   int slen = strlen(s);
407   int i;
408   for(i=0; i < slen; i++)
409     if (s[i] < '0' || s[i] > '9')
410       break;
411   if (i < slen)
412     return sel;
413 
414   return s;
415 }
416 
en_sel_keys_len(gboolean is_gtab)417 int en_sel_keys_len(gboolean is_gtab)
418 {
419   return strlen(en_sel_keys(is_gtab));
420 }
421 
422 extern int wselkeyN;
423 phokey_t utf8_pho_key(char *s);
424 gboolean tsin_seek_en(u_char *pho, int plen, int *r_sti, int *r_edi);
425 
scanphr_en(TSIN_HANDLE * th,gboolean is_gtab,int chpho_idx,int plen,int * rselN)426 u_char scanphr_en(TSIN_HANDLE *th, gboolean is_gtab, int chpho_idx, int plen,  int *rselN)
427 {
428   if (rselN)
429     *rselN = 0;
430 
431   if (plen >= MAX_PHRASE_LEN)
432     return 0;
433   if (chpho_idx < 0)
434     return 0;
435 
436   u_int64_t pp64[MAX_PHRASE_LEN + 1];
437   phokey_t *pp = (phokey_t*)pp64;
438   char *pp8 = (char *)pp64;
439 
440   tss.pre_selN = 0;
441   int maxlen=0;
442 //#define selNMax 20
443   PRE_SEL sel[selNMax];
444   int selN = 0;
445 
446   if (!is_gtab) {
447 	extract_pho(TRUE, chpho_idx, plen, pp);
448   } else {
449     extract_gtab_key(TRUE, chpho_idx, plen, pp64);
450   }
451 
452   gboolean isup = isupper(pp8[0]);
453   gboolean isup1 = isup && plen > 1 && isupper(pp8[1]);
454   int loopN = isup?4:5;
455 
456   int loop;
457   int used_first;
458   char pp8_o[MAX_PHRASE_LEN * 8];
459   memcpy(pp8_o, pp8, plen);
460   pp8[plen]=0;
461   dbg("pp8 '%s'\n", pp8);
462 
463   for(used_first=1;used_first>=0; used_first--) {
464   for(loop=0; loop<loopN;loop++) {
465   memcpy(pp8, pp8_o, plen);
466   if (loop==1) {
467 	if (isup1) {
468 	  int i;
469 	  for(i=0;i<plen;i++)
470 	    pp8[i] = tolower(pp8[i]);
471 	} else
472 	if (isup){
473 	  pp8[0] = tolower(pp8[0]);
474 	} else
475 	  pp8[0] = toupper(pp8[0]);
476   } else if (loop==2) {
477 	  // loop==2 SHOUT
478 	  int i;
479 	  for(i=0;i<plen;i++)
480 	    pp8[i] = toupper(pp8[i]);
481   } else if (loop==3) {  // iPhone, iPad
482     pp8[1]=toupper(pp8[1]);
483   } else if (loop==4) { // loop==4 PlayStation
484 	int i;
485 	for(i=0;i<plen;i++)
486 	  pp8[i] = tolower(pp8[i]);
487   }
488 
489   dbg("loop:%d %s\n", loop, pp8);
490 
491   int sti, edi;
492   if (!tsin_seek_en((u_char *)pp8, plen, &sti, &edi)) {
493 	  continue;
494   }
495 
496   dbg("plen:%d sti:%d edi:%d\n", loop, plen, sti, edi);
497 
498   u_int64_t mtk64[MAX_PHRASE_LEN+1];
499   u_char *mtk8 = (u_char *)mtk64;
500 
501   while (sti < edi && selN < selNMax) {
502     u_char mtch[MAX_PHRASE_LEN*CH_SZ+1];
503     char match_len;
504     usecount_t usecount;
505 
506     load_tsin_entry_ex(th, sti, &match_len, &usecount, (phokey_t*)mtk64, mtch);
507 	if (!mtch[0]) {
508 		memcpy(mtch, mtk8, match_len);
509 		mtch[match_len] = 0;
510 	}
511 
512 #if DEBUG && 0
513 	   dbg("load %d", sti);
514 	   utf8_putcharn((char*)mtk8, match_len);
515 	   dbg("\n");
516 #endif
517 
518     sti++;
519     if (plen > match_len) {
520       continue;
521     }
522 
523 	if (used_first && !usecount)
524       continue;
525 
526     int i;
527     if (loop == 4) {
528       for(i=0; i < plen; i++) {
529          if (tolower(mtch[i])!=pp8[i])
530 	       break;
531 	  }
532    } else {
533      for(i=0; i < plen; i++) {
534        if (mtk8[i]!=pp8[i])
535          break;
536      }
537    }
538 
539     if (i < plen) {
540       continue;
541     }
542 
543 
544 #if 0
545     dbg("nnn ");
546     nputs(mtch, match_len);
547     dbg("\n");
548 #endif
549 
550     if (maxlen < match_len)
551       maxlen = match_len;
552 
553     sel[selN].len = match_len;
554 //    sel[selN].phidx = sti - 1;
555     sel[selN].usecount = usecount;
556 
557     if (loop==1) {
558 	  if (isup1) {
559 		int i;
560 		for(i=0;i<match_len;i++)
561 		  mtch[i]=toupper(mtch[i]);
562       } else
563         mtch[0]=toupper(mtch[0]);
564     }
565 
566     memcpy(sel[selN].str, mtch, match_len);
567     sel[selN].str[match_len]=0;
568 	dbg("%s %d\n", sel[selN].str, usecount);
569 	for(i=0;i<selN;i++)
570 		if (!strcmp(sel[i].str, sel[selN].str))
571 		break;
572 	if (i < selN) {
573 	  if (sel[i].usecount<usecount)
574 		sel[i].usecount=usecount;
575 	  continue;
576 	}
577 
578     bzero(sel[selN].phkey, sizeof(sel[selN].phkey));
579 
580 #if 0
581 	for(i=0;i<match_len;) {
582 	  char t[CH_SZ + 1];
583 	  i+=utf8cpy(t, (char *)&mtk8[i]);
584 //	  sel[selN].phkey[i] = utf8_pho_key(t);
585 	}
586 #endif
587  //   memcpy(sel[selN].phkey, mtk8, match_len*th->ph_key_sz);
588     selN++;
589   }
590 
591   }
592   }
593 
594   dbg("SelN:%d  maxlen:%d\n", selN, maxlen);
595   qsort(sel, selN, sizeof(PRE_SEL), qcmp_pre_sel_usecount);
596   dbg("selN:%d\n", selN);
597 #if 0
598   for(int i=0;i<selN;i++) {
599 	  dbg("%s:%d ", sel[i].str, sel[i].usecount);
600   }
601   dbg("\n");
602 #endif
603   tss.pre_selN = Min(selN, wselkeyN);
604   dbg("tss.pre_selN %d\n", tss.pre_selN);
605   memcpy(tss.pre_sel, sel, sizeof(PRE_SEL) * tss.pre_selN);
606 
607   if (rselN)
608     *rselN = selN;
609 
610   return maxlen;
611 }
612 
613 void load_en_db();
614 
misalpha(char c)615 gboolean misalpha(char c)
616 {
617   return c>='A' && c<='Z' || c>='a' && c<='z';
618 }
619 
620 void get_en_miss_cand(FILE *fp, char *s, int slen, char best[][MAX_PHRASE_LEN]);
621 
tsin_en_scan_pre_select()622 void tsin_en_scan_pre_select()
623 {
624   dbg("tsin_en_scan_pre_select\n");
625 
626   if (!en_hand.fph)
627     load_en_db();
628 
629   dbg("tsin_en_scan_pre_select %d th->ph_key_sz:%d\n", tss.c_len, en_hand.ph_key_sz);
630 
631   tss.pre_selN = 0;
632 
633   hide_pre_sel();
634 
635   if (!tss.c_idx || !tss.c_len)
636     return;
637 
638   init_pre_sel();
639 
640   int Maxlen = tss.c_len;
641   if (Maxlen > MAX_PHRASE_LEN)
642     Maxlen = MAX_PHRASE_LEN;
643 
644   int len, selN, max_len=-1, max_selN=-1;
645   for(len=2; len <= Maxlen; len++) {
646     int idx = tss.c_len - len;
647     if (tss.chpho[idx].flag & FLAG_CHPHO_PHRASE_TAIL) {
648 //      dbg("phrase tail %d\n", idx);
649       break;
650     }
651 
652     char c = tss.chpho[idx].cha[0];
653     char c1 = idx==0?0:tss.chpho[idx-1].cha[0];
654     char c2 = idx<=1?0:tss.chpho[idx-2].cha[0];
655 
656     if (c & 0x80)
657       break;
658 
659 	if (misalpha(c1))
660 	  continue;
661 	if (misalpha(c) && c1=='\'' && misalpha(c2))
662 	  continue;
663 
664     int mlen = scanphr_en(&en_hand, FALSE, tss.c_len - len, len, &selN);
665 	dbg("mlen %d len:%d\n", mlen, len);
666 
667     if (mlen) {
668       max_len = len;
669       max_selN = selN;
670     }
671   }
672 
673   dbg("max_len:%d  max_selN:%d\n", max_len, max_selN);
674 
675   if (max_len < 0 /* || max_selN > 40 */) { // will ctrl press/release + keys as select keys
676     dbg("too many or no %d\n", max_len);
677 
678     if (max_len < 0) {
679 		dbg("max_len < 0\n");
680 		int i;
681 		for(i=tss.c_len;i>0;i--) {
682 			char c = tss.chpho[i-1].cha[0];
683 			if (!((c>='A' && c<='Z') || (c>='a' && c<='z') || c=='@'))
684 				break;
685 		}
686 
687 		if (tss.c_len - i > 2) {
688 			u_int64_t pp64[MAX_PHRASE_LEN + 1];
689 			phokey_t *pp = (phokey_t*)pp64;
690 			char *pp8 = (char *)pp64;
691 			int len = tss.c_len-i;
692 			extract_pho(TRUE, i, len, pp);
693 			pp8[len]=0;
694 			dbg("pp8 '%s'\n", pp8);
695 			char best[10][MAX_PHRASE_LEN];
696 			get_en_miss_cand(en_hand.fph, pp8, len, best);
697 			int n=0;
698 			for(int i=0;i<10;i++) {
699 				if (best[i][0]) {
700 					dbg("best %d %s", i, best[i]);
701 					bzero(tss.pre_sel[i].phkey, sizeof(tss.pre_sel[i].phkey));
702 					tss.pre_sel[i].len = strlen(best[i]);
703 					strcpy(tss.pre_sel[i].str, best[i]);
704 					n++;
705 				}
706 			}
707 
708 			dbg("\nn %d\n", n);
709 			tss.pre_selN = n;
710 			tss.ph_sta = tss.c_len - len;
711 			disp_pre_sel_page();
712 			return;
713 		}
714 	}
715 
716     tss.pre_selN=0;
717     return;
718   }
719 
720   scanphr_en(&en_hand, FALSE, tss.c_len - max_len, max_len, &selN);
721 
722   dbg("selN %d %d\n",selN, tss.pre_selN);
723   tss.ph_sta = tss.c_len - max_len;
724 
725   if (selN==1 && tss.pre_sel[0].len==max_len) {
726     char out[MAX_PHRASE_LEN * CH_SZ + 1];
727     chpho_get_str(tss.c_len - max_len, max_len, out);
728 
729     dbg("rrr %s %s\n", out, tss.pre_sel[0].str);
730     if (!strcmp(out, tss.pre_sel[0].str)) {
731 	  dbg("ssss\n");
732 	  tsin_sele_by_idx(0);
733       return;
734     }
735   }
736 
737   disp_pre_sel_page();
738 }
739