PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/efte-1.1/src/con_i18n.cpp

#
C++ | 413 lines | 249 code | 47 blank | 117 comment | 107 complexity | a086a1b5d47606482dc6c3a70b8ab217 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. * con_i18n.cpp
  3. *
  4. * Copyright (c) 2008, eFTE SF Group (see AUTHORS file)
  5. * Copyright (c) 1998, Zdenek Kabelac
  6. *
  7. * You may distribute under the terms of either the GNU General Public
  8. * License or the Artistic License, as specified in the README file.
  9. *
  10. * I18N support by kabi@fi.muni.cz
  11. *
  12. * written as plain 'C' module and might be used
  13. * in other programs to implement I18N support
  14. */
  15. #include <X11/Xlib.h>
  16. #include <X11/Xutil.h>
  17. #include <X11/keysym.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include <ctype.h>
  22. #include "con_i18n.h"
  23. #define KEYMASK 0xff
  24. #define KEYBYTEMAX 0xf00
  25. #ifdef USE_HARD_REMAP
  26. /*
  27. * This part is used when your Xserver doesn't work well with XKB extension
  28. */
  29. /* Keyboard definition file - currently only Czech national keyboard
  30. * write your own keyboard for your language
  31. * And remember - this is supposed to be used only if your Xserver
  32. * is not supporting keyboard extension
  33. */
  34. #include "con_ikcz.h"
  35. /*
  36. * Quite a complex function to convert normal keys
  37. * to dead-keys and remapped keys
  38. */
  39. static int i18n_key_analyze(XKeyEvent * keyEvent, KeySym * key, /*FOLD00*/
  40. char *keyName, int nbytes) {
  41. static long prev_state = 0, local_switch = 0,
  42. keypos = 0, last_keypos = 0, remap = 0;
  43. long i;
  44. struct keyboardRec *kbdActual;
  45. /* Find the state of keyboard
  46. * Check for different ISO group or modifier 5
  47. * So to activate remaping, you need to press at least
  48. * ScrollLock which is usually mapped as modifier 5
  49. */
  50. i = ((keyEvent->state | local_switch) & 0xFFA0);
  51. if (i != prev_state) {
  52. /* reset table position */
  53. last_keypos = keypos = 0;
  54. prev_state = i;
  55. }
  56. if (keyEvent->type == KeyPress) {
  57. if (i && ((*key == XK_Pause) || (*key == XK_F21))) {
  58. remap = !remap;
  59. return 0;
  60. } else if (*key == XK_F23) {
  61. local_switch ^= (1UL << 12);
  62. return 0;
  63. }
  64. }
  65. /*
  66. * Check for already remapped ISO8859-X keys
  67. * this should not normaly happen :-)
  68. * as we need to use this hack
  69. */
  70. if ((*key > KEYMASK) && (*key < KEYBYTEMAX) || (*key > 0xffffff00)) {
  71. *key &= KEYMASK;
  72. keyName[0] = (char) * key;
  73. return 1;
  74. }
  75. /* Select keyboard map */
  76. if (!i)
  77. kbdActual = nationalKey[0];
  78. else if (!remap)
  79. kbdActual = nationalKey[1];
  80. else
  81. kbdActual = nationalKey[2];
  82. if (keyEvent->type == KeyPress) {
  83. long i = last_keypos;
  84. /*
  85. * Search for DeadKey -> do loop over all tables.
  86. *
  87. * Note: We can define ONE DeadKey and use
  88. * it for several tables sequentially
  89. */
  90. for (;;) {
  91. i++;
  92. if ((kbdActual[0].tab == NULL) || kbdActual[i].tab == NULL) {
  93. i = 0;
  94. if (kbdActual[i].tab == NULL) {
  95. /* Looks like empty table -> IGNORE */
  96. keypos = i;
  97. return nbytes;
  98. }
  99. }
  100. if (i == last_keypos)
  101. break;
  102. if (kbdActual[i].deadkey == *key) {
  103. keypos = kbdActual[i].next;
  104. /* Found DeadKey -> delete it
  105. * and mark actual position for next search */
  106. last_keypos = i;
  107. keyName[0] = *key = 0;
  108. return 0;
  109. }
  110. }
  111. } else if (keypos)
  112. return 0; /* ignore key release */
  113. /* Now we know it is not a DeadKey and we
  114. * are in selected remaping keyboard table */
  115. /* printf("** key:%5d\tstatus:0x%x\n", *key, prev_state); */
  116. if (*key < KEYBYTEMAX) {
  117. /*
  118. * this is selected constant and will change when
  119. * this editor will be able to write in japan :-)
  120. */
  121. int i = 0;
  122. /* remaping only real keys */
  123. while (kbdActual[keypos].tab[i].key_english != 0) {
  124. if (*key == kbdActual[keypos].tab[i].key_english) {
  125. *key = kbdActual[keypos].tab[i].key_remap;
  126. break;
  127. }
  128. i++;
  129. }
  130. last_keypos = keypos = kbdActual[keypos].next;
  131. /* printf("** remap: %3d %3d\n", keypos, *key); */
  132. keyName[0] = *key && KEYMASK;
  133. return 1;
  134. }
  135. return 0;
  136. }
  137. /*FOLD00*/
  138. #else
  139. /*********************************************
  140. * *
  141. * Standart methods for reading Keyboard *
  142. * *
  143. *********************************************/
  144. /* ISO-8859-2 key-change
  145. * All these functions are for keyboard reading.
  146. * Correct displaing of this text is another thing,
  147. * but as I only need ISO-8859 encoding support,
  148. * I don't care about this (for now).
  149. */
  150. static int i18n_key_analyze(XKeyEvent * /*keyEvent*/, KeySym * key, /*FOLD00*/
  151. char *keyName, int nbytes) {
  152. KeySym t = (unsigned char) keyName[0];
  153. /*
  154. * ISO-8859-2 is using some characters from 8859-1 and
  155. * rest of them is located between 0x100 - 0x200 in 'X' so
  156. * with ISO-8859-2 font we'll remap them down bellow < 0x100
  157. * This is mostly true for all Latin-X alphas, just
  158. * special font to display them correctly is needed.
  159. * This jobs does Xserver - and keysymbol is returned
  160. * in the 1st. byte of keyName string.
  161. */
  162. if ((nbytes == 1) && *key < KEYBYTEMAX)
  163. *key = t;
  164. #ifdef USE_HACK_FOR_BAD_XSERVER
  165. /*
  166. * this is really hack - but some Xservers are somewhat
  167. * strange, so we remap character manually
  168. */
  169. else if (!nbytes && (*key > KEYMASK) && (*key < KEYBYTEMAX)) {
  170. *key &= KEYMASK;
  171. keyName[0] = *key & KEYMASK;
  172. nbytes = 1;
  173. }
  174. #endif
  175. return nbytes;
  176. }
  177. /*FOLD00*/
  178. #endif
  179. /*
  180. * Initialize I18N functions - took me hours to
  181. * figure out how this works even though it was
  182. * cut & pasted from 'xterm' sources, but as 'xterm'
  183. * is using Xt Toolkit some things have to be made
  184. * different
  185. */
  186. i18n_context_t* i18n_open(Display * display, Window win, unsigned long *mask) { /*FOLD00*/
  187. *mask = 0;
  188. #if XlibSpecificationRelease >= 6
  189. char *s, tmp[256];
  190. int found = False;
  191. i18n_context_t* ctx = (i18n_context_t*) malloc(sizeof(i18n_context_t));
  192. memset(ctx, 0, sizeof(i18n_context_t));
  193. /* Locale setting taken from XtSetLanguageProc */
  194. if (!(s = setlocale(LC_ALL, "")))
  195. fprintf(stderr, "I18N warning: Locale not supported by C library, "
  196. "locale unchanged!\n");
  197. if (!XSupportsLocale()) {
  198. fprintf(stderr, "I18N warning: Locale not supported by Xlib, "
  199. "locale set to C!\n");
  200. s = setlocale(LC_ALL, "C");
  201. }
  202. if (!XSetLocaleModifiers(""))
  203. fprintf(stderr, "I18N warning: X locale modifiers not supported, "
  204. "using default\n");
  205. ctx->xim = XOpenIM(display, NULL, NULL, NULL);
  206. if (ctx->xim == NULL) {
  207. // there are languages without Input Methods ????
  208. fprintf(stderr, "I18N warning: Input method not specified\n");
  209. i18n_destroy(&ctx);
  210. return NULL;
  211. }
  212. if (XGetIMValues(ctx->xim, XNQueryInputStyle, &ctx->xim_styles, NULL)
  213. || ctx->xim_styles == NULL) {
  214. fprintf(stderr, "I18N error: Input method doesn't support any style\n");
  215. i18n_destroy(&ctx);
  216. return NULL;
  217. }
  218. /*
  219. * This is some kind of debugging message to inform user
  220. * that something is wrong with his system
  221. */
  222. if (s != NULL && (strstr(s, XLocaleOfIM(ctx->xim)) == NULL))
  223. fprintf(stderr, "I18N warning: System locale: \"%s\" differs from "
  224. "IM locale: \"%s\"...\n", s, XLocaleOfIM(ctx->xim));
  225. /*
  226. * This part is cut&paste from other sources
  227. * There is no reason to do it this way, because
  228. * the only input style currently supported is Root
  229. * but for the future extension I'll leave it here
  230. */
  231. strcpy(tmp, XIM_INPUT_STYLE);
  232. for (s = tmp; s && !found;) {
  233. char *ns, *end;
  234. int i;
  235. while ((*s != 0) && isspace(*s))
  236. s++;
  237. if (*s == 0)
  238. break;
  239. if ((ns = end = strchr(s, ',')) != 0)
  240. ns++;
  241. else
  242. end = s + strlen(s);
  243. while (isspace(*end))
  244. end--;
  245. *end = '\0';
  246. if (!strcmp(s, "OverTheSpot"))
  247. ctx->input_style = (XIMPreeditPosition | XIMStatusArea);
  248. else if (!strcmp(s, "OffTheSpot"))
  249. ctx->input_style = (XIMPreeditArea | XIMStatusArea);
  250. else if (!strcmp(s, "Root"))
  251. ctx->input_style = (XIMPreeditNothing | XIMStatusNothing);
  252. for (i = 0; (unsigned short) i < ctx->xim_styles->count_styles; i++)
  253. if (ctx->input_style == ctx->xim_styles->supported_styles[i])
  254. //if (ctx->xim_styles->supported_styles[i] & (XIMPreeditNothing | XIMPreeditNone) &&
  255. // ctx->xim_styles->supported_styles[i] & (XIMStatusNothing | XIMStatusNone))
  256. {
  257. found = True;
  258. /* do not modify this!
  259. * unless consulted with kabi@users.sf.net
  260. */
  261. //ctx->input_style = ctx->xim_styles->supported_styles[i];
  262. break;
  263. }
  264. s = ns;
  265. }
  266. XFree(ctx->xim_styles);
  267. if (!found) {
  268. fprintf(stderr, "I18N error: Input method doesn't support my "
  269. "preedit type\n");
  270. i18n_destroy(&ctx);
  271. return NULL;
  272. }
  273. /* This program only understand the Root preedit_style yet */
  274. if (ctx->input_style != (XIMPreeditNothing | XIMStatusNothing)) {
  275. fprintf(stderr, "I18N error: This program only supports the "
  276. "'Root' preedit type\n");
  277. i18n_destroy(&ctx);
  278. return NULL;
  279. }
  280. ctx->xic = XCreateIC(ctx->xim, XNInputStyle, ctx->input_style,
  281. XNClientWindow, win,
  282. XNFocusWindow, win,
  283. NULL);
  284. if (ctx->xic == NULL) {
  285. fprintf(stderr, "I18N error: Failed to create input context\n");
  286. i18n_destroy(&ctx);
  287. } else if (XGetICValues(ctx->xic, XNFilterEvents, mask, NULL))
  288. fprintf(stderr, "I18N error: Can't get Event Mask\n");
  289. return ctx;
  290. #else
  291. return NULL;
  292. #endif
  293. }
  294. /*FOLD00*/
  295. void i18n_destroy(i18n_context_t** ctx) {
  296. if (ctx && *ctx) {
  297. if ((*ctx)->xic)
  298. XDestroyIC((*ctx)->xic);
  299. if ((*ctx)->xim)
  300. XCloseIM((*ctx)->xim);
  301. free(*ctx);
  302. *ctx = NULL;
  303. }
  304. }
  305. void i18n_focus_in(i18n_context_t* ctx) { /*FOLD00*/
  306. #if XlibSpecificationRelease >= 6
  307. if (ctx->xic != NULL)
  308. XSetICFocus(ctx->xic);
  309. #endif
  310. }
  311. /*FOLD00*/
  312. void i18n_focus_out(i18n_context_t* ctx) { /*FOLD00*/
  313. #if XlibSpecificationRelease >= 6
  314. if (ctx->xic != NULL)
  315. XUnsetICFocus(ctx->xic);
  316. #endif
  317. }
  318. /*FOLD00*/
  319. /*
  320. * Lookup correct keysymbol from keymap event
  321. */
  322. int i18n_lookup_sym(XKeyEvent * keyEvent, char *keyName, int keySize, /*FOLD00*/
  323. KeySym * key, XIC xic) {
  324. static int showKeys = 0;
  325. int nbytes = 0;
  326. #if XlibSpecificationRelease >= 6
  327. if (xic != NULL) {
  328. if (keyEvent->type == KeyPress) {
  329. Status status_return;
  330. /* No KeyRelease events here ! */
  331. #if 1
  332. nbytes = XmbLookupString(xic, keyEvent, keyName, keySize,
  333. key, &status_return);
  334. #else
  335. wchar_t wk;
  336. nbytes = XwcLookupString(xic, keyEvent, &wk, 1, key, &status_return);
  337. printf("code=%0X\n", wk);
  338. keySize = 1;
  339. keyName[0] = wk & 0xFF;
  340. #endif
  341. }
  342. } else
  343. #endif
  344. do {
  345. static XComposeStatus compose_status = { NULL, 0 };
  346. nbytes = XLookupString(keyEvent, keyName, keySize,
  347. key, &compose_status);
  348. } while (0);
  349. if (showKeys) {
  350. fprintf(stderr, "Key: 0x%04lx '%s'\tKeyEventState:0x%x\t",
  351. *key, XKeysymToString(*key), keyEvent->state);
  352. if (nbytes && isprint(keyName[0])) {
  353. keyName[nbytes] = 0;
  354. fprintf(stderr, "String:'%s' Size:%2d ", keyName, nbytes);
  355. }
  356. fputs("\n", stderr);
  357. }
  358. if (((*key == XK_F1) || (*key == XK_F11))
  359. && ((keyEvent->state & (ShiftMask | ControlMask))
  360. == (ShiftMask | ControlMask))
  361. && (keyEvent->type == KeyPress))
  362. showKeys = !showKeys;
  363. return i18n_key_analyze(keyEvent, key, keyName, nbytes);
  364. }
  365. /*FOLD00*/