1 /*
2
3 Copyright (c) 2003-2013 uim Project https://github.com/uim/uim
4
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 3. Neither the name of authors nor the names of its contributors
17 may be used to endorse or promote products derived from this software
18 without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 SUCH DAMAGE.
31 */
32 #include <config.h>
33
34 #include "quiminputcontext_compose.h"
35
36 #include <cctype>
37 #include <cerrno>
38 #include <clocale>
39 #include <cstdio>
40 #include <cstdlib>
41 #include <cstring>
42 #include <sys/stat.h>
43 #include <sys/param.h>
44 #ifdef HAVE_LANGINFO_CODESET
45 #include <langinfo.h>
46 #endif
47
48 #include <QtCore/QTextCodec>
49 #if QT_VERSION >= 0x050000
50 # undef Expose
51 #endif
52 #include <QtGui/QKeyEvent>
53
54 #include <X11/Xlib.h>
55 #include <X11/Xutil.h>
56 #include <X11/keysym.h>
57
58 #include "uim/uim.h"
59
60 #if QT_VERSION < 0x050000
61 #include "quiminputcontext.h"
62 #else
63 #include <quimplatforminputcontext.h>
64 #endif
65
66 static const char COMPOSE_FILE[] = "Compose";
67 static const char COMPOSE_DIR_FILE[] = "X11/locale/compose.dir";
68 static const char XLOCALE_DIR[] = "X11/locale";
69 static const char FALLBACK_XLIB_DIR[] = "/usr/X11R6/lib";
70 #define XLC_BUFSIZE 256
iscomment(char ch)71 static inline bool iscomment(char ch)
72 {
73 return ch == '#' || ch == '\0';
74 }
75
76
77 static int parse_line(char *line, char **argv, int argsize);
78 static unsigned int KeySymToUcs4(KeySym keysym);
79
80 #if QT_VERSION < 0x050000
Compose(DefTree * top,QUimInputContext * ic)81 Compose::Compose(DefTree *top, QUimInputContext *ic)
82 #else
83 Compose::Compose(DefTree *top, QUimPlatformInputContext *ic)
84 #endif
85 {
86 m_ic = ic;
87 m_composed = 0;
88 m_top = top;
89 m_context = top;
90 }
91
~Compose()92 Compose::~Compose()
93 {
94 }
95
handle_qkey(const QKeyEvent * event)96 bool Compose::handle_qkey(const QKeyEvent *event)
97 {
98 int qstate = event->modifiers();
99 unsigned int xstate = 0;
100 if (qstate & Qt::ShiftModifier)
101 xstate |= ShiftMask;
102 if (qstate & Qt::ControlModifier)
103 xstate |= ControlMask;
104 if (qstate & Qt::AltModifier)
105 xstate |= Mod1Mask; // XXX
106 if (qstate & Qt::MetaModifier)
107 xstate |= Mod1Mask; // XXX
108
109 int qkey = event->key();
110 unsigned int xkeysym;
111 if (qkey >= 0x20 && qkey <= 0xff) {
112 if (isascii(qkey) && isprint(qkey)) {
113 QString str = event->text();
114 int ascii = str.length() ? str.unicode()->toLatin1() : 0;
115 if (isalpha(ascii))
116 xkeysym = ascii;
117 else
118 if ((qstate & Qt::ControlModifier) &&
119 (ascii >= 0x01 && ascii <= 0x1a))
120 if (qstate & Qt::ShiftModifier)
121 xkeysym = ascii + 0x40;
122 else
123 xkeysym = ascii + 0x60;
124 else
125 xkeysym = qkey;
126 } else {
127 xkeysym = qkey;
128 }
129 } else if (qkey >= Qt::Key_Dead_Grave && qkey <= Qt::Key_Dead_Horn) {
130 xkeysym = qkey + 0xec00 - 0x01000000;
131 } else {
132 switch (qkey) {
133 case Qt::Key_Escape: xkeysym = XK_Escape; break;
134 case Qt::Key_Tab: xkeysym = XK_Tab; break;
135 case Qt::Key_Backspace: xkeysym = XK_BackSpace; break;
136 case Qt::Key_Return: xkeysym = XK_Return; break;
137 case Qt::Key_Insert: xkeysym = XK_Insert; break;
138 case Qt::Key_Delete: xkeysym = XK_Delete; break;
139 case Qt::Key_Pause: xkeysym = XK_Pause; break;
140 case Qt::Key_Print: xkeysym = XK_Print; break;
141 case Qt::Key_SysReq: xkeysym = XK_Sys_Req; break;
142 case Qt::Key_Clear: xkeysym = XK_Clear; break;
143 case Qt::Key_Home: xkeysym = XK_Home; break;
144 case Qt::Key_End: xkeysym = XK_End; break;
145 case Qt::Key_Left: xkeysym = XK_Left; break;
146 case Qt::Key_Up: xkeysym = XK_Up; break;
147 case Qt::Key_Right: xkeysym = XK_Right; break;
148 case Qt::Key_Down: xkeysym = XK_Down; break;
149 case Qt::Key_PageUp: xkeysym = XK_Prior; break;
150 case Qt::Key_PageDown: xkeysym = XK_Next; break;
151 case Qt::Key_Shift: xkeysym = XK_Shift_L; break;
152 case Qt::Key_Control: xkeysym = XK_Control_L; break;
153 case Qt::Key_Meta: xkeysym = XK_Meta_L; break;
154 case Qt::Key_Alt: xkeysym = XK_Alt_L; break;
155 case Qt::Key_CapsLock: xkeysym = XK_Caps_Lock; break;
156 case Qt::Key_NumLock: xkeysym = XK_Num_Lock; break;
157 case Qt::Key_ScrollLock: xkeysym = XK_Scroll_Lock; break;
158 case Qt::Key_F1: xkeysym = XK_F1; break;
159 case Qt::Key_F2: xkeysym = XK_F2; break;
160 case Qt::Key_F3: xkeysym = XK_F3; break;
161 case Qt::Key_F4: xkeysym = XK_F4; break;
162 case Qt::Key_F5: xkeysym = XK_F5; break;
163 case Qt::Key_F6: xkeysym = XK_F6; break;
164 case Qt::Key_F7: xkeysym = XK_F7; break;
165 case Qt::Key_F8: xkeysym = XK_F8; break;
166 case Qt::Key_F9: xkeysym = XK_F9; break;
167 case Qt::Key_F10: xkeysym = XK_F10; break;
168 case Qt::Key_F11: xkeysym = XK_F11; break;
169 case Qt::Key_F12: xkeysym = XK_F12; break;
170 case Qt::Key_F13: xkeysym = XK_F13; break;
171 case Qt::Key_F14: xkeysym = XK_F14; break;
172 case Qt::Key_F15: xkeysym = XK_F15; break;
173 case Qt::Key_F16: xkeysym = XK_F16; break;
174 case Qt::Key_F17: xkeysym = XK_F17; break;
175 case Qt::Key_F18: xkeysym = XK_F18; break;
176 case Qt::Key_F19: xkeysym = XK_F19; break;
177 case Qt::Key_F20: xkeysym = XK_F20; break;
178 case Qt::Key_F21: xkeysym = XK_F21; break;
179 case Qt::Key_F22: xkeysym = XK_F22; break;
180 case Qt::Key_F23: xkeysym = XK_F23; break;
181 case Qt::Key_F24: xkeysym = XK_F24; break;
182 case Qt::Key_F25: xkeysym = XK_F25; break;
183 case Qt::Key_F26: xkeysym = XK_F26; break;
184 case Qt::Key_F27: xkeysym = XK_F27; break;
185 case Qt::Key_F28: xkeysym = XK_F28; break;
186 case Qt::Key_F29: xkeysym = XK_F29; break;
187 case Qt::Key_F30: xkeysym = XK_F30; break;
188 case Qt::Key_F31: xkeysym = XK_F31; break;
189 case Qt::Key_F32: xkeysym = XK_F32; break;
190 case Qt::Key_F33: xkeysym = XK_F33; break;
191 case Qt::Key_F34: xkeysym = XK_F34; break;
192 case Qt::Key_F35: xkeysym = XK_F35; break;
193 case Qt::Key_Super_L: xkeysym = XK_Super_L; break;
194 case Qt::Key_Super_R: xkeysym = XK_Super_R; break;
195 case Qt::Key_Menu: xkeysym = XK_Menu; break;
196 case Qt::Key_Hyper_L: xkeysym = XK_Hyper_L; break;
197 case Qt::Key_Hyper_R: xkeysym = XK_Hyper_R; break;
198 case Qt::Key_Help: xkeysym = XK_Help; break;
199 case Qt::Key_Multi_key: xkeysym = XK_Multi_key; break;
200 case Qt::Key_Codeinput: xkeysym = XK_Codeinput; break;
201 case Qt::Key_SingleCandidate: xkeysym = XK_SingleCandidate; break;
202 case Qt::Key_PreviousCandidate: xkeysym = XK_PreviousCandidate; break;
203 case Qt::Key_Mode_switch: xkeysym = XK_Mode_switch; break;
204 case Qt::Key_Kanji: xkeysym = XK_Kanji; break;
205 case Qt::Key_Muhenkan: xkeysym = XK_Muhenkan; break;
206 case Qt::Key_Henkan: xkeysym = XK_Henkan_Mode; break;
207 case Qt::Key_Romaji: xkeysym = XK_Romaji; break;
208 case Qt::Key_Hiragana: xkeysym = XK_Hiragana; break;
209 case Qt::Key_Katakana: xkeysym = XK_Katakana; break;
210 case Qt::Key_Hiragana_Katakana: xkeysym = XK_Hiragana_Katakana; break;
211 case Qt::Key_Zenkaku: xkeysym = XK_Zenkaku; break;
212 case Qt::Key_Hankaku: xkeysym = XK_Hankaku; break;
213 case Qt::Key_Zenkaku_Hankaku: xkeysym = XK_Zenkaku_Hankaku; break;
214 case Qt::Key_Touroku: xkeysym = XK_Touroku; break;
215 case Qt::Key_Massyo: xkeysym = XK_Massyo; break;
216 case Qt::Key_Kana_Lock: xkeysym = XK_Kana_Lock; break;
217 case Qt::Key_Kana_Shift: xkeysym = XK_Kana_Shift; break;
218 case Qt::Key_Eisu_Shift: xkeysym = XK_Eisu_Shift; break;
219 case Qt::Key_Eisu_toggle: xkeysym = XK_Eisu_toggle; break;
220
221 case Qt::Key_Hangul: xkeysym = XK_Hangul; break;
222 case Qt::Key_Hangul_Start: xkeysym = XK_Hangul_Start; break;
223 case Qt::Key_Hangul_End: xkeysym = XK_Hangul_End; break;
224 case Qt::Key_Hangul_Jamo: xkeysym = XK_Hangul_Jamo; break;
225 case Qt::Key_Hangul_Romaja: xkeysym = XK_Hangul_Romaja; break;
226 case Qt::Key_Hangul_Jeonja: xkeysym = XK_Hangul_Jeonja; break;
227 case Qt::Key_Hangul_Banja: xkeysym = XK_Hangul_Banja; break;
228 case Qt::Key_Hangul_PreHanja: xkeysym = XK_Hangul_PreHanja; break;
229 case Qt::Key_Hangul_PostHanja: xkeysym = XK_Hangul_PostHanja; break;
230 case Qt::Key_Hangul_Special: xkeysym = XK_Hangul_Special; break;
231 default: xkeysym = qkey; break;
232 }
233 }
234
235 int type = event->type();
236 bool press = (type == QEvent::KeyPress);
237 return handleKey(xkeysym, xstate, press);
238 }
239
handleKey(KeySym xkeysym,int xkeystate,bool is_push)240 bool Compose::handleKey(KeySym xkeysym, int xkeystate, bool is_push)
241 {
242 if ((is_push == false) || m_top == 0)
243 return false;
244
245 if (IsModifierKey(xkeysym))
246 return false;
247
248 DefTree *p;
249 for (p = m_context; p ; p = p->next) {
250 if (((xkeystate & p->modifier_mask) == p->modifier) &&
251 (xkeysym == p->keysym)) {
252 break;
253 }
254 }
255
256 if (p) { // Matched
257 if (p->succession) { // Intermediate
258 m_context = p->succession;
259 return true;
260 } else { // Terminate (reached to leaf)
261 m_composed = p;
262 // commit string here
263 m_ic->commitString(QString::fromUtf8(m_composed->utf8));
264 // initialize internal state for next key sequence
265 m_context = m_top;
266 return true;
267 }
268 } else { // Unmatched
269 if (m_context == m_top)
270 return false;
271 // Error (Sequence Unmatch occurred)
272 m_context = m_top;
273 return true;
274 }
275 }
276
reset()277 void Compose::reset()
278 {
279 m_context = m_top;
280 m_composed = 0;
281 }
282
283 static int
nextch(FILE * fp,int * lastch)284 nextch(FILE *fp, int *lastch)
285 {
286 int c;
287
288 if (*lastch != 0) {
289 c = *lastch;
290 *lastch = 0;
291 } else {
292 c = getc(fp);
293 if (c == '\\') {
294 c = getc(fp);
295 if (c == '\n') {
296 c = getc(fp);
297 } else {
298 ungetc(c, fp);
299 c = '\\';
300 }
301 }
302 }
303 return(c);
304 }
305
306 static void
putbackch(int c,int * lastch)307 putbackch(int c, int *lastch)
308 {
309 *lastch = c;
310 }
311
312
313 static const int ENDOFFILE = 0;
314 static const int ENDOFLINE = 1;
315 static const int COLON = 2;
316 static const int LESS = 3;
317 static const int GREATER = 4;
318 static const int EXCLAM = 5;
319 static const int TILDE = 6;
320 static const int STRING = 7;
321 static const int KEY = 8;
322 static const int ERROR = 9;
323
324
325 #ifndef isalnum
isalnum(char c)326 static inline bool isalnum(char c)
327 {
328 return ('0' <= c && c <= '9') ||
329 ('A' <= c && c <= 'Z') ||
330 ('a' <= c && c <= 'z');
331 }
332 #endif
333
334 static int
nexttoken(FILE * fp,char ** tokenbuf,int * lastch,size_t * buflen)335 nexttoken(FILE *fp, char **tokenbuf, int *lastch, size_t *buflen)
336 {
337 int c;
338 while ((c = nextch(fp, lastch)) == ' ' || c == '\t') {
339 }
340
341 int token;
342 char *p;
343 int i;
344 size_t len = 0;
345 switch (c) {
346 case EOF:
347 token = ENDOFFILE;
348 break;
349 case '\n':
350 token = ENDOFLINE;
351 break;
352 case '<':
353 token = LESS;
354 break;
355 case '>':
356 token = GREATER;
357 break;
358 case ':':
359 token = COLON;
360 break;
361 case '!':
362 token = EXCLAM;
363 break;
364 case '~':
365 token = TILDE;
366 break;
367 case '"':
368 p = *tokenbuf;
369 while ((c = nextch(fp, lastch)) != '"') {
370 if (len >= *buflen - 1) {
371 *buflen += BUFSIZ;
372 *tokenbuf = (char *)realloc(*tokenbuf, *buflen);
373 p = *tokenbuf + len;
374 }
375 if (c == '\n' || c == EOF) {
376 putbackch(c, lastch);
377 token = ERROR;
378 goto string_error;
379 } else if (c == '\\') {
380 c = nextch(fp, lastch);
381 switch (c) {
382 case '\\':
383 case '"':
384 *p++ = static_cast<char>(c);
385 len++;
386 break;
387 case 'n':
388 *p++ = '\n';
389 len++;
390 break;
391 case 'r':
392 *p++ = '\r';
393 len++;
394 break;
395 case 't':
396 *p++ = '\t';
397 len++;
398 break;
399 case '0':
400 case '1':
401 case '2':
402 case '3':
403 case '4':
404 case '5':
405 case '6':
406 case '7':
407 i = c - '0';
408 c = nextch(fp, lastch);
409 for (int j = 0; j < 2 && c >= '0' && c <= '7'; j++) {
410 i <<= 3;
411 i += c - '0';
412 c = nextch(fp, lastch);
413 }
414 putbackch(c, lastch);
415 *p++ = static_cast<char>(i);
416 len++;
417 break;
418 case 'X':
419 case 'x':
420 i = 0;
421 int j;
422 for (j = 0; j < 2; j++) {
423 c = nextch(fp, lastch);
424 i <<= 4;
425 if (c >= '0' && c <= '9') {
426 i += c - '0';
427 } else if (c >= 'A' && c <= 'F') {
428 i += c - 'A' + 10;
429 } else if (c >= 'a' && c <= 'f') {
430 i += c - 'a' + 10;
431 } else {
432 putbackch(c, lastch);
433 i >>= 4;
434 break;
435 }
436 }
437 if (j == 0) {
438 token = ERROR;
439 goto string_error;
440 }
441 *p++ = static_cast<char>(i);
442 len++;
443 break;
444 case EOF:
445 putbackch(c, lastch);
446 token = ERROR;
447 goto string_error;
448 default:
449 *p++ = static_cast<char>(c);
450 len++;
451 break;
452 }
453 } else {
454 *p++ = static_cast<char>(c);
455 len++;
456 }
457 }
458 *p = '\0';
459 token = STRING;
460 break;
461 case '#':
462 while ((c = nextch(fp, lastch)) != '\n' && c != EOF) {
463 }
464 if (c == '\n') {
465 token = ENDOFLINE;
466 } else {
467 token = ENDOFFILE;
468 }
469 break;
470 default:
471 if (isalnum(c) || c == '_' || c == '-') {
472 if (len >= *buflen - 1) {
473 *buflen += BUFSIZ;
474 *tokenbuf = (char *)realloc(*tokenbuf, *buflen);
475 }
476 p = *tokenbuf;
477 *p++ = static_cast<char>(c);
478 len++;
479 c = nextch(fp, lastch);
480 while (isalnum(c) || c == '_' || c == '-') {
481 if (len >= *buflen - 1) {
482 *buflen += BUFSIZ;
483 *tokenbuf = (char *)realloc(*tokenbuf, *buflen);
484 p = *tokenbuf + len;
485 }
486 *p++ = static_cast<char>(c);
487 len++;
488 c = nextch(fp, lastch);
489 }
490 *p = '\0';
491 putbackch(c, lastch);
492 token = KEY;
493 } else {
494 token = ERROR;
495 }
496 break;
497 }
498 string_error:
499 return(token);
500 }
501
502 static long
modmask(char * name)503 modmask(char *name)
504 {
505 struct _modtbl {
506 const char *name;
507 long mask;
508 };
509
510 static struct _modtbl tbl[] = {
511 { "Ctrl", ControlMask },
512 { "Lock", LockMask },
513 { "Caps", LockMask },
514 { "Shift", ShiftMask },
515 { "Alt", Mod1Mask },
516 { "Meta", Mod1Mask },
517 { 0, 0 }};
518
519 long mask = 0;
520 for (struct _modtbl *p = tbl; p->name != 0; p++) {
521 if (strcmp(name, p->name) == 0) {
522 mask = p->mask;
523 break;
524 }
525 }
526 return(mask);
527 }
528
529 #if defined(Q_WS_X11)
530 int
TransFileName(char * transname,const char * name,size_t len)531 QUimInputContext::TransFileName(char *transname, const char *name, size_t len)
532 {
533 char *home = 0;
534 char lcCompose[MAXPATHLEN];
535 const char *i = name;
536 char ret[MAXPATHLEN];
537 char *j = ret;
538 lcCompose[0] = ret[0] = '\0';
539 while (*i && j - ret < MAXPATHLEN - 1) {
540 if (*i == '%') {
541 i++;
542 switch (*i) {
543 case '%':
544 *j++ = '%';
545 break;
546 case 'H':
547 home = getenv("HOME");
548 if (home) {
549 strlcat(ret, home, sizeof(ret));
550 j += strlen(home);
551 }
552 break;
553 case 'L':
554 get_compose_filename(lcCompose, sizeof(lcCompose));
555 if (lcCompose[0] != '\0') {
556 strlcat(ret, lcCompose, sizeof(ret));
557 j += strlen(lcCompose);
558 }
559 break;
560 }
561 i++;
562 } else {
563 *j++ = *i++;
564 }
565 *j = '\0';
566 }
567 strlcpy(transname, ret, len);
568
569 return 1;
570 }
571
572 #ifndef MB_LEN_MAX
573 #define MB_LEN_MAX 6
574 #endif
575
576 const char *
get_encoding()577 QUimInputContext::get_encoding()
578 {
579 #if 0
580 // starting from Qt 4.2.0, QTextCodec::codecForLocale()->name()
581 // returns "System"
582 QTextCodec *codec = QTextCodec::codecForLocale();
583
584 return codec->name();
585 #else
586
587 #ifdef HAVE_LANGINFO_CODESET
588 return nl_langinfo(CODESET);
589 #else
590 char *p = setlocale(LC_CTYPE, 0);
591 if (p)
592 p = strchr(p, '.');
593
594 return p ? p + 1 : "UTF-8";
595 #endif
596
597 #endif
598 }
599
600 int
get_lang_region(char * locale,size_t len)601 QUimInputContext::get_lang_region(char *locale, size_t len)
602 {
603 strlcpy(locale, setlocale(LC_CTYPE, 0), len);
604 if (locale[0] == '\0') {
605 return 0;
606 }
607
608 char *p = strrchr(locale, '.');
609 if (p)
610 *p = '\0';
611
612 return 1;
613 }
614
615 int
get_mb_string(char * buf,unsigned int ks)616 QUimInputContext::get_mb_string(char *buf, unsigned int ks)
617 {
618 unsigned int ucs = KeySymToUcs4(ks);
619 QString qs = QString(QChar(ucs));
620 const char *mb = qs.toLocal8Bit().data();
621 if (!mb)
622 return 0;
623 int len = strlen(mb);
624 strlcpy(buf, mb, MB_LEN_MAX + 1);
625
626 return len;
627 }
628
629 static const unsigned AllMask = (ShiftMask | LockMask | ControlMask | Mod1Mask);
630 #define SEQUENCE_MAX 10
631
632 int
parse_compose_line(FILE * fp,char ** tokenbuf,size_t * buflen)633 QUimInputContext::parse_compose_line(FILE *fp, char **tokenbuf, size_t *buflen)
634 {
635 struct DefBuffer {
636 unsigned modifier_mask;
637 unsigned modifier;
638 KeySym keysym;
639 };
640
641 int token;
642 int lastch = 0;
643 do {
644 token = nexttoken(fp, tokenbuf, &lastch, buflen);
645 } while (token == ENDOFLINE);
646
647 if (token == ENDOFFILE) {
648 return(-1);
649 }
650
651 unsigned modifier_mask;
652 unsigned modifier;
653 unsigned tmp;
654 KeySym keysym = NoSymbol;
655 Bool exclam;
656 Bool tilde;
657 KeySym rhs_keysym = 0;
658 char *rhs_string_mb;
659 int l;
660 char local_mb_buf[MB_LEN_MAX + 1];
661 struct DefBuffer buf[SEQUENCE_MAX];
662 int n = 0;
663
664 DefTree **top = &mTreeTop;
665 DefTree *p = 0;
666 do {
667 if ((token == KEY) && (strcmp("include", *tokenbuf) == 0)) {
668 char filename[MAXPATHLEN];
669 FILE *infp;
670 token = nexttoken(fp, tokenbuf, &lastch, buflen);
671 if (token != KEY && token != STRING)
672 goto error;
673
674 if (!TransFileName(filename, *tokenbuf, sizeof(filename)) || filename[0] == '\0')
675 goto error;
676 infp = fopen(filename, "r");
677 if (infp == 0)
678 goto error;
679 ParseComposeStringFile(infp);
680 fclose(infp);
681 return 0;
682 } else if ((token == KEY) && (strcmp("None", *tokenbuf) == 0)) {
683 modifier = 0;
684 modifier_mask = AllMask;
685 token = nexttoken(fp, tokenbuf, &lastch, buflen);
686 } else {
687 modifier_mask = modifier = 0;
688 exclam = False;
689 if (token == EXCLAM) {
690 exclam = True;
691 token = nexttoken(fp, tokenbuf, &lastch, buflen);
692 }
693 while (token == TILDE || token == KEY) {
694 tilde = False;
695 if (token == TILDE) {
696 tilde = True;
697 token = nexttoken(fp, tokenbuf, &lastch, buflen);
698 if (token != KEY)
699 goto error;
700 }
701 tmp = modmask(*tokenbuf);
702 if (!tmp) {
703 goto error;
704 }
705 modifier_mask |= tmp;
706 if (tilde) {
707 modifier &= ~tmp;
708 } else {
709 modifier |= tmp;
710 }
711 token = nexttoken(fp, tokenbuf, &lastch, buflen);
712 }
713 if (exclam) {
714 modifier_mask = AllMask;
715
716 }
717 }
718
719 if (token != LESS) {
720 goto error;
721 }
722
723 token = nexttoken(fp, tokenbuf, &lastch, buflen);
724 if (token != KEY) {
725 goto error;
726 }
727
728 token = nexttoken(fp, tokenbuf, &lastch, buflen);
729 if (token != GREATER) {
730 goto error;
731 }
732
733 keysym = XStringToKeysym(*tokenbuf);
734 if (keysym == NoSymbol) {
735 goto error;
736 }
737
738 buf[n].keysym = keysym;
739 buf[n].modifier = modifier;
740 buf[n].modifier_mask = modifier_mask;
741 n++;
742 if (n >= SEQUENCE_MAX)
743 goto error;
744 token = nexttoken(fp, tokenbuf, &lastch, buflen);
745 } while (token != COLON);
746
747 token = nexttoken(fp, tokenbuf, &lastch, buflen);
748 if (token == STRING) {
749 if ((rhs_string_mb = (char *)malloc(strlen(*tokenbuf) + 1)) == 0)
750 goto error;
751 strcpy(rhs_string_mb, *tokenbuf);
752 token = nexttoken(fp, tokenbuf, &lastch, buflen);
753 if (token == KEY) {
754 rhs_keysym = XStringToKeysym(*tokenbuf);
755 if (rhs_keysym == NoSymbol) {
756 free(rhs_string_mb);
757 goto error;
758 }
759 token = nexttoken(fp, tokenbuf, &lastch, buflen);
760 }
761 if (token != ENDOFLINE && token != ENDOFFILE) {
762 free(rhs_string_mb);
763 goto error;
764 }
765 } else if (token == KEY) {
766 rhs_keysym = XStringToKeysym(*tokenbuf);
767 if (rhs_keysym == NoSymbol) {
768 goto error;
769 }
770 token = nexttoken(fp, tokenbuf, &lastch, buflen);
771 if (token != ENDOFLINE && token != ENDOFFILE) {
772 goto error;
773 }
774
775 l = get_mb_string(local_mb_buf, rhs_keysym);
776 if (l == 0) {
777 rhs_string_mb = (char *)malloc(1);
778 } else {
779 rhs_string_mb = (char *)malloc(l + 1);
780 }
781 if (rhs_string_mb == 0) {
782 goto error;
783 }
784 memcpy(rhs_string_mb, local_mb_buf, l);
785 rhs_string_mb[l] = '\0';
786 } else {
787 goto error;
788 }
789
790 for (int i = 0; i < n; i++) {
791 for (p = *top; p; p = p->next) {
792 if (buf[i].keysym == p->keysym &&
793 buf[i].modifier == p->modifier &&
794 buf[i].modifier_mask == p->modifier_mask) {
795 break;
796 }
797 }
798 if (p) {
799 top = &p->succession;
800 } else {
801 if ((p = (DefTree*)malloc(sizeof(DefTree))) == 0) {
802 free(rhs_string_mb);
803 goto error;
804 }
805 p->keysym = buf[i].keysym;
806 p->modifier = buf[i].modifier;
807 p->modifier_mask = buf[i].modifier_mask;
808 p->succession = 0;
809 p->next = *top;
810 p->mb = 0;
811 p->utf8 = 0;
812 p->ks = NoSymbol;
813 *top = p;
814 top = &p->succession;
815 }
816 }
817
818 free(p->mb);
819 p->mb = rhs_string_mb;
820 free(p->utf8);
821 {
822 QTextCodec *codec = QTextCodec::codecForLocale();
823 QString qs = codec->toUnicode(rhs_string_mb);
824 char *rhs_string_utf8 = strdup(qs.toUtf8().data());
825 p->utf8 = rhs_string_utf8;
826 }
827 p->ks = rhs_keysym;
828 return n;
829 error:
830 while (token != ENDOFLINE && token != ENDOFFILE) {
831 token = nexttoken(fp, tokenbuf, &lastch, buflen);
832 }
833 return 0;
834 }
835
836 void
FreeComposeTree(DefTree * top)837 QUimInputContext::FreeComposeTree(DefTree *top)
838 {
839 if (!top)
840 return;
841
842 if (top->succession)
843 FreeComposeTree(top->succession);
844 if (top->next)
845 FreeComposeTree(top->next);
846 free(top->mb);
847 free(top->utf8);
848 free(top);
849 }
850
851 void
ParseComposeStringFile(FILE * fp)852 QUimInputContext::ParseComposeStringFile(FILE *fp)
853 {
854 char *tbp, *p[1];
855 struct stat st;
856 size_t buflen = BUFSIZ;
857
858 if (fstat(fileno(fp), &st) != -1 && S_ISREG(st.st_mode) &&
859 st.st_size > 0) {
860
861 tbp = (char *)malloc(buflen);
862 p[0] = tbp;
863 if (tbp != 0) {
864 while (parse_compose_line(fp, p, &buflen) >= 0) {
865 }
866 free(p[0]);
867 }
868 }
869 }
870
create_compose_tree()871 void QUimInputContext::create_compose_tree()
872 {
873 char *compose_env = getenv("XCOMPOSEFILE");
874 char name[MAXPATHLEN];
875 name[0] = '\0';
876 FILE *fp = 0;
877 if (compose_env != 0) {
878 strlcpy(name, compose_env, sizeof(name));
879 } else {
880 char *home = getenv("HOME");
881 if (home != 0) {
882 snprintf(name, sizeof(name), "%s/.XCompose", home);
883 fp = fopen(name, "r");
884 if (fp == 0)
885 name[0] = '\0';
886 }
887 }
888
889 if (name[0] == '\0' && !get_compose_filename(name, sizeof(name))) {
890 if (fp)
891 fclose(fp);
892 return;
893 }
894
895 if (fp == 0 && ((fp = fopen(name, "r")) == 0))
896 return;
897
898 char lang_region[BUFSIZ];
899 int ret = get_lang_region(lang_region, sizeof(lang_region));
900 const char *encoding = get_encoding();
901 if (!ret || encoding == 0) {
902 fprintf(stderr, "Warning: locale name is NULL\n");
903 fclose(fp);
904 return;
905 }
906
907 ParseComposeStringFile(fp);
908 fclose(fp);
909 }
910
get_compose_filename(char * filename,size_t len)911 int QUimInputContext::get_compose_filename(char *filename, size_t len)
912 {
913 char lang_region[BUFSIZ];
914 int ret = get_lang_region(lang_region, sizeof(lang_region));
915 const char *encoding = get_encoding();
916
917 if (!ret || encoding == 0)
918 return 0;
919
920 char locale[BUFSIZ];
921 snprintf(locale, sizeof(locale), "%s.%s", lang_region, encoding);
922 char compose_dir_file[MAXPATHLEN];
923 const char *xlib_dir = XLIB_DIR ;
924 snprintf(compose_dir_file, sizeof(compose_dir_file), "%s/%s", XLIB_DIR, COMPOSE_DIR_FILE);
925
926 FILE *fp = fopen(compose_dir_file, "r");
927 if (fp == 0) {
928 /* retry with fallback file */
929 if (strcmp(FALLBACK_XLIB_DIR, XLIB_DIR)) {
930 snprintf(compose_dir_file, sizeof(compose_dir_file), "%s/%s",
931 FALLBACK_XLIB_DIR, COMPOSE_DIR_FILE);
932 fp = fopen(compose_dir_file, "r");
933 if (fp == 0)
934 return 0;
935 xlib_dir = FALLBACK_XLIB_DIR;
936 } else
937 return 0;
938 }
939
940 char name[MAXPATHLEN];
941 name[0] = '\0';
942 char buf[XLC_BUFSIZE];
943 while (fgets(buf, XLC_BUFSIZE, fp) != 0) {
944 char *p = buf;
945 int n;
946 char *args[2], *from, *to;
947 // isspace for tab doesn't seem to work with Qt4...
948 while (static_cast<unsigned char>(isspace(*p)) || *p == '\t') {
949 ++p;
950 }
951 if (iscomment(*p)) {
952 continue;
953 }
954 n = parse_line(p, args, 2);
955 if (n != 2) {
956 continue;
957 }
958 from = args[1], to = args[0];
959 if (!strcmp(from, locale)) {
960 strlcpy(name, to, sizeof(name));
961 break;
962 }
963 }
964 fclose(fp);
965
966 if (name[0] == '\0')
967 return 0;
968
969 snprintf(filename, len, "%s/%s/%s", xlib_dir, XLOCALE_DIR, name);
970
971 return 1;
972 }
973 #endif
974
975 static int
parse_line(char * line,char ** argv,int argsize)976 parse_line(char *line, char **argv, int argsize)
977 {
978 int argc = 0;
979 char *p = line;
980
981 while (argc < argsize) {
982 // isspace for tab doesn't seem to work with Qt4...
983 while (static_cast<unsigned char>(isspace(*p)) || *p == '\t') {
984 ++p;
985 }
986 if (*p == '\0') {
987 break;
988 }
989 argv[argc++] = p;
990 while (*p != ':' && *p != '\n' && *p != '\0') {
991 ++p;
992 }
993 if (*p == '\0') {
994 break;
995 }
996 *p++ = '\0';
997 }
998
999 return argc;
1000 }
1001
1002 static unsigned short const keysym_to_unicode_1a1_1ff[] = {
1003 0x0104, 0x02d8, 0x0141, 0x0000, 0x013d, 0x015a, 0x0000, /* 0x01a0-0x01a7 */
1004 0x0000, 0x0160, 0x015e, 0x0164, 0x0179, 0x0000, 0x017d, 0x017b, /* 0x01a8-0x01af */
1005 0x0000, 0x0105, 0x02db, 0x0142, 0x0000, 0x013e, 0x015b, 0x02c7, /* 0x01b0-0x01b7 */
1006 0x0000, 0x0161, 0x015f, 0x0165, 0x017a, 0x02dd, 0x017e, 0x017c, /* 0x01b8-0x01bf */
1007 0x0154, 0x0000, 0x0000, 0x0102, 0x0000, 0x0139, 0x0106, 0x0000, /* 0x01c0-0x01c7 */
1008 0x010c, 0x0000, 0x0118, 0x0000, 0x011a, 0x0000, 0x0000, 0x010e, /* 0x01c8-0x01cf */
1009 0x0110, 0x0143, 0x0147, 0x0000, 0x0000, 0x0150, 0x0000, 0x0000, /* 0x01d0-0x01d7 */
1010 0x0158, 0x016e, 0x0000, 0x0170, 0x0000, 0x0000, 0x0162, 0x0000, /* 0x01d8-0x01df */
1011 0x0155, 0x0000, 0x0000, 0x0103, 0x0000, 0x013a, 0x0107, 0x0000, /* 0x01e0-0x01e7 */
1012 0x010d, 0x0000, 0x0119, 0x0000, 0x011b, 0x0000, 0x0000, 0x010f, /* 0x01e8-0x01ef */
1013 0x0111, 0x0144, 0x0148, 0x0000, 0x0000, 0x0151, 0x0000, 0x0000, /* 0x01f0-0x01f7 */
1014 0x0159, 0x016f, 0x0000, 0x0171, 0x0000, 0x0000, 0x0163, 0x02d9 /* 0x01f8-0x01ff */
1015 };
1016
1017 static unsigned short const keysym_to_unicode_2a1_2fe[] = {
1018 0x0126, 0x0000, 0x0000, 0x0000, 0x0000, 0x0124, 0x0000, /* 0x02a0-0x02a7 */
1019 0x0000, 0x0130, 0x0000, 0x011e, 0x0134, 0x0000, 0x0000, 0x0000, /* 0x02a8-0x02af */
1020 0x0000, 0x0127, 0x0000, 0x0000, 0x0000, 0x0000, 0x0125, 0x0000, /* 0x02b0-0x02b7 */
1021 0x0000, 0x0131, 0x0000, 0x011f, 0x0135, 0x0000, 0x0000, 0x0000, /* 0x02b8-0x02bf */
1022 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x010a, 0x0108, 0x0000, /* 0x02c0-0x02c7 */
1023 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x02c8-0x02cf */
1024 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0120, 0x0000, 0x0000, /* 0x02d0-0x02d7 */
1025 0x011c, 0x0000, 0x0000, 0x0000, 0x0000, 0x016c, 0x015c, 0x0000, /* 0x02d8-0x02df */
1026 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x010b, 0x0109, 0x0000, /* 0x02e0-0x02e7 */
1027 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x02e8-0x02ef */
1028 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0121, 0x0000, 0x0000, /* 0x02f0-0x02f7 */
1029 0x011d, 0x0000, 0x0000, 0x0000, 0x0000, 0x016d, 0x015d /* 0x02f8-0x02ff */
1030 };
1031
1032 static unsigned short const keysym_to_unicode_3a2_3fe[] = {
1033 0x0138, 0x0156, 0x0000, 0x0128, 0x013b, 0x0000, /* 0x03a0-0x03a7 */
1034 0x0000, 0x0000, 0x0112, 0x0122, 0x0166, 0x0000, 0x0000, 0x0000, /* 0x03a8-0x03af */
1035 0x0000, 0x0000, 0x0000, 0x0157, 0x0000, 0x0129, 0x013c, 0x0000, /* 0x03b0-0x03b7 */
1036 0x0000, 0x0000, 0x0113, 0x0123, 0x0167, 0x014a, 0x0000, 0x014b, /* 0x03b8-0x03bf */
1037 0x0100, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x012e, /* 0x03c0-0x03c7 */
1038 0x0000, 0x0000, 0x0000, 0x0000, 0x0116, 0x0000, 0x0000, 0x012a, /* 0x03c8-0x03cf */
1039 0x0000, 0x0145, 0x014c, 0x0136, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x03d0-0x03d7 */
1040 0x0000, 0x0172, 0x0000, 0x0000, 0x0000, 0x0168, 0x016a, 0x0000, /* 0x03d8-0x03df */
1041 0x0101, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x012f, /* 0x03e0-0x03e7 */
1042 0x0000, 0x0000, 0x0000, 0x0000, 0x0117, 0x0000, 0x0000, 0x012b, /* 0x03e8-0x03ef */
1043 0x0000, 0x0146, 0x014d, 0x0137, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x03f0-0x03f7 */
1044 0x0000, 0x0173, 0x0000, 0x0000, 0x0000, 0x0169, 0x016b /* 0x03f8-0x03ff */
1045 };
1046
1047 static unsigned short const keysym_to_unicode_4a1_4df[] = {
1048 0x3002, 0x3008, 0x3009, 0x3001, 0x30fb, 0x30f2, 0x30a1, /* 0x04a0-0x04a7 */
1049 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30e3, 0x30e5, 0x30e7, 0x30c3, /* 0x04a8-0x04af */
1050 0x30fc, 0x30a2, 0x30a4, 0x30a6, 0x30a8, 0x30aa, 0x30ab, 0x30ad, /* 0x04b0-0x04b7 */
1051 0x30af, 0x30b1, 0x30b3, 0x30b5, 0x30b7, 0x30b9, 0x30bb, 0x30bd, /* 0x04b8-0x04bf */
1052 0x30bf, 0x30c1, 0x30c4, 0x30c6, 0x30c8, 0x30ca, 0x30cb, 0x30cc, /* 0x04c0-0x04c7 */
1053 0x30cd, 0x30ce, 0x30cf, 0x30d2, 0x30d5, 0x30d8, 0x30db, 0x30de, /* 0x04c8-0x04cf */
1054 0x30df, 0x30e0, 0x30e1, 0x30e2, 0x30e4, 0x30e6, 0x30e8, 0x30e9, /* 0x04d0-0x04d7 */
1055 0x30ea, 0x30eb, 0x30ec, 0x30ed, 0x30ef, 0x30f3, 0x309b, 0x309c /* 0x04d8-0x04df */
1056 };
1057
1058 static unsigned short const keysym_to_unicode_590_5fe[] = {
1059 0x06f0, 0x06f1, 0x06f2, 0x06f3, 0x06f4, 0x06f5, 0x06f6, 0x06f7, /* 0x0590-0x0597 */
1060 0x06f8, 0x06f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x0598-0x059f */
1061 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x066a, 0x0670, 0x0679, /* 0x05a0-0x05a7 */
1062
1063 0x067e, 0x0686, 0x0688, 0x0691, 0x060c, 0x0000, 0x06d4, 0x0000, /* 0x05ac-0x05af */
1064 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, /* 0x05b0-0x05b7 */
1065 0x0668, 0x0669, 0x0000, 0x061b, 0x0000, 0x0000, 0x0000, 0x061f, /* 0x05b8-0x05bf */
1066 0x0000, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, /* 0x05c0-0x05c7 */
1067 0x0628, 0x0629, 0x062a, 0x062b, 0x062c, 0x062d, 0x062e, 0x062f, /* 0x05c8-0x05cf */
1068 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, /* 0x05d0-0x05d7 */
1069 0x0638, 0x0639, 0x063a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x05d8-0x05df */
1070 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, /* 0x05e0-0x05e7 */
1071 0x0648, 0x0649, 0x064a, 0x064b, 0x064c, 0x064d, 0x064e, 0x064f, /* 0x05e8-0x05ef */
1072 0x0650, 0x0651, 0x0652, 0x0653, 0x0654, 0x0655, 0x0698, 0x06a4, /* 0x05f0-0x05f7 */
1073 0x06a9, 0x06af, 0x06ba, 0x06be, 0x06cc, 0x06d2, 0x06c1 /* 0x05f8-0x05fe */
1074 };
1075
1076 static unsigned short keysym_to_unicode_680_6ff[] = {
1077 0x0492, 0x0496, 0x049a, 0x049c, 0x04a2, 0x04ae, 0x04b0, 0x04b2, /* 0x0680-0x0687 */
1078 0x04b6, 0x04b8, 0x04ba, 0x0000, 0x04d8, 0x04e2, 0x04e8, 0x04ee, /* 0x0688-0x068f */
1079 0x0493, 0x0497, 0x049b, 0x049d, 0x04a3, 0x04af, 0x04b1, 0x04b3, /* 0x0690-0x0697 */
1080 0x04b7, 0x04b9, 0x04bb, 0x0000, 0x04d9, 0x04e3, 0x04e9, 0x04ef, /* 0x0698-0x069f */
1081 0x0000, 0x0452, 0x0453, 0x0451, 0x0454, 0x0455, 0x0456, 0x0457, /* 0x06a0-0x06a7 */
1082 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x0491, 0x045e, 0x045f, /* 0x06a8-0x06af */
1083 0x2116, 0x0402, 0x0403, 0x0401, 0x0404, 0x0405, 0x0406, 0x0407, /* 0x06b0-0x06b7 */
1084 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x0490, 0x040e, 0x040f, /* 0x06b8-0x06bf */
1085 0x044e, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, /* 0x06c0-0x06c7 */
1086 0x0445, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, /* 0x06c8-0x06cf */
1087 0x043f, 0x044f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, /* 0x06d0-0x06d7 */
1088 0x044c, 0x044b, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447, 0x044a, /* 0x06d8-0x06df */
1089 0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, /* 0x06e0-0x06e7 */
1090 0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, /* 0x06e8-0x06ef */
1091 0x041f, 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, /* 0x06f0-0x06f7 */
1092 0x042c, 0x042b, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x042a /* 0x06f8-0x06ff */
1093 };
1094
1095 static unsigned short const keysym_to_unicode_7a1_7f9[] = {
1096 0x0386, 0x0388, 0x0389, 0x038a, 0x03aa, 0x0000, 0x038c, /* 0x07a0-0x07a7 */
1097 0x038e, 0x03ab, 0x0000, 0x038f, 0x0000, 0x0000, 0x0385, 0x2015, /* 0x07a8-0x07af */
1098 0x0000, 0x03ac, 0x03ad, 0x03ae, 0x03af, 0x03ca, 0x0390, 0x03cc, /* 0x07b0-0x07b7 */
1099 0x03cd, 0x03cb, 0x03b0, 0x03ce, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x07b8-0x07bf */
1100 0x0000, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, /* 0x07c0-0x07c7 */
1101 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, /* 0x07c8-0x07cf */
1102 0x03a0, 0x03a1, 0x03a3, 0x0000, 0x03a4, 0x03a5, 0x03a6, 0x03a7, /* 0x07d0-0x07d7 */
1103 0x03a8, 0x03a9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x07d8-0x07df */
1104 0x0000, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, /* 0x07e0-0x07e7 */
1105 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, /* 0x07e8-0x07ef */
1106 0x03c0, 0x03c1, 0x03c3, 0x03c2, 0x03c4, 0x03c5, 0x03c6, 0x03c7, /* 0x07f0-0x07f7 */
1107 0x03c8, 0x03c9 /* 0x07f8-0x07ff */
1108 };
1109
1110 static unsigned short const keysym_to_unicode_8a4_8fe[] = {
1111 0x2320, 0x2321, 0x0000, 0x231c, /* 0x08a0-0x08a7 */
1112 0x231d, 0x231e, 0x231f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08a8-0x08af */
1113 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08b0-0x08b7 */
1114 0x0000, 0x0000, 0x0000, 0x0000, 0x2264, 0x2260, 0x2265, 0x222b, /* 0x08b8-0x08bf */
1115 0x2234, 0x0000, 0x221e, 0x0000, 0x0000, 0x2207, 0x0000, 0x0000, /* 0x08c0-0x08c7 */
1116 0x2245, 0x2246, 0x0000, 0x0000, 0x0000, 0x0000, 0x22a2, 0x0000, /* 0x08c8-0x08cf */
1117 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x221a, 0x0000, /* 0x08d0-0x08d7 */
1118 0x0000, 0x0000, 0x2282, 0x2283, 0x2229, 0x222a, 0x2227, 0x2228, /* 0x08d8-0x08df */
1119 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08e0-0x08e7 */
1120 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08e8-0x08ef */
1121 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0192, 0x0000, /* 0x08f0-0x08f7 */
1122 0x0000, 0x0000, 0x0000, 0x2190, 0x2191, 0x2192, 0x2193 /* 0x08f8-0x08ff */
1123 };
1124
1125 static unsigned short const keysym_to_unicode_9df_9f8[] = {
1126 0x2422, /* 0x09d8-0x09df */
1127 0x2666, 0x25a6, 0x2409, 0x240c, 0x240d, 0x240a, 0x0000, 0x0000, /* 0x09e0-0x09e7 */
1128 0x240a, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x2500, /* 0x09e8-0x09ef */
1129 0x0000, 0x0000, 0x0000, 0x0000, 0x251c, 0x2524, 0x2534, 0x252c, /* 0x09f0-0x09f7 */
1130 0x2502 /* 0x09f8-0x09ff */
1131 };
1132
1133 static unsigned short const keysym_to_unicode_aa1_afe[] = {
1134 0x2003, 0x2002, 0x2004, 0x2005, 0x2007, 0x2008, 0x2009, /* 0x0aa0-0x0aa7 */
1135 0x200a, 0x2014, 0x2013, 0x0000, 0x0000, 0x0000, 0x2026, 0x2025, /* 0x0aa8-0x0aaf */
1136 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215a, /* 0x0ab0-0x0ab7 */
1137 0x2105, 0x0000, 0x0000, 0x2012, 0x2039, 0x2024, 0x203a, 0x0000, /* 0x0ab8-0x0abf */
1138 0x0000, 0x0000, 0x0000, 0x215b, 0x215c, 0x215d, 0x215e, 0x0000, /* 0x0ac0-0x0ac7 */
1139 0x0000, 0x2122, 0x2120, 0x0000, 0x25c1, 0x25b7, 0x25cb, 0x25ad, /* 0x0ac8-0x0acf */
1140 0x2018, 0x2019, 0x201c, 0x201d, 0x211e, 0x0000, 0x2032, 0x2033, /* 0x0ad0-0x0ad7 */
1141 0x0000, 0x271d, 0x0000, 0x220e, 0x25c2, 0x2023, 0x25cf, 0x25ac, /* 0x0ad8-0x0adf */
1142 0x25e6, 0x25ab, 0x25ae, 0x25b5, 0x25bf, 0x2606, 0x2022, 0x25aa, /* 0x0ae0-0x0ae7 */
1143 0x25b4, 0x25be, 0x261a, 0x261b, 0x2663, 0x2666, 0x2665, 0x0000, /* 0x0ae8-0x0aef */
1144 0x2720, 0x2020, 0x2021, 0x2713, 0x2612, 0x266f, 0x266d, 0x2642, /* 0x0af0-0x0af7 */
1145 0x2640, 0x2121, 0x2315, 0x2117, 0x2038, 0x201a, 0x201e /* 0x0af8-0x0aff */
1146 };
1147
1148 /* none of the APL keysyms match the Unicode characters */
1149
1150 static unsigned short const keysym_to_unicode_cdf_cfa[] = {
1151 0x2017, /* 0x0cd8-0x0cdf */
1152 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, /* 0x0ce0-0x0ce7 */
1153 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, /* 0x0ce8-0x0cef */
1154 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, /* 0x0cf0-0x0cf7 */
1155 0x05e8, 0x05e9, 0x05ea /* 0x0cf8-0x0cff */
1156 };
1157
1158 static unsigned short const keysym_to_unicode_da1_df9[] = {
1159 0x0e01, 0x0e02, 0x0e03, 0x0e04, 0x0e05, 0x0e06, 0x0e07, /* 0x0da0-0x0da7 */
1160 0x0e08, 0x0e09, 0x0e0a, 0x0e0b, 0x0e0c, 0x0e0d, 0x0e0e, 0x0e0f, /* 0x0da8-0x0daf */
1161 0x0e10, 0x0e11, 0x0e12, 0x0e13, 0x0e14, 0x0e15, 0x0e16, 0x0e17, /* 0x0db0-0x0db7 */
1162 0x0e18, 0x0e19, 0x0e1a, 0x0e1b, 0x0e1c, 0x0e1d, 0x0e1e, 0x0e1f, /* 0x0db8-0x0dbf */
1163 0x0e20, 0x0e21, 0x0e22, 0x0e23, 0x0e24, 0x0e25, 0x0e26, 0x0e27, /* 0x0dc0-0x0dc7 */
1164 0x0e28, 0x0e29, 0x0e2a, 0x0e2b, 0x0e2c, 0x0e2d, 0x0e2e, 0x0e2f, /* 0x0dc8-0x0dcf */
1165 0x0e30, 0x0e31, 0x0e32, 0x0e33, 0x0e34, 0x0e35, 0x0e36, 0x0e37, /* 0x0dd0-0x0dd7 */
1166 0x0e38, 0x0e39, 0x0e3a, 0x0000, 0x0000, 0x0000, 0x0e3e, 0x0e3f, /* 0x0dd8-0x0ddf */
1167 0x0e40, 0x0e41, 0x0e42, 0x0e43, 0x0e44, 0x0e45, 0x0e46, 0x0e47, /* 0x0de0-0x0de7 */
1168 0x0e48, 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c, 0x0e4d, 0x0000, 0x0000, /* 0x0de8-0x0def */
1169 0x0e50, 0x0e51, 0x0e52, 0x0e53, 0x0e54, 0x0e55, 0x0e56, 0x0e57, /* 0x0df0-0x0df7 */
1170 0x0e58, 0x0e59 /* 0x0df8-0x0dff */
1171 };
1172
1173 static unsigned short const keysym_to_unicode_ea0_eff[] = {
1174 0x0000, 0x1101, 0x1101, 0x11aa, 0x1102, 0x11ac, 0x11ad, 0x1103, /* 0x0ea0-0x0ea7 */
1175 0x1104, 0x1105, 0x11b0, 0x11b1, 0x11b2, 0x11b3, 0x11b4, 0x11b5, /* 0x0ea8-0x0eaf */
1176 0x11b6, 0x1106, 0x1107, 0x1108, 0x11b9, 0x1109, 0x110a, 0x110b, /* 0x0eb0-0x0eb7 */
1177 0x110c, 0x110d, 0x110e, 0x110f, 0x1110, 0x1111, 0x1112, 0x1161, /* 0x0eb8-0x0ebf */
1178 0x1162, 0x1163, 0x1164, 0x1165, 0x1166, 0x1167, 0x1168, 0x1169, /* 0x0ec0-0x0ec7 */
1179 0x116a, 0x116b, 0x116c, 0x116d, 0x116e, 0x116f, 0x1170, 0x1171, /* 0x0ec8-0x0ecf */
1180 0x1172, 0x1173, 0x1174, 0x1175, 0x11a8, 0x11a9, 0x11aa, 0x11ab, /* 0x0ed0-0x0ed7 */
1181 0x11ac, 0x11ad, 0x11ae, 0x11af, 0x11b0, 0x11b1, 0x11b2, 0x11b3, /* 0x0ed8-0x0edf */
1182 0x11b4, 0x11b5, 0x11b6, 0x11b7, 0x11b8, 0x11b9, 0x11ba, 0x11bb, /* 0x0ee0-0x0ee7 */
1183 0x11bc, 0x11bd, 0x11be, 0x11bf, 0x11c0, 0x11c1, 0x11c2, 0x0000, /* 0x0ee8-0x0eef */
1184 0x0000, 0x0000, 0x1140, 0x0000, 0x0000, 0x1159, 0x119e, 0x0000, /* 0x0ef0-0x0ef7 */
1185 0x11eb, 0x0000, 0x11f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x20a9, /* 0x0ef8-0x0eff */
1186 };
1187
1188 static unsigned short keysym_to_unicode_12a1_12fe[] = {
1189 0x1e02, 0x1e03, 0x0000, 0x0000, 0x0000, 0x1e0a, 0x0000, /* 0x12a0-0x12a7 */
1190 0x1e80, 0x0000, 0x1e82, 0x1e0b, 0x1ef2, 0x0000, 0x0000, 0x0000, /* 0x12a8-0x12af */
1191 0x1e1e, 0x1e1f, 0x0000, 0x0000, 0x1e40, 0x1e41, 0x0000, 0x1e56, /* 0x12b0-0x12b7 */
1192 0x1e81, 0x1e57, 0x1e83, 0x1e60, 0x1ef3, 0x1e84, 0x1e85, 0x1e61, /* 0x12b8-0x12bf */
1193 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12c0-0x12c7 */
1194 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12c8-0x12cf */
1195 0x0174, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1e6a, /* 0x12d0-0x12d7 */
1196 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0176, 0x0000, /* 0x12d8-0x12df */
1197 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12e0-0x12e7 */
1198 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12e8-0x12ef */
1199 0x0175, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1e6b, /* 0x12f0-0x12f7 */
1200 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0177 /* 0x12f0-0x12ff */
1201 };
1202
1203 static unsigned short const keysym_to_unicode_13bc_13be[] = {
1204 0x0152, 0x0153, 0x0178 /* 0x13b8-0x13bf */
1205 };
1206
1207 static unsigned short keysym_to_unicode_14a1_14ff[] = {
1208 0x2741, 0x00a7, 0x0589, 0x0029, 0x0028, 0x00bb, 0x00ab, /* 0x14a0-0x14a7 */
1209 0x2014, 0x002e, 0x055d, 0x002c, 0x2013, 0x058a, 0x2026, 0x055c, /* 0x14a8-0x14af */
1210 0x055b, 0x055e, 0x0531, 0x0561, 0x0532, 0x0562, 0x0533, 0x0563, /* 0x14b0-0x14b7 */
1211 0x0534, 0x0564, 0x0535, 0x0565, 0x0536, 0x0566, 0x0537, 0x0567, /* 0x14b8-0x14bf */
1212 0x0538, 0x0568, 0x0539, 0x0569, 0x053a, 0x056a, 0x053b, 0x056b, /* 0x14c0-0x14c7 */
1213 0x053c, 0x056c, 0x053d, 0x056d, 0x053e, 0x056e, 0x053f, 0x056f, /* 0x14c8-0x14cf */
1214 0x0540, 0x0570, 0x0541, 0x0571, 0x0542, 0x0572, 0x0543, 0x0573, /* 0x14d0-0x14d7 */
1215 0x0544, 0x0574, 0x0545, 0x0575, 0x0546, 0x0576, 0x0547, 0x0577, /* 0x14d8-0x14df */
1216 0x0548, 0x0578, 0x0549, 0x0579, 0x054a, 0x057a, 0x054b, 0x057b, /* 0x14e0-0x14e7 */
1217 0x054c, 0x057c, 0x054d, 0x057d, 0x054e, 0x057e, 0x054f, 0x057f, /* 0x14e8-0x14ef */
1218 0x0550, 0x0580, 0x0551, 0x0581, 0x0552, 0x0582, 0x0553, 0x0583, /* 0x14f0-0x14f7 */
1219 0x0554, 0x0584, 0x0555, 0x0585, 0x0556, 0x0586, 0x2019, 0x0027, /* 0x14f8-0x14ff */
1220 };
1221
1222 static unsigned short keysym_to_unicode_15d0_15f6[] = {
1223 0x10d0, 0x10d1, 0x10d2, 0x10d3, 0x10d4, 0x10d5, 0x10d6, 0x10d7, /* 0x15d0-0x15d7 */
1224 0x10d8, 0x10d9, 0x10da, 0x10db, 0x10dc, 0x10dd, 0x10de, 0x10df, /* 0x15d8-0x15df */
1225 0x10e0, 0x10e1, 0x10e2, 0x10e3, 0x10e4, 0x10e5, 0x10e6, 0x10e7, /* 0x15e0-0x15e7 */
1226 0x10e8, 0x10e9, 0x10ea, 0x10eb, 0x10ec, 0x10ed, 0x10ee, 0x10ef, /* 0x15e8-0x15ef */
1227 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6 /* 0x15f0-0x15f7 */
1228 };
1229
1230 static unsigned short keysym_to_unicode_16a0_16f6[] = {
1231 0x0000, 0x0000, 0xf0a2, 0x1e8a, 0x0000, 0xf0a5, 0x012c, 0xf0a7, /* 0x16a0-0x16a7 */
1232 0xf0a8, 0x01b5, 0x01e6, 0x0000, 0x0000, 0x0000, 0x0000, 0x019f, /* 0x16a8-0x16af */
1233 0x0000, 0x0000, 0xf0b2, 0x1e8b, 0x01d1, 0xf0b5, 0x012d, 0xf0b7, /* 0x16b0-0x16b7 */
1234 0xf0b8, 0x01b6, 0x01e7, 0x0000, 0x0000, 0x01d2, 0x0000, 0x0275, /* 0x16b8-0x16bf */
1235 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x018f, 0x0000, /* 0x16c0-0x16c7 */
1236 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16c8-0x16cf */
1237 0x0000, 0x1e36, 0xf0d2, 0xf0d3, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16d0-0x16d7 */
1238 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16d8-0x16df */
1239 0x0000, 0x1e37, 0xf0e2, 0xf0e3, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16e0-0x16e7 */
1240 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16e8-0x16ef */
1241 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0259 /* 0x16f0-0x16f6 */
1242 };
1243
1244 static unsigned short const keysym_to_unicode_1e9f_1eff[] = {
1245 0x0303,
1246 0x1ea0, 0x1ea1, 0x1ea2, 0x1ea3, 0x1ea4, 0x1ea5, 0x1ea6, 0x1ea7, /* 0x1ea0-0x1ea7 */
1247 0x1ea8, 0x1ea9, 0x1eaa, 0x1eab, 0x1eac, 0x1ead, 0x1eae, 0x1eaf, /* 0x1ea8-0x1eaf */
1248 0x1eb0, 0x1eb1, 0x1eb2, 0x1eb3, 0x1eb4, 0x1eb5, 0x1eb6, 0x1eb7, /* 0x1eb0-0x1eb7 */
1249 0x1eb8, 0x1eb9, 0x1eba, 0x1ebb, 0x1ebc, 0x1ebd, 0x1ebe, 0x1ebf, /* 0x1eb8-0x1ebf */
1250 0x1ec0, 0x1ec1, 0x1ec2, 0x1ec3, 0x1ec4, 0x1ec5, 0x1ec6, 0x1ec7, /* 0x1ec0-0x1ec7 */
1251 0x1ec8, 0x1ec9, 0x1eca, 0x1ecb, 0x1ecc, 0x1ecd, 0x1ece, 0x1ecf, /* 0x1ec8-0x1ecf */
1252 0x1ed0, 0x1ed1, 0x1ed2, 0x1ed3, 0x1ed4, 0x1ed5, 0x1ed6, 0x1ed7, /* 0x1ed0-0x1ed7 */
1253 0x1ed8, 0x1ed9, 0x1eda, 0x1edb, 0x1edc, 0x1edd, 0x1ede, 0x1edf, /* 0x1ed8-0x1edf */
1254 0x1ee0, 0x1ee1, 0x1ee2, 0x1ee3, 0x1ee4, 0x1ee5, 0x1ee6, 0x1ee7, /* 0x1ee0-0x1ee7 */
1255 0x1ee8, 0x1ee9, 0x1eea, 0x1eeb, 0x1eec, 0x1eed, 0x1eee, 0x1eef, /* 0x1ee8-0x1eef */
1256 0x1ef0, 0x1ef1, 0x0300, 0x0301, 0x1ef4, 0x1ef5, 0x1ef6, 0x1ef7, /* 0x1ef0-0x1ef7 */
1257 0x1ef8, 0x1ef9, 0x01a0, 0x01a1, 0x01af, 0x01b0, 0x0309, 0x0323 /* 0x1ef8-0x1eff */
1258 };
1259
1260 static unsigned short const keysym_to_unicode_20a0_20ac[] = {
1261 0x20a0, 0x20a1, 0x20a2, 0x20a3, 0x20a4, 0x20a5, 0x20a6, 0x20a7, /* 0x20a0-0x20a7 */
1262 0x20a8, 0x20a9, 0x20aa, 0x20ab, 0x20ac /* 0x20a8-0x20af */
1263 };
1264
1265 static unsigned int
KeySymToUcs4(KeySym keysym)1266 KeySymToUcs4(KeySym keysym)
1267 {
1268 /* 'Unicode keysym' */
1269 if ((keysym & 0xff000000) == 0x01000000)
1270 return (keysym & 0x00ffffff);
1271
1272 if (keysym > 0 && keysym < 0x100)
1273 return keysym;
1274 else if (keysym > 0x1a0 && keysym < 0x200)
1275 return keysym_to_unicode_1a1_1ff[keysym - 0x1a1];
1276 else if (keysym > 0x2a0 && keysym < 0x2ff)
1277 return keysym_to_unicode_2a1_2fe[keysym - 0x2a1];
1278 else if (keysym > 0x3a1 && keysym < 0x3ff)
1279 return keysym_to_unicode_3a2_3fe[keysym - 0x3a2];
1280 else if (keysym > 0x4a0 && keysym < 0x4e0)
1281 return keysym_to_unicode_4a1_4df[keysym - 0x4a1];
1282 else if (keysym > 0x589 && keysym < 0x5ff)
1283 return keysym_to_unicode_590_5fe[keysym - 0x590];
1284 else if (keysym > 0x67f && keysym < 0x700)
1285 return keysym_to_unicode_680_6ff[keysym - 0x680];
1286 else if (keysym > 0x7a0 && keysym < 0x7fa)
1287 return keysym_to_unicode_7a1_7f9[keysym - 0x7a1];
1288 else if (keysym > 0x8a3 && keysym < 0x8ff)
1289 return keysym_to_unicode_8a4_8fe[keysym - 0x8a4];
1290 else if (keysym > 0x9de && keysym < 0x9f9)
1291 return keysym_to_unicode_9df_9f8[keysym - 0x9df];
1292 else if (keysym > 0xaa0 && keysym < 0xaff)
1293 return keysym_to_unicode_aa1_afe[keysym - 0xaa1];
1294 else if (keysym > 0xcde && keysym < 0xcfb)
1295 return keysym_to_unicode_cdf_cfa[keysym - 0xcdf];
1296 else if (keysym > 0xda0 && keysym < 0xdfa)
1297 return keysym_to_unicode_da1_df9[keysym - 0xda1];
1298 else if (keysym > 0xe9f && keysym < 0xf00)
1299 return keysym_to_unicode_ea0_eff[keysym - 0xea0];
1300 else if (keysym > 0x12a0 && keysym < 0x12ff)
1301 return keysym_to_unicode_12a1_12fe[keysym - 0x12a1];
1302 else if (keysym > 0x13bb && keysym < 0x13bf)
1303 return keysym_to_unicode_13bc_13be[keysym - 0x13bc];
1304 else if (keysym > 0x14a0 && keysym < 0x1500)
1305 return keysym_to_unicode_14a1_14ff[keysym - 0x14a1];
1306 else if (keysym > 0x15cf && keysym < 0x15f7)
1307 return keysym_to_unicode_15d0_15f6[keysym - 0x15d0];
1308 else if (keysym > 0x169f && keysym < 0x16f7)
1309 return keysym_to_unicode_16a0_16f6[keysym - 0x16a0];
1310 else if (keysym > 0x1e9e && keysym < 0x1f00)
1311 return keysym_to_unicode_1e9f_1eff[keysym - 0x1e9f];
1312 else if (keysym > 0x209f && keysym < 0x20ad)
1313 return keysym_to_unicode_20a0_20ac[keysym - 0x20a0];
1314 else
1315 return 0;
1316 }
1317
1318 /*
1319 * Local variables:
1320 * c-indent-level: 4
1321 * c-basic-offset: 4
1322 * End:
1323 */
1324