tools-common.c 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562
  1. /*
  2. * Copyright © 2009 Dan Nicholson <dbn.lists@gmail.com>
  3. * Copyright © 2012 Intel Corporation
  4. * Copyright © 2012 Ran Benita <ran234@gmail.com>
  5. * SPDX-License-Identifier: MIT-open-group
  6. *
  7. * Author: Dan Nicholson <dbn.lists@gmail.com>
  8. * Daniel Stone <daniel@fooishbar.org>
  9. * Ran Benita <ran234@gmail.com>
  10. */
  11. #include "config.h"
  12. #include "darray.h"
  13. #include <assert.h>
  14. #include <errno.h>
  15. #include <limits.h>
  16. #include <fcntl.h>
  17. #include <stdbool.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #ifdef _WIN32
  24. #include <io.h>
  25. #include <windows.h>
  26. #include <process.h>
  27. #else
  28. #include <unistd.h>
  29. #ifdef HAVE_TERMIOS
  30. #include <termios.h>
  31. #endif
  32. #endif
  33. #include "xkbcommon/xkbcommon.h"
  34. #include "xkbcommon/xkbcommon-compose.h"
  35. #include "tools-common.h"
  36. #include "src/compose/constants.h"
  37. #include "src/keysym.h"
  38. #include "src/keymap.h"
  39. #include "src/messages-codes.h"
  40. #include "src/utils.h"
  41. #include "src/utils-numbers.h"
  42. #include "src/utf8-decoding.h"
  43. #if defined(_WIN32) && !defined(S_ISFIFO)
  44. #define S_ISFIFO(mode) 0
  45. #endif
  46. static void
  47. print_keycode(struct xkb_keymap *keymap, const char* prefix,
  48. xkb_keycode_t keycode, const char *suffix) {
  49. const char *keyname = xkb_keymap_key_get_name(keymap, keycode);
  50. if (keyname) {
  51. printf("%s%-4s%s", prefix, keyname, suffix);
  52. } else {
  53. printf("%s%-4"PRIu32"%s", prefix, keycode, suffix);
  54. }
  55. }
  56. /* Variant of ModMaskText of main lib */
  57. static void
  58. print_mod_mask(struct xkb_keymap *keymap,
  59. enum mod_type type, xkb_mod_mask_t mask)
  60. {
  61. /* We want to avoid boolean blindness, but we expected only 2 values */
  62. assert(type == MOD_REAL || type == MOD_BOTH);
  63. if (!mask) {
  64. printf("0");
  65. return;
  66. }
  67. const xkb_mod_index_t num_mods = xkb_keymap_num_mods(keymap);
  68. const xkb_mod_mask_t keymap_named_mods = (type == MOD_REAL)
  69. ? MOD_REAL_MASK_ALL
  70. : (xkb_mod_mask_t) ((UINT64_C(1) << num_mods) - 1);
  71. /* Print known mods */
  72. bool first = true;
  73. xkb_mod_mask_t named = mask & keymap_named_mods;
  74. for (xkb_mod_index_t mod = 0; named && mod < num_mods; mod++, named >>= 1) {
  75. if (named & UINT32_C(0x1)) {
  76. if (first) {
  77. first = false;
  78. printf("%s", xkb_keymap_mod_get_name(keymap, mod));
  79. } else {
  80. printf(" + %s", xkb_keymap_mod_get_name(keymap, mod));
  81. }
  82. }
  83. }
  84. if (mask & ~keymap_named_mods) {
  85. /* If some bits of the mask cannot be expressed with the known modifiers
  86. * of the given type, print it as hexadecimal */
  87. printf("%s%#"PRIx32, (first ? "" : " + "), mask & ~keymap_named_mods);
  88. }
  89. }
  90. /* Modifiers encodings, formatted as YAML */
  91. void
  92. print_modifiers_encodings(struct xkb_keymap *keymap) {
  93. printf("Modifiers encodings:");
  94. /* Find the padding required for modifier names */
  95. int padding = 0;
  96. for (xkb_mod_index_t mod = 0; mod < xkb_keymap_num_mods(keymap); mod++) {
  97. const char* name = xkb_keymap_mod_get_name(keymap, mod);
  98. padding = MAX(padding, (int) strlen(name));
  99. }
  100. /* Print encodings */
  101. static const char indent[] = "\n ";
  102. for (xkb_mod_index_t mod = 0; mod < xkb_keymap_num_mods(keymap); mod++) {
  103. if (mod == 0)
  104. printf("%s# Real modifiers (predefined)", indent);
  105. else if (mod == _XKB_MOD_INDEX_NUM_ENTRIES)
  106. printf("\n%s# Virtual modifiers (keymap-dependent)", indent);
  107. const xkb_mod_mask_t encoding = xkb_keymap_mod_get_mask2(keymap, mod);
  108. const char* name = xkb_keymap_mod_get_name(keymap, mod);
  109. const int count = printf("%s%s", indent, name);
  110. printf(":%*s 0x%08"PRIx32,
  111. MAX(0, padding - count + (int)sizeof(indent) - 1), "", encoding);
  112. if (mod >= _XKB_MOD_INDEX_NUM_ENTRIES) {
  113. printf(" # ");
  114. if (encoding) {
  115. if (!(encoding & MOD_REAL_MASK_ALL)) {
  116. /* Prevent printing the numeric form again */
  117. if (encoding == (UINT32_C(1) << mod))
  118. printf("Canonical virtual modifier");
  119. else
  120. printf("Non-canonical virtual modifier");
  121. } else {
  122. print_mod_mask(keymap, MOD_REAL, encoding);
  123. }
  124. if (encoding & ~MOD_REAL_MASK_ALL)
  125. printf(" (incompatible with X11)");
  126. } else {
  127. printf("(unmapped)");
  128. }
  129. }
  130. }
  131. printf("\n");
  132. }
  133. /* Key modifier maps, formatted as YAML */
  134. void
  135. print_keys_modmaps(struct xkb_keymap *keymap) {
  136. printf("Keys modifier maps:");
  137. uint32_t count = 0;
  138. const struct xkb_key *key;
  139. xkb_keys_foreach(key, keymap) {
  140. if (!key->modmap && !key->vmodmap)
  141. continue;
  142. print_keycode(keymap, "\n ", key->keycode, ":");
  143. printf("\n real: ");
  144. print_mod_mask(keymap, MOD_REAL, key->modmap);
  145. printf("\n virtual: ");
  146. print_mod_mask(keymap, MOD_BOTH, key->vmodmap);
  147. count++;
  148. }
  149. if (count == 0)
  150. printf(" {} # No modifier map");
  151. printf("\n");
  152. }
  153. static void
  154. print_modifiers_names(struct xkb_state *state,
  155. enum xkb_state_component components,
  156. xkb_keycode_t keycode,
  157. enum xkb_consumed_mode consumed_mode)
  158. {
  159. struct xkb_keymap * const keymap = xkb_state_get_keymap(state);
  160. for (xkb_mod_index_t mod = 0; mod < xkb_keymap_num_mods(keymap); mod++) {
  161. if (xkb_state_mod_index_is_active(state, mod, components) <= 0)
  162. continue;
  163. // NOLINTBEGIN(readability-suspicious-call-argument)
  164. const bool consumed =
  165. keycode != XKB_KEYCODE_INVALID &&
  166. xkb_state_mod_index_is_consumed2(state, keycode, mod, consumed_mode);
  167. // NOLINTEND(readability-suspicious-call-argument)
  168. printf(" %s%s",
  169. (consumed ? "-" : ""), xkb_keymap_mod_get_name(keymap, mod));
  170. }
  171. }
  172. #define INDENT " "
  173. static void
  174. print_modifiers(struct xkb_state *state, enum xkb_state_component changed,
  175. xkb_keycode_t keycode, bool show_consumed,
  176. enum xkb_consumed_mode consumed_mode, bool verbose)
  177. {
  178. static const struct {
  179. enum xkb_state_component component;
  180. unsigned int padding;
  181. const char *label;
  182. } types[] = {
  183. { XKB_STATE_MODS_DEPRESSED, 0, "depressed" },
  184. { XKB_STATE_MODS_LATCHED, 2, "latched" },
  185. { XKB_STATE_MODS_LOCKED, 3, "locked" },
  186. { XKB_STATE_MODS_EFFECTIVE, 0, "effective" },
  187. };
  188. if (verbose) {
  189. static const char label[] = INDENT "modifiers: ";
  190. printf("%s", label);
  191. for (unsigned int k = 0; k < ARRAY_SIZE(types); k++) {
  192. const xkb_mod_mask_t mods =
  193. xkb_state_serialize_mods(state, types[k].component);
  194. const char * const changed_indicator = (changed)
  195. ? (changed & types[k].component ? "*" : " ")
  196. : "";
  197. printf("%*s%s%s: %*s0x%08"PRIx32,
  198. (k == 0) ? 0 : (unsigned int) sizeof(label) - 1, "",
  199. changed_indicator, types[k].label,
  200. types[k].padding, "", mods);
  201. print_modifiers_names(
  202. state, types[k].component,
  203. (show_consumed ? keycode : XKB_KEYCODE_INVALID), consumed_mode
  204. );
  205. printf("\n");
  206. }
  207. } else {
  208. if (changed) {
  209. for (unsigned int k = 0; k < ARRAY_SIZE(types); k++) {
  210. if (!(changed & types[k].component))
  211. continue;
  212. const xkb_mod_mask_t mods =
  213. xkb_state_serialize_mods(state, types[k].component);
  214. printf("%s-mods: 0x%08"PRIx32"; ", types[k].label, mods);
  215. }
  216. } else {
  217. const xkb_mod_mask_t mods =
  218. xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE);
  219. printf("modifiers: 0x%08"PRIx32, mods);
  220. print_modifiers_names(state, XKB_STATE_MODS_EFFECTIVE, keycode,
  221. consumed_mode);
  222. printf("\n");
  223. }
  224. }
  225. }
  226. static void
  227. print_layouts(struct xkb_state *state, enum xkb_state_component changed,
  228. xkb_keycode_t keycode, bool verbose)
  229. {
  230. struct xkb_keymap * const keymap = xkb_state_get_keymap(state);
  231. static const char label[] = INDENT "layout: ";
  232. static const struct {
  233. enum xkb_state_component component;
  234. unsigned int padding;
  235. const char *label;
  236. } types[] = {
  237. { XKB_STATE_LAYOUT_DEPRESSED, 0, "depressed" },
  238. { XKB_STATE_LAYOUT_LATCHED, 2, "latched" },
  239. { XKB_STATE_LAYOUT_LOCKED, 3, "locked" },
  240. { XKB_STATE_LAYOUT_EFFECTIVE, 0, "effective" },
  241. };
  242. if (verbose) {
  243. printf("%s", label);
  244. for (unsigned int k = 0; k < ARRAY_SIZE(types); k++) {
  245. const xkb_layout_index_t layout =
  246. xkb_state_serialize_layout(state, types[k].component);
  247. const char * const changed_indicator = (changed)
  248. ? (changed & types[k].component ? "*" : " ")
  249. : "";
  250. printf("%*s%s%s: %*s%"PRId32,
  251. (k == 0) ? 0 : (unsigned int) sizeof(label) - 1, "",
  252. changed_indicator, types[k].label,
  253. types[k].padding, "", layout);
  254. const char * const layout_name =
  255. xkb_keymap_layout_get_name(keymap, layout);
  256. if (layout_name &&
  257. (types[k].component == XKB_STATE_LAYOUT_LOCKED ||
  258. types[k].component == XKB_STATE_LAYOUT_EFFECTIVE)) {
  259. printf(" \"%s\"\n", layout_name);
  260. } else {
  261. printf("\n");
  262. }
  263. }
  264. } else if (changed) {
  265. for (unsigned int k = 0; k < ARRAY_SIZE(types); k++) {
  266. if (!(changed & types[k].component))
  267. continue;
  268. const xkb_layout_index_t layout =
  269. xkb_state_serialize_layout(state, types[k].component);
  270. printf("%s-layout: %"PRId32"; ", types[k].label, layout);
  271. }
  272. }
  273. if (keycode != XKB_KEYCODE_INVALID) {
  274. const xkb_layout_index_t layout =
  275. xkb_state_key_get_layout(state, keycode);
  276. const char * const layout_name =
  277. xkb_keymap_layout_get_name(keymap, layout);
  278. if (verbose) {
  279. printf("%*s%skey: %"PRIu32" \"%s\"\n",
  280. (unsigned int) sizeof(label) - 1, "",
  281. (changed ? " " : ""),
  282. layout, (layout_name ? layout_name : "(no name)"));
  283. } else {
  284. printf(INDENT "layout: %"PRIu32" \"%s\"\n",
  285. layout, (layout_name ? layout_name : "(no name)"));
  286. }
  287. }
  288. }
  289. static void
  290. print_leds(struct xkb_state *state, bool verbose) {
  291. struct xkb_keymap * const keymap = xkb_state_get_keymap(state);
  292. unsigned int count = 0;
  293. for (xkb_led_index_t led = 0; led < xkb_keymap_num_leds(keymap); led++) {
  294. if (xkb_state_led_index_is_active(state, led) <= 0)
  295. continue;
  296. if (count > 0)
  297. printf(", ");
  298. if (verbose) {
  299. printf("%"PRIu32" \"%s\"",
  300. led, xkb_keymap_led_get_name(keymap, led));
  301. } else {
  302. printf("%s", xkb_keymap_led_get_name(keymap, led));
  303. }
  304. count++;
  305. }
  306. /* TODO: refactor when `xkb_state_serialize_leds()` is available */
  307. if (verbose && !count)
  308. printf("(none)");
  309. }
  310. static void
  311. print_controls(struct xkb_state *state, bool verbose) {
  312. static const struct {
  313. enum xkb_action_controls control;
  314. const char *name;
  315. } controls[] = {
  316. { CONTROL_REPEAT, "repeat" },
  317. { CONTROL_SLOW, "slow" },
  318. { CONTROL_DEBOUNCE, "debounce" },
  319. { CONTROL_STICKY_KEYS, "sticky-keys" },
  320. { CONTROL_MOUSE_KEYS, "mouse-keys" },
  321. { CONTROL_MOUSE_KEYS_ACCEL, "mouse-keys-accel" },
  322. { CONTROL_AX, "ax" },
  323. { CONTROL_AX_TIMEOUT, "ax-timeout" },
  324. { CONTROL_AX_FEEDBACK, "ax-feedback" },
  325. { CONTROL_BELL, "bell" },
  326. { CONTROL_OVERLAY1, "overlay1" },
  327. { CONTROL_OVERLAY2, "overlay2" },
  328. { CONTROL_IGNORE_GROUP_LOCK, "ignore-group-lock" },
  329. { CONTROL_OVERLAY3, "overlay3" },
  330. { CONTROL_OVERLAY4, "overlay4" },
  331. { CONTROL_OVERLAY5, "overlay5" },
  332. { CONTROL_OVERLAY6, "overlay6" },
  333. { CONTROL_OVERLAY7, "overlay7" },
  334. { CONTROL_OVERLAY8, "overlay8" },
  335. };
  336. static_assert(
  337. CONTROL_ALL_BOOLEAN ==
  338. (CONTROL_REPEAT | CONTROL_SLOW | CONTROL_DEBOUNCE |
  339. CONTROL_STICKY_KEYS | CONTROL_MOUSE_KEYS | CONTROL_MOUSE_KEYS_ACCEL |
  340. CONTROL_AX | CONTROL_AX_TIMEOUT | CONTROL_AX_FEEDBACK |
  341. CONTROL_BELL | CONTROL_OVERLAY1 | CONTROL_OVERLAY2 |
  342. CONTROL_IGNORE_GROUP_LOCK |
  343. CONTROL_OVERLAY3 | CONTROL_OVERLAY4 | CONTROL_OVERLAY5 |
  344. CONTROL_OVERLAY6 | CONTROL_OVERLAY7 | CONTROL_OVERLAY8),
  345. "missing controls names"
  346. );
  347. const enum xkb_keyboard_control_flags ctrls =
  348. xkb_state_serialize_enabled_controls(state, XKB_STATE_CONTROLS);
  349. if (verbose)
  350. printf("0x%08x ", ctrls);
  351. if (!ctrls) {
  352. printf("(none)");
  353. return;
  354. }
  355. unsigned int count = 0;
  356. for (uint8_t c = 0; c < (uint8_t) ARRAY_SIZE(controls); c++) {
  357. if (!(controls[c].control & (enum xkb_action_controls)ctrls))
  358. continue;
  359. if (count > 0)
  360. printf(", ");
  361. printf("%s", controls[c].name);
  362. count++;
  363. }
  364. }
  365. static void
  366. tools_print_detailed_keycode_state(const char *prefix,
  367. struct xkb_state *state,
  368. struct xkb_compose_state *compose_state,
  369. xkb_keycode_t keycode,
  370. enum xkb_key_direction direction,
  371. enum xkb_consumed_mode consumed_mode,
  372. enum print_state_options options)
  373. {
  374. printf("------------\n");
  375. if (prefix)
  376. printf("%s", prefix);
  377. struct xkb_keymap * const keymap = xkb_state_get_keymap(state);
  378. const char * const keyname = xkb_keymap_key_get_name(keymap, keycode);
  379. printf("key %s 0x%03"PRIx32" <%s>\n",
  380. (direction == XKB_KEY_UP
  381. ? "up: "
  382. : direction == XKB_KEY_REPEATED
  383. ? "repeat:"
  384. : "down: "),
  385. keycode, (keyname ? keyname : "(no name)"));
  386. if (direction == XKB_KEY_UP)
  387. return;
  388. const xkb_layout_index_t layout = xkb_state_key_get_layout(state, keycode);
  389. const bool verbose = options & PRINT_VERBOSE;
  390. if (options & PRINT_LAYOUT)
  391. print_layouts(state, 0, keycode, verbose);
  392. if (verbose) {
  393. print_modifiers(state, 0, keycode, true, consumed_mode, verbose);
  394. printf(INDENT "level: %"PRIu32"\n",
  395. xkb_state_key_get_level(state, keycode, layout));
  396. } else {
  397. printf(INDENT "level: %"PRIu32", ",
  398. xkb_state_key_get_level(state, keycode, layout));
  399. print_modifiers(state, 0, keycode, true, consumed_mode, verbose);
  400. }
  401. enum xkb_compose_status status = XKB_COMPOSE_NOTHING;
  402. if (compose_state)
  403. status = xkb_compose_state_get_status(compose_state);
  404. #define BUFFER_SIZE MAX(XKB_COMPOSE_MAX_STRING_SIZE, XKB_KEYSYM_NAME_MAX_SIZE)
  405. static_assert(XKB_KEYSYM_UTF8_MAX_SIZE <= BUFFER_SIZE,
  406. "buffer too small");
  407. char s[BUFFER_SIZE];
  408. #undef BUFFER_SIZE
  409. bool show_unicode = false;
  410. const xkb_keysym_t *syms;
  411. const int nsyms = xkb_state_key_get_syms(state, keycode, &syms);
  412. if (nsyms > 0) {
  413. show_unicode = true;
  414. printf(INDENT "%skeysyms:",
  415. (status == XKB_COMPOSE_NOTHING ? "" : "raw "));
  416. for (int i = 0; i < nsyms; i++) {
  417. xkb_keysym_get_name(syms[i], s, sizeof(s));
  418. printf(" %s", s);
  419. }
  420. }
  421. switch (status) {
  422. case XKB_COMPOSE_NOTHING:
  423. break;
  424. case XKB_COMPOSE_COMPOSING:
  425. printf("\n" INDENT "compose: pending\n");
  426. show_unicode = false;
  427. break;
  428. case XKB_COMPOSE_COMPOSED: {
  429. const xkb_keysym_t sym = xkb_compose_state_get_one_sym(compose_state);
  430. xkb_keysym_get_name(sym, s, sizeof(s));
  431. printf("\n" INDENT "composed: %s", s);
  432. show_unicode = true;
  433. break;
  434. }
  435. case XKB_COMPOSE_CANCELLED:
  436. printf("\n" INDENT "compose: cancelled\n");
  437. show_unicode = false;
  438. break;
  439. default:
  440. fprintf(stderr, "\nERROR: Unexpected compose state: %d\n", status);
  441. assert(!"Unexpected compose state");
  442. }
  443. if ((options & PRINT_UNICODE) && show_unicode) {
  444. if (status == XKB_COMPOSE_COMPOSED)
  445. xkb_compose_state_get_utf8(compose_state, s, sizeof(s));
  446. else
  447. xkb_state_key_get_utf8(state, keycode, s, sizeof(s));
  448. if (!*s) {
  449. printf("\n");
  450. } else {
  451. /*
  452. * HACK: escape single control characters from C0 set using the
  453. * Unicode codepoint convention. Ideally we would like to escape
  454. * any non-printable character in the string.
  455. */
  456. if (strlen(s) == 1 && (*s <= 0x1F || *s == 0x7F))
  457. printf(" (");
  458. else
  459. printf(" \"%s\" (", s);
  460. /* Print Unicode code points */
  461. size_t offset = 0;
  462. size_t count = 0;
  463. uint32_t cp = utf8_next_code_point(s, sizeof(s), &offset);
  464. while (cp && cp != INVALID_UTF8_CODE_POINT) {
  465. if (count++ > 0)
  466. printf(" ");
  467. printf("U+%04"PRIX32, cp);
  468. cp = utf8_next_code_point(s + offset, sizeof(s) - offset,
  469. &offset);
  470. }
  471. printf(", %zu code point%s)\n", count, (count > 1 ? "s" : ""));
  472. }
  473. } else if (show_unicode) {
  474. printf("\n");
  475. }
  476. printf(INDENT "LEDs: ");
  477. print_leds(state, true);
  478. printf("\n");
  479. if (verbose) {
  480. printf(INDENT "Controls: ");
  481. print_controls(state, true);
  482. printf("\n");
  483. }
  484. }
  485. static void
  486. tools_print_one_liner_keycode_state(const char *prefix,
  487. struct xkb_state *state,
  488. struct xkb_compose_state *compose_state,
  489. xkb_keycode_t keycode,
  490. enum xkb_key_direction direction,
  491. enum xkb_consumed_mode consumed_mode,
  492. enum print_state_options options)
  493. {
  494. if (prefix)
  495. printf("%s", prefix);
  496. struct xkb_keymap * const keymap = xkb_state_get_keymap(state);
  497. printf("key %s",
  498. (direction == XKB_KEY_UP)
  499. ? "up "
  500. : (direction == XKB_KEY_REPEATED)
  501. ? "repeat"
  502. : "down ");
  503. print_keycode(keymap, " [ ", keycode, " ] ");
  504. if (direction == XKB_KEY_UP)
  505. return;
  506. const xkb_keysym_t *syms;
  507. int nsyms = xkb_state_key_get_syms(state, keycode, &syms);
  508. if (nsyms <= 0)
  509. return;
  510. enum xkb_compose_status status = XKB_COMPOSE_NOTHING;
  511. if (compose_state)
  512. status = xkb_compose_state_get_status(compose_state);
  513. xkb_keysym_t sym;
  514. if (status == XKB_COMPOSE_COMPOSED) {
  515. sym = xkb_compose_state_get_one_sym(compose_state);
  516. syms = &sym;
  517. nsyms = 1;
  518. } else if (nsyms == 1) {
  519. sym = xkb_state_key_get_one_sym(state, keycode);
  520. syms = &sym;
  521. }
  522. #define BUFFER_SIZE MAX(XKB_COMPOSE_MAX_STRING_SIZE, XKB_KEYSYM_NAME_MAX_SIZE)
  523. static_assert(XKB_KEYSYM_UTF8_MAX_SIZE <= BUFFER_SIZE,
  524. "buffer too small");
  525. char s[BUFFER_SIZE];
  526. #undef BUFFER_SIZE
  527. printf("keysyms [ ");
  528. for (int i = 0; i < nsyms; i++) {
  529. xkb_keysym_get_name(syms[i], s, sizeof(s));
  530. printf("%-*s ", XKB_KEYSYM_NAME_MAX_SIZE, s);
  531. }
  532. printf("] ");
  533. if (!(options & PRINT_UNICODE)) {
  534. /* Do nothing */
  535. } else if (status == XKB_COMPOSE_COMPOSING) {
  536. printf("composing [ ] ");
  537. } else if (status == XKB_COMPOSE_CANCELLED) {
  538. printf("cancelled [ ] ");
  539. } else {
  540. assert(status == XKB_COMPOSE_NOTHING || status == XKB_COMPOSE_COMPOSED);
  541. if (status == XKB_COMPOSE_COMPOSED) {
  542. printf("composed ");
  543. xkb_compose_state_get_utf8(compose_state, s, sizeof(s));
  544. } else {
  545. printf("unicode ");
  546. if (compose_state)
  547. printf(" ");
  548. xkb_state_key_get_utf8(state, keycode, s, sizeof(s));
  549. }
  550. if (!*s) {
  551. printf("[ ] ");
  552. } else if (strlen(s) == 1 && (*s <= 0x1F || *s == 0x7F)) {
  553. /*
  554. * HACK: escape single control characters from C0 set using the
  555. * Unicode codepoint convention. Ideally we would like to escape
  556. * any non-printable character in the string.
  557. */
  558. printf("[ U+%04hX ] ", *s);
  559. } else {
  560. printf("[ %s ] ", s);
  561. }
  562. }
  563. const xkb_layout_index_t layout = xkb_state_key_get_layout(state, keycode);
  564. if (options & PRINT_LAYOUT) {
  565. const char * const layout_name =
  566. xkb_keymap_layout_get_name(keymap, layout);
  567. printf("layout [ #%"PRIu32" %s ] ",
  568. layout, (layout_name ? layout_name : "(no name)"));
  569. }
  570. printf("level [ %"PRIu32" ] ",
  571. xkb_state_key_get_level(state, keycode, layout));
  572. printf("mods [");
  573. print_modifiers_names(state, XKB_STATE_MODS_EFFECTIVE, keycode,
  574. consumed_mode);
  575. printf(" ] ");
  576. printf("leds [ ");
  577. print_leds(state, false);
  578. printf(" ] ");
  579. }
  580. void
  581. tools_print_keycode_state(const char *prefix,
  582. struct xkb_state *state,
  583. struct xkb_compose_state *compose_state,
  584. xkb_keycode_t keycode,
  585. enum xkb_key_direction direction,
  586. enum xkb_consumed_mode consumed_mode,
  587. enum print_state_options options)
  588. {
  589. if (keycode == XKB_KEYCODE_INVALID)
  590. return;
  591. if (options & PRINT_UNILINE) {
  592. tools_print_one_liner_keycode_state(
  593. prefix, state, compose_state, keycode, direction,
  594. consumed_mode, options
  595. );
  596. printf("\n");
  597. } else {
  598. tools_print_detailed_keycode_state(
  599. prefix, state, compose_state, keycode, direction,
  600. consumed_mode, options
  601. );
  602. }
  603. }
  604. void
  605. tools_print_state_changes(const char *prefix, struct xkb_state *state,
  606. enum xkb_state_component changed,
  607. enum print_state_options options)
  608. {
  609. if (changed == 0)
  610. return;
  611. if (prefix)
  612. printf("%s", prefix);
  613. if (options & PRINT_UNILINE) {
  614. printf("state [ ");
  615. print_layouts(state, changed, XKB_KEYCODE_INVALID, false);
  616. print_modifiers(state, changed, XKB_KEYCODE_INVALID, false,
  617. XKB_CONSUMED_MODE_XKB /* unused*/, false);
  618. if (changed & XKB_STATE_LEDS)
  619. printf("leds ");
  620. if (changed & XKB_STATE_CONTROLS)
  621. printf("controls ");
  622. printf("]\n");
  623. } else {
  624. printf("state changes:\n");
  625. static const enum xkb_state_component mod_mask =
  626. XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED |
  627. XKB_STATE_MODS_LOCKED | XKB_STATE_MODS_EFFECTIVE;
  628. if (changed & mod_mask) {
  629. print_modifiers(state, changed, XKB_KEYCODE_INVALID,
  630. false, XKB_CONSUMED_MODE_XKB /* unused*/, true);
  631. }
  632. static const enum xkb_state_component layout_mask =
  633. XKB_STATE_LAYOUT_DEPRESSED | XKB_STATE_LAYOUT_LATCHED |
  634. XKB_STATE_LAYOUT_LOCKED | XKB_STATE_LAYOUT_EFFECTIVE;
  635. if (changed & layout_mask) {
  636. print_layouts(state, changed, XKB_KEYCODE_INVALID, true);
  637. }
  638. if (changed & XKB_STATE_LEDS) {
  639. printf(INDENT "LEDs: ");
  640. print_leds(state, true);
  641. printf("\n");
  642. }
  643. if (changed & XKB_STATE_CONTROLS) {
  644. printf(INDENT "Controls: ");
  645. print_controls(state, true);
  646. printf("\n");
  647. }
  648. }
  649. }
  650. #undef INDENT
  651. void
  652. tools_print_events(const char *prefix, struct xkb_state *state,
  653. struct xkb_events *events,
  654. struct xkb_compose_state *compose_state,
  655. enum xkb_consumed_mode consumed_mode,
  656. enum print_state_options options, bool report_state_changes)
  657. {
  658. const struct xkb_event *event;
  659. while ((event = xkb_events_next(events)) != NULL) {
  660. const enum xkb_event_type event_type =
  661. xkb_event_get_type(event);
  662. switch (event_type) {
  663. case XKB_EVENT_TYPE_KEY_DOWN:
  664. case XKB_EVENT_TYPE_KEY_REPEATED:
  665. case XKB_EVENT_TYPE_KEY_UP: {
  666. const xkb_keycode_t kc = xkb_event_get_keycode(event);
  667. const enum xkb_key_direction direction
  668. = (event_type == XKB_EVENT_TYPE_KEY_UP)
  669. ? XKB_KEY_UP
  670. : (event_type == XKB_EVENT_TYPE_KEY_REPEATED)
  671. ? XKB_KEY_REPEATED
  672. : XKB_KEY_DOWN;
  673. if (compose_state && direction == XKB_KEY_DOWN) {
  674. const xkb_keysym_t keysym =
  675. xkb_state_key_get_one_sym(state, kc);
  676. xkb_compose_state_feed(compose_state, keysym);
  677. }
  678. tools_print_keycode_state(prefix, state, compose_state, kc,
  679. direction, consumed_mode,
  680. options);
  681. if (compose_state) {
  682. const enum xkb_compose_status status =
  683. xkb_compose_state_get_status(compose_state);
  684. if (status == XKB_COMPOSE_CANCELLED ||
  685. status == XKB_COMPOSE_COMPOSED)
  686. xkb_compose_state_reset(compose_state);
  687. }
  688. break;
  689. }
  690. case XKB_EVENT_TYPE_COMPONENTS_CHANGE: {
  691. const enum xkb_state_component changed =
  692. xkb_state_update_event(state, event);
  693. if (report_state_changes && changed)
  694. tools_print_state_changes(prefix, state, changed, options);
  695. break;
  696. }
  697. default: {
  698. static_assert(XKB_EVENT_TYPE_COMPONENTS_CHANGE == 4 &&
  699. XKB_EVENT_TYPE_COMPONENTS_CHANGE ==
  700. (enum xkb_event_type) _LAST_XKB_EVENT_TYPE,
  701. "Missing event type");
  702. }
  703. }
  704. }
  705. }
  706. #ifdef _WIN32
  707. void
  708. tools_disable_stdin_echo(void)
  709. {
  710. HANDLE stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
  711. DWORD mode = 0;
  712. GetConsoleMode(stdin_handle, &mode);
  713. SetConsoleMode(stdin_handle, mode & ~ENABLE_ECHO_INPUT);
  714. }
  715. void
  716. tools_enable_stdin_echo(void)
  717. {
  718. HANDLE stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
  719. DWORD mode = 0;
  720. GetConsoleMode(stdin_handle, &mode);
  721. SetConsoleMode(stdin_handle, mode | ENABLE_ECHO_INPUT);
  722. }
  723. #elif defined(HAVE_TERMIOS)
  724. void
  725. tools_disable_stdin_echo(void)
  726. {
  727. /* Same as `stty -echo`. */
  728. struct termios termios;
  729. if (tcgetattr(STDIN_FILENO, &termios) == 0) {
  730. termios.c_lflag &= ~ECHO;
  731. (void) tcsetattr(STDIN_FILENO, TCSADRAIN, &termios);
  732. }
  733. }
  734. void
  735. tools_enable_stdin_echo(void)
  736. {
  737. /* Same as `stty echo`. */
  738. struct termios termios;
  739. if (tcgetattr(STDIN_FILENO, &termios) == 0) {
  740. termios.c_lflag |= ECHO;
  741. (void) tcsetattr(STDIN_FILENO, TCSADRAIN, &termios);
  742. }
  743. }
  744. #else
  745. /* Unsupported */
  746. void
  747. tools_disable_stdin_echo(void)
  748. {
  749. fprintf(stderr, "ERROR: Disabling stdin echo is not supported\n");
  750. }
  751. void
  752. tools_enable_stdin_echo(void)
  753. {
  754. fprintf(stderr, "ERROR: Enabling stdin echo is not supported\n");
  755. }
  756. #endif
  757. void
  758. tools_enable_verbose_logging(struct xkb_context *ctx)
  759. {
  760. xkb_context_set_log_level(ctx, XKB_LOG_LEVEL_DEBUG);
  761. xkb_context_set_log_verbosity(ctx, XKB_LOG_VERBOSITY_VERBOSE);
  762. }
  763. static inline bool
  764. is_wayland_session(void)
  765. {
  766. /* This simple check should be enough for our use case. */
  767. return !isempty(getenv("WAYLAND_DISPLAY"));
  768. }
  769. static inline bool
  770. is_x11_session(void)
  771. {
  772. /* This simple check should be enough for our use case. */
  773. return !isempty(getenv("DISPLAY"));
  774. }
  775. const char *
  776. select_backend(const char *wayland, const char *x11, const char *fallback)
  777. {
  778. if (wayland && is_wayland_session())
  779. return wayland;
  780. else if (x11 && is_x11_session())
  781. return x11;
  782. else
  783. return fallback;
  784. }
  785. int
  786. tools_exec_command(const char *prefix, int real_argc, const char **real_argv)
  787. {
  788. const char *argv[64] = {NULL};
  789. char executable[PATH_MAX];
  790. const char *command;
  791. int rc;
  792. if (((size_t)real_argc >= ARRAY_SIZE(argv))) {
  793. fprintf(stderr, "Too many arguments\n");
  794. return EXIT_INVALID_USAGE;
  795. }
  796. command = real_argv[0];
  797. rc = snprintf(executable, sizeof(executable),
  798. "%s/%s-%s", LIBXKBCOMMON_TOOL_PATH, prefix, command);
  799. if (rc < 0 || (size_t) rc >= sizeof(executable)) {
  800. fprintf(stderr, "Failed to assemble command\n");
  801. return EXIT_FAILURE;
  802. }
  803. argv[0] = executable;
  804. for (int i = 1; i < MIN(real_argc, (int) ARRAY_SIZE(argv)); i++)
  805. argv[i] = real_argv[i];
  806. execv(executable, (char **) argv);
  807. if (errno == ENOENT) {
  808. fprintf(stderr, "Command '%s' is not available\n", command);
  809. return EXIT_INVALID_USAGE;
  810. } else {
  811. fprintf(stderr, "Failed to execute '%s' (%s)\n",
  812. command, strerror(errno));
  813. }
  814. return EXIT_FAILURE;
  815. }
  816. bool
  817. is_pipe_or_regular_file(int fd)
  818. {
  819. struct stat info;
  820. if (fstat(fd, &info) == 0) {
  821. return S_ISFIFO(info.st_mode) || S_ISREG(info.st_mode);
  822. } else {
  823. return false;
  824. }
  825. }
  826. FILE*
  827. tools_read_stdin(void)
  828. {
  829. FILE *file = tmpfile();
  830. if (!file) {
  831. fprintf(stderr, "Failed to create tmpfile\n");
  832. return NULL;
  833. }
  834. while (true) {
  835. char buf[4096] = {0};
  836. const size_t len = fread(buf, 1, sizeof(buf), stdin);
  837. if (ferror(stdin)) {
  838. fprintf(stderr, "Failed to read from stdin\n");
  839. goto err;
  840. }
  841. if (len > 0) {
  842. size_t wlen = fwrite(buf, 1, len, file);
  843. if (wlen != len) {
  844. fprintf(stderr, "Failed to write to tmpfile\n");
  845. goto err;
  846. }
  847. }
  848. if (feof(stdin))
  849. break;
  850. }
  851. fseek(file, 0, SEEK_SET);
  852. return file;
  853. err:
  854. fclose(file);
  855. return NULL;
  856. }
  857. bool
  858. tools_parse_bool(const char *s, enum tools_arg_optionality optional, bool *out)
  859. {
  860. if (isempty(s)) {
  861. if (optional == TOOLS_ARG_REQUIRED) {
  862. fprintf(stderr, "ERROR: boolean value is required, but got none\n");
  863. return false;
  864. } else {
  865. /* Keep value unchanged */
  866. return true;
  867. }
  868. } else if (strncmp(s, "true", sizeof("true")) == 0) {
  869. *out = true;
  870. return true;
  871. } else if (strncmp(s, "false", sizeof("false")) == 0) {
  872. *out = false;
  873. return true;
  874. } else {
  875. fprintf(stderr, "ERROR: invalid boolean value: \"%s\"\n", s);
  876. return false;
  877. }
  878. }
  879. bool
  880. tools_parse_mask(const char *s, enum tools_arg_optionality optional, uint32_t *out)
  881. {
  882. #define HEX_PREFIX "0x"
  883. if (isempty(s)) {
  884. if (optional == TOOLS_ARG_REQUIRED) {
  885. fprintf(stderr, "ERROR: mask value is required, but got none\n");
  886. return false;
  887. } else {
  888. /* Keep value unchanged */
  889. return true;
  890. }
  891. } else if (strncmp(s, HEX_PREFIX, sizeof(HEX_PREFIX) - 1) == 0) {
  892. const int count =
  893. parse_hex_to_uint32_t(s + sizeof(HEX_PREFIX) - 1, SIZE_MAX, out);
  894. const size_t expected = strlen(s) - (sizeof(HEX_PREFIX) - 1);
  895. if (count == (int)expected) {
  896. return true;
  897. }
  898. }
  899. fprintf(stderr, "ERROR: invalid mask value: \"%s\"\n", s);
  900. return false;
  901. #undef HEX_PREFIX
  902. }
  903. static void
  904. xkb_raw_modifiers_free(struct xkb_raw_mod_mask *raw_mods)
  905. {
  906. darray_free(raw_mods->names);
  907. darray_free(raw_mods->indices);
  908. }
  909. static void
  910. xkb_machine_mods_raw_mapping_free(struct xkb_machine_mods_raw_mapping *mapping)
  911. {
  912. xkb_raw_modifiers_free(&mapping->source);
  913. xkb_raw_modifiers_free(&mapping->target);
  914. }
  915. void
  916. xkb_machine_options_free(struct xkb_machine_options *options)
  917. {
  918. xkb_raw_modifiers_free(&options->shortcuts.mask);
  919. darray_free(options->shortcuts.mappings);
  920. struct xkb_machine_mods_raw_mapping *mapping;
  921. darray_foreach(mapping, options->modifiers)
  922. xkb_machine_mods_raw_mapping_free(mapping);
  923. darray_free(options->modifiers);
  924. }
  925. static bool
  926. xkb_machine_options_update_boolean_ctrls(struct xkb_machine_options *options,
  927. enum xkb_keyboard_control_flags flags,
  928. bool disable)
  929. {
  930. if (disable)
  931. options->controls.boolean.flags &= ~flags;
  932. else
  933. options->controls.boolean.flags |= flags;
  934. options->controls.boolean.affect |= flags;
  935. return true;
  936. }
  937. static bool
  938. xkb_machine_options_update_a11y_flags(struct xkb_machine_options *options,
  939. enum xkb_a11y_flags flags,
  940. bool disable)
  941. {
  942. if (disable)
  943. options->controls.a11y.flags &= ~flags;
  944. else
  945. options->controls.a11y.flags |= flags;
  946. options->controls.a11y.affect |= flags;
  947. return true;
  948. }
  949. bool
  950. tools_parse_controls(const char *raw, struct xkb_machine_options *options)
  951. {
  952. if (isempty(raw))
  953. return true;
  954. enum control_field {
  955. CONTROL_FIELD_OVERLAY1 = 0,
  956. CONTROL_FIELD_OVERLAY2,
  957. CONTROL_FIELD_OVERLAY3,
  958. CONTROL_FIELD_OVERLAY4,
  959. CONTROL_FIELD_OVERLAY5,
  960. CONTROL_FIELD_OVERLAY6,
  961. CONTROL_FIELD_OVERLAY7,
  962. CONTROL_FIELD_OVERLAY8,
  963. CONTROL_FIELD_STICKY_KEYS,
  964. CONTROL_FIELD_STICKY_KEYS_NO_SIMULTANEOUS_KEYS,
  965. CONTROL_FIELD_STICKY_KEYS_LATCH_TO_LOCK,
  966. CONTROL_FIELD_LATCH_SIMULTANEOUS,
  967. _NUM_CONTROL_FIELDS,
  968. };
  969. static const char * fields[] = {
  970. [CONTROL_FIELD_OVERLAY1] = "overlay1",
  971. [CONTROL_FIELD_OVERLAY2] = "overlay2",
  972. [CONTROL_FIELD_OVERLAY3] = "overlay3",
  973. [CONTROL_FIELD_OVERLAY4] = "overlay4",
  974. [CONTROL_FIELD_OVERLAY5] = "overlay5",
  975. [CONTROL_FIELD_OVERLAY6] = "overlay6",
  976. [CONTROL_FIELD_OVERLAY7] = "overlay7",
  977. [CONTROL_FIELD_OVERLAY8] = "overlay8",
  978. [CONTROL_FIELD_STICKY_KEYS] = "sticky-keys",
  979. [CONTROL_FIELD_STICKY_KEYS_NO_SIMULTANEOUS_KEYS] = "sticky-keys-no-simultaneous",
  980. [CONTROL_FIELD_STICKY_KEYS_LATCH_TO_LOCK] = "sticky-keys-latch-to-lock",
  981. [CONTROL_FIELD_LATCH_SIMULTANEOUS]= "latch-simultaneous",
  982. };
  983. static_assert(CONTROL_FIELD_LATCH_SIMULTANEOUS == 11 &&
  984. CONTROL_FIELD_LATCH_SIMULTANEOUS + 1 == _NUM_CONTROL_FIELDS &&
  985. ARRAY_SIZE(fields) == _NUM_CONTROL_FIELDS, "");
  986. const char *start = raw;
  987. const char *s = start;
  988. bool ret = true;
  989. /* Parse comma-separated list of options */
  990. while (true) {
  991. /* Consume until reaching next item or end of string */
  992. while (*s != '\0' && *s != ',') { s++; }
  993. /*
  994. * Handle +/- prefix, to respectively enable or disable the
  995. * corresponding option. This enables explicitly overriding defaults.
  996. */
  997. const bool disable = (start[0] == '-');
  998. if (disable || start[0] == '+')
  999. start++;
  1000. const size_t len = (size_t)(s - start);
  1001. if (!len) {
  1002. if (s[0] == ',') {
  1003. /* Accept empty entry */
  1004. goto next;
  1005. } else {
  1006. break;
  1007. }
  1008. }
  1009. bool ok = false;
  1010. for (enum control_field type = 0;
  1011. type < (enum control_field) ARRAY_SIZE(fields);
  1012. type++) {
  1013. if (strncmp(start, fields[type], len) != 0 ||
  1014. fields[type][len] != '\0') {
  1015. continue;
  1016. }
  1017. ok = true;
  1018. switch (type) {
  1019. case CONTROL_FIELD_OVERLAY1:
  1020. case CONTROL_FIELD_OVERLAY2:
  1021. case CONTROL_FIELD_OVERLAY3:
  1022. case CONTROL_FIELD_OVERLAY4:
  1023. case CONTROL_FIELD_OVERLAY5:
  1024. case CONTROL_FIELD_OVERLAY6:
  1025. case CONTROL_FIELD_OVERLAY7:
  1026. case CONTROL_FIELD_OVERLAY8: {
  1027. static_assert(CONTROL_FIELD_OVERLAY1 == 0, "");
  1028. static_assert(
  1029. XKB_KEYBOARD_CONTROL_OVERLAY1 ==
  1030. (XKB_KEYBOARD_CONTROL_OVERLAY1 << CONTROL_FIELD_OVERLAY1),
  1031. ""
  1032. );
  1033. static_assert(CONTROL_FIELD_OVERLAY2 == 1, "");
  1034. static_assert(
  1035. XKB_KEYBOARD_CONTROL_OVERLAY2 ==
  1036. (XKB_KEYBOARD_CONTROL_OVERLAY1 << CONTROL_FIELD_OVERLAY2),
  1037. ""
  1038. );
  1039. static_assert(CONTROL_FIELD_OVERLAY3 == 2, "");
  1040. static_assert(
  1041. XKB_KEYBOARD_CONTROL_OVERLAY3 ==
  1042. (XKB_KEYBOARD_CONTROL_OVERLAY1 << CONTROL_FIELD_OVERLAY3),
  1043. ""
  1044. );
  1045. static_assert(CONTROL_FIELD_OVERLAY8 == 7, "");
  1046. static_assert(
  1047. XKB_KEYBOARD_CONTROL_OVERLAY8 ==
  1048. (XKB_KEYBOARD_CONTROL_OVERLAY1 << CONTROL_FIELD_OVERLAY8),
  1049. ""
  1050. );
  1051. const enum xkb_keyboard_control_flags flag =
  1052. XKB_KEYBOARD_CONTROL_OVERLAY1 << type;
  1053. ok = xkb_machine_options_update_boolean_ctrls(
  1054. options, flag, disable
  1055. );
  1056. break;
  1057. }
  1058. case CONTROL_FIELD_STICKY_KEYS:
  1059. ok = xkb_machine_options_update_boolean_ctrls(
  1060. options, XKB_KEYBOARD_CONTROL_A11Y_STICKY_KEYS, disable
  1061. );
  1062. break;
  1063. case CONTROL_FIELD_STICKY_KEYS_NO_SIMULTANEOUS_KEYS:
  1064. ok = xkb_machine_options_update_a11y_flags(
  1065. options, XKB_A11Y_STICKY_KEYS_NO_SIMULTANEOUS_KEYS, disable
  1066. );
  1067. break;
  1068. case CONTROL_FIELD_STICKY_KEYS_LATCH_TO_LOCK:
  1069. ok = xkb_machine_options_update_a11y_flags(
  1070. options, XKB_A11Y_STICKY_KEYS_LATCH_TO_LOCK, disable
  1071. );
  1072. break;
  1073. case CONTROL_FIELD_LATCH_SIMULTANEOUS:
  1074. ok = xkb_machine_options_update_a11y_flags(
  1075. options, XKB_A11Y_LATCH_SIMULTANEOUS_KEYS, disable
  1076. );
  1077. break;
  1078. default:
  1079. {} /* Label followed by declaration requires C23 */
  1080. static_assert(
  1081. CONTROL_FIELD_LATCH_SIMULTANEOUS == 11 &&
  1082. CONTROL_FIELD_LATCH_SIMULTANEOUS + 1 == _NUM_CONTROL_FIELDS,
  1083. "missing case"
  1084. );
  1085. ret = false;
  1086. }
  1087. }
  1088. if (!ok) {
  1089. fprintf(stderr, "ERROR: cannot parse control entry: \"%.*s\"\n",
  1090. (unsigned int) len, start);
  1091. ret = false;
  1092. break;
  1093. }
  1094. next:
  1095. if (s[0] == '\0')
  1096. break;
  1097. s++;
  1098. start = s;
  1099. }
  1100. return ret;
  1101. }
  1102. static size_t
  1103. tools_parse_raw_mod_mask(const char *raw, size_t length,
  1104. struct xkb_raw_mod_mask *raw_mask)
  1105. {
  1106. const char *start = raw;
  1107. const char *s = start;
  1108. char buf[64] = {0};
  1109. /* Parse plus-separated list of mask */
  1110. static const char sep = '+';
  1111. size_t count = 0;
  1112. while (true) {
  1113. /* Consume until reaching next item or end of string */
  1114. while (count < length && *s != '\0' && *s != sep) { s++; count++; }
  1115. const size_t len = (size_t)(s - start);
  1116. if (!len) {
  1117. if (s[0] == sep) {
  1118. /* Accept empty entry */
  1119. goto next;
  1120. } else {
  1121. break;
  1122. }
  1123. }
  1124. if (len >= ARRAY_SIZE(buf) || !memcpy(buf, start, len))
  1125. return 0;
  1126. const darray_size_t idx = darray_size(raw_mask->names);
  1127. darray_append_items(raw_mask->names, buf, (darray_size_t)len);
  1128. darray_append(raw_mask->names, '\0');
  1129. darray_append(raw_mask->indices, idx);
  1130. next:
  1131. if (count >= length || s[0] == '\0')
  1132. break;
  1133. s++;
  1134. count++;
  1135. start = s;
  1136. }
  1137. return count;
  1138. }
  1139. static bool
  1140. tools_parse_mod_mask(struct xkb_keymap *keymap,
  1141. const struct xkb_raw_mod_mask *raw_mask, const char *field,
  1142. xkb_mod_mask_t *out)
  1143. {
  1144. bool ret = true;
  1145. darray_size_t *name_idx;
  1146. darray_foreach(name_idx, raw_mask->indices) {
  1147. const char *name = &darray_item(raw_mask->names, *name_idx);
  1148. const xkb_mod_index_t idx = xkb_keymap_mod_get_index(keymap, name);
  1149. if (idx == XKB_MOD_INVALID) {
  1150. fprintf(stderr,
  1151. "ERROR: unknown modifier in %s: \"%s\"\n",
  1152. field, name);
  1153. ret = false;
  1154. } else {
  1155. *out |= xkb_keymap_mod_get_mask2(keymap, idx);
  1156. }
  1157. }
  1158. return ret;
  1159. }
  1160. bool
  1161. tools_parse_modifiers_mappings(const char *raw,
  1162. struct xkb_machine_options *options)
  1163. {
  1164. const char *start = raw;
  1165. const char *s = start;
  1166. static const char list_sep = ',';
  1167. static const char mods_sep = ':';
  1168. /* Parse comma-separated list of mappings */
  1169. while (true) {
  1170. /* Consume until reaching next item or end of string */
  1171. while (*s != '\0' && *s != list_sep) { s++; }
  1172. size_t len = s - start;
  1173. if (!len) {
  1174. if (s[0] == list_sep) {
  1175. /* Accept empty entry */
  1176. goto next;
  1177. } else {
  1178. break;
  1179. }
  1180. }
  1181. size_t source_len = 0;
  1182. while (source_len < len && start[source_len] != mods_sep)
  1183. source_len++;
  1184. struct xkb_machine_mods_raw_mapping mapping = {0};
  1185. size_t consumed = tools_parse_raw_mod_mask(start, source_len,
  1186. &mapping.source);
  1187. if (consumed != source_len) {
  1188. fprintf(stderr, "ERROR: invalid modifiers mapping source\n");
  1189. xkb_machine_mods_raw_mapping_free(&mapping);
  1190. return false;
  1191. }
  1192. if (start[consumed] != mods_sep) {
  1193. fprintf(stderr, "ERROR: invalid modifiers mapping: \"%s\"\n",
  1194. start);
  1195. xkb_machine_mods_raw_mapping_free(&mapping);
  1196. return false;
  1197. }
  1198. start += consumed + 1;
  1199. len -= consumed + 1;
  1200. consumed = tools_parse_raw_mod_mask(start, len, &mapping.target);
  1201. if (consumed != len) {
  1202. fprintf(stderr, "ERROR: invalid modifiers mapping target: \"%s\"\n",
  1203. start);
  1204. xkb_machine_mods_raw_mapping_free(&mapping);
  1205. return false;
  1206. }
  1207. /* Steal */
  1208. darray_append(options->modifiers, mapping);
  1209. next:
  1210. if (s[0] == '\0')
  1211. break;
  1212. s++;
  1213. start = s;
  1214. }
  1215. return true;
  1216. }
  1217. static bool
  1218. tools_set_modifiers_mappings(const struct xkb_machine_options *options,
  1219. struct xkb_machine_builder *builder)
  1220. {
  1221. bool ret = true;
  1222. struct xkb_keymap *keymap = xkb_machine_builder_get_keymap(builder);
  1223. struct xkb_machine_mods_raw_mapping *mapping;
  1224. darray_foreach(mapping, options->modifiers) {
  1225. bool ok;
  1226. xkb_mod_mask_t source = 0;
  1227. ok = tools_parse_mod_mask(keymap, &mapping->source,
  1228. "mapping source", &source);
  1229. xkb_mod_mask_t target = 0;
  1230. ok = tools_parse_mod_mask(keymap, &mapping->target,
  1231. "mapping target", &target) && ok;
  1232. if (!ok) {
  1233. ret = false;
  1234. continue;
  1235. }
  1236. if (xkb_machine_builder_remap_mods(builder, source, target) !=
  1237. XKB_SUCCESS) {
  1238. fprintf(stderr,
  1239. "ERROR: cannot add modifiers mapping: "
  1240. "0x%"PRIx32" -> 0x%"PRIx32"\n", source, target);
  1241. ret = false;
  1242. }
  1243. }
  1244. return ret;
  1245. }
  1246. bool
  1247. tools_parse_shortcuts_mask(const char *raw, struct xkb_machine_options *options)
  1248. {
  1249. const size_t len = strlen_safe(raw);
  1250. struct xkb_raw_mod_mask raw_mask = {0};
  1251. const size_t consumed = tools_parse_raw_mod_mask(raw, len, &raw_mask);
  1252. if (consumed != len) {
  1253. fprintf(stderr, "ERROR: invalid shortcut modifiers mask: %s\n", raw);
  1254. xkb_raw_modifiers_free(&raw_mask);
  1255. return false;
  1256. }
  1257. /* Steal */
  1258. options->shortcuts.mask = raw_mask;
  1259. return true;
  1260. }
  1261. static bool
  1262. tools_set_shortcuts_mask(const struct xkb_machine_options *options,
  1263. struct xkb_machine_builder *builder)
  1264. {
  1265. struct xkb_keymap *keymap = xkb_machine_builder_get_keymap(builder);
  1266. xkb_mod_mask_t mask = 0;
  1267. return (
  1268. tools_parse_mod_mask(keymap, &options->shortcuts.mask,
  1269. "shortcut modifier mask", &mask) &&
  1270. !xkb_machine_builder_update_shortcut_mods(builder, mask, mask)
  1271. );
  1272. }
  1273. static int
  1274. tools_parse_layout_index1(const char *raw, size_t len, xkb_layout_index_t *out)
  1275. {
  1276. xkb_layout_index_t idx = XKB_LAYOUT_INVALID;
  1277. int consumed = parse_dec_to_uint32_t(raw, len, &idx);
  1278. if (consumed > 0 && idx == XKB_LAYOUT_INVALID) {
  1279. consumed = -1;
  1280. }
  1281. /* 1-indexed */
  1282. if (consumed < 0 || idx == 0 || idx > XKB_MAX_GROUPS) {
  1283. fprintf(stderr,
  1284. "ERROR: invalid layout index: "
  1285. "expected value in range 1..%"PRIu32", but got \"%.*s\"\n",
  1286. XKB_MAX_GROUPS, (unsigned int) len, raw);
  1287. consumed = -1;
  1288. } else {
  1289. /* Convert to 0-indexed */
  1290. *out = idx - 1;
  1291. }
  1292. return consumed;
  1293. }
  1294. bool
  1295. tools_parse_shortcuts_mappings(const char *raw,
  1296. struct xkb_machine_options *options)
  1297. {
  1298. const char *start = raw;
  1299. const char *s = start;
  1300. static const char list_sep = ',';
  1301. static const char layout_sep = ':';
  1302. /* Parse comma-separated list of mappings */
  1303. while (true) {
  1304. /* Consume until reaching next item or end of string */
  1305. while (*s != '\0' && *s != list_sep) { s++; }
  1306. size_t len = s - start;
  1307. if (!len) {
  1308. if (s[0] == list_sep) {
  1309. /* Accept empty entry */
  1310. goto next;
  1311. } else {
  1312. break;
  1313. }
  1314. }
  1315. xkb_layout_index_t source = XKB_LAYOUT_INVALID;
  1316. int consumed = tools_parse_layout_index1(start, len, &source);
  1317. if (consumed <= 0) {
  1318. fprintf(stderr, "ERROR: invalid shortcuts layout source: \"%s\"\n",
  1319. start);
  1320. return false;
  1321. }
  1322. if (start[consumed] != layout_sep) {
  1323. fprintf(stderr, "ERROR: invalid shortcuts layout mapping: \"%s\"\n",
  1324. start);
  1325. return false;
  1326. }
  1327. start += consumed + 1;
  1328. len -= (size_t) consumed + 1;
  1329. xkb_layout_index_t target = XKB_LAYOUT_INVALID;
  1330. consumed = tools_parse_layout_index1(start, len, &target);
  1331. if ((size_t) consumed != len) {
  1332. fprintf(stderr, "ERROR: invalid shortcuts layout target: \"%s\"\n",
  1333. start);
  1334. return false;
  1335. }
  1336. if (source >= darray_size(options->shortcuts.mappings)) {
  1337. if (target == source) {
  1338. /* Skip default setting */
  1339. goto next;
  1340. }
  1341. xkb_layout_index_t new =
  1342. (xkb_layout_index_t)darray_size(options->shortcuts.mappings);
  1343. darray_resize(options->shortcuts.mappings, source + 1);
  1344. for (; new < source; new++)
  1345. darray_item(options->shortcuts.mappings, new) = XKB_LAYOUT_INVALID;
  1346. }
  1347. darray_item(options->shortcuts.mappings, source) = target;
  1348. next:
  1349. if (s[0] == '\0')
  1350. break;
  1351. s++;
  1352. start = s;
  1353. }
  1354. return true;
  1355. }
  1356. static bool
  1357. tools_set_shortcuts_mappings(const struct xkb_machine_options *options,
  1358. struct xkb_machine_builder *builder)
  1359. {
  1360. bool ret = true;
  1361. xkb_layout_index_t source;
  1362. xkb_layout_index_t *target;
  1363. darray_enumerate(source, target, options->shortcuts.mappings) {
  1364. if (*target == XKB_LAYOUT_INVALID)
  1365. continue;
  1366. const enum xkb_error_code error =
  1367. xkb_machine_builder_remap_shortcut_layout(builder, source, *target);
  1368. if (error != XKB_SUCCESS) {
  1369. fprintf(stderr,
  1370. "ERROR %d: cannot add shortcuts layout mapping: "
  1371. "%"PRIu32" -> %"PRIu32"\n", error, source + 1, *target + 1);
  1372. ret = false;
  1373. }
  1374. }
  1375. return ret;
  1376. }
  1377. struct xkb_machine_builder *
  1378. xkb_machine_builder_new_from_options(struct xkb_keymap *keymap,
  1379. const struct xkb_machine_options *options)
  1380. {
  1381. struct xkb_machine_builder * const builder =
  1382. xkb_machine_builder_new(keymap, XKB_MACHINE_BUILDER_NO_FLAGS);
  1383. if (!builder)
  1384. return NULL;
  1385. if ((unsigned)(xkb_machine_builder_update_a11y_flags(
  1386. builder, options->controls.a11y.affect, options->controls.a11y.flags
  1387. ) != XKB_SUCCESS) |
  1388. (unsigned)!tools_set_modifiers_mappings(options, builder) |
  1389. (unsigned)!tools_set_shortcuts_mask(options, builder) |
  1390. (unsigned)!tools_set_shortcuts_mappings(options, builder)) {
  1391. xkb_machine_builder_destroy(builder);
  1392. return NULL;
  1393. }
  1394. return builder;
  1395. }