1 /***************************************************************************
2 * Copyright (C) 2002~2005 by Yuking *
3 * yuking_net@sohu.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
20 #include <limits.h>
21 #include <ctype.h>
22 #include <X11/Xatom.h>
23 #include <X11/Xlib.h>
24 #include <cairo.h>
25 #include <libintl.h>
26 #include <cairo-xlib.h>
27
28 #include "fcitx/fcitx.h"
29 #include "fcitx/module.h"
30
31 #include "fcitx/ime.h"
32 #include "fcitx/instance.h"
33 #include "fcitx-utils/log.h"
34 #include "fcitx/frontend.h"
35 #include "fcitx-config/xdg.h"
36 #include "fcitx/hook.h"
37 #include "fcitx-utils/utils.h"
38 #include "module/x11/fcitx-x11.h"
39 #include "ui/cairostuff/cairostuff.h"
40 #include "ui/cairostuff/font.h"
41 #include "ui/classic/fcitx-classicui.h"
42
43 #define VK_FILE "vk.conf"
44
45 #define VK_WINDOW_WIDTH 354
46 #define VK_WINDOW_HEIGHT 164
47 #define VK_NUMBERS 47
48 #define VK_MAX 50
49
50 const char* dummyTranslate[] = {
51 N_("Latin"),
52 N_("Fullwidth"),
53 N_("Greek"),
54 N_("Russian"),
55 N_("Index"),
56 N_("Math"),
57 N_("Number"),
58 N_("Special"),
59 N_("Hiragana"),
60 N_("Katakana"),
61 N_("Table Symbol")
62 };
63
64 struct _FcitxVKState;
65
66 typedef struct _VKS {
67 char strSymbol[VK_NUMBERS][2][UTF8_MAX_LENGTH + 1]; //相应的符号
68 char *strName;
69 } VKS;
70
71 typedef struct _VKWindow {
72 Window window;
73 int fontSize;
74 cairo_surface_t* surface;
75 cairo_surface_t* keyboard;
76 Display* dpy;
77 struct _FcitxVKState* owner;
78 char *defaultFont;
79 int iVKWindowX;
80 int iVKWindowY;
81 } VKWindow;
82
83 typedef struct _FcitxVKState {
84 VKWindow* vkWindow;
85 int iCurrentVK ;
86 int iVKCount ;
87 VKS vks[VK_MAX];
88 boolean bShiftPressed;
89 boolean bVKCaps;
90 boolean bVK;
91 FcitxUIMenu vkmenu;
92 FcitxInstance* owner;
93 } FcitxVKState;
94
95 const char vkTable[VK_NUMBERS + 1] = "`1234567890-=qwertyuiop[]\\asdfghjkl;'zxcvbnm,./";
96 const char strCharTable[] = "`~1!2@3#4$5%6^7&8*9(0)-_=+[{]}\\|;:'\",<.>/?"; //用于转换上/下档键
97
98 static boolean VKWindowEventHandler(void* arg, XEvent* event);
99 static void
100 VKInitWindowAttribute(FcitxVKState* vkstate, Visual ** vs, Colormap * cmap,
101 XSetWindowAttributes * attrib,
102 unsigned long *attribmask, int *depth);
103 static Visual * VKFindARGBVisual(FcitxVKState* vkstate);
104 static void VKSetWindowProperty(FcitxVKState* vkstate, Window window, FcitxXWindowType type, char *windowTitle);
105 static boolean VKMouseClick(FcitxVKState* vkstate, Window window, int *x, int *y);
106 static void SwitchVK(FcitxVKState *vkstate);
107 static void LoadVKMapFile(FcitxVKState *vkstate);
108 static void ChangVK(FcitxVKState* vkstate);
109 static void ReloadVK(void *arg);
110 static int MyToUpper(int iChar);
111 static int MyToLower(int iChar);
112 static cairo_surface_t* LoadVKImage(VKWindow* vkWindow);
113 static void *VKCreate(FcitxInstance* instance);
114 static VKWindow* CreateVKWindow(FcitxVKState* vkstate);
115 static boolean GetVKState(void *arg);
116 static void ToggleVKState(void *arg);
117 static INPUT_RETURN_VALUE ToggleVKStateWithHotkey(void* arg);
118 static void DrawVKWindow(VKWindow* vkWindow);
119 static boolean VKMouseKey(FcitxVKState* vkstate, int x, int y);
120 static boolean VKPreFilter(void* arg, FcitxKeySym sym,
121 unsigned int state,
122 INPUT_RETURN_VALUE *retval
123 );
124 static void VKReset(void* arg);
125 static void VKUpdate(void* arg);
126 static INPUT_RETURN_VALUE DoVKInput(FcitxVKState* vkstate, KeySym sym, int state);
127 static void DisplayVKWindow(VKWindow* vkWindow);
128 static boolean VKMenuAction(FcitxUIMenu *menu, int index);
129 static void UpdateVKMenu(FcitxUIMenu *menu);
130 static void SelectVK(FcitxVKState* vkstate, int vkidx);
131
132 static FcitxConfigColor blackColor = {0, 0, 0};
133
134 FCITX_DEFINE_PLUGIN(fcitx_vk, module, FcitxModule) = {
135 VKCreate,
136 NULL,
137 NULL,
138 NULL,
139 ReloadVK
140 };
141
VKCreate(FcitxInstance * instance)142 void *VKCreate(FcitxInstance* instance)
143 {
144 FcitxVKState *vkstate = fcitx_utils_malloc0(sizeof(FcitxVKState));
145 FcitxGlobalConfig* config = FcitxInstanceGetGlobalConfig(instance);
146 vkstate->owner = instance;
147
148 FcitxHotkeyHook hotkey;
149 hotkey.hotkey = config->hkVK;
150 hotkey.hotkeyhandle = ToggleVKStateWithHotkey;
151 hotkey.arg = vkstate;
152 FcitxInstanceRegisterHotkeyFilter(instance, hotkey);
153
154 FcitxUIRegisterStatus(instance, vkstate, "vk", _("Toggle Virtual Keyboard"), _("Virtual Keyboard State"), ToggleVKState, GetVKState);
155
156 LoadVKMapFile(vkstate);
157
158 FcitxKeyFilterHook hk;
159 hk.arg = vkstate ;
160 hk.func = VKPreFilter;
161 FcitxInstanceRegisterPreInputFilter(instance, hk);
162
163 hk.arg = &vkstate->bVK;
164 hk.func = FcitxDummyReleaseInputHook;
165 FcitxInstanceRegisterPreReleaseInputFilter(instance, hk);
166
167 FcitxIMEventHook resethk;
168 resethk.arg = vkstate;
169 resethk.func = VKReset;
170 FcitxInstanceRegisterTriggerOnHook(instance, resethk);
171 FcitxInstanceRegisterTriggerOffHook(instance, resethk);
172
173 resethk.func = VKUpdate;
174 FcitxInstanceRegisterInputFocusHook(instance, resethk);
175 FcitxInstanceRegisterInputUnFocusHook(instance, resethk);
176
177 FcitxMenuInit(&vkstate->vkmenu);
178 vkstate->vkmenu.candStatusBind = strdup("vk");
179 vkstate->vkmenu.name = strdup(_("Virtual Keyboard"));
180
181 vkstate->vkmenu.UpdateMenu = UpdateVKMenu;
182 vkstate->vkmenu.MenuAction = VKMenuAction;
183 vkstate->vkmenu.priv = vkstate;
184 vkstate->vkmenu.isSubMenu = false;
185
186 FcitxUIRegisterMenu(instance, &vkstate->vkmenu);
187
188 return vkstate;
189 }
190
VKMenuAction(FcitxUIMenu * menu,int index)191 boolean VKMenuAction(FcitxUIMenu *menu, int index)
192 {
193 FcitxVKState* vkstate = (FcitxVKState*) menu->priv;
194 if (index < vkstate->iVKCount)
195 SelectVK(vkstate, index);
196 else {
197 if (vkstate->bVK) {
198 FcitxUIUpdateStatus(vkstate->owner, "vk");
199 }
200 }
201 return true;
202 }
203
UpdateVKMenu(FcitxUIMenu * menu)204 void UpdateVKMenu(FcitxUIMenu *menu)
205 {
206 FcitxVKState* vkstate = (FcitxVKState*) menu->priv;
207 FcitxMenuClear(menu);
208 int i;
209 for (i = 0; i < vkstate->iVKCount; i ++)
210 FcitxMenuAddMenuItem(&vkstate->vkmenu, vkstate->vks[i].strName, MENUTYPE_SIMPLE, NULL);
211 if (vkstate->bVK) {
212 FcitxMenuAddMenuItem(&vkstate->vkmenu, _("Close virtual keyboard"), MENUTYPE_SIMPLE, NULL);
213 }
214 menu->mark = vkstate->iCurrentVK;
215 }
216
VKReset(void * arg)217 void VKReset(void* arg)
218 {
219 FcitxVKState *vkstate = (FcitxVKState*) arg;
220 VKWindow* vkWindow = vkstate->vkWindow;
221 if (vkstate->bVK != false)
222 FcitxUIUpdateStatus(vkstate->owner, "vk");
223 if (vkWindow)
224 XUnmapWindow(vkWindow->dpy, vkWindow->window);
225 }
226
VKUpdate(void * arg)227 void VKUpdate(void* arg)
228 {
229 FcitxVKState *vkstate = (FcitxVKState*) arg;
230 VKWindow* vkWindow = vkstate->vkWindow;
231 if (vkWindow) {
232
233 if (FcitxInstanceGetCurrentState(vkstate->owner) != IS_CLOSED && vkstate->bVK) {
234 DrawVKWindow(vkWindow);
235 DisplayVKWindow(vkWindow);
236 } else
237 XUnmapWindow(vkWindow->dpy, vkWindow->window);
238 }
239 }
240
VKPreFilter(void * arg,FcitxKeySym sym,unsigned int state,INPUT_RETURN_VALUE * retval)241 boolean VKPreFilter(void* arg, FcitxKeySym sym, unsigned int state, INPUT_RETURN_VALUE* retval)
242 {
243 FcitxVKState *vkstate = (FcitxVKState*) arg;
244 if (vkstate->bVK) {
245 INPUT_RETURN_VALUE ret = DoVKInput(vkstate, sym, state);
246 *retval = ret;
247 return true;
248 }
249 return false;
250 }
251
GetVKState(void * arg)252 boolean GetVKState(void *arg)
253 {
254 FcitxVKState *vkstate = (FcitxVKState*) arg;
255 return vkstate->bVK;
256 }
257
ToggleVKState(void * arg)258 void ToggleVKState(void *arg)
259 {
260 FcitxVKState *vkstate = (FcitxVKState*) arg;
261 SwitchVK(vkstate);
262 }
263
ToggleVKStateWithHotkey(void * arg)264 INPUT_RETURN_VALUE ToggleVKStateWithHotkey(void* arg)
265 {
266 FcitxVKState *vkstate = (FcitxVKState*) arg;
267 FcitxUIUpdateStatus(vkstate->owner, "vk");
268 return IRV_DO_NOTHING;
269 }
270
CreateVKWindow(FcitxVKState * vkstate)271 VKWindow* CreateVKWindow(FcitxVKState* vkstate)
272 {
273 XSetWindowAttributes attrib;
274 unsigned long attribmask;
275 char strWindowName[] = "Fcitx VK Window";
276 Colormap cmap;
277 Visual * vs;
278 int depth;
279 VKWindow* vkWindow = fcitx_utils_new(VKWindow);
280 vkWindow->owner = vkstate;
281
282 LoadVKImage(vkWindow);
283
284 vs = VKFindARGBVisual(vkstate);
285 VKInitWindowAttribute(vkstate, &vs, &cmap, &attrib, &attribmask, &depth);
286 vkWindow->dpy = FcitxX11GetDisplay(vkstate->owner);
287
288 vkWindow->fontSize = 12;
289 vkWindow->defaultFont = strdup("sans");
290 #ifndef _ENABLE_PANGO
291 GetValidFont("zh", &vkWindow->defaultFont);
292 #endif
293
294 vkWindow->window = XCreateWindow(vkWindow->dpy,
295 DefaultRootWindow(vkWindow->dpy),
296 0, 0,
297 VK_WINDOW_WIDTH, VK_WINDOW_HEIGHT,
298 0, depth, InputOutput, vs, attribmask, &attrib);
299 if (vkWindow->window == (Window) None)
300 return NULL;
301
302 vkWindow->surface = cairo_xlib_surface_create(vkWindow->dpy, vkWindow->window, vs, VK_WINDOW_WIDTH, VK_WINDOW_HEIGHT);
303
304 XSelectInput(vkWindow->dpy, vkWindow->window, ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask);
305
306 VKSetWindowProperty(vkstate, vkWindow->window, FCITX_WINDOW_DOCK, strWindowName);
307
308 FcitxX11AddXEventHandler(vkstate->owner, VKWindowEventHandler, vkWindow);
309
310 return vkWindow;
311 }
312
VKWindowEventHandler(void * arg,XEvent * event)313 boolean VKWindowEventHandler(void* arg, XEvent* event)
314 {
315 VKWindow* vkWindow = arg;
316 if (event->xany.window == vkWindow->window) {
317 switch (event->type) {
318 case Expose:
319 DrawVKWindow(vkWindow);
320 break;
321 case ButtonPress:
322 switch (event->xbutton.button) {
323 case Button1: {
324 if (!VKMouseKey(vkWindow->owner, event->xbutton.x, event->xbutton.y)) {
325 vkWindow->iVKWindowX = event->xbutton.x;
326 vkWindow->iVKWindowY = event->xbutton.y;
327 VKMouseClick(vkWindow->owner, vkWindow->window, &vkWindow->iVKWindowX, &vkWindow->iVKWindowY);
328 DrawVKWindow(vkWindow);
329 }
330 }
331 break;
332 }
333 break;
334 }
335 return true;
336 }
337
338 return false;
339 }
340
LoadVKImage(VKWindow * vkWindow)341 cairo_surface_t* LoadVKImage(VKWindow* vkWindow)
342 {
343 FcitxVKState* vkstate = vkWindow->owner;
344 boolean fallback = true;
345 char vkimage[] = "keyboard.png";
346 cairo_surface_t *image = FcitxClassicUILoadImage(vkstate->owner,
347 vkimage, &fallback);
348
349 if (image)
350 return image;
351
352 if (!vkWindow->keyboard) {
353 char* path = fcitx_utils_get_fcitx_path_with_filename("pkgdatadir", "skin/default/keyboard.png");
354 if (fcitx_utils_isreg(path)) {
355 vkWindow->keyboard = cairo_image_surface_create_from_png(path);
356 }
357 free(path);
358 }
359 return vkWindow->keyboard;
360 }
361
DisplayVKWindow(VKWindow * vkWindow)362 void DisplayVKWindow(VKWindow* vkWindow)
363 {
364 XMapRaised(vkWindow->dpy, vkWindow->window);
365 }
366
DestroyVKWindow(VKWindow * vkWindow)367 void DestroyVKWindow(VKWindow* vkWindow)
368 {
369 cairo_surface_destroy(vkWindow->surface);
370 XDestroyWindow(vkWindow->dpy, vkWindow->window);
371 }
372
DrawVKWindow(VKWindow * vkWindow)373 void DrawVKWindow(VKWindow* vkWindow)
374 {
375 int i;
376 int iPos;
377 cairo_t *cr;
378 FcitxVKState *vkstate = vkWindow->owner;
379 VKS *vks = vkstate->vks;
380
381 FcitxConfigColor *fontColor;
382 fontColor = FcitxClassicUIGetKeyboardFontColor(vkstate->owner);
383 char **font = FcitxClassicUIGetFont(vkstate->owner);
384
385 if (!fontColor || !font) {
386 fontColor = &blackColor;
387 font = &vkWindow->defaultFont;
388 }
389
390 cr = cairo_create(vkWindow->surface);
391 cairo_surface_t* vkimage = LoadVKImage(vkWindow);
392 if (vkimage) {
393 cairo_set_source_surface(cr, vkimage, 0, 0);
394 } else {
395 cairo_set_source_rgb(cr, 1, 1, 1);
396 }
397 cairo_paint(cr);
398
399 FcitxCairoTextContext* ctc = FcitxCairoTextContextCreate(cr);
400 FcitxCairoTextContextSet(ctc, *font, vkWindow->fontSize, 0);
401 /* 显示字符 */
402 /* 名称 */
403 FcitxCairoTextContextOutputString(ctc, vks[vkstate->iCurrentVK].strName, (VK_WINDOW_WIDTH - FcitxCairoTextContextStringWidth(ctc, vks[vkstate->iCurrentVK].strName)) / 2, 6, fontColor);
404
405 /* 第一排 */
406 iPos = 13;
407 for (i = 0; i < 13; i++) {
408 FcitxCairoTextContextOutputString(ctc, vks[vkstate->iCurrentVK].strSymbol[i][1], iPos, 27, fontColor);
409 FcitxCairoTextContextOutputString(ctc, vks[vkstate->iCurrentVK].strSymbol[i][0], iPos - 5, 40, fontColor);
410 iPos += 24;
411 }
412 /* 第二排 */
413 iPos = 48;
414 for (i = 13; i < 26; i++) {
415 FcitxCairoTextContextOutputString(ctc, vks[vkstate->iCurrentVK].strSymbol[i][1], iPos, 55, fontColor);
416 FcitxCairoTextContextOutputString(ctc, vks[vkstate->iCurrentVK].strSymbol[i][0], iPos - 5, 68, fontColor);
417 iPos += 24;
418 }
419 /* 第三排 */
420 iPos = 55;
421 for (i = 26; i < 37; i++) {
422 FcitxCairoTextContextOutputString(ctc, vks[vkstate->iCurrentVK].strSymbol[i][1], iPos, 83, fontColor);
423 FcitxCairoTextContextOutputString(ctc, vks[vkstate->iCurrentVK].strSymbol[i][0], iPos - 5, 96, fontColor);
424 iPos += 24;
425 }
426
427 /* 第四排 */
428 iPos = 72;
429 for (i = 37; i < 47; i++) {
430 FcitxCairoTextContextOutputString(ctc, vks[vkstate->iCurrentVK].strSymbol[i][1], iPos, 111, fontColor);
431 FcitxCairoTextContextOutputString(ctc, vks[vkstate->iCurrentVK].strSymbol[i][0], iPos - 5, 124, fontColor);
432 iPos += 24;
433 }
434
435 cairo_destroy(cr);
436 cairo_surface_flush(vkWindow->surface);
437 }
438
439 /*
440 * 处理相关鼠标键
441 */
VKMouseKey(FcitxVKState * vkstate,int x,int y)442 boolean VKMouseKey(FcitxVKState* vkstate, int x, int y)
443 {
444 int iIndex = 0;
445 char strKey[3] = { 0, 0, 0};
446 char *pstr = NULL;
447 FcitxInstance* instance = vkstate->owner;
448
449 if (FcitxUIIsInBox(x, y, 1, 1, VK_WINDOW_WIDTH, 16))
450 ChangVK(vkstate);
451 else {
452 if (FcitxInstanceGetCurrentIC(instance) == NULL)
453 return false;
454
455 strKey[1] = '\0';
456 pstr = strKey;
457 if (y >= 28 && y <= 55) { //第一行
458 if (x < 4 || x > 348)
459 return false;
460
461 x -= 4;
462 if (x >= 313 && x <= 344) { //backspace
463 FcitxInstanceForwardKey(instance, FcitxInstanceGetCurrentIC(instance), FCITX_PRESS_KEY, FcitxKey_BackSpace, 0);
464 return true;
465 } else {
466 iIndex = x / 24;
467 if (iIndex > 12) //避免出现错误
468 iIndex = 12;
469 pstr = vkstate->vks[vkstate->iCurrentVK].strSymbol[iIndex][vkstate->bShiftPressed ^ vkstate->bVKCaps];
470 if (vkstate->bShiftPressed) {
471 vkstate->bShiftPressed = false;
472 DrawVKWindow(vkstate->vkWindow);
473 }
474 }
475 } else if (y >= 56 && y <= 83) { //第二行
476 if (x < 4 || x > 350)
477 return false;
478
479 if (x >= 4 && x < 38) { //Tab
480 FcitxInstanceForwardKey(instance, FcitxInstanceGetCurrentIC(instance), FCITX_PRESS_KEY, FcitxKey_Tab, 0);
481 return true;
482 } else {
483 iIndex = 13 + (x - 38) / 24;
484 pstr = vkstate->vks[vkstate->iCurrentVK].strSymbol[iIndex][vkstate->bShiftPressed ^ vkstate->bVKCaps];
485 if (vkstate->bShiftPressed) {
486 vkstate->bShiftPressed = false;
487 DrawVKWindow(vkstate->vkWindow);
488 }
489 }
490 } else if (y >= 84 && y <= 111) { //第三行
491 if (x < 4 || x > 350)
492 return false;
493
494 if (x >= 4 && x < 44) { //Caps
495 //改变大写键状态
496 vkstate->bVKCaps = !vkstate->bVKCaps;
497 pstr = (char *) NULL;
498 DrawVKWindow(vkstate->vkWindow);
499 } else if (x > 308 && x <= 350) //Return
500 strKey[0] = '\n';
501 else {
502 iIndex = 26 + (x - 44) / 24;
503 pstr = vkstate->vks[vkstate->iCurrentVK].strSymbol[iIndex][vkstate->bShiftPressed ^ vkstate->bVKCaps];
504 if (vkstate->bShiftPressed) {
505 vkstate->bShiftPressed = false;
506 DrawVKWindow(vkstate->vkWindow);
507 }
508 }
509 } else if (y >= 112 && y <= 139) { //第四行
510 if (x < 4 || x > 302)
511 return false;
512
513 if (x >= 4 && x < 62) { //SHIFT
514 //改变SHIFT键状态
515 vkstate->bShiftPressed = !vkstate->bShiftPressed;
516 pstr = (char *) NULL;
517 DrawVKWindow(vkstate->vkWindow);
518 } else {
519 iIndex = 37 + (x - 62) / 24;
520 pstr = vkstate->vks[vkstate->iCurrentVK].strSymbol[iIndex][vkstate->bShiftPressed ^ vkstate->bVKCaps];
521 if (vkstate->bShiftPressed) {
522 vkstate->bShiftPressed = false;
523 DrawVKWindow(vkstate->vkWindow);
524 }
525 }
526 } else if (y >= 140 && y <= 162) { //第五行
527 if (x >= 4 && x < 38) { //Ins
528 //改变INS键状态
529 FcitxInstanceForwardKey(instance, FcitxInstanceGetCurrentIC(instance), FCITX_PRESS_KEY, FcitxKey_Insert, 0);
530 return true;
531 } else if (x >= 61 && x < 98) { //DEL
532 FcitxInstanceForwardKey(instance, FcitxInstanceGetCurrentIC(instance), FCITX_PRESS_KEY, FcitxKey_Delete, 0);
533 return true;
534 } else if (x >= 99 && x < 270) //空格
535 strcpy(strKey, " ");
536 else if (x >= 312 && x <= 350) { //ESC
537 SwitchVK(vkstate);
538 pstr = (char *) NULL;
539 } else
540 return false;
541 }
542
543 if (pstr) {
544 FcitxInstanceCommitString(instance, FcitxInstanceGetCurrentIC(instance), pstr);
545 }
546 }
547
548 return true;
549 }
550
551 /*
552 * 读取虚拟键盘映射文件
553 */
LoadVKMapFile(FcitxVKState * vkstate)554 void LoadVKMapFile(FcitxVKState *vkstate)
555 {
556 int i, j;
557 FILE *fp;
558 char *buf = NULL;
559 char *pstr;
560 VKS* vks = vkstate->vks;
561 size_t len;
562
563 for (j = 0; j < VK_MAX; j++) {
564 for (i = 0; i < VK_NUMBERS; i++) {
565 vks[j].strSymbol[i][0][0] = '\0';
566 vks[j].strSymbol[i][1][0] = '\0';
567 }
568 if (vks[j].strName) {
569 free(vks[j].strName);
570 vks[j].strName = NULL;
571 }
572 }
573
574 fp = FcitxXDGGetFileWithPrefix("data", VK_FILE, "r", NULL);
575
576 if (!fp)
577 return;
578
579 vkstate->iVKCount = 0;
580
581 while (getline(&buf, &len, fp) != -1) {
582 pstr = buf;
583 while (*pstr == ' ' || *pstr == '\t')
584 pstr++;
585 if (pstr[0] == '#')
586 continue;
587
588 i = strlen(pstr) - 1;
589 if (pstr[i] == '\n')
590 pstr[i] = '\0';
591 if (!strlen(pstr))
592 continue;
593
594 if (!strcmp(pstr, "[VK]"))
595 vkstate->iVKCount++;
596 else if (!strncmp(pstr, "NAME=", 5))
597 vks[vkstate->iVKCount - 1].strName = strdup(gettext(pstr + 5));
598 else {
599 if (pstr[1] != '=' && !vkstate->iVKCount)
600 continue;
601
602 for (i = 0; i < VK_NUMBERS; i++) {
603 if (vkTable[i] == tolower(pstr[0])) {
604 pstr += 2;
605 while (*pstr == ' ' || *pstr == '\t')
606 pstr++;
607
608 if (!(*pstr))
609 break;
610
611 j = 0;
612 while (*pstr && (*pstr != ' ' && *pstr != '\t'))
613 vks[vkstate->iVKCount - 1].strSymbol[i][0][j++] = *pstr++;
614 vks[vkstate->iVKCount - 1].strSymbol[i][0][j] = '\0';
615
616 j = 0;
617 while (*pstr == ' ' || *pstr == '\t')
618 pstr++;
619 if (*pstr) {
620 while (*pstr && (*pstr != ' ' && *pstr != '\t'))
621 vks[vkstate->iVKCount - 1].strSymbol[i][1][j++] = *pstr++;
622 vks[vkstate->iVKCount - 1].strSymbol[i][1][j] = '\0';
623 }
624
625 break;
626 }
627 }
628 }
629 }
630
631 if (buf)
632 free(buf);
633
634 fclose(fp);
635 }
636
637 /*
638 * 根据字符查找符号
639 */
VKGetSymbol(FcitxVKState * vkstate,char cChar)640 char *VKGetSymbol(FcitxVKState *vkstate, char cChar)
641 {
642 int i;
643
644 for (i = 0; i < VK_NUMBERS; i++) {
645 if (MyToUpper(vkTable[i]) == cChar)
646 return vkstate->vks[vkstate->iCurrentVK].strSymbol[i][1];
647 if (MyToLower(vkTable[i]) == cChar)
648 return vkstate->vks[vkstate->iCurrentVK].strSymbol[i][0];
649 }
650
651 return NULL;
652 }
653
654 /*
655 * 上/下档键字符转换,以取代toupper和tolower
656 */
MyToUpper(int iChar)657 int MyToUpper(int iChar)
658 {
659 const char *pstr;
660
661 pstr = strCharTable;
662 while (*pstr) {
663 if (*pstr == iChar)
664 return *(pstr + 1);
665 pstr += 2;
666 }
667
668 return toupper(iChar);
669 }
670
MyToLower(int iChar)671 int MyToLower(int iChar)
672 {
673 const char *pstr;
674
675 pstr = strCharTable + 1;
676 for (;;) {
677 if (*pstr == iChar)
678 return *(pstr - 1);
679 if (!(*(pstr + 1)))
680 break;
681 pstr += 2;
682 }
683
684 return tolower(iChar);
685 }
686
ChangVK(FcitxVKState * vkstate)687 void ChangVK(FcitxVKState* vkstate)
688 {
689 vkstate->iCurrentVK++;
690 if (vkstate->iCurrentVK == vkstate->iVKCount)
691 vkstate->iCurrentVK = 0;
692
693 vkstate->bVKCaps = false;
694 vkstate->bShiftPressed = false;
695
696 DrawVKWindow(vkstate->vkWindow);
697 }
698
DoVKInput(FcitxVKState * vkstate,KeySym sym,int state)699 INPUT_RETURN_VALUE DoVKInput(FcitxVKState* vkstate, KeySym sym, int state)
700 {
701 char *pstr = NULL;
702 FcitxInputState *input = FcitxInstanceGetInputState(vkstate->owner);
703
704 if (FcitxHotkeyIsHotKeySimple(sym, state))
705 pstr = VKGetSymbol(vkstate, sym);
706 if (!pstr)
707 return IRV_TO_PROCESS;
708 else {
709 strcpy(FcitxInputStateGetOutputString(input), pstr);
710 return IRV_COMMIT_STRING;
711 }
712 }
713
SwitchVK(FcitxVKState * vkstate)714 void SwitchVK(FcitxVKState *vkstate)
715 {
716 FcitxInstance* instance = vkstate->owner;
717 if (vkstate->vkWindow == NULL)
718 vkstate->vkWindow = CreateVKWindow(vkstate);
719 VKWindow *vkWindow = vkstate->vkWindow;
720 if (!vkstate->iVKCount)
721 return;
722
723 vkstate->bVK = !vkstate->bVK;
724
725 if (vkstate->bVK) {
726 int x, y;
727 FcitxRect rect;
728 int icx = 0, icy = 0, w = 0, h = 0;
729 FcitxInputContext* ic = FcitxInstanceGetCurrentIC(instance);
730 FcitxInstanceGetWindowRect(instance, ic, &icx, &icy, &w, &h);
731 FcitxX11GetScreenGeometry(instance, &icx, &icy, &rect);
732 x = (rect.x1 + rect.x2) / 2 - VK_WINDOW_WIDTH / 2;
733 y = rect.y1 + 40;
734
735 if ((y + VK_WINDOW_HEIGHT) >= rect.y2)
736 y = rect.y2 - VK_WINDOW_HEIGHT - 2;
737 if (y < rect.y1)
738 y = rect.y1;
739 if ((x + VK_WINDOW_WIDTH) >= rect.x2)
740 x = rect.x2 - VK_WINDOW_WIDTH - 1;
741 if (x < rect.x1)
742 x = rect.x1;
743
744
745 XMoveWindow(vkWindow->dpy, vkWindow->window, x, y);
746 DisplayVKWindow(vkWindow);
747 FcitxUICloseInputWindow(instance);
748
749 if (ic && FcitxInstanceGetCurrentState(instance) == IS_CLOSED)
750 FcitxInstanceEnableIM(instance, ic, true);
751 } else {
752 XUnmapWindow(vkWindow->dpy, vkWindow->window);
753 FcitxInstanceCleanInputWindow(instance);
754 FcitxUIUpdateInputWindow(instance);
755 }
756 }
757
758 /*
759 *选择指定index的虚拟键盘
760 */
SelectVK(FcitxVKState * vkstate,int vkidx)761 void SelectVK(FcitxVKState* vkstate, int vkidx)
762 {
763 vkstate->bVK = false;
764 vkstate->iCurrentVK = vkidx;
765 FcitxUIUpdateStatus(vkstate->owner, "vk");
766 if (vkstate->vkWindow)
767 DrawVKWindow(vkstate->vkWindow);
768 }
769
770 void
VKInitWindowAttribute(FcitxVKState * vkstate,Visual ** vs,Colormap * cmap,XSetWindowAttributes * attrib,unsigned long * attribmask,int * depth)771 VKInitWindowAttribute(FcitxVKState* vkstate, Visual ** vs, Colormap * cmap,
772 XSetWindowAttributes * attrib,
773 unsigned long *attribmask, int *depth)
774 {
775 FcitxX11InitWindowAttribute(vkstate->owner,
776 vs, cmap, attrib, attribmask, depth);
777 }
778
VKFindARGBVisual(FcitxVKState * vkstate)779 Visual * VKFindARGBVisual(FcitxVKState* vkstate)
780 {
781 return FcitxX11FindARGBVisual(vkstate->owner);
782 }
783
VKSetWindowProperty(FcitxVKState * vkstate,Window window,FcitxXWindowType type,char * windowTitle)784 void VKSetWindowProperty(FcitxVKState* vkstate, Window window, FcitxXWindowType type, char *windowTitle)
785 {
786 FcitxX11SetWindowProp(vkstate->owner, &window, &type, windowTitle);
787 }
788
789 boolean
VKMouseClick(FcitxVKState * vkstate,Window window,int * x,int * y)790 VKMouseClick(FcitxVKState* vkstate, Window window, int *x, int *y)
791 {
792 boolean bMoved = false;
793 FcitxX11MouseClick(vkstate->owner, &window, x, y, &bMoved);
794 return bMoved;
795 }
796
ReloadVK(void * arg)797 void ReloadVK(void* arg)
798 {
799 FcitxVKState* vkstate = (FcitxVKState*)arg;
800 LoadVKMapFile(vkstate);
801 }
802
803
804 // kate: indent-mode cstyle; space-indent on; indent-width 0;
805