interactive-evdev.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907
  1. /*
  2. * Copyright © 2012 Ran Benita <ran234@gmail.com>
  3. * SPDX-License-Identifier: MIT
  4. */
  5. #include "config.h"
  6. #include <assert.h>
  7. #include <dirent.h>
  8. #include <errno.h>
  9. #include <fcntl.h>
  10. #include <fnmatch.h>
  11. #include <getopt.h>
  12. #include <limits.h>
  13. #include <locale.h>
  14. #include <poll.h>
  15. #include <signal.h>
  16. #include <stdbool.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <unistd.h>
  21. #include <linux/input.h>
  22. #include "xkbcommon/xkbcommon.h"
  23. #include "src/utils.h"
  24. #include "src/keymap-formats.h"
  25. #include "tools-common.h"
  26. struct keyboard {
  27. char *path;
  28. int fd;
  29. struct xkb_machine *machine;
  30. struct xkb_events *events;
  31. struct xkb_state *state;
  32. struct xkb_compose_state *compose_state;
  33. struct keyboard *next;
  34. };
  35. static bool verbose = false;
  36. static bool terminate = false;
  37. static xkb_keycode_t evdev_offset = 8;
  38. static bool use_events_api = true;
  39. static bool report_state_changes = true;
  40. static bool with_compose = false;
  41. static enum xkb_consumed_mode consumed_mode = XKB_CONSUMED_MODE_XKB;
  42. static enum print_state_options print_options = DEFAULT_PRINT_OPTIONS;
  43. #define DEFAULT_INCLUDE_PATH_PLACEHOLDER "__defaults__"
  44. #define NLONGS(n) (((n) + LONG_BIT - 1) / LONG_BIT)
  45. static bool
  46. evdev_bit_is_set(const unsigned long *array, int bit)
  47. {
  48. return array[bit / LONG_BIT] & (1ULL << (bit % LONG_BIT));
  49. }
  50. /* Some heuristics to see if the device is a keyboard. */
  51. static bool
  52. is_keyboard(int fd)
  53. {
  54. int i;
  55. unsigned long evbits[NLONGS(EV_CNT)] = { 0 };
  56. unsigned long keybits[NLONGS(KEY_CNT)] = { 0 };
  57. errno = 0;
  58. ioctl(fd, EVIOCGBIT(0, sizeof(evbits)), evbits);
  59. if (errno)
  60. return false;
  61. if (!evdev_bit_is_set(evbits, EV_KEY))
  62. return false;
  63. errno = 0;
  64. ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits);
  65. if (errno)
  66. return false;
  67. for (i = KEY_RESERVED; i <= KEY_MIN_INTERESTING; i++)
  68. if (evdev_bit_is_set(keybits, i))
  69. return true;
  70. return false;
  71. }
  72. static int
  73. keyboard_new(struct dirent *ent,
  74. struct xkb_context *ctx, struct xkb_keymap *keymap,
  75. const struct xkb_machine_builder *builder,
  76. const struct xkb_machine_options *options,
  77. struct xkb_compose_table *compose_table, struct keyboard **out)
  78. {
  79. int ret;
  80. char *path;
  81. int fd;
  82. struct xkb_machine *machine = NULL;
  83. struct xkb_events *events = NULL;
  84. struct xkb_state *state = NULL;
  85. struct xkb_compose_state *compose_state = NULL;
  86. struct keyboard *kbd = NULL;
  87. ret = asprintf(&path, "/dev/input/%s", ent->d_name);
  88. if (ret < 0)
  89. return -ENOMEM;
  90. fd = open(path, O_NONBLOCK | O_CLOEXEC | O_RDONLY);
  91. if (fd < 0) {
  92. ret = -errno;
  93. goto err_path;
  94. }
  95. if (!is_keyboard(fd)) {
  96. /* Dummy "skip this device" value. */
  97. ret = -ENOTSUP;
  98. goto err_fd;
  99. }
  100. if (use_events_api) {
  101. machine = xkb_machine_new(builder);
  102. if (!machine) {
  103. fprintf(stderr, "Couldn't create xkb state machine for %s\n", path);
  104. ret = -EFAULT;
  105. goto err_machine;
  106. }
  107. events = xkb_events_new_batch(ctx, XKB_EVENTS_NO_FLAGS);
  108. if (!events) {
  109. fprintf(stderr, "Couldn't create xkb events for %s\n", path);
  110. ret = -EFAULT;
  111. goto err_xkb_events;
  112. }
  113. }
  114. state = xkb_state_new(keymap);
  115. if (!state) {
  116. fprintf(stderr, "Couldn't create xkb state for %s\n", path);
  117. ret = -EFAULT;
  118. goto err_state;
  119. }
  120. const struct xkb_state_components_update components = {
  121. .size = sizeof(components),
  122. .components = XKB_STATE_CONTROLS,
  123. .affect_controls = options->controls.boolean.affect,
  124. .controls = options->controls.boolean.flags,
  125. };
  126. const struct xkb_state_update update = {
  127. .size = sizeof(update),
  128. .components = &components,
  129. };
  130. if (use_events_api) {
  131. // FIXME: handle error
  132. xkb_machine_process_synthetic(machine, &update, events);
  133. const struct xkb_event *event;
  134. while ((event = xkb_events_next(events))) {
  135. xkb_state_update_event(state, event);
  136. }
  137. } else {
  138. // FIXME: handle error
  139. xkb_state_update_synthetic(state, &update, NULL);
  140. }
  141. if (with_compose) {
  142. compose_state = xkb_compose_state_new(compose_table,
  143. XKB_COMPOSE_STATE_NO_FLAGS);
  144. if (!compose_state) {
  145. fprintf(stderr, "Couldn't create compose state for %s\n", path);
  146. ret = -EFAULT;
  147. goto err_compose_state;
  148. }
  149. }
  150. kbd = calloc(1, sizeof(*kbd));
  151. if (!kbd) {
  152. ret = -ENOMEM;
  153. goto err_kbd;
  154. }
  155. kbd->path = path;
  156. kbd->fd = fd;
  157. kbd->machine = machine;
  158. kbd->events = events;
  159. kbd->state = state;
  160. kbd->compose_state = compose_state;
  161. *out = kbd;
  162. return 0;
  163. err_kbd:
  164. xkb_compose_state_unref(compose_state);
  165. err_compose_state:
  166. xkb_state_unref(state);
  167. err_state:
  168. xkb_events_destroy(events);
  169. err_xkb_events:
  170. xkb_machine_unref(machine);
  171. err_machine:
  172. err_fd:
  173. close(fd);
  174. err_path:
  175. free(path);
  176. return ret;
  177. }
  178. static void
  179. keyboard_free(struct keyboard *kbd)
  180. {
  181. if (!kbd)
  182. return;
  183. if (kbd->fd >= 0)
  184. close(kbd->fd);
  185. free(kbd->path);
  186. xkb_machine_unref(kbd->machine);
  187. xkb_events_destroy(kbd->events);
  188. xkb_state_unref(kbd->state);
  189. xkb_compose_state_unref(kbd->compose_state);
  190. free(kbd);
  191. }
  192. static int
  193. filter_device_name(const struct dirent *ent)
  194. {
  195. return !fnmatch("event*", ent->d_name, 0);
  196. }
  197. static struct keyboard *
  198. get_keyboards(struct xkb_context *ctx, struct xkb_keymap *keymap,
  199. const struct xkb_machine_builder *builder,
  200. const struct xkb_machine_options *options,
  201. struct xkb_compose_table *compose_table)
  202. {
  203. int ret, i, nents;
  204. struct dirent **ents;
  205. struct keyboard *kbds = NULL, *kbd = NULL;
  206. nents = scandir("/dev/input", &ents, filter_device_name, alphasort);
  207. if (nents < 0) {
  208. fprintf(stderr, "Couldn't scan /dev/input: %s\n", strerror(errno));
  209. return NULL;
  210. }
  211. for (i = 0; i < nents; i++) {
  212. ret = keyboard_new(ents[i], ctx, keymap, builder, options,
  213. compose_table, &kbd);
  214. if (ret) {
  215. if (ret == -EACCES) {
  216. fprintf(stderr, "Couldn't open /dev/input/%s: %s. "
  217. "You probably need root to run this.\n",
  218. ents[i]->d_name, strerror(-ret));
  219. break;
  220. }
  221. if (ret != -ENOTSUP) {
  222. fprintf(stderr, "Couldn't open /dev/input/%s: %s. Skipping.\n",
  223. ents[i]->d_name, strerror(-ret));
  224. }
  225. continue;
  226. }
  227. assert(kbd != NULL);
  228. kbd->next = kbds;
  229. kbds = kbd;
  230. }
  231. if (!kbds) {
  232. fprintf(stderr, "Couldn't find any keyboards I can use! Quitting.\n");
  233. goto err;
  234. }
  235. err:
  236. for (i = 0; i < nents; i++)
  237. free(ents[i]);
  238. free(ents);
  239. return kbds;
  240. }
  241. static void
  242. free_keyboards(struct keyboard *kbds)
  243. {
  244. struct keyboard *next;
  245. while (kbds) {
  246. next = kbds->next;
  247. keyboard_free(kbds);
  248. kbds = next;
  249. }
  250. }
  251. /* The meaning of the input_event 'value' field. */
  252. enum {
  253. KEY_STATE_RELEASE = 0,
  254. KEY_STATE_PRESS = 1,
  255. KEY_STATE_REPEAT = 2,
  256. };
  257. static void
  258. process_event(struct keyboard *kbd, uint16_t type, uint16_t code, int32_t value)
  259. {
  260. if (type != EV_KEY)
  261. return;
  262. const xkb_keycode_t keycode = evdev_offset + code;
  263. struct xkb_keymap * const keymap = xkb_state_get_keymap(kbd->state);
  264. if ((value == KEY_STATE_REPEAT && !xkb_keymap_key_repeats(keymap, keycode)) ||
  265. (value != KEY_STATE_PRESS && value != KEY_STATE_REPEAT &&
  266. value != KEY_STATE_RELEASE))
  267. return;
  268. const enum xkb_key_direction direction = (value == KEY_STATE_RELEASE)
  269. ? XKB_KEY_UP
  270. : (value == KEY_STATE_REPEAT)
  271. ? XKB_KEY_REPEATED
  272. : XKB_KEY_DOWN;
  273. if (use_events_api) {
  274. /* Use the xkb_machine API */
  275. const int ret = xkb_machine_process_key(kbd->machine, keycode, direction,
  276. kbd->events);
  277. if (ret) {
  278. fprintf(stderr, "ERROR: could not update the state machine\n");
  279. // TODO: better error handling
  280. } else {
  281. tools_print_events(NULL, kbd->state, kbd->events,
  282. kbd->compose_state, consumed_mode,
  283. print_options, report_state_changes);
  284. }
  285. } else {
  286. /* Use the legacy state API */
  287. if (with_compose && direction == XKB_KEY_DOWN) {
  288. xkb_keysym_t keysym = xkb_state_key_get_one_sym(kbd->state, keycode);
  289. xkb_compose_state_feed(kbd->compose_state, keysym);
  290. }
  291. tools_print_keycode_state(
  292. NULL, kbd->state, kbd->compose_state, keycode, direction,
  293. consumed_mode, print_options
  294. );
  295. if (with_compose) {
  296. const enum xkb_compose_status status =
  297. xkb_compose_state_get_status(kbd->compose_state);
  298. if (status == XKB_COMPOSE_CANCELLED || status == XKB_COMPOSE_COMPOSED)
  299. xkb_compose_state_reset(kbd->compose_state);
  300. }
  301. const enum xkb_state_component changed =
  302. xkb_state_update_key(kbd->state, keycode, direction);
  303. if (changed && report_state_changes)
  304. tools_print_state_changes(NULL, kbd->state, changed, print_options);
  305. }
  306. }
  307. static int
  308. read_keyboard(struct keyboard *kbd)
  309. {
  310. ssize_t len;
  311. struct input_event evs[16];
  312. /* No fancy error checking here. */
  313. while ((len = read(kbd->fd, &evs, sizeof(evs))) > 0) {
  314. const size_t nevs = len / sizeof(struct input_event);
  315. for (size_t i = 0; i < nevs; i++)
  316. process_event(kbd, evs[i].type, evs[i].code, evs[i].value);
  317. }
  318. if (len < 0 && errno != EWOULDBLOCK) {
  319. fprintf(stderr, "Couldn't read %s: %s\n", kbd->path, strerror(errno));
  320. return 1;
  321. }
  322. return 0;
  323. }
  324. static int
  325. loop(struct keyboard *kbds)
  326. {
  327. int ret = -1;
  328. struct keyboard *kbd;
  329. nfds_t nfds, i;
  330. for (kbd = kbds, nfds = 0; kbd; kbd = kbd->next, nfds++) {}
  331. struct pollfd *fds = calloc(nfds, sizeof(*fds));
  332. if (!fds) {
  333. fprintf(stderr, "Out of memory");
  334. goto out;
  335. }
  336. for (i = 0, kbd = kbds; kbd && i < nfds; kbd = kbd->next, i++) {
  337. fds[i].fd = kbd->fd;
  338. fds[i].events = POLLIN;
  339. }
  340. while (!terminate) {
  341. ret = poll(fds, nfds, -1);
  342. if (ret < 0) {
  343. if (errno == EINTR)
  344. continue;
  345. fprintf(stderr, "Couldn't poll for events: %s\n",
  346. strerror(errno));
  347. goto out;
  348. }
  349. for (i = 0, kbd = kbds; kbd && i < nfds; kbd = kbd->next, i++) {
  350. if (fds[i].revents != 0) {
  351. ret = read_keyboard(kbd);
  352. if (ret) {
  353. goto out;
  354. }
  355. }
  356. }
  357. }
  358. ret = 0;
  359. out:
  360. free(fds);
  361. return ret;
  362. }
  363. static void
  364. sigintr_handler(int signum)
  365. {
  366. terminate = true;
  367. }
  368. static void
  369. usage(FILE *fp, char *progname)
  370. {
  371. fprintf(fp, "Usage: %s [--include=<path>] [--include-defaults] [--format=<format>]"
  372. "[--rules=<rules>] [--model=<model>] [--layout=<layout>] "
  373. "[--variant=<variant>] [--options=<options>] "
  374. "[--enable-environment-names]\n"
  375. " or: %s --keymap <path to keymap file>\n"
  376. "Options:\n"
  377. " --format <FORMAT>\n"
  378. " Use keymap format FORMAT (default: '%s')\n"
  379. " --strict\n"
  380. " Parse using strict mode\n"
  381. " --verbose\n"
  382. " Enable verbose debugging output\n"
  383. " -1, --uniline\n"
  384. " Enable uniline event output\n"
  385. " -*, --multiline\n"
  386. " Enable uniline event output\n"
  387. " --short\n"
  388. " Shorter event output\n"
  389. " --report-state-changes\n"
  390. " Report changes to the state\n"
  391. " --no-state-report\n"
  392. " Do not report changes to the state\n"
  393. " --legacy-state-api[=true|false]\n"
  394. " Use legacy state API instead of event API\n"
  395. " --controls\n"
  396. " Keyboard controls: sticky-keys, sticky-keys-no-simultaneous,\n"
  397. " sticky-keys-latch-to-lock, latch-simultaneous, overlay{1-8}\n"
  398. " --modifiers-mapping <MAPPING>\n"
  399. " Remap the modifiers\n"
  400. " --shortcuts-mask <MASK>\n"
  401. " Set the modifier mask for shortcuts tweaks\n"
  402. " --shortcuts-mapping <MAPPING>\n"
  403. " Set the layout indices mapping for shortcuts tweaks\n"
  404. " --enable-compose\n"
  405. " Enable Compose\n"
  406. " --consumed-mode={xkb|gtk}\n"
  407. " Select the consumed modifiers mode (default: xkb)\n"
  408. " --without-x11-offset\n"
  409. " Don't add X11 keycode offset\n"
  410. "Other:\n"
  411. " --help\n"
  412. " Display this help and exit\n"
  413. " --version\n"
  414. " Print version information and exit\n",
  415. progname, progname,
  416. xkb_keymap_get_format_label(DEFAULT_INPUT_KEYMAP_FORMAT)
  417. );
  418. }
  419. int
  420. main(int argc, char *argv[])
  421. {
  422. int ret = EXIT_FAILURE;
  423. struct keyboard *kbds;
  424. struct xkb_context *ctx = NULL;
  425. struct xkb_keymap *keymap = NULL;
  426. struct xkb_compose_table *compose_table = NULL;
  427. struct xkb_machine_builder *machine_builder = NULL;
  428. const char *includes[64];
  429. size_t num_includes = 0;
  430. bool use_env_names = false;
  431. enum xkb_keymap_format keymap_format = DEFAULT_INPUT_KEYMAP_FORMAT;
  432. static enum xkb_keymap_compile_flags compile_flags =
  433. (enum xkb_keymap_compile_flags) DEFAULT_KEYMAP_COMPILE_FLAGS;
  434. const char *rules = NULL;
  435. const char *model = NULL;
  436. const char *layout = NULL;
  437. const char *variant = NULL;
  438. const char *options = NULL;
  439. const char *keymap_path = NULL;
  440. bool with_keymap_file = false;
  441. const char *locale;
  442. struct sigaction act;
  443. enum options {
  444. OPT_VERBOSE,
  445. OPT_UNILINE,
  446. OPT_MULTILINE,
  447. OPT_INCLUDE,
  448. OPT_INCLUDE_DEFAULTS,
  449. OPT_ENABLE_ENV_NAMES,
  450. OPT_KEYMAP_FORMAT,
  451. OPT_KEYMAP_STRICT_PARSER,
  452. OPT_RULES,
  453. OPT_MODEL,
  454. OPT_LAYOUT,
  455. OPT_VARIANT,
  456. OPT_OPTION,
  457. OPT_KEYMAP,
  458. OPT_WITHOUT_X11_OFFSET,
  459. OPT_LEGACY_STATE_API,
  460. OPT_CONTROLS,
  461. OPT_MODIFIERS_TWEAK_MAPPING,
  462. OPT_SHORTCUTS_TWEAK_MASK,
  463. OPT_SHORTCUTS_TWEAK_MAPPING,
  464. OPT_CONSUMED_MODE,
  465. OPT_COMPOSE,
  466. OPT_SHORT,
  467. OPT_REPORT_STATE,
  468. OPT_NO_STATE_REPORT,
  469. };
  470. static struct option opts[] = {
  471. {"help", no_argument, 0, 'h'},
  472. {"version", no_argument, 0, 'V'},
  473. {"verbose", no_argument, 0, OPT_VERBOSE},
  474. {"uniline", no_argument, 0, OPT_UNILINE},
  475. {"multiline", no_argument, 0, OPT_MULTILINE},
  476. {"include", required_argument, 0, OPT_INCLUDE},
  477. {"include-defaults", no_argument, 0, OPT_INCLUDE_DEFAULTS},
  478. {"enable-environment-names", no_argument, 0, OPT_ENABLE_ENV_NAMES},
  479. {"format", required_argument, 0, OPT_KEYMAP_FORMAT},
  480. {"strict", no_argument, 0, OPT_KEYMAP_STRICT_PARSER},
  481. {"rules", required_argument, 0, OPT_RULES},
  482. {"model", required_argument, 0, OPT_MODEL},
  483. {"layout", required_argument, 0, OPT_LAYOUT},
  484. {"variant", required_argument, 0, OPT_VARIANT},
  485. {"options", required_argument, 0, OPT_OPTION},
  486. {"keymap", required_argument, 0, OPT_KEYMAP},
  487. {"legacy-state-api", optional_argument, 0, OPT_LEGACY_STATE_API},
  488. {"controls", required_argument, 0, OPT_CONTROLS},
  489. {"modifiers-mapping", required_argument, 0, OPT_MODIFIERS_TWEAK_MAPPING},
  490. {"shortcuts-mask", required_argument, 0, OPT_SHORTCUTS_TWEAK_MASK},
  491. {"shortcuts-mapping", required_argument, 0, OPT_SHORTCUTS_TWEAK_MAPPING},
  492. {"consumed-mode", required_argument, 0, OPT_CONSUMED_MODE},
  493. {"enable-compose", no_argument, 0, OPT_COMPOSE},
  494. {"short", no_argument, 0, OPT_SHORT},
  495. {"report-state-changes", no_argument, 0, OPT_REPORT_STATE},
  496. {"no-state-report", no_argument, 0, OPT_NO_STATE_REPORT},
  497. {"without-x11-offset", no_argument, 0, OPT_WITHOUT_X11_OFFSET},
  498. {0, 0, 0, 0},
  499. };
  500. setlocale(LC_ALL, "");
  501. bool has_rmlvo_options = false;
  502. /* Initialize machine options */
  503. struct xkb_machine_options machine_options = xkb_machine_options_new();
  504. /* Ensure synced with usage() and man page */
  505. assert(consumed_mode == XKB_CONSUMED_MODE_XKB);
  506. while (1) {
  507. int option_index = 0;
  508. int opt = getopt_long(argc, argv, "*1hV", opts, &option_index);
  509. if (opt == -1)
  510. break;
  511. switch (opt) {
  512. case OPT_VERBOSE:
  513. verbose = true;
  514. break;
  515. case '1':
  516. case OPT_UNILINE:
  517. print_options |= PRINT_UNILINE;
  518. break;
  519. case '*':
  520. case OPT_MULTILINE:
  521. print_options &= ~PRINT_UNILINE;
  522. break;
  523. case OPT_INCLUDE:
  524. if (num_includes >= ARRAY_SIZE(includes))
  525. goto too_many_includes;
  526. includes[num_includes++] = optarg;
  527. break;
  528. case OPT_INCLUDE_DEFAULTS:
  529. if (num_includes >= ARRAY_SIZE(includes))
  530. goto too_many_includes;
  531. includes[num_includes++] = DEFAULT_INCLUDE_PATH_PLACEHOLDER;
  532. break;
  533. case OPT_ENABLE_ENV_NAMES:
  534. use_env_names = true;
  535. break;
  536. case OPT_KEYMAP_FORMAT:
  537. keymap_format = xkb_keymap_parse_format(optarg);
  538. if (!keymap_format) {
  539. fprintf(stderr, "ERROR: invalid --format \"%s\"\n", optarg);
  540. usage(stderr, argv[0]);
  541. ret = EXIT_INVALID_USAGE;
  542. goto error_parse_args;
  543. }
  544. break;
  545. case OPT_KEYMAP_STRICT_PARSER:
  546. compile_flags |= XKB_KEYMAP_COMPILE_STRICT_MODE;
  547. break;
  548. case OPT_RULES:
  549. if (keymap_path)
  550. goto input_format_error;
  551. rules = optarg;
  552. has_rmlvo_options = true;
  553. break;
  554. case OPT_MODEL:
  555. if (keymap_path)
  556. goto input_format_error;
  557. model = optarg;
  558. has_rmlvo_options = true;
  559. break;
  560. case OPT_LAYOUT:
  561. if (keymap_path)
  562. goto input_format_error;
  563. layout = optarg;
  564. has_rmlvo_options = true;
  565. break;
  566. case OPT_VARIANT:
  567. if (keymap_path)
  568. goto input_format_error;
  569. variant = optarg;
  570. has_rmlvo_options = true;
  571. break;
  572. case OPT_OPTION:
  573. if (keymap_path)
  574. goto input_format_error;
  575. options = optarg;
  576. has_rmlvo_options = true;
  577. break;
  578. case OPT_KEYMAP:
  579. if (has_rmlvo_options)
  580. goto input_format_error;
  581. with_keymap_file = true;
  582. keymap_path = optarg;
  583. break;
  584. case OPT_WITHOUT_X11_OFFSET:
  585. evdev_offset = 0;
  586. break;
  587. case OPT_REPORT_STATE:
  588. report_state_changes = true;
  589. break;
  590. case OPT_NO_STATE_REPORT:
  591. report_state_changes = false;
  592. break;
  593. case OPT_COMPOSE:
  594. with_compose = true;
  595. break;
  596. case OPT_SHORT:
  597. print_options &= ~PRINT_VERBOSE;
  598. break;
  599. case OPT_CONSUMED_MODE:
  600. if (strcmp(optarg, "gtk") == 0) {
  601. consumed_mode = XKB_CONSUMED_MODE_GTK;
  602. } else if (strcmp(optarg, "xkb") == 0) {
  603. consumed_mode = XKB_CONSUMED_MODE_XKB;
  604. } else {
  605. fprintf(stderr, "ERROR: invalid --consumed-mode \"%s\"\n", optarg);
  606. usage(stderr, argv[0]);
  607. ret = EXIT_INVALID_USAGE;
  608. goto error_parse_args;
  609. }
  610. break;
  611. #ifdef ENABLE_PRIVATE_APIS
  612. case OPT_PRINT_MODMAPS:
  613. print_modmaps = true;
  614. break;
  615. #endif
  616. case OPT_LEGACY_STATE_API: {
  617. bool legacy_api = true;
  618. if (!tools_parse_bool(optarg, TOOLS_ARG_OPTIONAL, &legacy_api)) {
  619. usage(stderr, argv[0]);
  620. ret = EXIT_INVALID_USAGE;
  621. goto error_parse_args;
  622. }
  623. use_events_api = !legacy_api;
  624. break;
  625. }
  626. case OPT_CONTROLS:
  627. if (!tools_parse_controls(optarg, &machine_options)) {
  628. usage(stderr, argv[0]);
  629. ret = EXIT_INVALID_USAGE;
  630. goto error_parse_args;
  631. }
  632. /* --legacy-state-api=false is implied */
  633. use_events_api = true;
  634. break;
  635. case OPT_MODIFIERS_TWEAK_MAPPING:
  636. if (!tools_parse_modifiers_mappings(optarg, &machine_options)) {
  637. usage(stderr, argv[0]);
  638. ret = EXIT_INVALID_USAGE;
  639. goto error_parse_args;
  640. }
  641. /* --legacy-state-api=false is implied */
  642. use_events_api = true;
  643. break;
  644. case OPT_SHORTCUTS_TWEAK_MASK:
  645. if (!tools_parse_shortcuts_mask(optarg, &machine_options)) {
  646. usage(stderr, argv[0]);
  647. ret = EXIT_INVALID_USAGE;
  648. goto error_parse_args;
  649. }
  650. /* --legacy-state-api=false is implied */
  651. use_events_api = true;
  652. break;
  653. case OPT_SHORTCUTS_TWEAK_MAPPING:
  654. if (!tools_parse_shortcuts_mappings(optarg, &machine_options)) {
  655. usage(stderr, argv[0]);
  656. ret = EXIT_INVALID_USAGE;
  657. goto error_parse_args;
  658. }
  659. /* --legacy-state-api=false is implied */
  660. use_events_api = true;
  661. break;
  662. case 'h':
  663. usage(stdout, argv[0]);
  664. ret = EXIT_SUCCESS;
  665. goto error_parse_args;
  666. case 'V':
  667. printf("%s\n", LIBXKBCOMMON_VERSION);
  668. ret = EXIT_SUCCESS;
  669. goto error_parse_args;
  670. default:
  671. usage(stderr, argv[0]);
  672. ret = EXIT_INVALID_USAGE;
  673. goto error_parse_args;
  674. }
  675. }
  676. if (optind < argc && !isempty(argv[optind])) {
  677. /* Some positional arguments left: use as a keymap input */
  678. if (keymap_path || has_rmlvo_options)
  679. goto too_much_arguments;
  680. keymap_path = argv[optind++];
  681. if (optind < argc) {
  682. too_much_arguments:
  683. fprintf(stderr, "ERROR: Too much positional arguments\n");
  684. usage(stderr, argv[0]);
  685. ret = EXIT_INVALID_USAGE;
  686. goto error_parse_args;
  687. }
  688. with_keymap_file = true;
  689. } else if (is_pipe_or_regular_file(STDIN_FILENO) && !with_keymap_file) {
  690. /* No positional argument: piping detected */
  691. with_keymap_file = true;
  692. }
  693. if (isempty(keymap_path) || strcmp(keymap_path, "-") == 0)
  694. keymap_path = NULL;
  695. if (!(print_options & PRINT_VERBOSE) && (print_options & PRINT_UNILINE)) {
  696. print_options &= ~PRINT_VERBOSE_ONE_LINE_FIELDS;
  697. }
  698. enum xkb_context_flags ctx_flags = XKB_CONTEXT_NO_DEFAULT_INCLUDES;
  699. if (!use_env_names)
  700. ctx_flags |= XKB_CONTEXT_NO_ENVIRONMENT_NAMES;
  701. ctx = xkb_context_new(ctx_flags);
  702. if (!ctx) {
  703. fprintf(stderr, "ERROR: Couldn't create xkb context\n");
  704. goto out;
  705. }
  706. if (verbose)
  707. tools_enable_verbose_logging(ctx);
  708. if (num_includes == 0)
  709. includes[num_includes++] = DEFAULT_INCLUDE_PATH_PLACEHOLDER;
  710. for (size_t i = 0; i < num_includes; i++) {
  711. const char *include = includes[i];
  712. if (strcmp(include, DEFAULT_INCLUDE_PATH_PLACEHOLDER) == 0)
  713. xkb_context_include_path_append_default(ctx);
  714. else
  715. xkb_context_include_path_append(ctx, include);
  716. }
  717. if (with_keymap_file) {
  718. FILE *file = NULL;
  719. if (keymap_path) {
  720. /* Read from regular file */
  721. file = fopen(keymap_path, "rb");
  722. } else {
  723. /* Read from stdin */
  724. file = tools_read_stdin();
  725. }
  726. if (!file) {
  727. fprintf(stderr, "ERROR: Failed to open keymap file \"%s\": %s\n",
  728. keymap_path ? keymap_path : "stdin", strerror(errno));
  729. goto out;
  730. }
  731. keymap = xkb_keymap_new_from_file(ctx, file, keymap_format,
  732. compile_flags);
  733. fclose(file);
  734. }
  735. else {
  736. struct xkb_rule_names rmlvo = {
  737. .rules = (isempty(rules)) ? NULL : rules,
  738. .model = (isempty(model)) ? NULL : model,
  739. .layout = (isempty(layout)) ? NULL : layout,
  740. .variant = (isempty(variant)) ? NULL : variant,
  741. .options = (isempty(options)) ? NULL : options
  742. };
  743. if (!rules && !model && !layout && !variant && !options)
  744. keymap = xkb_keymap_new_from_names2(ctx, NULL, keymap_format,
  745. compile_flags);
  746. else
  747. keymap = xkb_keymap_new_from_names2(ctx, &rmlvo, keymap_format,
  748. compile_flags);
  749. if (!keymap) {
  750. fprintf(stderr,
  751. "ERROR: Failed to compile RMLVO: "
  752. "'%s', '%s', '%s', '%s', '%s'\n",
  753. rules, model, layout, variant, options);
  754. goto out;
  755. }
  756. }
  757. if (!keymap) {
  758. fprintf(stderr, "ERROR: Couldn't create xkb keymap\n");
  759. goto out;
  760. }
  761. machine_builder = xkb_machine_builder_new_from_options(keymap,
  762. &machine_options);
  763. if (!machine_builder) {
  764. fprintf(stderr, "ERROR: Failed to create state machine builder\n");
  765. ret = EXIT_FAILURE;
  766. goto out;
  767. }
  768. if (with_compose) {
  769. locale = setlocale(LC_CTYPE, NULL);
  770. compose_table =
  771. xkb_compose_table_new_from_locale(ctx, locale,
  772. XKB_COMPOSE_COMPILE_NO_FLAGS);
  773. if (!compose_table) {
  774. fprintf(stderr, "ERROR: Couldn't create compose from locale\n");
  775. goto out;
  776. }
  777. }
  778. kbds = get_keyboards(ctx, keymap, machine_builder, &machine_options,
  779. compose_table);
  780. if (!kbds) {
  781. goto out;
  782. }
  783. #ifdef ENABLE_PRIVATE_APIS
  784. if (print_modmaps) {
  785. print_keys_modmaps(keymap);
  786. putchar('\n');
  787. print_modifiers_encodings(keymap);
  788. putchar('\n');
  789. }
  790. #endif
  791. act.sa_handler = sigintr_handler;
  792. sigemptyset(&act.sa_mask);
  793. act.sa_flags = 0;
  794. sigaction(SIGINT, &act, NULL);
  795. sigaction(SIGTERM, &act, NULL);
  796. tools_disable_stdin_echo();
  797. ret = loop(kbds);
  798. tools_enable_stdin_echo();
  799. free_keyboards(kbds);
  800. out:
  801. xkb_compose_table_unref(compose_table);
  802. xkb_machine_builder_destroy(machine_builder);
  803. xkb_keymap_unref(keymap);
  804. error_parse_args:
  805. xkb_machine_options_free(&machine_options);
  806. xkb_context_unref(ctx);
  807. return ret;
  808. too_many_includes:
  809. fprintf(stderr, "ERROR: too many includes (max: %zu)\n",
  810. ARRAY_SIZE(includes));
  811. xkb_machine_options_free(&machine_options);
  812. exit(EXIT_INVALID_USAGE);
  813. input_format_error:
  814. fprintf(stderr, "ERROR: Cannot use RMLVO options with keymap input\n");
  815. usage(stderr, argv[0]);
  816. xkb_machine_options_free(&machine_options);
  817. exit(EXIT_INVALID_USAGE);
  818. }