1 #include "gcin.h"
2 #include "gtab.h"
3 #if UNIX
4 #include <signal.h>
5 #include <X11/extensions/XTest.h>
6 #if !GTK_CHECK_VERSION(2,16,0)
7 #include <X11/XKBlib.h>
8 #include <gdk/gdkx.h>
9 #define gdk_keymap_get_caps_lock_state(x) get_caps_lock_state()
10 #endif
11 #endif
12 #include "pho.h"
13 #include "gst.h"
14 #include "im-client/gcin-im-client-attr.h"
15 #include "win1.h"
16 #include "gcin-module.h"
17 #include "gcin-module-cb.h"
18 
19 #define STRBUFLEN 64
20 
21 extern Display *dpy;
22 #if USE_XIM
23 extern XIMS current_ims;
24 static IMForwardEventStruct *current_forward_eve;
25 #endif
26 extern gboolean win_kbm_inited;
27 
28 static char *callback_str_buffer;
29 Window focus_win;
30 static int timeout_handle;
31 char *output_buffer;
32 int output_bufferN;
33 static char *output_buffer_raw, *output_buffer_raw_bak;
34 static int output_buffer_rawN;
35 #if WIN32
36 gboolean test_mode;
37 int last_input_method;
38 #endif
39 void set_wselkey();
40 void gtab_set_win1_cb();
41 void toggle_symbol_table();
42 
43 gboolean old_capslock_on;
44 
45 
46 void init_gtab(int inmdno);
47 
current_method_type()48 char current_method_type()
49 {
50 //  dbg("default_input_method %d\n",default_input_method);
51   if (!current_CS)
52 #if UNIX
53     return inmd[default_input_method].method_type;
54 #else
55   {
56     if (!last_input_method)
57       last_input_method = default_input_method;
58     return inmd[last_input_method].method_type;
59   }
60 #endif
61 
62 //  dbg("current_CS->in_method %d\n", current_CS->in_method);
63   return inmd[current_CS->in_method].method_type;
64 }
65 
66 
67 #if WIN32
68 void win32_FakeKey(UINT vk, bool key_pressed);
69 #endif
send_fake_key_eve(KeySym key)70 void send_fake_key_eve(KeySym key)
71 {
72 #if WIN32
73   win32_FakeKey(key, true);
74   Sleep(10);
75   win32_FakeKey(key, false);
76 #else
77   KeyCode kc = XKeysymToKeycode(dpy, key);
78   XTestFakeKeyEvent(dpy, kc, True, CurrentTime);
79   usleep(10000);
80   XTestFakeKeyEvent(dpy, kc, False, CurrentTime);
81 #endif
82 }
83 
fake_shift()84 void fake_shift()
85 {
86 #if 0
87   send_fake_key_eve(XK_Control_L);
88 #else
89   send_fake_key_eve(XK_Shift_L);
90 #endif
91 }
92 
swap_ptr(char ** a,char ** b)93 void swap_ptr(char **a, char **b)
94 {
95   char *t = *a;
96   *a = *b;
97   *b = t;
98 }
99 
100 int force_preedit=0;
force_preedit_shift()101 void force_preedit_shift()
102 {
103   fake_shift();
104   force_preedit=1;
105 }
106 
send_text_call_back(char * text)107 void send_text_call_back(char *text)
108 {
109   callback_str_buffer = (char *)realloc(callback_str_buffer, strlen(text)+1);
110   strcpy(callback_str_buffer, text);
111   fake_shift();
112 }
113 
output_buffer_call_back()114 void output_buffer_call_back()
115 {
116   swap_ptr(&callback_str_buffer, &output_buffer);
117 
118   if (output_buffer)
119     output_buffer[0] = 0;
120   output_bufferN = 0;
121 
122   fake_shift();
123 }
124 
125 ClientState *current_CS;
126 static ClientState temp_CS;
127 
save_CS_current_to_temp()128 void save_CS_current_to_temp()
129 {
130 #if UNIX
131   if (!gcin_single_state)
132     return;
133 
134 //  dbg("save_CS_current_to_temp\n");
135   temp_CS.b_half_full_char = current_CS->b_half_full_char;
136   temp_CS.im_state = current_CS->im_state;
137   temp_CS.in_method = current_CS->in_method;
138   temp_CS.tsin_pho_mode = current_CS->tsin_pho_mode;
139 #endif
140 }
141 
142 
save_CS_temp_to_current()143 void save_CS_temp_to_current()
144 {
145 #if UNIX
146   if (!gcin_single_state)
147     return;
148 
149 //  dbg("save_CS_temp_to_current\n");
150   current_CS->b_half_full_char = temp_CS.b_half_full_char;
151   current_CS->im_state = temp_CS.im_state;
152   current_CS->in_method = temp_CS.in_method;
153   current_CS->tsin_pho_mode = temp_CS.tsin_pho_mode;
154 #endif
155 }
156 
157 
158 gboolean init_in_method(int in_no);
159 
160 
clear_output_buffer()161 void clear_output_buffer()
162 {
163   if (output_buffer)
164     output_buffer[0] = 0;
165   output_bufferN = 0;
166 
167   swap_ptr(&output_buffer_raw, &output_buffer_raw_bak);
168 
169   if (output_buffer_raw)
170     output_buffer_raw[0] = 0;
171   output_buffer_rawN = 0;
172 }
173 
174 gboolean gb_output = FALSE;
175 
toggle_gb_output()176 void toggle_gb_output()
177 {
178   gb_output = !gb_output;
179 }
180 
append_str(char ** buf,int * bufN,char * text,int len)181 static void append_str(char **buf, int *bufN, char *text, int len)
182 {
183   int requiredN = len + 1 + *bufN;
184   *buf = (char *)realloc(*buf, requiredN);
185   (*buf)[*bufN] = 0;
186   strcat(*buf, text);
187   *bufN += len;
188 }
189 
190 int trad2sim(char *str, int strN, char **out);
191 void add_ch_time_str(char *s);
192 
send_text(char * text)193 void send_text(char *text)
194 {
195 #if WIN32
196   if (test_mode)
197     return;
198 #endif
199   dbg("send_text %s\n", text);
200   char *filter;
201 
202   if (!text)
203     return;
204   int len = strlen(text);
205 
206   add_ch_time_str(text);
207 
208   append_str(&output_buffer_raw, &output_buffer_rawN, text, len);
209 
210   char *utf8_gbtext = NULL;
211 
212   if (gb_output) {
213     len = trad2sim(text, len, &utf8_gbtext);
214     text = utf8_gbtext;
215   }
216 
217 direct:
218 #if UNIX && 0
219   filter = getenv("GCIN_OUTPUT_FILTER");
220   char filter_text[512];
221 
222   if (filter) {
223     int pfdr[2], pfdw[2];
224 
225     if (pipe(pfdr) == -1) {
226       dbg("cannot pipe r\n");
227       goto next;
228     }
229 
230     if (pipe(pfdw) == -1) {
231       dbg("cannot pipe w\n");
232       goto next;
233     }
234 
235     int pid = fork();
236 
237     if (pid < 0) {
238       dbg("cannot fork filter\n");
239       goto next;
240     }
241 
242     if (pid) {
243       close(pfdw[0]);
244       close(pfdr[1]);
245       if (write(pfdw[1], text, len) < 0) {
246       }
247       close(pfdw[1]);
248       int rn = read(pfdr[0], filter_text, sizeof(filter_text) - 1);
249       filter_text[rn] = 0;
250 //      puts(filter_text);
251       close(pfdr[0]);
252       text = filter_text;
253       len = rn;
254     } else {
255       close(pfdr[0]);
256       close(pfdw[1]);
257       dup2(pfdw[0], 0);
258       dup2(pfdr[1], 1);
259       if (execl(filter, filter, NULL) < 0) {
260         dbg("execl %s err", filter);
261         goto next;
262       }
263     }
264 
265   }
266 #endif
267 next:
268   if (len) {
269     append_str(&output_buffer, &output_bufferN, text, len);
270   }
271 
272   free(utf8_gbtext);
273 }
274 
send_output_buffer_bak()275 void send_output_buffer_bak()
276 {
277   send_text(output_buffer_raw_bak);
278 }
279 
set_output_buffer_bak_to_clipboard()280 void set_output_buffer_bak_to_clipboard()
281 {
282   char *text, *utf8_gbtext=NULL;
283 
284   if (gb_output) {
285     trad2sim(output_buffer_raw_bak, strlen(output_buffer_raw_bak),
286       &utf8_gbtext);
287     text = utf8_gbtext;
288   } else
289     text = output_buffer_raw_bak;
290 
291 #if UNIX && 0
292   GtkClipboard *pclipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
293 #else
294   GtkClipboard *pclipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
295 #endif
296 
297   gtk_clipboard_set_text(pclipboard, text, -1);
298 
299   free(utf8_gbtext);
300 }
301 
send_utf8_ch(char * bchar)302 void send_utf8_ch(char *bchar)
303 {
304 #if WIN32
305   if (test_mode)
306     return;
307 #endif
308   char tt[CH_SZ+1];
309   int len = utf8_sz(bchar);
310 
311   memcpy(tt, bchar, len);
312   tt[len]=0;
313 
314   send_text(tt);
315 }
316 
317 
send_ascii(char key)318 void send_ascii(char key)
319 {
320   send_utf8_ch(&key);
321 }
322 
323 #if USE_XIM
export_text_xim()324 void export_text_xim()
325 {
326   char *text = output_buffer;
327 
328   if (!output_bufferN)
329     return;
330 
331   XTextProperty tp;
332 #if 0
333   char outbuf[512];
334   utf8_big5(output_buffer, outbuf);
335   text = outbuf;
336   XmbTextListToTextProperty(dpy, &text, 1, XCompoundTextStyle, &tp);
337 #else
338   Xutf8TextListToTextProperty(dpy, &text, 1, XCompoundTextStyle, &tp);
339 #endif
340 
341 #if DEBUG && 0
342   dbg("send_utf8_ch: %s\n", text);
343 #endif
344 
345   ((IMCommitStruct*)current_forward_eve)->flag |= XimLookupChars;
346   ((IMCommitStruct*)current_forward_eve)->commit_string = (char *)tp.value;
347   IMCommitString(current_ims, (XPointer)current_forward_eve);
348 
349   clear_output_buffer();
350 
351   XFree(tp.value);
352 }
353 
354 
bounce_back_key()355 static void bounce_back_key()
356 {
357     IMForwardEventStruct forward_ev = *(current_forward_eve);
358     IMForwardEvent(current_ims, (XPointer)&forward_ev);
359 }
360 #endif
361 
362 void hide_win0();
363 void hide_win_gtab();
364 void hide_win_pho();
365 
366 int current_in_win_x = -1, current_in_win_y = -1;  // request x/y
367 
reset_current_in_win_xy()368 void reset_current_in_win_xy()
369 {
370 #if 0
371   current_in_win_x = current_in_win_y = -1;
372 #endif
373 }
374 
module_cb1(ClientState * cs)375 GCIN_module_callback_functions *module_cb1(ClientState *cs)
376 {
377   return inmd[cs->in_method].mod_cb_funcs;
378 }
379 
module_cb()380 GCIN_module_callback_functions *module_cb()
381 {
382   if (!current_CS)
383     return NULL;
384   return module_cb1(current_CS);
385 }
386 
hide_in_win(ClientState * cs)387 void hide_in_win(ClientState *cs)
388 {
389 #if WIN32
390   if (test_mode)
391 	  return;
392 #endif
393   if (!cs) {
394 #if 0
395     dbg("hide_in_win: ic is null\n");
396 #endif
397     return;
398   }
399 #if 0
400   dbg("hide_in_win %d\n", ic->in_method);
401 #endif
402 
403   if (timeout_handle) {
404     g_source_remove(timeout_handle);
405     timeout_handle = 0;
406   }
407 
408   switch (current_method_type()) {
409     case method_type_PHO:
410       hide_win_pho();
411       break;
412 #if USE_TSIN
413     case method_type_TSIN:
414 //      flush_tsin_buffer();
415       hide_win0();
416       break;
417 #endif
418     case method_type_MODULE:
419       if (inmd[cs->in_method].mod_cb_funcs)
420         module_cb1(cs)->module_hide_win();
421       break;
422     default:
423       hide_win_gtab();
424   }
425 
426   reset_current_in_win_xy();
427 }
428 
429 void show_win_pho();
430 void show_win0();
431 void show_win_gtab();
432 void disp_tray_icon();
433 
check_CS()434 void check_CS()
435 {
436   if (!current_CS) {
437 //    dbg("!current_CS");
438     current_CS = &temp_CS;
439 //    temp_CS.input_style = InputStyleOverSpot;
440 //    temp_CS.im_state = GCIN_STATE_CHINESE;
441 #if TRAY_ENABLED
442     disp_tray_icon();
443 #endif
444   }
445   else {
446 #if 0
447     if (gcin_single_state)
448       save_CS_temp_to_current();
449     else
450 #endif
451       temp_CS = *current_CS;
452   }
453 }
454 
455 gboolean force_show;
456 
show_in_win(ClientState * cs)457 void show_in_win(ClientState *cs)
458 {
459   if (!cs) {
460 #if 0
461     dbg("show_in_win: ic is null");
462 #endif
463     return;
464   }
465 
466   switch (current_method_type()) {
467     case method_type_PHO:
468       show_win_pho();
469       break;
470 #if USE_TSIN
471     case method_type_TSIN:
472       show_win0();
473       break;
474 #endif
475     case method_type_MODULE:
476       if (!module_cb1(cs))
477         return;
478       module_cb1(cs)->module_show_win();
479       break;
480     default:
481       show_win_gtab();
482   }
483 #if 0
484   show_win_stautus();
485 #endif
486 }
487 
488 
489 void move_win_gtab(int x, int y);
490 void move_win0(int x, int y);
491 void move_win_pho(int x, int y);
492 void disp_selections(int x, int y);
493 extern GtkWidget *gwin1;
494 
move_in_win(ClientState * cs,int x,int y)495 void move_in_win(ClientState *cs, int x, int y)
496 {
497   check_CS();
498 
499   if (current_CS && current_CS->fixed_pos) {
500     x = current_CS->fixed_x;
501     y = current_CS->fixed_y;
502   } else
503   if (gcin_input_style == InputStyleRoot) {
504     x = gcin_root_x;
505     y = gcin_root_y;
506   }
507 
508 #if 0
509   dbg("move_in_win %d %d\n",x, y);
510 #endif
511 #if 0
512   if (current_in_win_x == x && current_in_win_y == y)
513     return;
514 #endif
515   current_in_win_x = x ; current_in_win_y = y;
516 
517   switch (current_method_type()) {
518     case method_type_PHO:
519       move_win_pho(x, y);
520       break;
521     case method_type_TSIN:
522       move_win0(x, y);
523       break;
524     case method_type_MODULE:
525       if (inmd[cs->in_method].mod_cb_funcs)
526         module_cb1(cs)->module_move_win(x, y);
527       break;
528     default:
529       if (!cs->in_method)
530         return;
531       move_win_gtab(x, y);
532   }
533 
534 #if WIN32
535   if (GTK_WIDGET_VISIBLE(gwin1))
536 		disp_selections(-1, -1);
537 #endif
538 }
539 #if UNIX
xerror_handler(Display * d,XErrorEvent * eve)540 static int xerror_handler(Display *d, XErrorEvent *eve)
541 {
542   return 0;
543 }
544 #endif
545 
getRootXY(Window win,int wx,int wy,int * tx,int * ty)546 void getRootXY(Window win, int wx, int wy, int *tx, int *ty)
547 {
548   if (!win) {
549 	*tx = wx;
550 	*ty = wy;
551 	return;
552   }
553 
554 #if WIN32
555   POINT pt;
556   pt.x = wx; pt.y = wy;
557   ClientToScreen((HWND)win, &pt);
558   *tx = pt.x; *ty=pt.y;
559 #else
560   Window ow;
561   XErrorHandler olderr = XSetErrorHandler((XErrorHandler)xerror_handler);
562   XTranslateCoordinates(dpy,win,root,wx,wy,tx,ty,&ow);
563   XSetErrorHandler(olderr);
564 #endif
565 }
566 
567 extern int dpy_x_ofs, dpy_y_ofs;
568 
move_IC_in_win(ClientState * cs)569 void move_IC_in_win(ClientState *cs)
570 {
571 #if 0
572    dbg("move_IC_in_win %d,%d\n", cs->spot_location.x, cs->spot_location.y);
573 #endif
574 #if WIN32
575    if (test_mode)
576 	   return;
577 #endif
578 
579    Window inpwin = cs->client_win;
580 #if UNIX
581    if (!inpwin) {
582      dbg("no inpwin %p\n", cs);
583      return;
584    }
585 #endif
586    // non focus win filtering is done in the client lib
587    if (inpwin != focus_win && focus_win && !cs->b_gcin_protocol) {
588       return;
589    }
590 
591    int inpx = cs->spot_location.x;
592    int inpy = cs->spot_location.y;
593 #if WIN32 && 0
594    if (inpx >= dpy_xl-1 || inpy >= dpy_yl-1)
595 	   return;
596 #endif
597    dbg("move_IC_in_win %d,%d\n", inpx, inpy);
598 
599 #if UNIX
600    XWindowAttributes att;
601    XGetWindowAttributes(dpy, inpwin, &att);
602 // chrome window is override_redirect
603 //   if (att.override_redirect)
604 //     return;
605 
606    if (inpx >= att.width)
607      inpx = att.width - 1;
608    if (inpy >= att.height)
609      inpy = att.height - 1;
610 #else
611    if (inpwin) {
612      RECT rect;
613      GetClientRect((HWND)inpwin, &rect);
614 
615 	 rect.right -= dpy_x_ofs;
616 	 rect.bottom -= dpy_y_ofs;
617 
618      if (inpx >= rect.right)
619        inpx = rect.right - 1;
620      if (inpy >= rect.bottom)
621        inpy = rect.bottom - 1;
622    }
623    dbg("GetClientRect %x %d,%d\n", inpwin, inpx, inpy);
624 #endif
625    int tx,ty;
626    getRootXY(inpwin, inpx, inpy, &tx, &ty);
627 
628 #if 1
629    dbg("move_IC_in_win inpxy:%d,%d txy:%d,%d\n", inpx, inpy, tx, ty);
630 #endif
631 
632    move_in_win(cs, tx, ty+1);
633 }
634 
635 
update_in_win_pos()636 void update_in_win_pos()
637 {
638 #if WIN32
639   if (test_mode)
640     return;
641 #endif
642 
643   check_CS();
644 
645 //  dbg("update_in_win_pos %x %d\n", current_CS, current_CS->input_style);
646 
647   if (current_CS->input_style == InputStyleRoot) {
648 #if UNIX
649     Window r_root, r_child;
650     int winx, winy, rootx, rooty;
651     u_int mask;
652 
653     XQueryPointer(dpy, root, &r_root, &r_child, &rootx, &rooty, &winx, &winy, &mask);
654 
655     winx++; winy++;
656 
657     Window inpwin = current_CS->client_win;
658 #if 0
659     dbg("update_in_win_pos\n");
660 #endif
661     if (inpwin) {
662       int tx, ty;
663       Window ow;
664 
665       XTranslateCoordinates(dpy, root, inpwin, winx, winy, &tx, &ty, &ow);
666 
667       current_CS->spot_location.x = tx;
668       current_CS->spot_location.y = ty;
669     }
670 #else
671 	  int winx=0, winy=0;
672       current_CS->spot_location.x = 0;
673       current_CS->spot_location.y = 0;
674 #endif
675 
676     move_in_win(current_CS, winx, winy);
677   } else {
678     move_IC_in_win(current_CS);
679   }
680 
681   disp_tray_icon();
682 }
683 
684 void win_pho_disp_half_full();
685 void win_tsin_disp_half_full();
686 void win_gtab_disp_half_full();
687 void update_tray_icon(), load_tray_icon(), load_tray_icon_win32();
688 static int current_gcin_win32_icon = -1;
689 void restart_gcin0();
690 extern void destroy_tray_win32();
691 extern void destroy_tray_icon();
692 void load_tray_icon_indicator();
693 void destroy_tray_indicator();
694 
695 #if TRAY_ENABLED
696 #if UNIX
destroy_tray()697 void destroy_tray()
698 {
699   if (current_gcin_win32_icon==GCIN_TRAY_WIN32)
700     destroy_tray_win32();
701   else
702   if (current_gcin_win32_icon==GCIN_TRAY_UNIX)
703     destroy_tray_icon();
704 #if USE_INDICATOR
705   else
706     destroy_tray_indicator();
707 #endif
708 }
709 #endif
710 
disp_tray_icon()711 void disp_tray_icon()
712 {
713 #if WIN32
714   if (test_mode)
715 	  return;
716 #endif
717 //  dbg("disp_tray_icon\n");
718 //dbg("disp_tray_icon %d %d\n", current_gcin_win32_icon, gcin_win32_icon);
719 #if UNIX
720   if (current_gcin_win32_icon >= 0 && current_gcin_win32_icon != gcin_win32_icon) {
721     destroy_tray();
722   }
723 
724   current_gcin_win32_icon = gcin_win32_icon;
725 
726   if (gcin_win32_icon==GCIN_TRAY_WIN32)
727 #endif
728     load_tray_icon_win32();
729 #if UNIX
730   else
731   if (gcin_win32_icon==GCIN_TRAY_UNIX)
732     load_tray_icon();
733 #if USE_INDICATOR
734   else
735     load_tray_icon_indicator();
736 #endif
737 #endif
738 }
739 #endif
740 
disp_im_half_full()741 void disp_im_half_full()
742 {
743 //  dbg("disp_im_half_full\n");
744 #if WIN32
745   if (test_mode)
746 	  return;
747 #endif
748 
749 #if TRAY_ENABLED
750   disp_tray_icon();
751 #endif
752 
753   switch (current_method_type()) {
754     case method_type_PHO:
755       win_pho_disp_half_full();
756       break;
757 #if USE_TSIN
758     case method_type_TSIN:
759       win_tsin_disp_half_full();
760       break;
761 #endif
762     default:
763       win_gtab_disp_half_full();
764       break;
765   }
766 }
767 
768 void flush_tsin_buffer();
769 void reset_gtab_all();
770 void set_tsin_pho_mode0(ClientState *cs, gboolean tsin_pho_mode);
771 
772 //static u_int orig_caps_state;
773 gboolean init_in_method2(ClientState *cs, int in_no);
774 void set_wselkey();
775 
init_state_chinese(ClientState * cs,gboolean tsin_pho_mode)776 void init_state_chinese(ClientState *cs, gboolean tsin_pho_mode)
777 {
778   dbg("init_state_chinese %p\n",cs);
779 #if WIN32
780   if (test_mode)
781 	  return;
782 #endif
783 
784   cs->im_state = GCIN_STATE_CHINESE;
785   set_tsin_pho_mode0(cs, tsin_pho_mode);
786   if (!cs->in_method)
787 #if UNIX
788     init_in_method2(cs, default_input_method);
789 #else
790   if (!last_input_method)
791     last_input_method = default_input_method;
792   init_in_method(last_input_method);
793 #endif
794 
795   set_wselkey();
796   save_CS_current_to_temp();
797 }
798 
799 gboolean output_gbuf();
800 void update_win_kbm();
801 void flush_edit_buffer(), ClrIn();
802 void tsin_set_eng_ch(int nmod);
803 int current_kbd_state;
804 
toggle_im_enabled()805 void toggle_im_enabled()
806 {
807 //    dbg("toggle_im_enabled\n");
808 #if WIN32
809 	if (test_mode)
810 		return;
811 #endif
812 
813     check_CS();
814 
815     if (current_CS->in_method < 0)
816       p_err("err found");
817 
818     int status=0;
819 
820 //  dbg("feedkey_pp %x %x\n", xkey, kbstate);
821 //  if (xkey=='1')
822 //    dbg("aaa\n");
823 
824 
825     if (current_CS->im_state != GCIN_STATE_DISABLED) {
826       if (current_CS->im_state == GCIN_STATE_ENG_FULL) {
827         current_CS->im_state = GCIN_STATE_CHINESE;
828         disp_im_half_full();
829         save_CS_current_to_temp();
830         return;
831       }
832 
833       flush_edit_buffer();
834 
835       hide_in_win(current_CS);
836 #if 0
837       hide_win_status();
838 #endif
839       current_CS->im_state = GCIN_STATE_DISABLED;
840 
841       update_win_kbm();
842 
843       disp_tray_icon();
844     } else {
845       if (!current_method_type())
846         init_gtab(current_CS->in_method);
847 
848 	  ClrIn();
849 
850       init_state_chinese(current_CS, TRUE);
851       reset_current_in_win_xy();
852 #if 1
853       show_in_win(current_CS);
854       update_in_win_pos();
855 #else
856       update_in_win_pos();
857       show_in_win(current_CS);
858 #endif
859 
860       update_win_kbm();
861 
862       if (tsin_chinese_english_toggle_key == TSIN_CHINESE_ENGLISH_TOGGLE_KEY_CapsLock) {
863         tsin_set_eng_ch(!(current_kbd_state&LockMask));
864       }
865 
866       disp_tray_icon();
867     }
868 
869     save_CS_current_to_temp();
870 }
871 
872 void get_win_gtab_geom();
873 void get_win0_geom();
874 void get_win_pho_geom();
875 
update_active_in_win_geom()876 void update_active_in_win_geom()
877 {
878 #if WIN32
879   if (test_mode)
880     return;
881 #endif
882 //  dbg("update_active_in_win_geom\n");
883   switch (current_method_type()) {
884     case method_type_PHO:
885       get_win_pho_geom();
886       break;
887 #if USE_TSIN
888     case method_type_TSIN:
889       get_win0_geom();
890       break;
891 #endif
892     case method_type_MODULE:
893       if (module_cb() && module_cb()->module_get_win_geom)
894         module_cb()->module_get_win_geom();
895       break;
896     default:
897       get_win_gtab_geom();
898       break;
899   }
900 }
901 
902 extern GtkWidget *gwin_pho, *gwin0, *gwin_gtab;
903 
win_is_visible()904 gboolean win_is_visible()
905 {
906   if (!current_CS)
907     return FALSE;
908   switch (current_method_type()) {
909     case method_type_PHO:
910       return gwin_pho && GTK_WIDGET_VISIBLE(gwin_pho);
911 #if USE_TSIN
912     case method_type_TSIN:
913       return gwin0 && GTK_WIDGET_VISIBLE(gwin0);
914 #endif
915     case method_type_MODULE:
916       if (!module_cb())
917         return FALSE;
918       return module_cb()->module_win_visible();
919     default:
920       if (!gwin_gtab)
921         return FALSE;
922       return gwin_gtab && GTK_WIDGET_VISIBLE(gwin_gtab);
923   }
924 
925   return FALSE;
926 }
927 
928 
929 void disp_gtab_half_full(gboolean hf);
930 void tsin_toggle_half_full();
931 
toggle_half_full_char_sub()932 void toggle_half_full_char_sub()
933 {
934 #if WIN32
935   if (test_mode)
936 	  return;
937 #endif
938 
939   if (current_method_type() == method_type_TSIN && current_CS->im_state == GCIN_STATE_CHINESE) {
940     tsin_toggle_half_full();
941   }
942   else {
943     if (current_CS->im_state == GCIN_STATE_ENG_FULL) {
944       current_CS->im_state = GCIN_STATE_DISABLED;
945       hide_in_win(current_CS);
946     } else
947     if (current_CS->im_state == GCIN_STATE_DISABLED) {
948       toggle_im_enabled();
949       current_CS->im_state = GCIN_STATE_ENG_FULL;
950     } else
951     if (current_CS->im_state == GCIN_STATE_CHINESE) {
952       current_CS->b_half_full_char = !current_CS->b_half_full_char;
953     }
954 
955 //    dbg("current_CS->in_method %d\n", current_CS->in_method);
956     disp_im_half_full();
957   }
958 
959   save_CS_current_to_temp();
960 }
961 
toggle_half_full_char()962 void toggle_half_full_char()
963 {
964 #if WIN32
965   if (test_mode)
966     return;
967 #endif
968 
969   check_CS();
970 
971   if (!gcin_shift_space_eng_full) {
972     current_CS->b_half_full_char = 0;
973     tss.tsin_half_full=0;
974     disp_im_half_full();
975     return;
976   }
977 
978 //  dbg("toggle_half_full_char\n");
979   toggle_half_full_char_sub() ;
980 }
981 
982 void init_tab_pp(gboolean init);
983 void init_tab_pho();
984 
985 
986 extern int b_show_win_kbm;
987 
988 void hide_win_kbm();
989 extern gboolean win_sym_enabled;
990 void show_win_kbm();
991 extern char *TableDir;
992 void set_gtab_input_method_name(char *s);
993 GCIN_module_callback_functions *init_GCIN_module_callback_functions(char *sofile);
994 time_t find_tab_file(char *fname, char *out_file);
995 gboolean tsin_page_up(), tsin_page_down();
996 int tsin_sele_by_idx(int);
997 void free_tsin();
998 
tsin_set_win1_cb()999 void tsin_set_win1_cb()
1000 {
1001   set_win1_cb((cb_selec_by_idx_t)tsin_sele_by_idx, (cb_page_ud_t)tsin_page_up, (cb_page_ud_t)tsin_page_down);
1002 }
1003 
update_win_kbm_inited()1004 void update_win_kbm_inited()
1005 {
1006   if (win_kbm_inited)
1007     update_win_kbm();
1008 }
1009 
init_in_method2(ClientState * cs,int in_no)1010 gboolean init_in_method2(ClientState *cs, int in_no)
1011 {
1012   dbg("init_in_method2 %p %d\n", cs, in_no);
1013   gboolean init_im = !(cur_inmd && (cur_inmd->flag & FLAG_GTAB_SYM_KBM));
1014 
1015   if (in_no < 0)
1016     return FALSE;
1017 
1018   if (cs==current_CS && cs->in_method != in_no) {
1019     if (!(inmd[in_no].flag & FLAG_GTAB_SYM_KBM)) {
1020       flush_edit_buffer();
1021       hide_in_win(cs);
1022     }
1023 
1024     if (cur_inmd && (cur_inmd->flag & FLAG_GTAB_SYM_KBM))
1025       hide_win_kbm();
1026   }
1027 #if 0
1028   if (cs==current_CS)
1029     reset_current_in_win_xy();
1030 #endif
1031 
1032 //  dbg("switch init_in_method %x %d\n", current_CS, in_no);
1033 //  set_tsin_pho_mode0(cs, ini_tsin_pho_mode);
1034   tsin_set_win1_cb();
1035 
1036   switch (inmd[in_no].method_type) {
1037     case method_type_PHO:
1038 #if WIN32
1039 	  if (test_mode)
1040 		break;
1041 #endif
1042       cs->in_method = in_no;
1043       init_tab_pho();
1044       break;
1045     case method_type_TSIN:
1046 #if WIN32
1047 	  if (test_mode)
1048 		break;
1049 #endif
1050 	  free_tsin();
1051       set_wselkey();
1052       cs->in_method = in_no;
1053 //      if (cs==current_CS || !current_CS)
1054 		init_tab_pp(init_im);
1055       break;
1056     case method_type_SYMBOL_TABLE:
1057 #if WIN32
1058 	  if (test_mode)
1059 		break;
1060 #endif
1061       toggle_symbol_table();
1062       break;
1063     case method_type_MODULE:
1064     {
1065 #if WIN32
1066 	  if (test_mode)
1067 		break;
1068 #endif
1069       GCIN_module_main_functions gmf;
1070       init_GCIN_module_main_functions(&gmf);
1071       if (!inmd[in_no].mod_cb_funcs) {
1072         char ttt[256];
1073         strcpy(ttt, inmd[in_no].filename);
1074 
1075         dbg("module %s\n", ttt);
1076         if (!(inmd[in_no].mod_cb_funcs = init_GCIN_module_callback_functions(ttt))) {
1077           dbg("module not found\n");
1078           return FALSE;
1079         }
1080       }
1081 
1082       if ((cs==current_CS || !current_CS) && inmd[in_no].mod_cb_funcs->module_init_win(&gmf)) {
1083 #if WIN32
1084         if (!test_mode)
1085 #endif
1086         {
1087 			cs->in_method = in_no;
1088 			module_cb()->module_show_win();
1089 			if (cs==current_CS)
1090 				set_wselkey();
1091         }
1092       } else {
1093         return FALSE;
1094       }
1095 
1096       break;
1097     }
1098     case method_type_EN:
1099     {
1100 #if WIN32
1101 	  if (test_mode)
1102 		return TRUE;
1103 #endif
1104       if (cs==current_CS && current_CS->im_state==GCIN_STATE_CHINESE)
1105         toggle_im_enabled();
1106       return TRUE;
1107     }
1108     case method_type_GTAB:
1109     {
1110       dbg("method_type_GTAB\n");
1111 #if WIN32
1112 //	  if (!test_mode)
1113 	  {
1114 #endif
1115 		free_tsin();
1116 		if (cs==current_CS || !current_CS)
1117 			init_gtab(in_no);
1118 #if WIN32
1119 	  }
1120 #endif
1121 
1122       if (!inmd[in_no].DefChars)
1123         return FALSE;
1124 
1125 #if WIN32
1126       if (test_mode)
1127         return TRUE;
1128 #endif
1129       cs->in_method = in_no;
1130       if (!(inmd[in_no].flag & FLAG_GTAB_SYM_KBM))
1131         show_win_gtab();
1132       else {
1133         win_kbm_inited = 1;
1134         show_win_kbm();
1135       }
1136 
1137       set_gtab_input_method_name(inmd[in_no].cname);
1138       break;
1139     }
1140     default:
1141       dbg("unknown\n");
1142       return FALSE;
1143   }
1144 
1145 #if WIN32
1146   if (test_mode)
1147     return TRUE;
1148 
1149   if (cs==current_CS && current_CS->in_method != last_input_method)
1150     last_input_method = current_CS->in_method;
1151 #endif
1152 
1153   if (cs==current_CS) {
1154 	char *selkey;
1155 //    if (selkey=inmd[current_CS->in_method].selkey)
1156     {
1157       set_wselkey();
1158       gtab_set_win1_cb();
1159   //    dbg("aa selkey %s\n", inmd[current_CS->in_method].selkey);
1160     }
1161     update_in_win_pos();
1162     update_win_kbm_inited();
1163     disp_tray_icon();
1164   }
1165 
1166   return TRUE;
1167 }
1168 
init_in_method(int in_no)1169 gboolean init_in_method(int in_no)
1170 {
1171   check_CS();
1172   return init_in_method2(current_CS, in_no);
1173 }
1174 
cycle_next_in_method()1175 static void cycle_next_in_method()
1176 {
1177   int i;
1178   dbg("cycle_next_in_method\n");
1179 #if WIN32
1180   if (test_mode)
1181     return;
1182 #endif
1183 
1184   for(i=0; i < inmdN; i++) {
1185     int v = (current_CS->in_method + 1 + i) % inmdN;
1186     if (!inmd[v].in_cycle)
1187       continue;
1188     if (!inmd[v].cname || !inmd[v].cname[0])
1189       continue;
1190 
1191     if (!init_in_method(v))
1192       continue;
1193 
1194     return;
1195   }
1196 }
1197 
1198 void add_to_tsin_buf_str(char *str);
1199 gboolean gtab_phrase_on();
1200 void insert_gbuf_nokey(char *s);
1201 
full_char_proc(KeySym keysym)1202 gboolean full_char_proc(KeySym keysym)
1203 {
1204   char *s = half_char_to_full_char(keysym);
1205   if (!s)
1206     return 0;
1207 
1208 #if WIN32
1209   if (test_mode)
1210     return TRUE;
1211 #endif
1212 
1213   char tt[CH_SZ+1];
1214 
1215   utf8cpy(tt, s);
1216 
1217   if (current_CS->im_state  == GCIN_STATE_ENG_FULL) {
1218     send_text(tt);
1219     return 1;
1220   }
1221 
1222   if (current_method_type() == method_type_TSIN && current_CS->im_state == GCIN_STATE_CHINESE)
1223     add_to_tsin_buf_str(tt);
1224   else
1225   if (gtab_phrase_on() && ggg.gbufN)
1226     insert_gbuf_nokey(tt);
1227   else
1228     send_text(tt);
1229 
1230   return 1;
1231 }
1232 
1233 int feedkey_pho(KeySym xkey, int kbstate);
1234 int feedkey_tsin(KeySym xkey, int state);
1235 int feedkey_gtab(KeySym key, int kbstate);
1236 int feed_phrase(KeySym ksym, int state);
1237 void tsin_set_eng_ch(int nmod);
1238 static KeySym last_keysym;
1239 
timeout_raise_window(gpointer data)1240 gboolean timeout_raise_window(gpointer data)
1241 {
1242 //  dbg("timeout_raise_window\n");
1243   timeout_handle = 0;
1244   show_in_win(current_CS);
1245   return FALSE;
1246 }
1247 
1248 extern Window xwin_pho, xwin0, xwin_gtab;
1249 void create_win_sym(), win_kbm_disp_caplock();
1250 
1251 #if !GTK_CHECK_VERSION(2,16,0) && 0
1252 #include <X11/extensions/XKBsrv.h>
get_caps_lock_state()1253 gboolean get_caps_lock_state()
1254 {
1255   XkbStateRec states;
1256 
1257   if (XkbGetState(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), XkbUseCoreKbd, &states) == Success) {
1258     if (states.locked_mods & LockMask) return TRUE;
1259   }
1260   return FALSE;
1261 }
1262 #endif
1263 
1264 gboolean capslock_on;
1265 
disp_win_kbm_capslock()1266 void disp_win_kbm_capslock()
1267 {
1268   if (!b_show_win_kbm)
1269     return;
1270 
1271   gboolean o_state = old_capslock_on;
1272   old_capslock_on = capslock_on;
1273 
1274 //  dbg("%x %x\n", old_capslock_on, o_state);
1275 
1276   if (o_state != old_capslock_on) {
1277     win_kbm_disp_caplock();
1278   }
1279 }
1280 
1281 
disp_win_kbm_capslock_init()1282 void disp_win_kbm_capslock_init()
1283 {
1284   old_capslock_on = gdk_keymap_get_caps_lock_state(gdk_keymap_get_default());
1285 //  dbg("disp_win_kbm_capslock_init %d\n",old_capslock_on);
1286 
1287   if (b_show_win_kbm)
1288     win_kbm_disp_caplock();
1289 }
1290 
toggle_symbol_table()1291 void toggle_symbol_table()
1292 {
1293 #if WIN32
1294   if (test_mode)
1295 	return;
1296 #endif
1297   if (current_CS->im_state == GCIN_STATE_CHINESE) {
1298     if (!win_is_visible())
1299       win_sym_enabled=1;
1300     else
1301       win_sym_enabled^=1;
1302   } else
1303     win_sym_enabled=0;
1304 
1305   create_win_sym();
1306   if (win_sym_enabled) {
1307     force_show = TRUE;
1308     if (current_CS->im_state == GCIN_STATE_CHINESE)
1309       show_in_win(current_CS);
1310     force_show = FALSE;
1311   }
1312 }
1313 
1314 
1315 void destroy_phrase_save_menu();
1316 int gcin_switch_keys_lookup(int key);
1317 gboolean b_menu_key_pressed;
1318 void cb_trad_sim_toggle();
1319 void set_tsin_pho_mode();
1320 
1321 // return TRUE if the key press is processed
ProcessKeyPress(KeySym keysym,u_int kev_state)1322 gboolean ProcessKeyPress(KeySym keysym, u_int kev_state)
1323 {
1324 #if 1
1325   dbg("key press %x %x\n", keysym, kev_state);
1326 #endif
1327 
1328   current_kbd_state = kev_state;
1329   destroy_phrase_save_menu();
1330 
1331   capslock_on = (kev_state&LockMask) > 0;
1332   if (keysym == XK_Caps_Lock) {
1333 #if UNIX
1334     capslock_on = !(kev_state&LockMask);
1335 #endif
1336     disp_tray_icon();
1337   }
1338 
1339   disp_win_kbm_capslock();
1340   check_CS();
1341 
1342   if (current_CS->client_win)
1343     focus_win = current_CS->client_win;
1344 
1345   if (
1346   callback_str_buffer && strlen(callback_str_buffer)) {
1347 #if WIN32
1348 	if (!test_mode)
1349 #endif
1350 	{
1351 		send_text(callback_str_buffer);
1352 		callback_str_buffer[0]=0;
1353 	}
1354     return TRUE;
1355   }
1356 
1357   if (force_preedit==1) {
1358 	dbg("orce_preedit==1\n");
1359     force_preedit = 2;
1360     return 1;
1361   }
1362 
1363 #if 1
1364   // Chrome win32 has this problem
1365   if (keysym==XK_Menu) {
1366     b_menu_key_pressed = TRUE;
1367   } else {
1368     gboolean old_pressed = b_menu_key_pressed;
1369     b_menu_key_pressed = FALSE;
1370     if (old_pressed && strchr("utcpda", keysym))
1371       return FALSE;
1372   }
1373 #endif
1374 
1375 
1376   if (keysym == XK_space) {
1377 #if 0
1378     dbg("state %x\n", kev->state);
1379     dbg("%x\n", Mod4Mask);
1380 #endif
1381     if (
1382       ((kev_state & (ControlMask|Mod1Mask|ShiftMask))==ControlMask && gcin_im_toggle_keys==Control_Space) ||
1383       ((kev_state & Mod1Mask) && gcin_im_toggle_keys==Alt_Space) ||
1384       ((kev_state & ShiftMask) && gcin_im_toggle_keys==Shift_Space) ||
1385       ((kev_state & Mod4Mask) && gcin_im_toggle_keys==Windows_Space)
1386     ) {
1387 	  dbg("ctrl-space\n");
1388 
1389       if (
1390 #if 0
1391 		  current_method_type() == method_type_TSIN &&
1392 #endif
1393 		  tsin_chinese_english_toggle_key != TSIN_CHINESE_ENGLISH_TOGGLE_KEY_CapsLock) {
1394         tsin_set_eng_ch(1);
1395       }
1396 
1397       toggle_im_enabled();
1398 #if UNIX
1399       return TRUE;
1400 #else
1401 #if 0
1402 	return TRUE;
1403 #else
1404     return FALSE;
1405 #endif
1406 #endif
1407     }
1408   }
1409 
1410   if (keysym == XK_space && (kev_state & ShiftMask)) {
1411     if (last_keysym != XK_Shift_L && last_keysym != XK_Shift_R)
1412       return FALSE;
1413 
1414     toggle_half_full_char();
1415 
1416     return TRUE;
1417   }
1418 
1419 
1420   if (((kev_state & (Mod1Mask|ShiftMask)) == (Mod1Mask|ShiftMask)) ||
1421 	  (gcin_ctrl_punc && (kev_state&(Mod1Mask|Mod5Mask|ShiftMask|ControlMask))==ControlMask && keysym < 127 && !(keysym>='0' && keysym<='9')) ) {
1422     if (current_CS->im_state != GCIN_STATE_DISABLED || gcin_eng_phrase_enabled)
1423       return feed_phrase(keysym, kev_state);
1424     else
1425       return 0;
1426   }
1427 
1428 //  dbg("state %x\n", kev_state);
1429   if ((current_CS->im_state & (GCIN_STATE_ENG_FULL)) ) {
1430     return full_char_proc(keysym);
1431   }
1432 
1433 
1434   if ((kev_state & ControlMask) && (kev_state&(Mod1Mask|Mod5Mask|ShiftMask))) {
1435     if (keysym == 'g' || keysym == 'r' || keysym == XK_F5) {
1436       last_keysym = 0;
1437       send_output_buffer_bak();
1438       return TRUE;
1439     }
1440 
1441     if (keysym == XK_F8) {
1442       last_keysym = 0;
1443       cb_trad_sim_toggle();
1444     }
1445 
1446     if (!gcin_enable_ctrl_alt_switch)
1447       return FALSE;
1448 
1449 #if WIN32
1450 	if (kev_state & ShiftMask) {
1451 		struct {
1452 			KeySym frm, to;
1453 		} tkeys[]={{0x1e, '6'}, {0,0}};
1454 
1455 		for(int i=0; tkeys[i].frm; i++) {
1456 			if (tkeys[i].frm == keysym) {
1457 				keysym = tkeys[i].to;
1458 				break;
1459 			}
1460 		}
1461 	}
1462 #endif
1463 
1464     int kidx = gcin_switch_keys_lookup(keysym);
1465 	dbg("kidx 0 %d\n", kidx);
1466 
1467 #if WIN32
1468 	if (!test_mode)
1469 #endif
1470 		last_keysym = keysym;
1471 
1472     if (kidx < 0) {
1473       return FALSE;
1474     }
1475 
1476     if (inmd[kidx].method_type == method_type_SYMBOL_TABLE) {
1477       toggle_symbol_table();
1478       return TRUE;
1479     }
1480 
1481     if (!inmd[kidx].cname)
1482       return FALSE;
1483 
1484 	dbg("kidx %d\n", kidx);
1485 
1486 #if WIN32
1487     if (!test_mode)
1488 #endif
1489     {
1490       current_CS->im_state = GCIN_STATE_CHINESE;
1491       init_in_method(kidx);
1492       set_tsin_pho_mode();
1493     }
1494 
1495     return TRUE;
1496   }
1497 #if WIN32
1498 	if (!test_mode)
1499 #endif
1500 		last_keysym = keysym;
1501 
1502   if (current_CS->im_state == GCIN_STATE_DISABLED) {
1503     return FALSE;
1504   }
1505 
1506 #if 0
1507   if (!current_CS->b_gcin_protocol) {
1508   if (((keysym == XK_Control_L || keysym == XK_Control_R)
1509                    && (kev_state & ShiftMask)) ||
1510       ((keysym == XK_Shift_L || keysym == XK_Shift_R)
1511                    && (kev_state & ControlMask))) {
1512      cycle_next_in_method();
1513      return TRUE;
1514   }
1515   }
1516 #endif
1517 
1518 #if WIN32
1519   if (!test_mode) {
1520 #endif
1521   if (current_CS->b_raise_window && keysym>=' ' && keysym < 127) {
1522     if (timeout_handle)
1523       g_source_remove(timeout_handle);
1524     timeout_handle = g_timeout_add(200, timeout_raise_window, NULL);
1525   }
1526 #if WIN32
1527   }
1528 #endif
1529 
1530   switch(current_method_type()) {
1531     case method_type_PHO:
1532       return feedkey_pho(keysym, kev_state);
1533     case method_type_TSIN:
1534       return feedkey_tsin(keysym, kev_state);
1535     case method_type_MODULE:
1536       if (!module_cb())
1537         return FALSE;
1538       return module_cb()->module_feedkey(keysym, kev_state);
1539     case method_type_GTAB:
1540       return feedkey_gtab(keysym, kev_state);
1541     default:
1542       dbg("ProcessKeyPress unknown current_CS:%x %d\n", current_CS, current_method_type());
1543   }
1544 
1545   return FALSE;
1546 }
1547 
1548 int feedkey_pp_release(KeySym xkey, int kbstate);
1549 int feedkey_gtab_release(KeySym xkey, int kbstate);
1550 int feedkey_pho_release(KeySym xkey, int kbstate);
1551 
1552 // return TRUE if the key press is processed
ProcessKeyRelease(KeySym keysym,u_int kev_state)1553 gboolean ProcessKeyRelease(KeySym keysym, u_int kev_state)
1554 {
1555   check_CS();
1556   current_kbd_state = kev_state;
1557 
1558   if (force_preedit==2) {
1559 	dbg("orce_preedit==2\n");
1560 	force_preedit = 0;
1561 	return TRUE;
1562   }
1563 
1564   disp_win_kbm_capslock();
1565 
1566 //  check_CS();
1567 #if 0
1568   dbg_time("key release %x %x\n", keysym, kev_state);
1569 #endif
1570 
1571   if (current_CS->im_state == GCIN_STATE_DISABLED)
1572     return FALSE;
1573 
1574 
1575 #if 1
1576   dbg("last_keysym %x\n", last_keysym);
1577 
1578   if (current_CS->b_gcin_protocol && (last_keysym == XK_Shift_L ||
1579   last_keysym == XK_Shift_R || last_keysym == XK_Control_L || last_keysym == XK_Control_R)) {
1580     if (((keysym == XK_Control_L || keysym == XK_Control_R)
1581           && (kev_state & ShiftMask)) ||
1582         ((keysym == XK_Shift_L || keysym == XK_Shift_R)
1583           && (kev_state & ControlMask))) {
1584        cycle_next_in_method();
1585        return TRUE;
1586     }
1587   }
1588 #endif
1589 
1590   switch(current_method_type()) {
1591     case method_type_TSIN:
1592       return feedkey_pp_release(keysym, kev_state);
1593 #if 0
1594 	case method_type_PHO:
1595 	  return feedkey_pho_release(keysym, kev_state);
1596 #endif
1597     case method_type_MODULE:
1598       if (!module_cb())
1599         return FALSE;
1600       return module_cb()->module_feedkey_release(keysym, kev_state);
1601     case method_type_GTAB:
1602       return feedkey_gtab_release(keysym, kev_state);
1603   }
1604 
1605   return FALSE;
1606 }
1607 
1608 
1609 #if USE_XIM
xim_ForwardEventHandler(IMForwardEventStruct * call_data)1610 int xim_ForwardEventHandler(IMForwardEventStruct *call_data)
1611 {
1612     current_forward_eve = call_data;
1613 
1614     if (call_data->event.type != KeyPress && call_data->event.type != KeyRelease) {
1615 #if DEBUG || 1
1616         dbg("bogus event type, ignored\n");
1617 #endif
1618         return True;
1619     }
1620 
1621     char strbuf[STRBUFLEN];
1622     KeySym keysym;
1623 
1624     bzero(strbuf, STRBUFLEN);
1625     XKeyEvent *kev = (XKeyEvent*)&current_forward_eve->event;
1626     XLookupString(kev, strbuf, STRBUFLEN, &keysym, NULL);
1627 
1628     int ret;
1629     if (call_data->event.type == KeyPress)
1630       ret = ProcessKeyPress(keysym, kev->state);
1631     else
1632       ret = ProcessKeyRelease(keysym, kev->state);
1633 
1634     if (!ret)
1635       bounce_back_key();
1636 
1637     export_text_xim();
1638 
1639     return False;
1640 }
1641 #endif
1642 
1643 
1644 void gcin_reset();
1645 
1646 #if UNIX
is_tip_window(Window inpwin)1647 gboolean is_tip_window(Window inpwin)
1648 {
1649    // Dirty fix for chrome, doesn't work well.
1650    if (!inpwin)
1651      return FALSE;
1652    XWindowAttributes att;
1653    XGetWindowAttributes(dpy, inpwin, &att);
1654 
1655    dbg("%d, %d\n", att.width, att.height);
1656 // chrome window is override_redirect
1657 //   if (att.override_redirect)
1658 //     return;
1659 
1660    return att.override_redirect && att.height < 24;
1661 }
1662 #endif
1663 
gcin_FocusIn(ClientState * cs)1664 int gcin_FocusIn(ClientState *cs)
1665 {
1666   dbg("gcin_FocusIn %p\n", cs);
1667   if (!cs) {
1668     dbg("cs is null");
1669     return FALSE;
1670   } else {
1671 //    dbg("gcin_FocusIn %x\n", cs);
1672   }
1673 
1674   Window win = cs->client_win;
1675   dbg("win: %x\n", win);
1676 
1677   if (!win) {
1678 	dbg("!win");
1679     return FALSE;
1680   }
1681 #if UNIX && 0
1682   if (is_tip_window(win)) {
1683 	dbg("is_tip_window\n");
1684 	return FALSE;
1685   }
1686 #endif
1687   reset_current_in_win_xy();
1688 
1689   if (cs) {
1690     Window win = cs->client_win;
1691 
1692     if (focus_win != win) {
1693 #if 1
1694       dbg("reset %x,%x\n", focus_win, win);
1695       gcin_reset();
1696 #endif
1697       hide_in_win(current_CS);
1698       focus_win = win;
1699     }
1700   }
1701 
1702   current_CS = cs;
1703   save_CS_temp_to_current();
1704 
1705 //  dbg("current_CS %x %d %d\n", cs, cs->im_state, current_CS->im_state);
1706 
1707   if (win == focus_win) {
1708     if (cs->im_state != GCIN_STATE_DISABLED) {
1709       show_in_win(cs);
1710       move_IC_in_win(cs);
1711     } else {
1712       hide_in_win(cs);
1713       move_IC_in_win(cs);
1714     }
1715   }
1716 
1717   cur_inmd = &inmd[current_CS->in_method];
1718 
1719 //  if (inmd[cs->in_method].selkey)
1720 //    set_wselkey();
1721 //  else
1722   {
1723     set_wselkey();
1724 #if 0
1725     gtab_set_win1_cb();
1726     tsin_set_win1_cb();
1727 #endif
1728   }
1729 
1730   update_win_kbm();
1731 
1732   disp_tray_icon();
1733 
1734 #if 0
1735   dbg_time("gcin_FocusIn %x %x\n",cs, current_CS);
1736 #endif
1737   return True;
1738 }
1739 
1740 
1741 #if USE_XIM
1742 IC *FindIC(CARD16 icid);
1743 void load_IC(IC *rec);
1744 CARD16 connect_id;
1745 
xim_gcin_FocusIn(IMChangeFocusStruct * call_data)1746 int xim_gcin_FocusIn(IMChangeFocusStruct *call_data)
1747 {
1748     IC *ic = FindIC(call_data->icid);
1749     ClientState *cs = &ic->cs;
1750     connect_id = call_data->connect_id;
1751 
1752     if (ic) {
1753       gcin_FocusIn(cs);
1754 
1755       load_IC(ic);
1756     }
1757 
1758 #if DEBUG
1759     dbg("xim_gcin_FocusIn %d\n", call_data->icid);
1760 #endif
1761     return True;
1762 }
1763 #endif
1764 
1765 
1766 
1767 static gint64 last_focus_out_time;
1768 
gcin_FocusOut(ClientState * cs)1769 int gcin_FocusOut(ClientState *cs)
1770 {
1771   gint64 t = current_time();
1772 //  dbg("gcin_FocusOut\n");
1773 
1774   if (cs != current_CS)
1775      return FALSE;
1776 
1777   if (!cs) {
1778 	 dbg("gcin_FocusOut is null\n");
1779 	 return FALSE;
1780   }
1781 
1782   if (!cs->client_win)
1783     return FALSE;
1784 
1785 #if UNIX
1786   if (is_tip_window(cs->client_win)) {
1787 	return FALSE;
1788   }
1789 #endif
1790 
1791 
1792   if (t - last_focus_out_time < 100000) {
1793     last_focus_out_time = t;
1794     return FALSE;
1795   }
1796 
1797   last_focus_out_time = t;
1798 
1799   if (cs == current_CS) {
1800     hide_in_win(cs);
1801   }
1802 
1803   reset_current_in_win_xy();
1804 
1805   if (cs == current_CS)
1806     temp_CS = *current_CS;
1807 
1808 #if 0
1809   dbg("focus out\n");
1810 #endif
1811 
1812   return True;
1813 }
1814 
1815 int tsin_get_preedit(char *str, GCIN_PREEDIT_ATTR attr[], int *cursor, int *sub_comp_len);
1816 int gtab_get_preedit(char *str, GCIN_PREEDIT_ATTR attr[], int *pcursor, int *sub_comp_len);
1817 int int_get_preedit(char *str, GCIN_PREEDIT_ATTR attr[], int *cursor, int *sub_comp_len);
1818 int pho_get_preedit(char *str, GCIN_PREEDIT_ATTR attr[], int *cursor, int *sub_comp_len);
1819 
gcin_get_preedit(ClientState * cs,char * str,GCIN_PREEDIT_ATTR attr[],int * cursor,int * comp_flag)1820 int gcin_get_preedit(ClientState *cs, char *str, GCIN_PREEDIT_ATTR attr[], int *cursor, int *comp_flag)
1821 {
1822 //  dbg("gcin_get_preedit %x\n", current_CS);
1823   if (!current_CS) {
1824 empty:
1825 //    dbg("empty\n");
1826     str[0]=0;
1827     *cursor=0;
1828     return 0;
1829   }
1830 
1831   str[0]=0;
1832   *comp_flag=0;
1833 
1834 //  cs->use_preedit = TRUE;
1835 
1836   switch(current_method_type()) {
1837     case method_type_PHO:
1838       return pho_get_preedit(str, attr, cursor, comp_flag);
1839 #if USE_TSIN
1840     case method_type_TSIN:
1841       return tsin_get_preedit(str, attr, cursor, comp_flag);
1842 #endif
1843     case method_type_MODULE:
1844       if (inmd[current_CS->in_method].mod_cb_funcs)
1845         return module_cb()->module_get_preedit(str, attr, cursor, comp_flag);
1846     default:
1847       return gtab_get_preedit(str, attr, cursor, comp_flag);
1848 //      dbg("metho %d\n", current_CS->in_method);
1849   }
1850 
1851   return 0;
1852 }
1853 
1854 void pho_reset();
1855 int tsin_reset();
1856 void gtab_reset();
1857 
gcin_reset()1858 void gcin_reset()
1859 {
1860 #if 1
1861   if (!current_CS)
1862     return;
1863 //  dbg("gcin_reset\n");
1864 
1865   switch(current_method_type()) {
1866     case method_type_PHO:
1867       pho_reset();
1868       return;
1869 #if USE_TSIN
1870     case method_type_TSIN:
1871       tsin_reset();
1872       return;
1873 #endif
1874     case method_type_MODULE:
1875       if (inmd[current_CS->in_method].mod_cb_funcs)
1876         module_cb()->module_reset();
1877       return;
1878     default:
1879       gtab_reset();
1880 //      dbg("metho %d\n", current_CS->in_method);
1881   }
1882 #endif
1883 }
1884 
1885 #if WIN32
1886 void show_tsin_stat();
gcin_set_tsin_pho_mode(ClientState * cs,gboolean pho_mode)1887 void gcin_set_tsin_pho_mode(ClientState *cs, gboolean pho_mode)
1888 {
1889 	set_tsin_pho_mode0(cs, pho_mode);
1890 
1891 	if (!pho_mode) {
1892 		cs->b_half_full_char = 0;
1893 		tss.tsin_half_full = 0;
1894 	}
1895 	show_tsin_stat();
1896 }
1897 #endif
1898 
1899 #if USE_XIM
xim_gcin_FocusOut(IMChangeFocusStruct * call_data)1900 int xim_gcin_FocusOut(IMChangeFocusStruct *call_data)
1901 {
1902     IC *ic = FindIC(call_data->icid);
1903     ClientState *cs = &ic->cs;
1904 
1905     gcin_FocusOut(cs);
1906 
1907     return True;
1908 }
1909 #endif
1910 
1911 
gcin_edit_display_ap_only()1912 gboolean gcin_edit_display_ap_only()
1913 {
1914 #if WIN32
1915   if (test_mode)
1916     return TRUE;
1917 #endif
1918   if (!current_CS)
1919     return FALSE;
1920 //  dbg("gcin_edit_display_ap_only %d\n", current_CS->use_preedit)
1921   return current_CS->use_preedit && gcin_edit_display==GCIN_EDIT_DISPLAY_ON_THE_SPOT;
1922 }
1923 
1924 
gcin_display_on_the_spot_key()1925 gboolean gcin_display_on_the_spot_key()
1926 {
1927   return gcin_edit_display_ap_only() && gcin_on_the_spot_key;
1928 }
1929 
flush_edit_buffer()1930 void flush_edit_buffer()
1931 {
1932 //  dbg("flush_edit_buffer\n");
1933   if (!current_CS)
1934     return;
1935 #if WIN32
1936   if (test_mode)
1937     return;
1938 #endif
1939 
1940 //  dbg("gcin_reset\n");
1941   switch(current_method_type()) {
1942 #if USE_TSIN
1943     case method_type_TSIN:
1944       flush_tsin_buffer();
1945       break;
1946 #endif
1947     case method_type_MODULE:
1948       if (inmd[current_CS->in_method].mod_cb_funcs)
1949       module_cb()->module_flush_input();
1950       break;
1951     default:
1952       output_gbuf();
1953 //      dbg("metho %d\n", current_CS->in_method);
1954   }
1955 }
1956 
1957 #if WIN32
1958 void pho_save_gst(), tsin_save_gst(), gtab_save_gst();
1959 void pho_restore_gst(), tsin_restore_gst(), gtab_restore_gst();
1960 
ProcessTestKeyPress(KeySym keysym,u_int kev_state)1961 gboolean ProcessTestKeyPress(KeySym keysym, u_int kev_state)
1962 {
1963   if (!current_CS)
1964     return TRUE;
1965   gboolean v;
1966 
1967   test_mode= TRUE;
1968 #if 0
1969   switch(current_method_type()) {
1970     case method_type_PHO:
1971       pho_save_gst();
1972       v = ProcessKeyPress(keysym, kev_state);
1973       pho_restore_gst();
1974       break;
1975     case method_type_TSIN:
1976       tsin_save_gst();
1977       v = ProcessKeyPress(keysym, kev_state);
1978       tsin_restore_gst();
1979       break;
1980     case method_type_MODULE:
1981       break;
1982     default:
1983       gtab_save_gst();
1984       v = ProcessKeyPress(keysym, kev_state);
1985       gtab_restore_gst();
1986   }
1987 #endif
1988   pho_save_gst();
1989   tsin_save_gst();
1990   gtab_save_gst();
1991   v = ProcessKeyPress(keysym, kev_state);
1992   pho_restore_gst();
1993   tsin_restore_gst();
1994   gtab_restore_gst();
1995   test_mode= FALSE;
1996 
1997   dbg("ProcessTestKeyPress %d\n", v);
1998 
1999   return v;
2000 }
2001 
2002 #if 0
2003 gboolean Process2KeyPress(KeySym keysym, u_int kev_state)
2004 {
2005   gboolean tv = ProcessTestKeyPress(keysym, kev_state);
2006   gboolean v = ProcessKeyPress(keysym, kev_state);
2007 
2008   if (tv != v)
2009     dbg("ProcessKeyPress %x -> %d %d\n",keysym, tv, v);
2010 
2011   return v;
2012 }
2013 #endif
2014 
ProcessTestKeyRelease(KeySym keysym,u_int kev_state)2015 gboolean ProcessTestKeyRelease(KeySym keysym, u_int kev_state)
2016 {
2017   test_mode = TRUE;
2018   gboolean v = ProcessKeyRelease(keysym, kev_state);
2019   test_mode = FALSE;
2020   return v;
2021 }
2022 
2023 #if 0
2024 gboolean Process2KeyRelease(KeySym keysym, u_int kev_state)
2025 {
2026   gboolean tv = ProcessTestKeyRelease(keysym, kev_state);
2027   gboolean v = ProcessKeyRelease(keysym, kev_state);
2028 
2029   if (tv != v)
2030     dbg("ProcessKeyRelease %x -> %d %d\n",keysym, tv, v);
2031 
2032   return v;
2033 }
2034 #endif
2035 #endif
2036