1 #include <sys/stat.h>
2 #if UNIX
3 #include <X11/extensions/XTest.h>
4 #endif
5 #include "gcin.h"
6 #include "gtab.h"
7 extern INMD *cur_inmd;
8 
9 static GtkWidget *gwin_kbm;
10 static GdkColor red;
11 int win_kbm_on;
12 extern gboolean test_mode;
13 
14 enum {
15   K_FILL=1,
16   K_HOLD=2,
17   K_PRESS=4,
18   K_AREA_R=8,
19   K_CAPSLOCK=16
20 };
21 
22 
23 typedef struct {
24   KeySym keysym;
25   char *enkey;
26   char shift_key;
27   char flag;
28   GtkWidget *lab, *but, *laben;
29 } KEY;
30 
31 #define COLN 19
32 static KEY keys[][COLN]={
33 {{XK_Escape,"Esc"},{XK_F1,"F1"},{XK_F2,"F2"},{XK_F3,"F3"},{XK_F4,"F4"},{XK_F5,"F5"},{XK_F6,"F6"},{XK_F7,"F7"},{XK_F8,"F8"},{XK_F9,"F9"},{XK_F10,"F10"},{XK_F11,"F11"},{XK_F12,"F12"},{XK_Print,"Pr",0,8},{XK_Scroll_Lock,"Slk",0,8},{XK_Pause,"Pau",0,8}},
34 
35 {{'`'," ` ",'~'},{'1'," 1 ", '!'},{'2'," 2 ",'@'},{'3'," 3 ",'#'},{'4'," 4 ",'$'},{'5'," 5 ",'%'},{'6'," 6 ",'^'},{'7'," 7 ",'&'},{'8'," 8 ",'*'},{'9'," 9 ",'('},{'0'," 0 ",')'},{'-'," - ",'_'},{'='," = ",'+'},
36 {XK_BackSpace,"←",0, K_FILL},
37 {XK_Insert,"Ins",0,8},{XK_Home,"Ho",0,8}, {XK_Prior,"P↑",0,8}},
38 
39 {{XK_Tab, "Tab"}, {'q'," q "},{'w'," w "},{'e'," e "},{'r'," r "},{'t'," t "}, {'y'," y "},{'u'," u "},{'i'," i "},{'o'," o "}, {'p'," p "},{'['," [ ",'{'},{']'," ] ",'}'},{'\\'," \\ ",'|',K_FILL},{XK_Delete,"Del",0,8},{XK_End,"En",0,8},
40 {XK_Next,"P↓",0,8}},
41 
42 {{XK_Caps_Lock, "Caps", 0, K_CAPSLOCK},{'a'," a "},{'s'," s "},{'d'," d "},{'f', " f "},{'g'," g "},{'h'," h "},{'j'," j "},{'k'," k "},{'l'," l "},{';'," ; ",':'},{'\''," ' ",'"'},{XK_Return," Enter ",0,1},{XK_Num_Lock,"Num",0,8},{XK_KP_Add," + ",0,8}},
43 
44 {{XK_Shift_L,"  Shift  ",0,K_HOLD},{'z'," z "},{'x'," x "},{'c'," c "},{'v'," v "},{'b'," b "},{'n'," n "},{'m'," m "},{','," , ",'<'},{'.'," . ",'>'},{'/'," / ",'?'},{XK_Shift_R," Shift",0,K_HOLD|K_FILL},{XK_KP_Multiply," * ",0,8},
45 {XK_Up,"↑",0,8}},
46 {{XK_Control_L,"Ctrl",0,K_HOLD},{XK_Super_L,"◆"},{XK_Alt_L,"Alt",0,K_HOLD},{' ',"Space",0, K_FILL}, {XK_Alt_R,"Alt",0,K_HOLD},{XK_Super_R,"◆"},{XK_Menu,"■"}, {XK_Control_R,"Ctrl",0,K_HOLD},
47 {XK_Left, "←",0,8},{XK_Down,"↓",0,8},{XK_Right, "→",0,8}}
48 };
49 
50 static int keysN=sizeof(keys)/sizeof(keys[0]);
51 
52 void update_win_kbm();
53 
mod_fg_all(GtkWidget * lab,GdkColor * col)54 void mod_fg_all(GtkWidget *lab, GdkColor *col)
55 {
56 #if !GTK_CHECK_VERSION(2,91,6)
57   gtk_widget_modify_fg(lab, GTK_STATE_NORMAL, col);
58   gtk_widget_modify_fg(lab, GTK_STATE_ACTIVE, col);
59   gtk_widget_modify_fg(lab, GTK_STATE_SELECTED, col);
60   gtk_widget_modify_fg(lab, GTK_STATE_PRELIGHT, col);
61 #else
62   GdkRGBA rgb, *prgb = NULL;
63   if (col) {
64     gdk_rgba_parse(&rgb, gdk_color_to_string(col));
65     prgb = &rgb;
66   }
67   gtk_widget_override_color(lab, GTK_STATE_FLAG_NORMAL, prgb);
68   gtk_widget_override_color(lab, GTK_STATE_FLAG_ACTIVE, prgb);
69   gtk_widget_override_color(lab, GTK_STATE_FLAG_SELECTED, prgb);
70   gtk_widget_override_color(lab, GTK_STATE_FLAG_PRELIGHT, prgb);
71 #endif
72 }
73 
74 
75 void send_fake_key_eve(KeySym key);
76 #if WIN32
77 void win32_FakeKey(UINT vk, bool key_press);
78 #endif
79 
send_fake_key_eve2(KeySym key,gboolean press)80 void send_fake_key_eve2(KeySym key, gboolean press)
81 {
82 #if WIN32
83   win32_FakeKey(key, press);
84 #else
85   KeyCode kc = XKeysymToKeycode(dpy, key);
86   XTestFakeKeyEvent(dpy, kc, press, CurrentTime);
87 #endif
88 }
89 
90 
91 static int kbm_timeout_handle;
92 
timeout_repeat(gpointer data)93 static gboolean timeout_repeat(gpointer data)
94 {
95   KeySym k = GPOINTER_TO_INT(data);
96 
97   send_fake_key_eve2(k, TRUE);
98   return TRUE;
99 }
100 
timeout_first_time(gpointer data)101 static gboolean timeout_first_time(gpointer data)
102 {
103   KeySym k = GPOINTER_TO_INT(data);
104   dbg("timeout_first_time %c\n", k);
105   send_fake_key_eve2(k, TRUE);
106   kbm_timeout_handle = g_timeout_add(50, timeout_repeat, data);
107   return FALSE;
108 }
109 
clear_hold(KEY * k)110 static void clear_hold(KEY *k)
111 {
112   KeySym keysym=k->keysym;
113   GtkWidget *laben = k->laben;
114   k->flag &= ~K_PRESS;
115   mod_fg_all(laben, NULL);
116   send_fake_key_eve2(keysym, FALSE);
117 }
118 
timeout_clear_hold(gpointer data)119 static gboolean timeout_clear_hold(gpointer data)
120 {
121   clear_hold((KEY *)data);
122   return FALSE;
123 }
124 
clear_kbm_timeout_handle()125 void clear_kbm_timeout_handle()
126 {
127   if (!kbm_timeout_handle)
128     return;
129   g_source_remove(kbm_timeout_handle);
130   kbm_timeout_handle = 0;
131 }
132 
cb_button_click(GtkWidget * wid,KEY * k)133 static void cb_button_click(GtkWidget *wid, KEY *k)
134 {
135   KeySym keysym=k->keysym;
136   GtkWidget *laben = k->laben;
137 
138   dbg("cb_button_click keysym %d\n", keysym);
139 
140   gtk_window_present(GTK_WINDOW(gwin_kbm));
141 
142   if (k->flag & K_HOLD) {
143     if (k->flag & K_PRESS) {
144       clear_hold(k);
145     } else {
146       send_fake_key_eve2(keysym, TRUE);
147       k->flag |= K_PRESS;
148       mod_fg_all(laben, &red);
149       g_timeout_add(10000, timeout_clear_hold, GINT_TO_POINTER(k));
150     }
151   } else {
152 	clear_kbm_timeout_handle();
153     kbm_timeout_handle = g_timeout_add(500, timeout_first_time, GINT_TO_POINTER(keysym));
154     send_fake_key_eve2(keysym, TRUE);
155   }
156 }
157 
158 
cb_button_release(GtkWidget * wid,KEY * k)159 static void cb_button_release(GtkWidget *wid, KEY *k)
160 {
161     dbg("cb_button_release %d\n", kbm_timeout_handle);
162 	clear_kbm_timeout_handle();
163 
164     send_fake_key_eve2(k->keysym, FALSE);
165 
166     int i;
167     for(i=0;i<keysN;i++) {
168       int j;
169       for(j=0; keys[i][j].enkey; j++) {
170         if (!(keys[i][j].flag & K_PRESS))
171           continue;
172         keys[i][j].flag &= ~K_PRESS;
173                 send_fake_key_eve2(keys[i][j].keysym, FALSE);
174         mod_fg_all(keys[i][j].laben, NULL);
175       }
176     }
177 }
178 
179 
create_win_kbm()180 static void create_win_kbm()
181 {
182   gdk_color_parse("red", &red);
183 
184   gwin_kbm = create_no_focus_win();
185 
186   gtk_container_set_border_width (GTK_CONTAINER (gwin_kbm), 0);
187   GtkWidget *hbox_top = gtk_hbox_new (FALSE, 0);
188   gtk_container_add (GTK_CONTAINER (gwin_kbm), hbox_top);
189 
190 
191   GtkWidget *vbox_l = gtk_vbox_new (FALSE, 0);
192   gtk_box_pack_start (GTK_BOX (hbox_top), vbox_l, TRUE, TRUE, 0);
193   gtk_container_set_border_width (GTK_CONTAINER (vbox_l), 0);
194   GtkWidget *vbox_r = gtk_vbox_new (FALSE, 0);
195   gtk_box_pack_start (GTK_BOX (hbox_top), vbox_r, FALSE, FALSE, 0);
196   gtk_container_set_border_width (GTK_CONTAINER (vbox_r), 0);
197 
198   int i;
199   for(i=0;i<keysN;i++) {
200     GtkWidget *hboxl = gtk_hbox_new (FALSE, 0);
201     gtk_container_set_border_width (GTK_CONTAINER (hboxl), 0);
202     gtk_box_pack_start (GTK_BOX (vbox_l), hboxl, TRUE, TRUE, 0);
203     GtkWidget *hboxr = gtk_hbox_new (FALSE, 0);
204     gtk_container_set_border_width (GTK_CONTAINER (hboxr), 0);
205     gtk_box_pack_start (GTK_BOX (vbox_r), hboxr, FALSE, FALSE, 0);
206     KEY *pk = keys[i];
207 
208     int j;
209     for(j=0; pk[j].enkey; j++) {
210       KEY *ppk=&pk[j];
211       char flag=ppk->flag;
212       if (!ppk->keysym)
213         continue;
214       GtkWidget *but=pk[j].but=gtk_button_new();
215       g_signal_connect (G_OBJECT (but), "pressed", G_CALLBACK (cb_button_click), ppk);
216       if (!(ppk->flag & K_HOLD))
217         g_signal_connect (G_OBJECT (but), "released", G_CALLBACK (cb_button_release), ppk);
218 
219       GtkWidget *hbox = (flag&K_AREA_R)?hboxr:hboxl;
220 
221       gtk_container_set_border_width (GTK_CONTAINER (but), 0);
222 
223       gboolean fill = (flag & K_FILL) > 0;
224       gtk_box_pack_start (GTK_BOX (hbox), but, fill, fill, 0);
225 
226       GtkWidget *v = gtk_vbox_new (FALSE, 0);
227       gtk_container_set_border_width (GTK_CONTAINER (v), 0);
228       gtk_container_add (GTK_CONTAINER (but), v);
229       GtkWidget *laben = ppk->laben=gtk_label_new(ppk->enkey);
230       set_label_font_size(laben, gcin_font_size_win_kbm_en);
231 
232       gtk_box_pack_start (GTK_BOX (v), laben, fill, fill, 0);
233 
234       if (i>0&&i<5) {
235         GtkWidget *lab = ppk->lab = gtk_label_new("  ");
236 //        set_label_font_size(lab, gcin_font_size_win_kbm);
237         gtk_box_pack_start (GTK_BOX (v), lab, fill, fill, 0);
238       }
239     }
240   }
241 
242   gtk_widget_realize (gwin_kbm);
243 #if WIN32
244   win32_init_win(gwin_kbm);
245 #else
246   GdkWindow *gdkwin_kbm = gtk_widget_get_window(gwin_kbm);
247   set_no_focus(gwin_kbm);
248 #endif
249 }
250 
251 extern GdkWindow *tray_da_win;
252 extern GtkStatusIcon *icon_main;
253 
move_win_kbm()254 static void move_win_kbm()
255 {
256   int width, height;
257   get_win_size(gwin_kbm, &width, &height);
258 
259   int ox, oy;
260   GdkRectangle r;
261   GtkOrientation ori;
262 
263 #if UNIX
264   int szx, szy;
265   if (tray_da_win) {
266     gdk_window_get_origin(tray_da_win, &ox, &oy);
267 #if !GTK_CHECK_VERSION(2,91,0)
268     gdk_drawable_get_size(tray_da_win, &szx, &szy);
269 #else
270     szx = gdk_window_get_width(tray_da_win);
271     szy = gdk_window_get_height(tray_da_win);
272 #endif
273     if (oy<height) {
274       oy = szy;
275     } else {
276       oy -= height;
277       if (oy + height > dpy_yl)
278         oy = dpy_yl - height;
279       if (oy < 0)
280         oy = szy;
281     }
282 
283     if (ox + width > dpy_xl)
284       ox = dpy_xl - width;
285     if (ox < 0)
286       ox = 0;
287   } else
288 #endif
289   if (icon_main && gtk_status_icon_get_geometry(icon_main, NULL, &r,  &ori)) {
290 //    dbg("rect %d:%d %d:%d\n", r.x, r.y, r.width, r.height);
291     ox = r.x;
292     if (ox + width > dpy_xl)
293       ox = dpy_xl - width;
294 
295     if (r.y < 100)
296       oy=r.y+r.height;
297     else {
298       oy = r.y - height;
299     }
300   } else {
301     ox = dpy_xl - width;
302     oy = dpy_yl - height - 31;
303   }
304 
305   gtk_window_move(GTK_WINDOW(gwin_kbm), ox, oy);
306 }
307 
show_win_kbm()308 void show_win_kbm()
309 {
310   if (!gwin_kbm) {
311     create_win_kbm();
312     update_win_kbm();
313   }
314 
315   gtk_widget_show_all(gwin_kbm);
316   win_kbm_on = 1;
317 #if WIN32
318   gtk_window_present(GTK_WINDOW(gwin_kbm));
319 #endif
320   move_win_kbm();
321 }
322 
323 static char   shift_chars[]="~!@#$%^&*()_+{}|:\"<>?";
324 static char shift_chars_o[]="`1234567890-=[]\\;',./";
325 
326 #include "pho.h"
327 
get_keys_ent(KeySym keysym)328 static KEY *get_keys_ent(KeySym keysym)
329 {
330   int i;
331   for(i=0;i<keysN;i++) {
332     int j;
333     for(j=0;j<COLN;j++) {
334       char *p;
335       if (keysym >='A' && keysym<='Z')
336         keysym += 0x20;
337       else
338       if (p=strchr(shift_chars, keysym)) {
339         keysym = shift_chars_o[p - shift_chars];
340       }
341 
342       if (keys[i][j].keysym!=keysym)
343         continue;
344       return &keys[i][j];
345     }
346   }
347 
348   return NULL;
349 }
350 
set_kbm_key(KeySym keysym,char * str)351 static void set_kbm_key(KeySym keysym, char *str)
352 {
353   if (!gwin_kbm)
354     return;
355 #if 0
356   if (strlen(str)==1 && !(str[0] & 0x80))
357     return;
358 #endif
359 
360   KEY *p = get_keys_ent(keysym);
361   if (!p)
362     return;
363 
364   GtkWidget *lab = p->lab;
365   char *t = (char *)gtk_label_get_text(GTK_LABEL(lab));
366   char tt[64];
367 
368   if (t && strcmp(t, str)) {
369     strcat(strcpy(tt, t), str);
370     str = tt;
371   }
372 
373   if (lab) {
374     gtk_label_set_text(GTK_LABEL(lab), str);
375     set_label_font_size(lab, gcin_font_size_win_kbm);
376   }
377 }
378 
clear_kbm()379 static void clear_kbm()
380 {
381   int i;
382   for(i=0;i<keysN;i++) {
383     int j;
384     for(j=0;j<COLN;j++) {
385       GtkWidget *lab = keys[i][j].lab;
386       if (lab)
387         gtk_label_set_text(GTK_LABEL(lab), NULL);
388 
389       if (keys[i][j].laben)
390         gtk_label_set_text(GTK_LABEL(keys[i][j].laben), keys[i][j].enkey);
391     }
392   }
393 }
394 
disp_shift_keys()395 static void disp_shift_keys()
396 {
397       int i;
398       for(i=127; i > 0; i--) {
399         char tt[64];
400           KEY *p = get_keys_ent(i);
401           if (p && p->shift_key) {
402             char *t = (char *)gtk_label_get_text(GTK_LABEL(p->lab));
403             if (t && t[0])
404               continue;
405 //            dbg("zzz %c %s\n",i, tt);
406             tt[0]=p->shift_key;
407             tt[1]=0;
408             set_kbm_key(i, tt);
409           }
410       }
411 }
412 
413 
update_win_kbm()414 void update_win_kbm()
415 {
416   if (!current_CS || !gwin_kbm)
417     return;
418 
419   clear_kbm();
420 
421   if (current_CS->im_state != GCIN_STATE_CHINESE) {
422     if (current_CS->im_state == GCIN_STATE_DISABLED) {
423       int i;
424       for(i=0;i<keysN;i++) {
425         int j;
426         for(j=0;j<COLN;j++) {
427           char kstr[2];
428           kstr[1]=0;
429           kstr[0] = keys[i][j].shift_key;
430 
431           if (keys[i][j].laben) {
432             if (kstr[0])
433               gtk_label_set_text(GTK_LABEL(keys[i][j].laben), kstr);
434             set_label_font_size(keys[i][j].laben, gcin_font_size_win_kbm_en);
435           }
436 
437           if (keys[i][j].lab) {
438             if (kstr[0])
439               gtk_label_set_text(GTK_LABEL(keys[i][j].lab), keys[i][j].enkey);
440             set_label_font_size(keys[i][j].lab, gcin_font_size_win_kbm_en);
441           }
442         }
443       }
444    }
445    goto ret;
446  }
447 
448   int i;
449   switch (current_method_type()) {
450     case method_type_PHO:
451     case method_type_TSIN:
452       for(i=0; i < 128; i++) {
453         int j;
454         char tt[64];
455         int ttN=0;
456 
457         for(j=0;j<3; j++) {
458           int num = phkbm.phokbm[i][j].num;
459           int typ = phkbm.phokbm[i][j].typ;
460           if (!num)
461             continue;
462           ttN+= utf8cpy(&tt[ttN], &pho_chars[typ][num * 3]);
463         }
464 
465         if (!ttN)
466          continue;
467         set_kbm_key(i, tt);
468       }
469 
470       disp_shift_keys();
471 
472       break;
473     case method_type_MODULE:
474       break;
475     default:
476       if (!cur_inmd || !cur_inmd->DefChars)
477         return;
478 
479       int loop;
480       for(loop=0;loop<2;loop++)
481       for(i=127; i > 0; i--) {
482         char tt[64];
483         char k=cur_inmd->keymap[i];
484         if (!k)
485           continue;
486 
487         char *keyname = &cur_inmd->keyname[k * CH_SZ];
488         if (!keyname[0])
489           continue;
490 
491 #if 0
492         if (loop==0 && !(keyname[0]&0x80))
493 #else
494 		if (loop==0 && !(keyname[0]&0x80) && toupper(i)==toupper(keyname[0]))
495 #endif
496           continue;
497 
498         if (loop==1) {
499           KEY *p = get_keys_ent(i);
500           char *t = (char *)gtk_label_get_text(GTK_LABEL(p->lab));
501           if (t && t[0]) {
502             continue;
503           }
504         }
505 
506 
507         tt[0]=0;
508         if (keyname[0] & 128)
509           utf8cpy(tt, keyname);
510         else {
511           tt[1]=0;
512           memcpy(tt, keyname, 2);
513           tt[2]=0;
514         }
515 
516 //        dbg("%c '%s'\n", i, tt);
517         set_kbm_key(i, tt);
518       }
519 
520       disp_shift_keys();
521 
522       break;
523   }
524 
525 ret:
526   gtk_window_resize(GTK_WINDOW(gwin_kbm), 1, 1);
527   move_win_kbm();
528 }
529 
530 
hide_win_kbm()531 void hide_win_kbm()
532 {
533   if (!gwin_kbm)
534     return;
535 #if WIN32
536   if (test_mode)
537     return;
538 #endif
539 
540   clear_kbm_timeout_handle();
541   win_kbm_on = 0;
542   gtk_widget_hide(gwin_kbm);
543 }
544 
545 extern gboolean old_capslock_on;
546 
win_kbm_disp_caplock()547 void win_kbm_disp_caplock()
548 {
549   KEY *p = get_keys_ent(XK_Caps_Lock);
550 
551   if (old_capslock_on) {
552  //   dbg("lock...\n");
553     mod_fg_all(p->laben, &red);
554   } else {
555     mod_fg_all(p->laben, NULL);
556   }
557 }
558