ddxLoad.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. /************************************************************
  2. Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
  3. Permission to use, copy, modify, and distribute this
  4. software and its documentation for any purpose and without
  5. fee is hereby granted, provided that the above copyright
  6. notice appear in all copies and that both that copyright
  7. notice and this permission notice appear in supporting
  8. documentation, and that the name of Silicon Graphics not be
  9. used in advertising or publicity pertaining to distribution
  10. of the software without specific prior written permission.
  11. Silicon Graphics makes no representation about the suitability
  12. of this software for any purpose. It is provided "as is"
  13. without any express or implied warranty.
  14. SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
  15. SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  16. AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
  17. GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
  18. DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  19. DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  20. OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
  21. THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22. ********************************************************/
  23. #ifdef HAVE_DIX_CONFIG_H
  24. #include <dix-config.h>
  25. #endif
  26. #include <xkb-config.h>
  27. #include <stdio.h>
  28. #include <ctype.h>
  29. #include <X11/X.h>
  30. #include <X11/Xos.h>
  31. #include <X11/Xproto.h>
  32. #include <X11/keysym.h>
  33. #include <X11/extensions/XKM.h>
  34. #include "inputstr.h"
  35. #include "scrnintstr.h"
  36. #include "windowstr.h"
  37. #define XKBSRV_NEED_FILE_FUNCS
  38. #include <xkbsrv.h>
  39. #include <X11/extensions/XI.h>
  40. #include "xkb.h"
  41. /*
  42. * If XKM_OUTPUT_DIR specifies a path without a leading slash, it is
  43. * relative to the top-level XKB configuration directory.
  44. * Making the server write to a subdirectory of that directory
  45. * requires some work in the general case (install procedure
  46. * has to create links to /var or somesuch on many machines),
  47. * so we just compile into /usr/tmp for now.
  48. */
  49. #ifndef XKM_OUTPUT_DIR
  50. #define XKM_OUTPUT_DIR "compiled/"
  51. #endif
  52. #define PRE_ERROR_MSG "\"The XKEYBOARD keymap compiler (xkbcomp) reports:\""
  53. #define ERROR_PREFIX "\"> \""
  54. #define POST_ERROR_MSG1 "\"Errors from xkbcomp are not fatal to the X server\""
  55. #define POST_ERROR_MSG2 "\"End of messages from xkbcomp\""
  56. #if defined(WIN32)
  57. #define PATHSEPARATOR "\\"
  58. #else
  59. #define PATHSEPARATOR "/"
  60. #endif
  61. static unsigned
  62. LoadXKM(unsigned want, unsigned need, const char *keymap, XkbDescPtr *xkbRtrn);
  63. static void
  64. OutputDirectory(char *outdir, size_t size)
  65. {
  66. #ifndef WIN32
  67. /* Can we write an xkm and then open it too? */
  68. if (access(XKM_OUTPUT_DIR, W_OK | X_OK) == 0 &&
  69. (strlen(XKM_OUTPUT_DIR) < size)) {
  70. (void) strcpy(outdir, XKM_OUTPUT_DIR);
  71. }
  72. else
  73. #else
  74. if (strlen(Win32TempDir()) + 1 < size) {
  75. (void) strcpy(outdir, Win32TempDir());
  76. (void) strcat(outdir, "\\");
  77. }
  78. else
  79. #endif
  80. if (strlen("/tmp/") < size) {
  81. (void) strcpy(outdir, "/tmp/");
  82. }
  83. }
  84. /**
  85. * Callback invoked by XkbRunXkbComp. Write to out to talk to xkbcomp.
  86. */
  87. typedef void (*xkbcomp_buffer_callback)(FILE *out, void *userdata);
  88. /**
  89. * Start xkbcomp, let the callback write into xkbcomp's stdin. When done,
  90. * return a strdup'd copy of the file name we've written to.
  91. */
  92. static char *
  93. RunXkbComp(xkbcomp_buffer_callback callback, void *userdata)
  94. {
  95. FILE *out;
  96. char *buf = NULL, keymap[PATH_MAX], xkm_output_dir[PATH_MAX];
  97. const char *emptystring = "";
  98. char *xkbbasedirflag = NULL;
  99. const char *xkbbindir = emptystring;
  100. const char *xkbbindirsep = emptystring;
  101. #ifdef WIN32
  102. /* WIN32 has no popen. The input must be stored in a file which is
  103. used as input for xkbcomp. xkbcomp does not read from stdin. */
  104. char tmpname[PATH_MAX];
  105. const char *xkmfile = tmpname;
  106. #else
  107. const char *xkmfile = "-";
  108. #endif
  109. snprintf(keymap, sizeof(keymap), "server-%s", display);
  110. OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir));
  111. #ifdef WIN32
  112. strcpy(tmpname, Win32TempDir());
  113. strcat(tmpname, "\\xkb_XXXXXX");
  114. (void) mktemp(tmpname);
  115. #endif
  116. if (XkbBaseDirectory != NULL) {
  117. if (asprintf(&xkbbasedirflag, "\"-R%s\"", XkbBaseDirectory) == -1)
  118. xkbbasedirflag = NULL;
  119. }
  120. if (XkbBinDirectory != NULL) {
  121. int ld = strlen(XkbBinDirectory);
  122. int lps = strlen(PATHSEPARATOR);
  123. xkbbindir = XkbBinDirectory;
  124. if ((ld >= lps) && (strcmp(xkbbindir + ld - lps, PATHSEPARATOR) != 0)) {
  125. xkbbindirsep = PATHSEPARATOR;
  126. }
  127. }
  128. if (asprintf(&buf,
  129. "\"%s%sxkbcomp\" -w %d %s -xkm \"%s\" "
  130. "-em1 %s -emp %s -eml %s \"%s%s.xkm\"",
  131. xkbbindir, xkbbindirsep,
  132. ((xkbDebugFlags < 2) ? 1 :
  133. ((xkbDebugFlags > 10) ? 10 : (int) xkbDebugFlags)),
  134. xkbbasedirflag ? xkbbasedirflag : "", xkmfile,
  135. PRE_ERROR_MSG, ERROR_PREFIX, POST_ERROR_MSG1,
  136. xkm_output_dir, keymap) == -1)
  137. buf = NULL;
  138. free(xkbbasedirflag);
  139. if (!buf) {
  140. LogMessage(X_ERROR,
  141. "XKB: Could not invoke xkbcomp: not enough memory\n");
  142. return NULL;
  143. }
  144. #ifndef WIN32
  145. out = Popen(buf, "w");
  146. #else
  147. out = fopen(tmpname, "w");
  148. #endif
  149. if (out != NULL) {
  150. /* Now write to xkbcomp */
  151. (*callback)(out, userdata);
  152. #ifndef WIN32
  153. if (Pclose(out) == 0)
  154. #else
  155. if (fclose(out) == 0 && System(buf) >= 0)
  156. #endif
  157. {
  158. if (xkbDebugFlags)
  159. DebugF("[xkb] xkb executes: %s\n", buf);
  160. free(buf);
  161. #ifdef WIN32
  162. unlink(tmpname);
  163. #endif
  164. return xnfstrdup(keymap);
  165. }
  166. else
  167. LogMessage(X_ERROR, "Error compiling keymap (%s)\n", keymap);
  168. #ifdef WIN32
  169. /* remove the temporary file */
  170. unlink(tmpname);
  171. #endif
  172. }
  173. else {
  174. #ifndef WIN32
  175. LogMessage(X_ERROR, "XKB: Could not invoke xkbcomp\n");
  176. #else
  177. LogMessage(X_ERROR, "Could not open file %s\n", tmpname);
  178. #endif
  179. }
  180. free(buf);
  181. return NULL;
  182. }
  183. typedef struct {
  184. XkbDescPtr xkb;
  185. XkbComponentNamesPtr names;
  186. unsigned int want;
  187. unsigned int need;
  188. } XkbKeymapNamesCtx;
  189. static void
  190. xkb_write_keymap_for_names_cb(FILE *out, void *userdata)
  191. {
  192. XkbKeymapNamesCtx *ctx = userdata;
  193. #ifdef DEBUG
  194. if (xkbDebugFlags) {
  195. ErrorF("[xkb] XkbDDXCompileKeymapByNames compiling keymap:\n");
  196. XkbWriteXKBKeymapForNames(stderr, ctx->names, ctx->xkb, ctx->want, ctx->need);
  197. }
  198. #endif
  199. XkbWriteXKBKeymapForNames(out, ctx->names, ctx->xkb, ctx->want, ctx->need);
  200. }
  201. static Bool
  202. XkbDDXCompileKeymapByNames(XkbDescPtr xkb,
  203. XkbComponentNamesPtr names,
  204. unsigned want,
  205. unsigned need, char *nameRtrn, int nameRtrnLen)
  206. {
  207. char *keymap;
  208. Bool rc = FALSE;
  209. XkbKeymapNamesCtx ctx = {
  210. .xkb = xkb,
  211. .names = names,
  212. .want = want,
  213. .need = need
  214. };
  215. keymap = RunXkbComp(xkb_write_keymap_for_names_cb, &ctx);
  216. if (keymap) {
  217. if(nameRtrn)
  218. strlcpy(nameRtrn, keymap, nameRtrnLen);
  219. free(keymap);
  220. rc = TRUE;
  221. } else if (nameRtrn)
  222. *nameRtrn = '\0';
  223. return rc;
  224. }
  225. typedef struct {
  226. const char *keymap;
  227. size_t len;
  228. } XkbKeymapString;
  229. static void
  230. xkb_write_keymap_string_cb(FILE *out, void *userdata)
  231. {
  232. XkbKeymapString *s = userdata;
  233. fwrite(s->keymap, s->len, 1, out);
  234. }
  235. static unsigned int
  236. XkbDDXLoadKeymapFromString(DeviceIntPtr keybd,
  237. const char *keymap, int keymap_length,
  238. unsigned int want,
  239. unsigned int need,
  240. XkbDescPtr *xkbRtrn)
  241. {
  242. unsigned int have;
  243. char *map_name;
  244. XkbKeymapString map = {
  245. .keymap = keymap,
  246. .len = keymap_length
  247. };
  248. *xkbRtrn = NULL;
  249. map_name = RunXkbComp(xkb_write_keymap_string_cb, &map);
  250. if (!map_name) {
  251. LogMessage(X_ERROR, "XKB: Couldn't compile keymap\n");
  252. return 0;
  253. }
  254. have = LoadXKM(want, need, map_name, xkbRtrn);
  255. free(map_name);
  256. return have;
  257. }
  258. static FILE *
  259. XkbDDXOpenConfigFile(const char *mapName, char *fileNameRtrn, int fileNameRtrnLen)
  260. {
  261. char buf[PATH_MAX], xkm_output_dir[PATH_MAX];
  262. FILE *file;
  263. buf[0] = '\0';
  264. if (mapName != NULL) {
  265. OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir));
  266. if ((XkbBaseDirectory != NULL) && (xkm_output_dir[0] != '/')
  267. #ifdef WIN32
  268. && (!isalpha(xkm_output_dir[0]) || xkm_output_dir[1] != ':')
  269. #endif
  270. ) {
  271. if (snprintf(buf, PATH_MAX, "%s/%s%s.xkm", XkbBaseDirectory,
  272. xkm_output_dir, mapName) >= PATH_MAX)
  273. buf[0] = '\0';
  274. }
  275. else {
  276. if (snprintf(buf, PATH_MAX, "%s%s.xkm", xkm_output_dir, mapName)
  277. >= PATH_MAX)
  278. buf[0] = '\0';
  279. }
  280. if (buf[0] != '\0')
  281. file = fopen(buf, "rb");
  282. else
  283. file = NULL;
  284. }
  285. else
  286. file = NULL;
  287. if ((fileNameRtrn != NULL) && (fileNameRtrnLen > 0)) {
  288. strlcpy(fileNameRtrn, buf, fileNameRtrnLen);
  289. }
  290. return file;
  291. }
  292. static unsigned
  293. LoadXKM(unsigned want, unsigned need, const char *keymap, XkbDescPtr *xkbRtrn)
  294. {
  295. FILE *file;
  296. char fileName[PATH_MAX];
  297. unsigned missing;
  298. file = XkbDDXOpenConfigFile(keymap, fileName, PATH_MAX);
  299. if (file == NULL) {
  300. LogMessage(X_ERROR, "Couldn't open compiled keymap file %s\n",
  301. fileName);
  302. return 0;
  303. }
  304. missing = XkmReadFile(file, need, want, xkbRtrn);
  305. if (*xkbRtrn == NULL) {
  306. LogMessage(X_ERROR, "Error loading keymap %s\n", fileName);
  307. fclose(file);
  308. (void) unlink(fileName);
  309. return 0;
  310. }
  311. else {
  312. DebugF("Loaded XKB keymap %s, defined=0x%x\n", fileName,
  313. (*xkbRtrn)->defined);
  314. }
  315. fclose(file);
  316. (void) unlink(fileName);
  317. return (need | want) & (~missing);
  318. }
  319. unsigned
  320. XkbDDXLoadKeymapByNames(DeviceIntPtr keybd,
  321. XkbComponentNamesPtr names,
  322. unsigned want,
  323. unsigned need,
  324. XkbDescPtr *xkbRtrn, char *nameRtrn, int nameRtrnLen)
  325. {
  326. XkbDescPtr xkb;
  327. *xkbRtrn = NULL;
  328. if ((keybd == NULL) || (keybd->key == NULL) ||
  329. (keybd->key->xkbInfo == NULL))
  330. xkb = NULL;
  331. else
  332. xkb = keybd->key->xkbInfo->desc;
  333. if ((names->keycodes == NULL) && (names->types == NULL) &&
  334. (names->compat == NULL) && (names->symbols == NULL) &&
  335. (names->geometry == NULL)) {
  336. LogMessage(X_ERROR, "XKB: No components provided for device %s\n",
  337. keybd->name ? keybd->name : "(unnamed keyboard)");
  338. return 0;
  339. }
  340. else if (!XkbDDXCompileKeymapByNames(xkb, names, want, need,
  341. nameRtrn, nameRtrnLen)) {
  342. LogMessage(X_ERROR, "XKB: Couldn't compile keymap\n");
  343. return 0;
  344. }
  345. return LoadXKM(want, need, nameRtrn, xkbRtrn);
  346. }
  347. Bool
  348. XkbDDXNamesFromRules(DeviceIntPtr keybd,
  349. const char *rules_name,
  350. XkbRF_VarDefsPtr defs, XkbComponentNamesPtr names)
  351. {
  352. char buf[PATH_MAX];
  353. FILE *file;
  354. Bool complete;
  355. XkbRF_RulesPtr rules;
  356. if (!rules_name)
  357. return FALSE;
  358. if (snprintf(buf, PATH_MAX, "%s/rules/%s", XkbBaseDirectory, rules_name)
  359. >= PATH_MAX) {
  360. LogMessage(X_ERROR, "XKB: Rules name is too long\n");
  361. return FALSE;
  362. }
  363. file = fopen(buf, "r");
  364. if (!file) {
  365. LogMessage(X_ERROR, "XKB: Couldn't open rules file %s\n", buf);
  366. return FALSE;
  367. }
  368. rules = XkbRF_Create();
  369. if (!rules) {
  370. LogMessage(X_ERROR, "XKB: Couldn't create rules struct\n");
  371. fclose(file);
  372. return FALSE;
  373. }
  374. if (!XkbRF_LoadRules(file, rules)) {
  375. LogMessage(X_ERROR, "XKB: Couldn't parse rules file %s\n", rules_name);
  376. fclose(file);
  377. XkbRF_Free(rules, TRUE);
  378. return FALSE;
  379. }
  380. memset(names, 0, sizeof(*names));
  381. complete = XkbRF_GetComponents(rules, defs, names);
  382. fclose(file);
  383. XkbRF_Free(rules, TRUE);
  384. if (!complete)
  385. LogMessage(X_ERROR, "XKB: Rules returned no components\n");
  386. return complete;
  387. }
  388. static Bool
  389. XkbRMLVOtoKcCGST(DeviceIntPtr dev, XkbRMLVOSet * rmlvo,
  390. XkbComponentNamesPtr kccgst)
  391. {
  392. XkbRF_VarDefsRec mlvo;
  393. mlvo.model = rmlvo->model;
  394. mlvo.layout = rmlvo->layout;
  395. mlvo.variant = rmlvo->variant;
  396. mlvo.options = rmlvo->options;
  397. return XkbDDXNamesFromRules(dev, rmlvo->rules, &mlvo, kccgst);
  398. }
  399. /**
  400. * Compile the given RMLVO keymap and return it. Returns the XkbDescPtr on
  401. * success or NULL on failure. If the components compiled are not a superset
  402. * or equal to need, the compiliation is treated as failure.
  403. */
  404. static XkbDescPtr
  405. XkbCompileKeymapForDevice(DeviceIntPtr dev, XkbRMLVOSet * rmlvo, int need)
  406. {
  407. XkbDescPtr xkb = NULL;
  408. unsigned int provided;
  409. XkbComponentNamesRec kccgst = { 0 };
  410. char name[PATH_MAX];
  411. if (XkbRMLVOtoKcCGST(dev, rmlvo, &kccgst)) {
  412. provided =
  413. XkbDDXLoadKeymapByNames(dev, &kccgst, XkmAllIndicesMask, need, &xkb,
  414. name, PATH_MAX);
  415. if ((need & provided) != need) {
  416. if (xkb) {
  417. XkbFreeKeyboard(xkb, 0, TRUE);
  418. xkb = NULL;
  419. }
  420. }
  421. }
  422. XkbFreeComponentNames(&kccgst, FALSE);
  423. return xkb;
  424. }
  425. static XkbDescPtr
  426. KeymapOrDefaults(DeviceIntPtr dev, XkbDescPtr xkb)
  427. {
  428. XkbRMLVOSet dflts;
  429. if (xkb)
  430. return xkb;
  431. /* we didn't get what we really needed. And that will likely leave
  432. * us with a keyboard that doesn't work. Use the defaults instead */
  433. LogMessage(X_ERROR, "XKB: Failed to load keymap. Loading default "
  434. "keymap instead.\n");
  435. XkbGetRulesDflts(&dflts);
  436. xkb = XkbCompileKeymapForDevice(dev, &dflts, 0);
  437. XkbFreeRMLVOSet(&dflts, FALSE);
  438. return xkb;
  439. }
  440. XkbDescPtr
  441. XkbCompileKeymap(DeviceIntPtr dev, XkbRMLVOSet * rmlvo)
  442. {
  443. XkbDescPtr xkb;
  444. unsigned int need;
  445. if (!dev || !rmlvo) {
  446. LogMessage(X_ERROR, "XKB: No device or RMLVO specified\n");
  447. return NULL;
  448. }
  449. /* These are the components we really really need */
  450. need = XkmSymbolsMask | XkmCompatMapMask | XkmTypesMask |
  451. XkmKeyNamesMask | XkmVirtualModsMask;
  452. xkb = XkbCompileKeymapForDevice(dev, rmlvo, need);
  453. return KeymapOrDefaults(dev, xkb);
  454. }
  455. XkbDescPtr
  456. XkbCompileKeymapFromString(DeviceIntPtr dev,
  457. const char *keymap, int keymap_length)
  458. {
  459. XkbDescPtr xkb;
  460. unsigned int need, provided;
  461. if (!dev || !keymap) {
  462. LogMessage(X_ERROR, "XKB: No device or keymap specified\n");
  463. return NULL;
  464. }
  465. /* These are the components we really really need */
  466. need = XkmSymbolsMask | XkmCompatMapMask | XkmTypesMask |
  467. XkmKeyNamesMask | XkmVirtualModsMask;
  468. provided =
  469. XkbDDXLoadKeymapFromString(dev, keymap, keymap_length,
  470. XkmAllIndicesMask, need, &xkb);
  471. if ((need & provided) != need) {
  472. if (xkb) {
  473. XkbFreeKeyboard(xkb, 0, TRUE);
  474. xkb = NULL;
  475. }
  476. }
  477. return KeymapOrDefaults(dev, xkb);
  478. }