interactive-wayland.c 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366
  1. /*
  2. * Copyright © 2012 Collabora, Ltd.
  3. * Copyright © 2013 Ran Benita <ran234@gmail.com>
  4. * Copyright © 2016 Daniel Stone <daniel@fooishbar.org>
  5. * SPDX-License-Identifier: MIT
  6. */
  7. #include "config.h"
  8. #include <assert.h>
  9. #include <errno.h>
  10. #include <fcntl.h>
  11. #include <getopt.h>
  12. #include <locale.h>
  13. #include <stdbool.h>
  14. #include <stdint.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <sys/mman.h>
  18. #include <unistd.h>
  19. #include "xkbcommon/xkbcommon.h"
  20. #include "xkbcommon/xkbcommon-compose.h"
  21. #include "src/utils.h"
  22. #include "src/keymap-formats.h"
  23. #include "tools-common.h"
  24. #include <wayland-client.h>
  25. #include "wayland-client-protocol.h"
  26. #include "xdg-shell-client-protocol.h"
  27. #include "xdg-decoration-unstable-v1-client-protocol.h"
  28. #include <wayland-util.h>
  29. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  30. /* Offset between evdev keycodes (where KEY_ESCAPE is 1), and the evdev XKB
  31. * keycode set (where ESC is 9). */
  32. #define EVDEV_OFFSET 8
  33. struct interactive_dpy {
  34. struct wl_display *dpy;
  35. struct wl_compositor *compositor;
  36. struct xdg_wm_base *shell;
  37. struct wl_shm *shm;
  38. uint32_t shm_format;
  39. struct wl_buffer *buf;
  40. struct zxdg_decoration_manager_v1 *decoration_manager;
  41. struct zxdg_toplevel_decoration_v1 *decoration;
  42. struct xkb_context *ctx;
  43. struct xkb_compose_table *compose_table;
  44. struct wl_surface *wl_surf;
  45. struct xdg_surface *xdg_surf;
  46. struct xdg_toplevel *xdg_top;
  47. struct wl_list seats;
  48. };
  49. struct interactive_seat {
  50. struct interactive_dpy *inter;
  51. struct wl_seat *wl_seat;
  52. struct wl_keyboard *wl_kbd;
  53. struct wl_pointer *wl_pointer;
  54. uint32_t version; /* ... of wl_seat */
  55. uint32_t global_name; /* an ID of sorts */
  56. char *name_str; /* a descriptor */
  57. struct xkb_keymap *keymap;
  58. struct xkb_state *state;
  59. struct xkb_machine *machine;
  60. struct xkb_events *events;
  61. struct xkb_compose_state *compose_state;
  62. struct wl_list link;
  63. };
  64. static bool terminate = false;
  65. static enum xkb_keymap_format keymap_input_format = DEFAULT_INPUT_KEYMAP_FORMAT;
  66. static enum xkb_keymap_compile_flags compile_flags =
  67. (enum xkb_keymap_compile_flags) DEFAULT_KEYMAP_COMPILE_FLAGS;
  68. #ifdef KEYMAP_DUMP
  69. static_assert(DEFAULT_OUTPUT_KEYMAP_FORMAT == XKB_KEYMAP_USE_ORIGINAL_FORMAT,
  70. "Out of sync usage()");
  71. static enum xkb_keymap_format keymap_output_format = DEFAULT_OUTPUT_KEYMAP_FORMAT;
  72. static enum xkb_keymap_serialize_flags serialize_flags =
  73. (enum xkb_keymap_serialize_flags) DEFAULT_KEYMAP_SERIALIZE_FLAGS;
  74. static bool dump_raw_keymap;
  75. #else
  76. static bool use_events_api = true;
  77. static enum xkb_consumed_mode consumed_mode = XKB_CONSUMED_MODE_XKB;
  78. static enum print_state_options print_options = DEFAULT_PRINT_OPTIONS;
  79. static bool report_state_changes = true;
  80. static bool use_local_state = false;
  81. static struct xkb_machine_options machine_options = xkb_machine_options_new();
  82. static struct xkb_keymap *custom_keymap = NULL;
  83. #endif
  84. #ifndef KEYMAP_DUMP
  85. static void
  86. surface_configure(void *data, struct xdg_surface *surface,
  87. uint32_t serial)
  88. {
  89. struct interactive_dpy *inter = data;
  90. xdg_surface_ack_configure(inter->xdg_surf, serial);
  91. wl_surface_commit(inter->wl_surf);
  92. }
  93. static const struct xdg_surface_listener surface_listener = {
  94. surface_configure,
  95. };
  96. #if HAVE_MKOSTEMP
  97. static int
  98. create_tmpfile_cloexec(char *tmpname)
  99. {
  100. int fd = mkostemp(tmpname, O_CLOEXEC);
  101. if (fd >= 0)
  102. unlink(tmpname);
  103. return fd;
  104. }
  105. #else
  106. /* The following utility functions are taken from Weston's
  107. * shared/os-compatibility.c. */
  108. static int
  109. os_fd_set_cloexec(int fd)
  110. {
  111. long flags;
  112. if (fd == -1)
  113. return -1;
  114. flags = fcntl(fd, F_GETFD);
  115. if (flags == -1)
  116. return -1;
  117. if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
  118. return -1;
  119. return 0;
  120. }
  121. static int
  122. set_cloexec_or_close(int fd)
  123. {
  124. if (os_fd_set_cloexec(fd) != 0) {
  125. close(fd);
  126. return -1;
  127. }
  128. return fd;
  129. }
  130. static int
  131. create_tmpfile_cloexec(char *tmpname)
  132. {
  133. int fd = mkstemp(tmpname);
  134. if (fd >= 0) {
  135. fd = set_cloexec_or_close(fd);
  136. unlink(tmpname);
  137. }
  138. return fd;
  139. }
  140. #endif
  141. static int
  142. os_resize_anonymous_file(int fd, off_t size)
  143. {
  144. int ret;
  145. #if HAVE_POSIX_FALLOCATE
  146. ret = posix_fallocate(fd, 0, size);
  147. if (ret == 0)
  148. return 0;
  149. /*
  150. * Filesystems that do support fallocate will return EINVAL
  151. * or EOPNOTSUPP, fallback to ftruncate() then.
  152. */
  153. if (ret != EINVAL && ret != EOPNOTSUPP)
  154. return ret;
  155. #endif
  156. ret = ftruncate(fd, size);
  157. if (ret != 0)
  158. return errno;
  159. return 0;
  160. }
  161. /*
  162. * Create a new, unique, anonymous file of the given size, and
  163. * return the file descriptor for it. The file descriptor is set
  164. * CLOEXEC. The file is immediately suitable for mmap()'ing
  165. * the given size at offset zero.
  166. *
  167. * The file should not have a permanent backing store like a disk,
  168. * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
  169. *
  170. * The file name is deleted from the file system.
  171. *
  172. * The file is suitable for buffer sharing between processes by
  173. * transmitting the file descriptor over Unix sockets using the
  174. * SCM_RIGHTS methods.
  175. *
  176. * If the C library implements posix_fallocate(), it is used to
  177. * guarantee that disk space is available for the file at the
  178. * given size. If disk space is insufficent, errno is set to ENOSPC.
  179. * If posix_fallocate() is not supported, program will fallback
  180. * to ftruncate() instead.
  181. */
  182. static int
  183. os_create_anonymous_file(off_t size)
  184. {
  185. static const char template[] = "/weston-shared-XXXXXX";
  186. const char *path;
  187. char *name;
  188. int fd;
  189. int ret;
  190. path = getenv("XDG_RUNTIME_DIR");
  191. if (!path) {
  192. errno = ENOENT;
  193. return -1;
  194. }
  195. const size_t len = strlen(path);
  196. name = malloc(len + sizeof(template));
  197. if (!name)
  198. return -1;
  199. memcpy(name, path, len);
  200. memcpy(name + len, template, sizeof(template));
  201. fd = create_tmpfile_cloexec(name);
  202. free(name);
  203. if (fd < 0)
  204. return -1;
  205. ret = os_resize_anonymous_file(fd, size);
  206. if (ret != 0) {
  207. close(fd);
  208. errno = ret;
  209. return -1;
  210. }
  211. return fd;
  212. }
  213. static void
  214. buffer_release(void *data, struct wl_buffer *buffer)
  215. {
  216. struct interactive_dpy *inter = data;
  217. wl_buffer_destroy(buffer);
  218. inter->buf = NULL;
  219. }
  220. static const struct wl_buffer_listener buffer_listener = {
  221. buffer_release
  222. };
  223. static void
  224. buffer_create(struct interactive_dpy *inter, uint32_t width, uint32_t height)
  225. {
  226. struct wl_shm_pool *pool;
  227. struct wl_region *opaque;
  228. uint32_t stride;
  229. size_t size;
  230. void *map;
  231. int fd;
  232. switch (inter->shm_format) {
  233. case WL_SHM_FORMAT_ARGB8888:
  234. case WL_SHM_FORMAT_XRGB8888:
  235. case WL_SHM_FORMAT_ABGR8888:
  236. case WL_SHM_FORMAT_XBGR8888:
  237. stride = width * 4;
  238. break;
  239. case WL_SHM_FORMAT_RGB565:
  240. case WL_SHM_FORMAT_BGR565:
  241. stride = width * 2;
  242. break;
  243. default:
  244. fprintf(stderr, "ERROR: Unsupported SHM format %"PRIu32"\n", inter->shm_format);
  245. exit(EXIT_FAILURE);
  246. }
  247. size = (size_t)(stride) * height;
  248. const off_t offset = (off_t) size;
  249. if ((size_t) offset != size) {
  250. fprintf(stderr, "ERROR: Couldn't create surface buffer (buffer size error)\n");
  251. exit(EXIT_FAILURE);
  252. }
  253. fd = os_create_anonymous_file(offset);
  254. if (fd < 0) {
  255. fprintf(stderr, "ERROR: Couldn't create surface buffer (buffer file error)\n");
  256. exit(EXIT_FAILURE);
  257. }
  258. map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  259. if (map == MAP_FAILED) {
  260. fprintf(stderr, "ERROR: Couldn't mmap surface buffer\n");
  261. exit(EXIT_FAILURE);
  262. }
  263. memset(map, 0xff, size);
  264. munmap(map, size);
  265. if (size > INT32_MAX) {
  266. fprintf(stderr, "ERROR: Couldn't create surface pool\n");
  267. exit(EXIT_FAILURE);
  268. }
  269. pool = wl_shm_create_pool(inter->shm, fd, (int32_t) size);
  270. if (width > INT32_MAX || height > INT32_MAX || stride > INT32_MAX) {
  271. fprintf(stderr, "ERROR: Couldn't create surface pool buffer\n");
  272. exit(EXIT_FAILURE);
  273. }
  274. const int32_t iwidth = (int32_t) width;
  275. const int32_t iheight = (int32_t) height;
  276. const int32_t istride = (int32_t) stride;
  277. if (inter->buf)
  278. wl_buffer_destroy(inter->buf);
  279. inter->buf = wl_shm_pool_create_buffer(pool, 0, iwidth, iheight, istride,
  280. inter->shm_format);
  281. wl_buffer_add_listener(inter->buf, &buffer_listener, inter);
  282. wl_surface_attach(inter->wl_surf, inter->buf, 0, 0);
  283. wl_surface_damage(inter->wl_surf, 0, 0, iwidth, iheight);
  284. opaque = wl_compositor_create_region(inter->compositor);
  285. wl_region_add(opaque, 0, 0, iwidth, iheight);
  286. wl_surface_set_opaque_region(inter->wl_surf, opaque);
  287. wl_region_destroy(opaque);
  288. wl_shm_pool_destroy(pool);
  289. close(fd);
  290. }
  291. static void
  292. toplevel_configure(void *data, struct xdg_toplevel *toplevel,
  293. int32_t width, int32_t height, struct wl_array *states)
  294. {
  295. struct interactive_dpy *inter = data;
  296. if (width == 0)
  297. width = 400;
  298. if (height == 0)
  299. height = 400;
  300. buffer_create(inter, width, height);
  301. }
  302. static void
  303. toplevel_close(void *data, struct xdg_toplevel *toplevel)
  304. {
  305. terminate = true;
  306. }
  307. static const struct xdg_toplevel_listener toplevel_listener = {
  308. toplevel_configure,
  309. toplevel_close
  310. };
  311. static void surface_create(struct interactive_dpy *inter)
  312. {
  313. inter->wl_surf = wl_compositor_create_surface(inter->compositor);
  314. inter->xdg_surf = xdg_wm_base_get_xdg_surface(inter->shell, inter->wl_surf);
  315. xdg_surface_add_listener(inter->xdg_surf, &surface_listener, inter);
  316. /* Create a window only for the interactive tool */
  317. inter->xdg_top = xdg_surface_get_toplevel(inter->xdg_surf);
  318. xdg_toplevel_add_listener(inter->xdg_top, &toplevel_listener, inter);
  319. xdg_toplevel_set_title(inter->xdg_top, "xkbcommon event tester");
  320. xdg_toplevel_set_app_id(inter->xdg_top,
  321. "org.xkbcommon.test.interactive-wayland");
  322. if (inter->decoration_manager) {
  323. inter->decoration =
  324. zxdg_decoration_manager_v1_get_toplevel_decoration(
  325. inter->decoration_manager, inter->xdg_top
  326. );
  327. zxdg_toplevel_decoration_v1_set_mode(
  328. inter->decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE
  329. );
  330. }
  331. wl_surface_commit(inter->wl_surf);
  332. }
  333. #endif
  334. static void
  335. shell_ping(void *data, struct xdg_wm_base *shell, uint32_t serial)
  336. {
  337. xdg_wm_base_pong(shell, serial);
  338. }
  339. static const struct xdg_wm_base_listener shell_listener = {
  340. shell_ping
  341. };
  342. static void
  343. kbd_keymap(void *data, struct wl_keyboard *wl_kbd, uint32_t format,
  344. int fd, uint32_t size)
  345. {
  346. struct interactive_seat *seat = data;
  347. #ifndef KEYMAP_DUMP
  348. if (custom_keymap) {
  349. /* Custom keymap: ignore keymap from the server */
  350. close(fd);
  351. if (!seat->keymap)
  352. seat->keymap = xkb_keymap_ref(custom_keymap);
  353. } else {
  354. #endif
  355. const char * const label = xkb_keymap_get_format_label(format);
  356. fprintf(stderr,
  357. "%s: keymap: format: %"PRIu32" (%s); size: %.3f kB (%.3f kiB)\n",
  358. seat->name_str, format, (label ? label : "unsupported"),
  359. (double) size / 1000.0, (double) size / 1024.0);
  360. void *buf = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
  361. if (buf == MAP_FAILED) {
  362. fprintf(stderr, "%s: ERROR: Failed to mmap keymap: errno=%d\n",
  363. seat->name_str, errno);
  364. close(fd);
  365. return;
  366. }
  367. #ifdef KEYMAP_DUMP
  368. /* We do not want to be interactive, so stop at next loop */
  369. terminate = true;
  370. if (dump_raw_keymap) {
  371. /* Dump the raw keymap */
  372. fprintf(stdout, "%s", (char *)buf);
  373. munmap(buf, size);
  374. close(fd);
  375. /* Do not go further */
  376. return;
  377. }
  378. #endif
  379. xkb_keymap_unref(seat->keymap);
  380. seat->keymap = xkb_keymap_new_from_buffer(seat->inter->ctx,
  381. buf, size - 1,
  382. keymap_input_format,
  383. compile_flags);
  384. munmap(buf, size);
  385. close(fd);
  386. #ifndef KEYMAP_DUMP
  387. }
  388. #endif
  389. if (!seat->keymap) {
  390. fprintf(stderr, "%s: ERROR: Failed to compile keymap!\n", seat->name_str);
  391. return;
  392. }
  393. #ifdef KEYMAP_DUMP
  394. /* Dump the reformatted keymap */
  395. char *dump = xkb_keymap_get_as_string2(seat->keymap, keymap_output_format,
  396. serialize_flags);
  397. fprintf(stdout, "%s", dump);
  398. free(dump);
  399. #else
  400. /* Reset the state, except if already set and not using a local state */
  401. if (!seat->state || !use_local_state) {
  402. xkb_state_unref(seat->state);
  403. seat->state = xkb_state_new(seat->keymap);
  404. if (!seat->state) {
  405. fprintf(stderr, "%s: ERROR: Failed to create XKB state!\n",
  406. seat->name_str);
  407. terminate = true;
  408. } else if (use_local_state && !use_events_api) {
  409. const struct xkb_state_components_update components = {
  410. .size = sizeof(components),
  411. .components = XKB_STATE_CONTROLS,
  412. .affect_controls = machine_options.controls.boolean.affect,
  413. .controls = machine_options.controls.boolean.flags,
  414. };
  415. const struct xkb_state_update update = {
  416. .size = sizeof(update),
  417. .components = &components,
  418. };
  419. // FIXME: handle error
  420. xkb_state_update_synthetic(seat->state, &update, NULL);
  421. }
  422. }
  423. if (use_local_state && use_events_api) {
  424. if (!seat->machine) {
  425. struct xkb_machine_builder * machine_builder =
  426. xkb_machine_builder_new_from_options(seat->keymap, &machine_options);
  427. if (!machine_builder) {
  428. fprintf(stderr, "ERROR: Couldn't create xkb state machine builder\n");
  429. terminate = true;
  430. return;
  431. }
  432. seat->machine = xkb_machine_new(machine_builder);
  433. xkb_machine_builder_destroy(machine_builder);
  434. if (!seat->machine) {
  435. fprintf(stderr, "%s: ERROR: Failed to create local XKB state!\n",
  436. seat->name_str);
  437. terminate = true;
  438. }
  439. }
  440. if (!seat->events && seat->machine) {
  441. /* Initialize the events queue */
  442. seat->events = xkb_events_new_batch(seat->inter->ctx,
  443. XKB_EVENTS_NO_FLAGS);
  444. if (seat->events) {
  445. const struct xkb_state_components_update components = {
  446. .size = sizeof(components),
  447. .components = XKB_STATE_CONTROLS,
  448. .affect_controls = machine_options.controls.boolean.affect,
  449. .controls = machine_options.controls.boolean.flags,
  450. };
  451. const struct xkb_state_update update = {
  452. .size = sizeof(update),
  453. .components = &components,
  454. };
  455. // FIXME: handle error
  456. xkb_machine_process_synthetic(seat->machine, &update,
  457. seat->events);
  458. const struct xkb_event *event;
  459. while ((event = xkb_events_next(seat->events))) {
  460. xkb_state_update_event(seat->state, event);
  461. }
  462. } else {
  463. fprintf(stderr,
  464. "%s: ERROR: Failed to create XKB event queue!\n",
  465. seat->name_str);
  466. }
  467. }
  468. }
  469. #endif
  470. }
  471. static void
  472. kbd_enter(void *data, struct wl_keyboard *wl_kbd, uint32_t serial,
  473. struct wl_surface *surf, struct wl_array *keys)
  474. {
  475. }
  476. static void
  477. kbd_leave(void *data, struct wl_keyboard *wl_kbd, uint32_t serial,
  478. struct wl_surface *surf)
  479. {
  480. }
  481. static void
  482. kbd_key(void *data, struct wl_keyboard *wl_kbd, uint32_t serial, uint32_t time,
  483. uint32_t key, uint32_t state)
  484. {
  485. #ifndef KEYMAP_DUMP
  486. struct interactive_seat *seat = data;
  487. xkb_keycode_t keycode = key + EVDEV_OFFSET;
  488. char * const prefix = asprintf_safe("%s: ", seat->name_str);
  489. const enum xkb_key_direction direction
  490. = (state == WL_KEYBOARD_KEY_STATE_RELEASED)
  491. ? XKB_KEY_UP
  492. #if HAVE_WL_KEYBOARD_KEY_STATE_REPEATED
  493. : (state == WL_KEYBOARD_KEY_STATE_REPEATED)
  494. ? XKB_KEY_REPEATED
  495. #endif
  496. : XKB_KEY_DOWN;
  497. if (use_local_state && use_events_api) {
  498. /* Run our local state machine with the xkb_machine API */
  499. const int ret = xkb_machine_process_key(seat->machine,
  500. keycode, direction,
  501. seat->events);
  502. if (ret) {
  503. fprintf(stderr, "%s: ERROR: could not update the state machine\n",
  504. seat->name_str);
  505. // TODO: better error handling
  506. } else {
  507. tools_print_events(prefix, seat->state, seat->events,
  508. seat->compose_state, consumed_mode,
  509. print_options, report_state_changes);
  510. }
  511. } else {
  512. if (seat->compose_state && direction == XKB_KEY_DOWN) {
  513. const xkb_keysym_t keysym =
  514. xkb_state_key_get_one_sym(seat->state, keycode);
  515. xkb_compose_state_feed(seat->compose_state, keysym);
  516. }
  517. tools_print_keycode_state(prefix, seat->state, seat->compose_state,
  518. keycode, direction, consumed_mode,
  519. print_options);
  520. if (seat->compose_state) {
  521. const enum xkb_compose_status status =
  522. xkb_compose_state_get_status(seat->compose_state);
  523. if (status == XKB_COMPOSE_CANCELLED || status == XKB_COMPOSE_COMPOSED)
  524. xkb_compose_state_reset(seat->compose_state);
  525. }
  526. if (use_local_state) {
  527. /* Run our local state machine with the legacy state API */
  528. const enum xkb_state_component changed =
  529. xkb_state_update_key(seat->state, keycode,
  530. (state == WL_KEYBOARD_KEY_STATE_RELEASED
  531. ? XKB_KEY_UP
  532. : XKB_KEY_DOWN));
  533. if (changed && report_state_changes)
  534. tools_print_state_changes(prefix, seat->state,
  535. changed, print_options);
  536. }
  537. }
  538. free(prefix);
  539. /* Exit on ESC. */
  540. if (xkb_state_key_get_one_sym(seat->state, keycode) == XKB_KEY_Escape &&
  541. state != WL_KEYBOARD_KEY_STATE_PRESSED)
  542. terminate = true;
  543. #endif
  544. }
  545. static void
  546. kbd_modifiers(void *data, struct wl_keyboard *wl_kbd, uint32_t serial,
  547. uint32_t mods_depressed, uint32_t mods_latched,
  548. uint32_t mods_locked, uint32_t group)
  549. {
  550. #ifndef KEYMAP_DUMP
  551. if (use_local_state) {
  552. /* Ignore state update if using a local state machine */
  553. return;
  554. }
  555. struct interactive_seat *seat = data;
  556. const enum xkb_state_component changed = xkb_state_update_mask(
  557. seat->state, mods_depressed, mods_latched, mods_locked, 0, 0, group
  558. );
  559. char * const prefix = asprintf_safe("%s: ", seat->name_str);
  560. if (report_state_changes)
  561. tools_print_state_changes(prefix, seat->state, changed, print_options);
  562. free(prefix);
  563. #endif
  564. }
  565. static void
  566. kbd_repeat_info(void *data, struct wl_keyboard *wl_kbd, int32_t rate,
  567. int32_t delay)
  568. {
  569. #ifndef KEYMAP_DUMP
  570. struct interactive_seat * const seat = data;
  571. fprintf(stderr,
  572. "%s: repeat info: rate: %"PRIi32" keys/s%s; delay: %"PRIi32" ms\n",
  573. seat->name_str, rate,
  574. (!rate ? " (compositor handles key repetition)" : ""), delay);
  575. #endif
  576. }
  577. static const struct wl_keyboard_listener kbd_listener = {
  578. kbd_keymap,
  579. kbd_enter,
  580. kbd_leave,
  581. kbd_key,
  582. kbd_modifiers,
  583. kbd_repeat_info
  584. };
  585. static void
  586. pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
  587. struct wl_surface *surf, wl_fixed_t fsx, wl_fixed_t fsy)
  588. {
  589. }
  590. static void
  591. pointer_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
  592. struct wl_surface *surf)
  593. {
  594. }
  595. static void
  596. pointer_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time,
  597. wl_fixed_t fsx, wl_fixed_t fsy)
  598. {
  599. }
  600. static void
  601. pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
  602. uint32_t time, uint32_t button, uint32_t state)
  603. {
  604. struct interactive_seat *seat = data;
  605. xdg_toplevel_move(seat->inter->xdg_top, seat->wl_seat, serial);
  606. }
  607. static void
  608. pointer_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time,
  609. uint32_t axis, wl_fixed_t value)
  610. {
  611. }
  612. static void
  613. pointer_frame(void *data, struct wl_pointer *wl_pointer)
  614. {
  615. }
  616. static void
  617. pointer_axis_source(void *data, struct wl_pointer *wl_pointer, uint32_t source)
  618. {
  619. }
  620. static void
  621. pointer_axis_stop(void *data, struct wl_pointer *wl_pointer, uint32_t time,
  622. uint32_t axis)
  623. {
  624. }
  625. static void
  626. pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer, uint32_t time,
  627. int32_t discrete)
  628. {
  629. }
  630. static const struct wl_pointer_listener pointer_listener = {
  631. pointer_enter,
  632. pointer_leave,
  633. pointer_motion,
  634. pointer_button,
  635. pointer_axis,
  636. pointer_frame,
  637. pointer_axis_source,
  638. pointer_axis_stop,
  639. pointer_axis_discrete
  640. };
  641. static void
  642. seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t caps)
  643. {
  644. struct interactive_seat *seat = data;
  645. if (!seat->wl_kbd && (caps & WL_SEAT_CAPABILITY_KEYBOARD)) {
  646. seat->wl_kbd = wl_seat_get_keyboard(seat->wl_seat);
  647. wl_keyboard_add_listener(seat->wl_kbd, &kbd_listener, seat);
  648. }
  649. else if (seat->wl_kbd && !(caps & WL_SEAT_CAPABILITY_KEYBOARD)) {
  650. if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION)
  651. wl_keyboard_release(seat->wl_kbd);
  652. else
  653. wl_keyboard_destroy(seat->wl_kbd);
  654. xkb_events_destroy(seat->events);
  655. xkb_state_unref(seat->state);
  656. xkb_machine_unref(seat->machine);
  657. xkb_keymap_unref(seat->keymap);
  658. xkb_compose_state_unref(seat->compose_state);
  659. seat->events = NULL;
  660. seat->state = NULL;
  661. seat->machine = NULL;
  662. seat->compose_state = NULL;
  663. seat->keymap = NULL;
  664. seat->wl_kbd = NULL;
  665. }
  666. if (!seat->wl_pointer && (caps & WL_SEAT_CAPABILITY_POINTER)) {
  667. seat->wl_pointer = wl_seat_get_pointer(seat->wl_seat);
  668. wl_pointer_add_listener(seat->wl_pointer, &pointer_listener,
  669. seat);
  670. }
  671. else if (seat->wl_pointer && !(caps & WL_SEAT_CAPABILITY_POINTER)) {
  672. if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION)
  673. wl_pointer_release(seat->wl_pointer);
  674. else
  675. wl_pointer_destroy(seat->wl_pointer);
  676. seat->wl_pointer = NULL;
  677. }
  678. }
  679. static void
  680. seat_name(void *data, struct wl_seat *wl_seat, const char *name)
  681. {
  682. struct interactive_seat *seat = data;
  683. free(seat->name_str);
  684. seat->name_str = strdup(name);
  685. }
  686. static const struct wl_seat_listener seat_listener = {
  687. seat_capabilities,
  688. seat_name
  689. };
  690. static void
  691. seat_create(struct interactive_dpy *inter, struct wl_registry *registry,
  692. uint32_t name, uint32_t version)
  693. {
  694. int ret;
  695. struct interactive_seat *seat = calloc(1, sizeof(*seat));
  696. if (!seat) {
  697. fprintf(stderr, "ERROR: cannot allocate seat\n");
  698. return;
  699. }
  700. seat->global_name = name;
  701. seat->inter = inter;
  702. seat->wl_seat = wl_registry_bind(registry, name, &wl_seat_interface,
  703. MIN(version, 10));
  704. wl_seat_add_listener(seat->wl_seat, &seat_listener, seat);
  705. if (seat->inter->compose_table) {
  706. seat->compose_state = xkb_compose_state_new(seat->inter->compose_table,
  707. XKB_COMPOSE_STATE_NO_FLAGS);
  708. }
  709. ret = asprintf(&seat->name_str, "seat:%"PRIu32,
  710. wl_proxy_get_id((struct wl_proxy *) seat->wl_seat));
  711. assert(ret >= 0);
  712. wl_list_insert(&inter->seats, &seat->link);
  713. }
  714. static void
  715. seat_destroy(struct interactive_seat *seat)
  716. {
  717. if (seat->wl_kbd) {
  718. if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION)
  719. wl_keyboard_release(seat->wl_kbd);
  720. else
  721. wl_keyboard_destroy(seat->wl_kbd);
  722. xkb_events_destroy(seat->events);
  723. xkb_machine_unref(seat->machine);
  724. xkb_state_unref(seat->state);
  725. xkb_compose_state_unref(seat->compose_state);
  726. xkb_keymap_unref(seat->keymap);
  727. }
  728. if (seat->wl_pointer) {
  729. if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION)
  730. wl_pointer_release(seat->wl_pointer);
  731. else
  732. wl_pointer_destroy(seat->wl_pointer);
  733. }
  734. if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION)
  735. wl_seat_release(seat->wl_seat);
  736. else
  737. wl_seat_destroy(seat->wl_seat);
  738. free(seat->name_str);
  739. wl_list_remove(&seat->link);
  740. free(seat);
  741. }
  742. static void
  743. registry_global(void *data, struct wl_registry *registry, uint32_t name,
  744. const char *interface, uint32_t version)
  745. {
  746. struct interactive_dpy *inter = data;
  747. if (strcmp(interface, "wl_seat") == 0) {
  748. seat_create(inter, registry, name, version);
  749. }
  750. else if (strcmp(interface, "xdg_wm_base") == 0) {
  751. inter->shell = wl_registry_bind(registry, name,
  752. &xdg_wm_base_interface,
  753. MIN(version, 2));
  754. xdg_wm_base_add_listener(inter->shell, &shell_listener, inter);
  755. }
  756. else if (strcmp(interface, "wl_compositor") == 0) {
  757. inter->compositor = wl_registry_bind(registry, name,
  758. &wl_compositor_interface,
  759. MIN(version, 1));
  760. }
  761. else if (strcmp(interface, "wl_shm") == 0) {
  762. inter->shm = wl_registry_bind(registry, name, &wl_shm_interface,
  763. MIN(version, 1));
  764. }
  765. #ifndef KEYMAP_DUMP
  766. else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0) {
  767. inter->decoration_manager = wl_registry_bind(
  768. registry, name, &zxdg_decoration_manager_v1_interface,
  769. MIN(version, 1)
  770. );
  771. }
  772. #endif
  773. }
  774. static void
  775. registry_delete(void *data, struct wl_registry *registry, uint32_t name)
  776. {
  777. struct interactive_dpy *inter = data;
  778. struct interactive_seat *seat, *tmp;
  779. wl_list_for_each_safe(seat, tmp, &inter->seats, link) {
  780. if (seat->global_name != name)
  781. continue;
  782. seat_destroy(seat);
  783. }
  784. }
  785. static const struct wl_registry_listener registry_listener = {
  786. registry_global,
  787. registry_delete
  788. };
  789. static void
  790. dpy_disconnect(struct interactive_dpy *inter)
  791. {
  792. struct interactive_seat *seat, *tmp;
  793. wl_list_for_each_safe(seat, tmp, &inter->seats, link)
  794. seat_destroy(seat);
  795. if (inter->decoration)
  796. zxdg_toplevel_decoration_v1_destroy(inter->decoration);
  797. if (inter->decoration_manager)
  798. zxdg_decoration_manager_v1_destroy(inter->decoration_manager);
  799. if (inter->xdg_top)
  800. xdg_toplevel_destroy(inter->xdg_top);
  801. if (inter->xdg_surf)
  802. xdg_surface_destroy(inter->xdg_surf);
  803. if (inter->wl_surf)
  804. wl_surface_destroy(inter->wl_surf);
  805. if (inter->shell)
  806. xdg_wm_base_destroy(inter->shell);
  807. if (inter->compositor)
  808. wl_compositor_destroy(inter->compositor);
  809. if (inter->shm)
  810. wl_shm_destroy(inter->shm);
  811. if (inter->buf)
  812. wl_buffer_destroy(inter->buf);
  813. /* Do one last roundtrip to try to destroy our wl_buffer. */
  814. wl_display_roundtrip(inter->dpy);
  815. xkb_context_unref(inter->ctx);
  816. wl_display_disconnect(inter->dpy);
  817. }
  818. static void
  819. usage(FILE *fp, char *progname)
  820. {
  821. fprintf(fp,
  822. "Usage: %s [--help] [--version] [--verbose]"
  823. #ifdef KEYMAP_DUMP
  824. " [--no-pretty] [--drop-unused] [--raw] [--input-format] [--strict]"
  825. " [--output-format] [--format] [--no-pretty] [--drop-unused]"
  826. #else
  827. " [--uniline] [--multiline] [--consumed-mode={xkb|gtk}]"
  828. " [--no-state-report] [--format] [--strict] [--enable-compose]"
  829. " [--local-state] [--legacy-state-api true|false]"
  830. " [--controls CONTROLS] [--modifiers-mapping MAPPING]"
  831. " [--shortcuts-mask MASK] [--shortcuts-mapping]"
  832. " [--keymap FILE]"
  833. #endif
  834. "\n",
  835. progname);
  836. fprintf(fp,
  837. #ifdef KEYMAP_DUMP
  838. " --input-format <FORMAT> use input keymap format FORMAT (default: '%s')\n"
  839. " --output-format <FORMAT> use output keymap format FORMAT (default: same as input)\n"
  840. " --format <FORMAT> keymap format to use for both input and output\n"
  841. " --strict parse using strict mode\n"
  842. " --no-pretty do not pretty-print when serializing a keymap\n"
  843. " --drop-unused disable unused bits serialization\n"
  844. " --raw dump the raw keymap, without parsing it\n"
  845. #else
  846. " --format <FORMAT> use keymap format FORMAT (default: '%s')\n"
  847. " --strict parse using strict mode\n"
  848. " --enable-compose enable Compose\n"
  849. " --local-state enable local state handling and ignore modifiers/layouts\n"
  850. " state updates from the compositor\n"
  851. " --legacy-state-api [=true|false]\n"
  852. " use the legacy state API instead of the event API.\n"
  853. " It implies --local-state if explicitly disabled.\n"
  854. " Default: false.\n"
  855. " --controls [<CONTROLS>]\n"
  856. " use the given keyboard controls; available values are:\n"
  857. " sticky-keys, sticky-keys-no-simultaneous,\n"
  858. " sticky-keys-latch-to-lock, latch-simultaneous and overlay{1-8}.\n"
  859. " It implies --local-state and --legacy-state-api=false.\n"
  860. " --modifiers-mapping <MAPPING>\n"
  861. " use the given modifiers mapping.\n"
  862. " <MAPPING> is a comma-separated list of modifiers masks\n"
  863. " mappings with format \"source:target\", e.g.\n"
  864. " \"Control+Alt:LevelThree,Alt:Meta\".\n"
  865. " It implies --local-state and --legacy-state-api=false.\n"
  866. " --shortcuts-mask <MASK>\n"
  867. " use the given modifier mask to enable selecting a specific\n"
  868. " layout (see --shortcuts-mapping) when some of these modifiers\n"
  869. " are active. The modifier mask is a plus-separated list of\n"
  870. " modifiers names, e.g. \"Control+Alt+Super\".\n"
  871. " It implies --local-state and --legacy-state-api=false.\n"
  872. " --shortcuts-mapping <MAPPING>\n"
  873. " use the given layout mapping to enable selecting a specific\n"
  874. " layout when some modifiers are active (see --shortcuts-mask).\n"
  875. " <MAPPING> is a comma-separated list of 1-indexed layout\n"
  876. " indices mappings with format \"source:target\", e.g. \"2:1,3:1\".\n"
  877. " It implies --local-state and --legacy-state-api=false.\n"
  878. " --keymap [<FILE>] use the given keymap instead of the keymap from the compositor.\n"
  879. " It implies --local-state.\n"
  880. " If <FILE> is \"-\" or missing, then load from stdin.\n"
  881. " -1, --uniline enable uniline event output\n"
  882. " -*, --multiline enable multiline event output\n"
  883. " --consumed-mode={xkb|gtk}\n"
  884. " select the consumed modifiers mode (default: xkb)\n"
  885. " --no-state-report do not report changes to the state\n"
  886. #endif
  887. " --verbose enable verbose debugging output\n"
  888. " --help display this help and exit\n"
  889. " --version print version information and exit\n",
  890. xkb_keymap_get_format_label(DEFAULT_INPUT_KEYMAP_FORMAT)
  891. );
  892. }
  893. int
  894. main(int argc, char *argv[])
  895. {
  896. int ret = 0;
  897. bool verbose = false;
  898. struct interactive_dpy inter;
  899. struct wl_registry *registry;
  900. #ifndef KEYMAP_DUMP
  901. bool with_keymap_file = false;
  902. const char *keymap_path = NULL;
  903. bool with_compose = false;
  904. struct xkb_compose_table *compose_table = NULL;
  905. #endif
  906. enum options {
  907. OPT_VERBOSE,
  908. OPT_UNILINE,
  909. OPT_MULTILINE,
  910. OPT_CONSUMED_MODE,
  911. OPT_NO_STATE_REPORT,
  912. OPT_COMPOSE,
  913. OPT_LOCAL_STATE,
  914. OPT_LEGACY_STATE_API,
  915. OPT_CONTROLS,
  916. OPT_MODIFIERS_TWEAK_MAPPING,
  917. OPT_SHORTCUTS_TWEAK_MASK,
  918. OPT_SHORTCUTS_TWEAK_MAPPING,
  919. OPT_INPUT_KEYMAP_FORMAT,
  920. OPT_OUTPUT_KEYMAP_FORMAT,
  921. OPT_KEYMAP_FORMAT,
  922. OPT_KEYMAP_STRICT_PARSER,
  923. OPT_KEYMAP_NO_PRETTY,
  924. OPT_KEYMAP_DROP_UNUSED,
  925. OPT_KEYMAP,
  926. OPT_RAW,
  927. };
  928. static struct option opts[] = {
  929. {"help", no_argument, 0, 'h'},
  930. {"version", no_argument, 0, 'V'},
  931. {"verbose", no_argument, 0, OPT_VERBOSE},
  932. {"strict", no_argument, 0, OPT_KEYMAP_STRICT_PARSER},
  933. #ifdef KEYMAP_DUMP
  934. {"input-format", required_argument, 0, OPT_INPUT_KEYMAP_FORMAT},
  935. {"output-format", required_argument, 0, OPT_OUTPUT_KEYMAP_FORMAT},
  936. {"format", required_argument, 0, OPT_KEYMAP_FORMAT},
  937. {"no-pretty", no_argument, 0, OPT_KEYMAP_NO_PRETTY},
  938. {"drop-unused", no_argument, 0, OPT_KEYMAP_DROP_UNUSED},
  939. {"raw", no_argument, 0, OPT_RAW},
  940. #else
  941. {"uniline", no_argument, 0, OPT_UNILINE},
  942. {"multiline", no_argument, 0, OPT_MULTILINE},
  943. {"consumed-mode", required_argument, 0, OPT_CONSUMED_MODE},
  944. {"no-state-report", no_argument, 0, OPT_NO_STATE_REPORT},
  945. {"format", required_argument, 0, OPT_INPUT_KEYMAP_FORMAT},
  946. {"enable-compose", no_argument, 0, OPT_COMPOSE},
  947. {"local-state", no_argument, 0, OPT_LOCAL_STATE},
  948. {"legacy-state-api", optional_argument, 0, OPT_LEGACY_STATE_API},
  949. {"controls", required_argument, 0, OPT_CONTROLS},
  950. {"modifiers-mapping", required_argument, 0, OPT_MODIFIERS_TWEAK_MAPPING},
  951. {"shortcuts-mask", required_argument, 0, OPT_SHORTCUTS_TWEAK_MASK},
  952. {"shortcuts-mapping", required_argument, 0, OPT_SHORTCUTS_TWEAK_MAPPING},
  953. {"keymap", optional_argument, 0, OPT_KEYMAP},
  954. #endif
  955. {0, 0, 0, 0},
  956. };
  957. setlocale(LC_ALL, "");
  958. #ifndef KEYMAP_DUMP
  959. /* Ensure synced with usage() and man page */
  960. assert(use_events_api);
  961. assert(consumed_mode == XKB_CONSUMED_MODE_XKB);
  962. #endif
  963. while (1) {
  964. int opt;
  965. int option_index = 0;
  966. opt = getopt_long(argc, argv, "*1hV", opts, &option_index);
  967. if (opt == -1)
  968. break;
  969. switch (opt) {
  970. case OPT_VERBOSE:
  971. verbose = true;
  972. break;
  973. case OPT_INPUT_KEYMAP_FORMAT:
  974. keymap_input_format = xkb_keymap_parse_format(optarg);
  975. if (!keymap_input_format) {
  976. fprintf(stderr, "ERROR: invalid %s \"%s\"\n",
  977. #ifdef KEYMAP_DUMP
  978. "--input-format",
  979. #else
  980. "--format",
  981. #endif
  982. optarg);
  983. goto invalid_usage;
  984. }
  985. break;
  986. case OPT_KEYMAP_STRICT_PARSER:
  987. compile_flags |= XKB_KEYMAP_COMPILE_STRICT_MODE;
  988. break;
  989. #ifdef KEYMAP_DUMP
  990. case OPT_OUTPUT_KEYMAP_FORMAT:
  991. keymap_output_format = xkb_keymap_parse_format(optarg);
  992. if (!keymap_output_format) {
  993. fprintf(stderr, "ERROR: invalid --output-format \"%s\"\n", optarg);
  994. goto invalid_usage;
  995. }
  996. break;
  997. case OPT_KEYMAP_FORMAT:
  998. keymap_input_format = xkb_keymap_parse_format(optarg);
  999. if (!keymap_input_format) {
  1000. fprintf(stderr, "ERROR: invalid --format: \"%s\"\n", optarg);
  1001. goto invalid_usage;
  1002. }
  1003. keymap_output_format = keymap_input_format;
  1004. break;
  1005. case OPT_KEYMAP_NO_PRETTY:
  1006. serialize_flags &= ~XKB_KEYMAP_SERIALIZE_PRETTY;
  1007. break;
  1008. case OPT_KEYMAP_DROP_UNUSED:
  1009. serialize_flags &= ~XKB_KEYMAP_SERIALIZE_KEEP_UNUSED;
  1010. break;
  1011. case OPT_RAW:
  1012. dump_raw_keymap = true;
  1013. break;
  1014. #else
  1015. case OPT_KEYMAP:
  1016. with_keymap_file = true;
  1017. /* Optional arguments require `=`, but we want to make this
  1018. * requirement optional too, so that both `--keymap=xxx` and
  1019. * `--keymap xxx` work. */
  1020. if (!optarg && argv[optind] &&
  1021. (argv[optind][0] != '-' || strcmp(argv[optind], "-") == 0 )) {
  1022. keymap_path = argv[optind++];
  1023. } else {
  1024. keymap_path = optarg;
  1025. }
  1026. /* --local-state is implied */
  1027. goto local_state;
  1028. case OPT_COMPOSE:
  1029. with_compose = true;
  1030. break;
  1031. case OPT_LOCAL_STATE:
  1032. local_state:
  1033. use_local_state = true;
  1034. break;
  1035. case OPT_LEGACY_STATE_API: {
  1036. bool legacy_api = true;
  1037. if (!tools_parse_bool(optarg, TOOLS_ARG_OPTIONAL, &legacy_api))
  1038. goto invalid_usage;
  1039. use_events_api = !legacy_api;
  1040. if (use_events_api)
  1041. goto local_state;
  1042. break;
  1043. }
  1044. case OPT_CONTROLS:
  1045. if (!tools_parse_controls(optarg, &machine_options))
  1046. goto invalid_usage;
  1047. /* --local-state and --legacy-state-api=false are implied */
  1048. use_events_api = true;
  1049. goto local_state;
  1050. case OPT_MODIFIERS_TWEAK_MAPPING:
  1051. if (!tools_parse_modifiers_mappings(optarg, &machine_options))
  1052. goto invalid_usage;
  1053. /* --local-state and --legacy-state-api=false are implied */
  1054. use_events_api = true;
  1055. goto local_state;
  1056. case OPT_SHORTCUTS_TWEAK_MASK:
  1057. if (!tools_parse_shortcuts_mask(optarg, &machine_options))
  1058. goto invalid_usage;
  1059. /* --local-state and --legacy-state-api=false are implied */
  1060. use_events_api = true;
  1061. goto local_state;
  1062. case OPT_SHORTCUTS_TWEAK_MAPPING:
  1063. if (!tools_parse_shortcuts_mappings(optarg, &machine_options))
  1064. goto invalid_usage;
  1065. /* --local-state and --legacy-state-api=false are implied */
  1066. use_events_api = true;
  1067. goto local_state;
  1068. case '1':
  1069. case OPT_UNILINE:
  1070. print_options |= PRINT_UNILINE;
  1071. break;
  1072. case '*':
  1073. case OPT_MULTILINE:
  1074. print_options &= ~PRINT_UNILINE;
  1075. break;
  1076. case OPT_CONSUMED_MODE:
  1077. if (strcmp(optarg, "gtk") == 0) {
  1078. consumed_mode = XKB_CONSUMED_MODE_GTK;
  1079. } else if (strcmp(optarg, "xkb") == 0) {
  1080. consumed_mode = XKB_CONSUMED_MODE_XKB;
  1081. } else {
  1082. fprintf(stderr, "ERROR: invalid --consumed-mode \"%s\"\n",
  1083. optarg);
  1084. usage(stderr, argv[0]);
  1085. ret = EXIT_INVALID_USAGE;
  1086. goto error_parse_args;
  1087. }
  1088. break;
  1089. case OPT_NO_STATE_REPORT:
  1090. report_state_changes = false;
  1091. break;
  1092. #endif
  1093. case 'h':
  1094. usage(stdout, argv[0]);
  1095. ret = EXIT_SUCCESS;
  1096. goto error_parse_args;
  1097. case 'V':
  1098. printf("%s\n", LIBXKBCOMMON_VERSION);
  1099. ret = EXIT_SUCCESS;
  1100. goto error_parse_args;
  1101. default:
  1102. invalid_usage:
  1103. usage(stderr, argv[0]);
  1104. ret = EXIT_INVALID_USAGE;
  1105. goto error_parse_args;
  1106. }
  1107. }
  1108. #ifndef KEYMAP_DUMP
  1109. if (optind < argc && !isempty(argv[optind])) {
  1110. /* Some positional arguments left: use as a keymap input */
  1111. if (keymap_path)
  1112. goto too_much_arguments;
  1113. keymap_path = argv[optind++];
  1114. if (optind < argc) {
  1115. /* Further positional arguments is an error */
  1116. too_much_arguments:
  1117. fprintf(stderr, "ERROR: Too many positional arguments\n");
  1118. goto invalid_usage;
  1119. }
  1120. with_keymap_file = true;
  1121. } else if (is_pipe_or_regular_file(STDIN_FILENO) && !with_keymap_file) {
  1122. /* No positional argument: piping detected */
  1123. with_keymap_file = true;
  1124. }
  1125. if (with_keymap_file) {
  1126. /* --local-state is implied with custom keymap */
  1127. use_local_state = true;
  1128. }
  1129. if (isempty(keymap_path) || strcmp(keymap_path, "-") == 0)
  1130. keymap_path = NULL;
  1131. #endif
  1132. memset(&inter, 0, sizeof(inter));
  1133. wl_list_init(&inter.seats);
  1134. inter.dpy = wl_display_connect(NULL);
  1135. if (!inter.dpy) {
  1136. fprintf(stderr, "ERROR: Couldn't connect to Wayland server\n");
  1137. ret = -1;
  1138. goto err_out;
  1139. }
  1140. inter.ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  1141. if (!inter.ctx) {
  1142. ret = -1;
  1143. fprintf(stderr, "ERROR: Couldn't create xkb context\n");
  1144. goto err_out;
  1145. }
  1146. if (verbose)
  1147. tools_enable_verbose_logging(inter.ctx);
  1148. #ifndef KEYMAP_DUMP
  1149. if (with_keymap_file) {
  1150. FILE *file = NULL;
  1151. if (keymap_path) {
  1152. /* Read from regular file */
  1153. file = fopen(keymap_path, "rb");
  1154. } else {
  1155. /* Read from stdin */
  1156. file = tools_read_stdin();
  1157. }
  1158. if (!file) {
  1159. fprintf(stderr, "ERROR: Failed to open keymap file \"%s\": %s\n",
  1160. keymap_path ? keymap_path : "stdin", strerror(errno));
  1161. xkb_context_unref(inter.ctx);
  1162. goto err_out;
  1163. }
  1164. custom_keymap = xkb_keymap_new_from_file(inter.ctx, file,
  1165. keymap_input_format,
  1166. compile_flags);
  1167. if (!custom_keymap)
  1168. goto err_out;
  1169. fclose(file);
  1170. }
  1171. if (with_compose) {
  1172. const char *locale = setlocale(LC_CTYPE, NULL);
  1173. compose_table =
  1174. xkb_compose_table_new_from_locale(inter.ctx, locale,
  1175. XKB_COMPOSE_COMPILE_NO_FLAGS);
  1176. if (!compose_table) {
  1177. fprintf(stderr, "ERROR: Couldn't create compose from locale\n");
  1178. goto err_compose;
  1179. }
  1180. inter.compose_table = compose_table;
  1181. } else {
  1182. inter.compose_table = NULL;
  1183. }
  1184. #endif
  1185. registry = wl_display_get_registry(inter.dpy);
  1186. wl_registry_add_listener(registry, &registry_listener, &inter);
  1187. /* The first roundtrip gets the list of advertised globals. */
  1188. wl_display_roundtrip(inter.dpy);
  1189. /* The second roundtrip dispatches the events sent after binding, e.g.
  1190. * after binding to wl_seat globals in the first roundtrip, we will get
  1191. * the wl_seat::capabilities event in this roundtrip. */
  1192. wl_display_roundtrip(inter.dpy);
  1193. if (!inter.shell || !inter.shm || !inter.compositor) {
  1194. fprintf(stderr, "Required Wayland interfaces %s%s%s unsupported\n",
  1195. (inter.shell) ? "" : "xdg_shell ",
  1196. (inter.shm) ? "" : "wl_shm",
  1197. (inter.compositor) ? "" : "wl_compositor");
  1198. ret = -1;
  1199. goto err_conn;
  1200. }
  1201. #ifndef KEYMAP_DUMP
  1202. surface_create(&inter);
  1203. #endif
  1204. tools_disable_stdin_echo();
  1205. do {
  1206. ret = wl_display_dispatch(inter.dpy);
  1207. } while (ret >= 0 && !terminate);
  1208. tools_enable_stdin_echo();
  1209. wl_registry_destroy(registry);
  1210. err_conn:
  1211. dpy_disconnect(&inter);
  1212. #ifndef KEYMAP_DUMP
  1213. err_compose:
  1214. xkb_compose_table_unref(compose_table);
  1215. #endif
  1216. err_out:
  1217. #ifndef KEYMAP_DUMP
  1218. xkb_keymap_unref(custom_keymap);
  1219. #endif
  1220. ret = (ret >= 0) ? EXIT_SUCCESS : EXIT_FAILURE;
  1221. error_parse_args:
  1222. #ifndef KEYMAP_DUMP
  1223. xkb_machine_options_free(&machine_options);
  1224. #endif
  1225. exit(ret);
  1226. }