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