update-merge-modes-tests.py 94 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889
  1. #!/usr/bin/env python3
  2. # Copyright © 2025 Pierre Le Marre <dev@wismill.eu>
  3. # SPDX-License-Identifier: MIT
  4. """
  5. This script generate tests for merge modes.
  6. """
  7. from __future__ import annotations
  8. import argparse
  9. import dataclasses
  10. import itertools
  11. import re
  12. import textwrap
  13. from abc import ABCMeta, abstractmethod
  14. from collections import defaultdict
  15. from collections.abc import Callable, Generator, Iterable, Iterator, Sequence
  16. from dataclasses import dataclass
  17. from enum import Flag, IntFlag, StrEnum, auto, unique
  18. from pathlib import Path
  19. from string import Template
  20. from typing import Any, ClassVar, NewType, Self
  21. import jinja2
  22. SCRIPT = Path(__file__)
  23. # Root of the project
  24. ROOT = SCRIPT.parent.parent
  25. ################################################################################
  26. #
  27. # XKB compiler
  28. #
  29. ################################################################################
  30. @dataclass
  31. class XkbCompiler:
  32. name: str
  33. extended_syntax: bool
  34. default: ClassVar[str] = "xkbcommon"
  35. @property
  36. def is_default(self) -> bool:
  37. return self.name == self.default
  38. @property
  39. def suffix(self) -> str:
  40. return "" if self.is_default else "-" + self.name
  41. @classmethod
  42. def parse(cls, name: str) -> Self:
  43. match name:
  44. case cls.default:
  45. return cls(name=name, extended_syntax=True)
  46. case "xkbcomp":
  47. return cls(name=name, extended_syntax=False)
  48. case "kbvm":
  49. return cls(name=name, extended_syntax=True)
  50. case _:
  51. raise ValueError(f"Invalid XKB compiler: {name}")
  52. ################################################################################
  53. #
  54. # Merge modes
  55. #
  56. ################################################################################
  57. @unique
  58. class MergeMode(StrEnum):
  59. Default = auto()
  60. Augment = auto()
  61. Override = auto()
  62. Replace = auto()
  63. @property
  64. def include(self) -> str:
  65. if self is self.__class__.Default:
  66. return "include"
  67. else:
  68. return self
  69. @property
  70. def char(self) -> str:
  71. match self:
  72. case self.__class__.Default:
  73. return "+"
  74. case self.__class__.Augment:
  75. return "|"
  76. case self.__class__.Override:
  77. return "+"
  78. case self.__class__.Replace:
  79. return "^"
  80. case _:
  81. raise ValueError(self)
  82. INDENT = "\t"
  83. ################################################################################
  84. #
  85. # Components
  86. #
  87. ################################################################################
  88. @unique
  89. class Component(StrEnum):
  90. keycodes = auto()
  91. types = auto()
  92. compat = auto()
  93. symbols = auto()
  94. def render_keymap(self, content) -> Generator[str]:
  95. yield "xkb_keymap {"
  96. for component in self.__class__:
  97. yield from (
  98. textwrap.indent(t, INDENT)
  99. for t in self.render(component, content if component is self else "")
  100. )
  101. yield "};"
  102. @classmethod
  103. def render(cls, component: Self, content: str, name: str = "") -> Generator[str]:
  104. if not content:
  105. match component:
  106. case cls.keycodes:
  107. pass
  108. case cls.types:
  109. pass
  110. case cls.compat:
  111. content = "interpret.repeat= True;"
  112. case cls.symbols:
  113. pass
  114. if name:
  115. name = f' "{name}"'
  116. if content:
  117. yield f'xkb_{component}{name} "" {{'
  118. yield textwrap.indent(content, INDENT)
  119. yield "};"
  120. else:
  121. yield f'xkb_{component}{name} "" {{}};'
  122. class ComponentTemplate(Template):
  123. def __init__(self, template) -> Self:
  124. super().__init__(textwrap.dedent(template).strip())
  125. def __bool__(self) -> bool:
  126. return bool(self.template)
  127. def render(self, merge: MergeMode) -> str:
  128. mode = "" if merge is MergeMode.Default else f"{merge} "
  129. return self.substitute(mode=mode)
  130. def __add__(self, other: Any) -> Self:
  131. if isinstance(other, str):
  132. return self.__class__(self.template + "\n" + other)
  133. elif isinstance(other, Template):
  134. return self.__class__(self.template + "\n" + other.template)
  135. else:
  136. return NotImplemented
  137. def __radd__(self, other: Any) -> Self:
  138. if isinstance(other, str):
  139. return self.__class__(other + "\n" + self.template)
  140. elif isinstance(other, Template):
  141. return self.__class__(other.template + "\n" + self.template)
  142. else:
  143. return NotImplemented
  144. ################################################################################
  145. #
  146. # Test templates
  147. #
  148. ################################################################################
  149. @dataclass
  150. class Test:
  151. title: str
  152. file: Path
  153. content: str
  154. expected: str
  155. @dataclass
  156. class TestGroup:
  157. title: str
  158. tests: Sequence[Test]
  159. c_template: ClassVar[Path] = Path("test/merge_modes.c.jinja")
  160. SLUG_PATTERN: ClassVar[re.Pattern[str]] = re.compile(r"[^-\w()]+")
  161. @classmethod
  162. def file(cls, title: str) -> Path:
  163. return Path(cls.SLUG_PATTERN.sub("-", title.lower().replace(" ", "_")))
  164. @classmethod
  165. def _write(
  166. cls,
  167. root: Path,
  168. jinja_env: jinja2.Environment,
  169. path: Path,
  170. **kwargs,
  171. ) -> None:
  172. template_path = root / cls.c_template
  173. template = jinja_env.get_template(template_path.relative_to(root).as_posix())
  174. with path.open("wt", encoding="utf-8") as fd:
  175. fd.writelines(template.generate(script=SCRIPT.relative_to(ROOT), **kwargs))
  176. @classmethod
  177. def write_c(
  178. cls,
  179. root: Path,
  180. jinja_env: jinja2.Environment,
  181. path: Path,
  182. compiler: XkbCompiler,
  183. tests: Sequence[TestGroup],
  184. ) -> None:
  185. return cls._write(
  186. root=root, jinja_env=jinja_env, path=path, compiler=compiler, tests=tests
  187. )
  188. @classmethod
  189. def write_data(
  190. cls,
  191. root: Path,
  192. compiler: XkbCompiler,
  193. tests: Sequence[TestGroup],
  194. ) -> None:
  195. tests_: dict[Path, list[Test]] = defaultdict(list)
  196. suffix = compiler.suffix
  197. for group in tests:
  198. for test in group.tests:
  199. file = test.file.parent
  200. file = file.with_name(file.name + suffix)
  201. tests_[file].append(test)
  202. for file, group_ in tests_.items():
  203. path = root / "test" / "data" / file
  204. with path.open("wt", encoding="utf-8") as fd:
  205. fd.write(
  206. "// WARNING: This file was auto-generated by: "
  207. f"{SCRIPT.relative_to(ROOT)}\n"
  208. )
  209. for test in group_:
  210. fd.write(test.content)
  211. @dataclass
  212. class TestTemplate(metaclass=ABCMeta):
  213. title: str
  214. _plain: ClassVar[str] = "plain"
  215. _include: ClassVar[str] = "include"
  216. _base: ClassVar[str] = "base"
  217. _update: ClassVar[str] = "update"
  218. _file: ClassVar[str] = "merge_modes"
  219. def make_title(self, name: str) -> str:
  220. return f"{self.title}: {name}"
  221. @classmethod
  222. def make_file(cls, name: str) -> Path:
  223. return TestGroup.file(name)
  224. @abstractmethod
  225. def generate_tests(self) -> TestGroup: ...
  226. @abstractmethod
  227. def generate_data(self) -> TestGroup: ...
  228. @classmethod
  229. @abstractmethod
  230. def write(
  231. cls,
  232. root: Path,
  233. jinja_env: jinja2.Environment,
  234. c_file: Path | None,
  235. xkb: bool,
  236. compiler: XkbCompiler,
  237. tests: Sequence[Self],
  238. debug: bool,
  239. ): ...
  240. @dataclass
  241. class ComponentTestTemplate(TestTemplate):
  242. component: Component
  243. # Templates to test
  244. base_template: ComponentTemplate
  245. update_template: ComponentTemplate
  246. # Expected result
  247. augment: str
  248. override: str
  249. replace: str = ""
  250. def __post_init__(self):
  251. self.augment = textwrap.dedent(self.augment).strip()
  252. self.override = textwrap.dedent(self.override).strip()
  253. if not self.replace:
  254. self.replace = self.override
  255. else:
  256. self.replace = textwrap.dedent(self.replace).strip()
  257. def expected(self, mode: MergeMode) -> str:
  258. match mode:
  259. case MergeMode.Default:
  260. return self.override
  261. case MergeMode.Augment:
  262. return self.augment
  263. case MergeMode.Override:
  264. return self.override
  265. case MergeMode.Replace:
  266. return self.replace
  267. case _:
  268. raise ValueError(mode)
  269. def _make_section_name(self, type: str, mode: MergeMode) -> str:
  270. file = self.make_file(f"{self.title}-{mode}" if self.title else mode)
  271. return f"{type}-{file}"
  272. def _make_file(self, type: str, mode: MergeMode) -> Path:
  273. section_name = self._make_section_name(type, mode)
  274. return Path(self.component) / self._file / section_name
  275. def render_section(self, content: str, name: str = "") -> str:
  276. return "\n".join(self.component.render(self.component, content, name))
  277. def render_keymap(self, content: str) -> str:
  278. return "\n".join(self.component.render_keymap(content))
  279. def _generate_tests(
  280. self, render: Callable[[str], str], compiler: XkbCompiler
  281. ) -> Generator[Test]:
  282. include_suffix = compiler.suffix
  283. for base_mode, update_mode in itertools.product(MergeMode, MergeMode):
  284. # Plain
  285. content = (
  286. self.base_template.render(base_mode)
  287. + ("\n" if self.base_template else "")
  288. + self.update_template.render(update_mode)
  289. )
  290. yield Test(
  291. title=self.make_title(
  292. f"{self._plain} ({base_mode}) - {self._plain} ({update_mode})"
  293. ),
  294. file=self.make_file(self.title) / self.make_file(update_mode),
  295. content=render(content),
  296. expected=render(self.expected(update_mode)),
  297. )
  298. for base_mode, update_mode in itertools.product(
  299. (MergeMode.Default,), MergeMode
  300. ):
  301. # Plain + Include
  302. file = self._make_file(self._update, update_mode)
  303. section = file.name
  304. file = file.parent.name
  305. for mode in MergeMode:
  306. yield Test(
  307. title=self.make_title(
  308. f"{self._plain} ({base_mode}) - {mode.include} ({update_mode})"
  309. ),
  310. file=self.make_file(self.title) / self.make_file(mode),
  311. content=render(
  312. self.base_template.render(base_mode)
  313. + (
  314. f'\n{mode.include} "{file}{include_suffix}({section})"'
  315. if self.base_template
  316. else ""
  317. )
  318. ),
  319. # Include does not leak local merge modes
  320. expected=render(self.expected(mode)),
  321. )
  322. # for base_mode, update_mode in itertools.product(MergeMode, MergeMode):
  323. # # Include + Plain
  324. # file = self._make_file(self.base, base_mode)
  325. # section = file.name
  326. # file = file.parent.name
  327. # for mode in (MergeMode.default,):
  328. # yield Test(
  329. # title=self.make_title(
  330. # f"{mode.include} ({base_mode}) - {self.plain} ({update_mode})"
  331. # ),
  332. # file=self.make_file(self.title)
  333. # / self.make_file(
  334. # f"{mode.include}({base_mode})-{self.plain}({update_mode})"
  335. # ),
  336. # content=render(
  337. # f'{mode.include} "{file}{include_suffix}({section})"\n'
  338. # + self.update_template.render(update_mode)
  339. # ),
  340. # expected=render(self.expected(update_mode)),
  341. # )
  342. # for base_mode, update_mode in itertools.product((MergeMode.Default,), MergeMode):
  343. # # Include + Include
  344. # mode = MergeMode.Default
  345. # base_file = self._make_file(self.base, mode)
  346. # base_section = base_file.name
  347. # base_file = base_file.parent.name
  348. # update_file = self._make_file(self.update, mode)
  349. # update_section = update_file.name
  350. # update_file = update_file.parent.name
  351. # yield Test(
  352. # title=self.make_title(
  353. # f"{base_mode.include} ({mode}) - {update_mode.include} ({mode})"
  354. # ),
  355. # file=self.make_file(self.title)
  356. # / self.make_file(
  357. # f"{base_mode.include}({mode})-{update_mode.include}({mode})"
  358. # ),
  359. # content=render(
  360. # f'{base_mode.include} "{base_file}{include_suffix}({base_section})"\n'
  361. # + f'{update_mode.include} "{update_file}{include_suffix}({update_section})"'
  362. # ),
  363. # expected=render(self.expected(update_mode)),
  364. # )
  365. for base_mode, update_mode in itertools.product(MergeMode, MergeMode):
  366. # Multi-include
  367. base_file = self._make_file(self._base, base_mode)
  368. base_section = base_file.name
  369. base_file = base_file.parent.name
  370. update_file = self._make_file(self._update, update_mode)
  371. update_section = update_file.name
  372. update_file = update_file.parent.name
  373. for mode in (MergeMode.Override, MergeMode.Augment, MergeMode.Replace):
  374. yield Test(
  375. title=self.make_title(
  376. f"{self._include} ({base_mode} {mode.char} {update_mode})"
  377. ),
  378. file=self.make_file(self.title) / self.make_file(mode),
  379. content=render(
  380. f'{base_mode.include} "{base_file}{include_suffix}({base_section})'
  381. + mode.char
  382. + f'{update_file}{include_suffix}({update_section})"'
  383. ),
  384. expected=render(self.expected(mode)),
  385. )
  386. def _generate_data(self) -> Generator[Test]:
  387. for type, template in (
  388. (self._base, self.base_template),
  389. (self._update, self.update_template),
  390. ):
  391. for mode in MergeMode:
  392. section_name = self._make_section_name(type, mode)
  393. file = self._make_file(type, mode)
  394. content = template.render(mode)
  395. content = self.render_section(content=content, name=section_name) + "\n"
  396. yield Test(title="", file=file, content=content, expected="")
  397. def generate_tests(
  398. self, compiler: XkbCompiler, as_keymap: bool = False
  399. ) -> TestGroup:
  400. if as_keymap:
  401. def render(content: str) -> str:
  402. return self.render_keymap(content)
  403. else:
  404. def render(content: str) -> str:
  405. return self.render_section(content)
  406. return TestGroup(self.title, tuple(self._generate_tests(render, compiler)))
  407. def generate_data(self) -> TestGroup:
  408. return TestGroup(self.title, tuple(self._generate_data()))
  409. @classmethod
  410. def write(
  411. cls,
  412. root: Path,
  413. jinja_env: jinja2.Environment,
  414. c_file: Path | None,
  415. xkb: bool,
  416. compiler: XkbCompiler,
  417. tests: Sequence[Self],
  418. debug: bool = False,
  419. ):
  420. if c_file is not None and c_file.name:
  421. c_data = tuple(
  422. t.generate_tests(as_keymap=True, compiler=compiler) for t in tests
  423. )
  424. TestGroup.write_c(
  425. root=root,
  426. jinja_env=jinja_env,
  427. path=c_file,
  428. compiler=compiler,
  429. tests=c_data,
  430. )
  431. if xkb:
  432. xkb_data = tuple(t.generate_data() for t in tests)
  433. TestGroup.write_data(root=root, compiler=compiler, tests=xkb_data)
  434. KeymapTemplate = Template(
  435. """\
  436. xkb_keymap {
  437. ${keycodes}
  438. ${types}
  439. ${compat}
  440. ${symbols}
  441. };"""
  442. )
  443. @dataclass
  444. class KeymapTestTemplate(TestTemplate):
  445. keycodes: ComponentTestTemplate | None = None
  446. types: ComponentTestTemplate | None = None
  447. compat: ComponentTestTemplate | None = None
  448. symbols: ComponentTestTemplate | None = None
  449. def __post_init__(self):
  450. if self.keycodes:
  451. self.keycodes = dataclasses.replace(self.keycodes, title="")
  452. if self.types:
  453. self.types = dataclasses.replace(self.types, title="")
  454. if self.compat:
  455. self.compat = dataclasses.replace(self.compat, title="")
  456. if self.symbols:
  457. self.symbols = dataclasses.replace(self.symbols, title="")
  458. def __iter__(self) -> Generator[ComponentTestTemplate]:
  459. def make_empty_template(component: Component) -> ComponentTestTemplate:
  460. return ComponentTestTemplate(
  461. title="",
  462. component=component,
  463. base_template=ComponentTemplate(""),
  464. update_template=ComponentTemplate(""),
  465. augment="",
  466. override="",
  467. )
  468. yield self.keycodes or make_empty_template(Component.keycodes)
  469. yield self.types or make_empty_template(Component.types)
  470. yield self.compat or make_empty_template(Component.compat)
  471. yield self.symbols or make_empty_template(Component.symbols)
  472. def _generate_tests(self, compiler: XkbCompiler) -> Generator[Test]:
  473. groups = tuple(
  474. c.generate_tests(as_keymap=False, compiler=compiler) for c in self
  475. )
  476. keycodes: Test
  477. types: Test
  478. compat: Test
  479. symbols: Test
  480. for keycodes, types, compat, symbols in zip(*(g.tests for g in groups)):
  481. title = self.title + keycodes.title
  482. file = keycodes.file
  483. content = KeymapTemplate.substitute(
  484. keycodes=textwrap.indent(keycodes.content, INDENT),
  485. types=textwrap.indent(types.content, INDENT),
  486. compat=textwrap.indent(compat.content, INDENT),
  487. symbols=textwrap.indent(symbols.content, INDENT),
  488. )
  489. expected = KeymapTemplate.substitute(
  490. keycodes=textwrap.indent(keycodes.expected, INDENT),
  491. types=textwrap.indent(types.expected, INDENT),
  492. compat=textwrap.indent(compat.expected, INDENT),
  493. symbols=textwrap.indent(symbols.expected, INDENT),
  494. )
  495. yield Test(title=title, file=file, content=content, expected=expected)
  496. def generate_tests(self, compiler: XkbCompiler) -> TestGroup:
  497. return TestGroup(self.title, tuple(self._generate_tests(compiler)))
  498. def _generate_data(self) -> Generator[Test]:
  499. for component in self:
  500. yield from component.generate_data().tests
  501. def generate_data(self) -> TestGroup:
  502. return TestGroup(self.title, tuple(self._generate_data()))
  503. @classmethod
  504. def write(
  505. cls,
  506. root: Path,
  507. jinja_env: jinja2.Environment,
  508. c_file: Path | None,
  509. xkb: bool,
  510. compiler: XkbCompiler,
  511. tests: Sequence[Self],
  512. debug: bool = False,
  513. ):
  514. if c_file is not None and c_file.name:
  515. c_data = tuple(t.generate_tests(compiler) for t in tests)
  516. TestGroup.write_c(
  517. root=root,
  518. jinja_env=jinja_env,
  519. path=c_file,
  520. compiler=compiler,
  521. tests=c_data,
  522. )
  523. if xkb:
  524. xkb_data = tuple(t.generate_data() for t in tests)
  525. TestGroup.write_data(root=root, compiler=compiler, tests=xkb_data)
  526. ################################################################################
  527. #
  528. # Key types tests
  529. #
  530. ################################################################################
  531. TYPES_TESTS = ComponentTestTemplate(
  532. "Types",
  533. component=Component.types,
  534. base_template=ComponentTemplate(
  535. """
  536. ${mode}virtual_modifiers NumLock, LevelThree=none, LevelFive=Mod3;
  537. ${mode}virtual_modifiers U1, U2, U3;
  538. // ${mode}virtual_modifiers U4, U5, U6;
  539. ${mode}virtual_modifiers Z1=none, Z2=none, Z3=none;
  540. // ${mode}virtual_modifiers Z4=none, Z5=none, Z6=none;
  541. ${mode}virtual_modifiers M1=0x1000, M2=0x2000, M3=0x3000;
  542. // ${mode}virtual_modifiers M4=0x4000, M5=0x5000, M6=0x6000;
  543. ${mode}type "ONE_LEVEL" {
  544. modifiers = None;
  545. map[None] = Level1;
  546. level_name[Level1]= "Any";
  547. };
  548. ${mode}type "TWO_LEVEL" {
  549. modifiers = Shift;
  550. map[Shift] = Level2;
  551. level_name[Level1] = "Base";
  552. level_name[Level2] = "Shift";
  553. };
  554. ${mode}type "ALPHABETIC" {
  555. modifiers = Shift+Lock;
  556. map[Shift] = Level2;
  557. map[Lock] = Level2;
  558. level_name[Level1] = "Base";
  559. level_name[Level2] = "Caps";
  560. };
  561. ${mode}type "KEYPAD" {
  562. modifiers = Shift+NumLock;
  563. map[None] = Level1;
  564. map[Shift] = Level2;
  565. map[NumLock] = Level2;
  566. map[Shift+NumLock] = Level1;
  567. level_name[Level1] = "Base";
  568. level_name[Level2] = "Number";
  569. };
  570. ${mode}type "FOUR_LEVEL" {
  571. modifiers = Shift+LevelThree;
  572. map[None] = Level1;
  573. map[Shift] = Level2;
  574. map[LevelThree] = Level3;
  575. map[Shift+LevelThree] = Level4;
  576. level_name[Level1] = "Base";
  577. level_name[Level2] = "Shift";
  578. level_name[Level3] = "Alt Base";
  579. level_name[Level4] = "Shift Alt";
  580. };
  581. ${mode}type "FOUR_LEVEL_ALPHABETIC" {
  582. modifiers = Shift+Lock+LevelThree;
  583. map[None] = Level1;
  584. map[Shift] = Level2;
  585. map[Lock] = Level2;
  586. map[LevelThree] = Level3;
  587. map[Shift+LevelThree] = Level4;
  588. map[Lock+LevelThree] = Level4;
  589. map[Lock+Shift+LevelThree] = Level3;
  590. level_name[Level1] = "Base";
  591. level_name[Level2] = "Shift";
  592. level_name[Level3] = "Alt Base";
  593. level_name[Level4] = "Shift Alt";
  594. };
  595. ${mode}type "FOUR_LEVEL_SEMIALPHABETIC" {
  596. modifiers = Shift+Lock+LevelThree;
  597. map[None] = Level1;
  598. map[Shift] = Level2;
  599. map[Lock] = Level2;
  600. map[LevelThree] = Level3;
  601. map[Shift+LevelThree] = Level4;
  602. map[Lock+LevelThree] = Level3;
  603. map[Lock+Shift+LevelThree] = Level4;
  604. preserve[Lock+LevelThree] = Lock;
  605. preserve[Lock+Shift+LevelThree] = Lock;
  606. level_name[Level1] = "Base";
  607. level_name[Level2] = "Shift";
  608. level_name[Level3] = "Alt Base";
  609. level_name[Level4] = "Shift Alt";
  610. };
  611. ${mode}type "XXX" {
  612. modifiers = Shift+Lock+LevelThree;
  613. map[None] = 1;
  614. map[Shift] = 2;
  615. map[Lock] = 2;
  616. map[LevelThree] = 3;
  617. level_name[1] = "1";
  618. level_name[2] = "2";
  619. level_name[3] = "3";
  620. };
  621. """
  622. ),
  623. update_template=ComponentTemplate(
  624. """\
  625. ${mode}virtual_modifiers NumLock=Mod2; // Changed: now mapped
  626. ${mode}virtual_modifiers LevelThree=Mod5; // Changed: altered mapping (from 0)
  627. ${mode}virtual_modifiers LevelFive=Mod3; // Unhanged: same mapping
  628. ${mode}virtual_modifiers U7, Z7=0, M7=0x700000; // Changed: new
  629. ${mode}virtual_modifiers U1; // Unchanged (unmapped)
  630. ${mode}virtual_modifiers U2 = none; // Changed: now mapped
  631. ${mode}virtual_modifiers U3 = 0x300000; // Changed: now mapped
  632. // ${mode}virtual_modifiers U4; // Unchanged (unmapped)
  633. // ${mode}virtual_modifiers U5 = none; // Changed: now mapped
  634. // ${mode}virtual_modifiers U6 = 0x600000; // Changed: now mapped
  635. ${mode}virtual_modifiers Z1; // Unchanged (= 0)
  636. ${mode}virtual_modifiers Z2 = none; // Unchanged (same mapping)
  637. ${mode}virtual_modifiers Z3 = 0x310000; // Changed: altered mapping (from 0)
  638. // ${mode}virtual_modifiers Z4; // Unchanged (= 0)
  639. // ${mode}virtual_modifiers Z5 = none; // Unchanged (same mapping)
  640. // ${mode}virtual_modifiers Z6 = 0x610000; // Changed: altered mapping (from 0)
  641. ${mode}virtual_modifiers M1; // Unchanged (≠ 0)
  642. ${mode}virtual_modifiers M2 = none; // Changed: reset
  643. ${mode}virtual_modifiers M3 = 0x320000; // Changed: altered mapping (from ≠ 0)
  644. // ${mode}virtual_modifiers M4; // Unchanged (≠ 0)
  645. // ${mode}virtual_modifiers M5 = none; // Changed: reset
  646. // ${mode}virtual_modifiers M6 = 0x620000; // Changed: altered mapping (from ≠ 0)
  647. ${mode}type "ONE_LEVEL" {
  648. modifiers = None;
  649. map[None] = Level1;
  650. level_name[Level1]= "New"; // Change name
  651. };
  652. ${mode}type "TWO_LEVEL" {
  653. modifiers = Shift+M1; // Changed
  654. map[Shift] = Level2;
  655. map[M1] = Level2; // Changed
  656. level_name[Level1] = "Base";
  657. level_name[Level2] = "Shift";
  658. };
  659. ${mode}type "ALPHABETIC" {
  660. modifiers = Lock; // Changed
  661. map[None] = Level2; // Changed
  662. map[Lock] = Level1; // Changed
  663. level_name[Level1] = "Base";
  664. level_name[Level2] = "Caps";
  665. };
  666. ${mode}type "KEYPAD" {
  667. modifiers = Shift+NumLock;
  668. map[None] = Level1;
  669. map[Shift] = Level2; // Changed
  670. map[NumLock] = Level2;
  671. map[Shift+NumLock] = Level1;
  672. level_name[Level1] = "Base";
  673. level_name[Level2] = "Number";
  674. };
  675. // Unchanged
  676. ${mode}type "FOUR_LEVEL" {
  677. modifiers = Shift+LevelThree;
  678. map[None] = Level1;
  679. map[Shift] = Level2;
  680. map[LevelThree] = Level3;
  681. map[Shift+LevelThree] = Level4;
  682. level_name[Level1] = "Base";
  683. level_name[Level2] = "Shift";
  684. level_name[Level3] = "Alt Base";
  685. level_name[Level4] = "Shift Alt";
  686. };
  687. ${mode}type "FOUR_LEVEL_ALPHABETIC" {
  688. modifiers = Shift+Lock+LevelThree;
  689. map[None] = Level1;
  690. map[Shift] = Level2;
  691. map[Lock] = Level2;
  692. map[LevelThree] = Level3;
  693. map[Shift+LevelThree] = Level4;
  694. map[Lock+LevelThree] = Level4;
  695. map[Lock+Shift+LevelThree] = Level3;
  696. level_name[Level1] = "Base";
  697. level_name[Level2] = "Shift";
  698. level_name[Level3] = "Alt Base";
  699. level_name[Level4] = "Shift Alt";
  700. };
  701. ${mode}type "FOUR_LEVEL_SEMIALPHABETIC" {
  702. modifiers = Shift+Lock+LevelThree;
  703. map[None] = Level1;
  704. map[Shift] = Level2;
  705. map[Lock] = Level2;
  706. map[LevelThree] = Level3;
  707. map[Shift+LevelThree] = Level4;
  708. map[Lock+LevelThree] = Level3;
  709. map[Lock+Shift+LevelThree] = Level4;
  710. preserve[Lock+LevelThree] = Lock;
  711. preserve[Lock+Shift+LevelThree] = Lock;
  712. level_name[Level1] = "Base";
  713. level_name[Level2] = "Shift";
  714. level_name[Level3] = "Alt Base";
  715. level_name[Level4] = "Shift Alt";
  716. };
  717. ${mode}type "XXX" {
  718. modifiers = Shift+Lock+LevelThree;
  719. map[None] = 1;
  720. map[Shift] = 2;
  721. // map[Lock] = 2; // Changed
  722. // map[LevelThree] = 3;
  723. map[LevelThree] = 1; // Changed
  724. map[Shift+LevelThree] = 4; // Changed
  725. level_name[1] = "A"; // Changed
  726. level_name[2] = "2";
  727. level_name[3] = "3";
  728. level_name[4] = "4"; // Changed
  729. };
  730. // New
  731. ${mode}type "YYY" {
  732. modifiers = None;
  733. map[None] = Level1;
  734. level_name[Level1]= "New";
  735. };
  736. """
  737. ),
  738. augment="""
  739. virtual_modifiers NumLock=Mod2,LevelThree=none,LevelFive=Mod3;
  740. virtual_modifiers U1,U2=0,U3=0x300000;
  741. // virtual_modifiers U4,U5=0,U6=0x600000;
  742. virtual_modifiers Z1=0,Z2=0,Z3=0;
  743. // virtual_modifiers Z4=0,Z5=0,Z6=0;
  744. virtual_modifiers M1=0x1000,M2=0x2000,M3=0x3000;
  745. // virtual_modifiers M4=0x4000,M5=0x5000,M6=0x6000;
  746. virtual_modifiers U7,Z7=0,M7=0x700000;
  747. type "ONE_LEVEL" {
  748. modifiers= none;
  749. map[none]= 1;
  750. level_name[1]= "Any";
  751. };
  752. type "TWO_LEVEL" {
  753. modifiers= Shift;
  754. map[Shift]= 2;
  755. level_name[1]= "Base";
  756. level_name[2]= "Shift";
  757. };
  758. type "ALPHABETIC" {
  759. modifiers= Shift+Lock;
  760. map[Shift]= 2;
  761. map[Lock]= 2;
  762. level_name[1]= "Base";
  763. level_name[2]= "Caps";
  764. };
  765. type "KEYPAD" {
  766. modifiers= Shift+NumLock;
  767. map[Shift]= 2;
  768. map[NumLock]= 2;
  769. level_name[1]= "Base";
  770. level_name[2]= "Number";
  771. };
  772. type "FOUR_LEVEL" {
  773. modifiers= Shift+LevelThree;
  774. map[none]= 1;
  775. map[Shift]= 2;
  776. map[LevelThree]= 3;
  777. map[Shift+LevelThree]= 4;
  778. level_name[1]= "Base";
  779. level_name[2]= "Shift";
  780. level_name[3]= "Alt Base";
  781. level_name[4]= "Shift Alt";
  782. };
  783. type "FOUR_LEVEL_ALPHABETIC" {
  784. modifiers= Shift+Lock+LevelThree;
  785. map[none]= 1;
  786. map[Shift]= 2;
  787. map[Lock]= 2;
  788. map[LevelThree]= 3;
  789. map[Shift+LevelThree]= 4;
  790. map[Lock+LevelThree]= 4;
  791. map[Shift+Lock+LevelThree]= 3;
  792. level_name[1]= "Base";
  793. level_name[2]= "Shift";
  794. level_name[3]= "Alt Base";
  795. level_name[4]= "Shift Alt";
  796. };
  797. type "FOUR_LEVEL_SEMIALPHABETIC" {
  798. modifiers= Shift+Lock+LevelThree;
  799. map[None]= 1;
  800. map[Shift]= 2;
  801. map[Lock]= 2;
  802. map[LevelThree]= 3;
  803. map[Shift+LevelThree]= 4;
  804. map[Lock+LevelThree]= 3;
  805. preserve[Lock+LevelThree]= Lock;
  806. map[Shift+Lock+LevelThree]= 4;
  807. preserve[Shift+Lock+LevelThree]= Lock;
  808. level_name[1]= "Base";
  809. level_name[2]= "Shift";
  810. level_name[3]= "Alt Base";
  811. level_name[4]= "Shift Alt";
  812. };
  813. type "XXX" {
  814. modifiers = Shift+Lock+LevelThree;
  815. map[None] = 1;
  816. map[Shift] = 2;
  817. map[Lock] = 2;
  818. map[LevelThree] = 3;
  819. level_name[1] = "1";
  820. level_name[2] = "2";
  821. level_name[3] = "3";
  822. };
  823. type "YYY" {
  824. modifiers = None;
  825. map[None] = Level1;
  826. level_name[Level1]= "New";
  827. };
  828. """,
  829. override="""
  830. virtual_modifiers NumLock=Mod2,LevelThree=Mod5,LevelFive=Mod3;
  831. virtual_modifiers U1,U2=0,U3=0x300000;
  832. // virtual_modifiers U4,U5=0,U6=0x600000;
  833. virtual_modifiers Z1=0,Z2=0,Z3=0x310000;
  834. // virtual_modifiers Z4=0,Z5=0,Z6=0x610000;
  835. virtual_modifiers M1=0x1000,M2=0,M3=0x320000;
  836. // virtual_modifiers M4=0x4000,M5=0,M6=0x620000;
  837. virtual_modifiers U7,Z7=0,M7=0x700000;
  838. type "ONE_LEVEL" {
  839. modifiers= none;
  840. map[None] = Level1;
  841. level_name[1]= "New";
  842. };
  843. type "TWO_LEVEL" {
  844. modifiers= Shift+M1;
  845. map[Shift]= 2;
  846. map[M1]= 2;
  847. level_name[1]= "Base";
  848. level_name[2]= "Shift";
  849. };
  850. type "ALPHABETIC" {
  851. modifiers= Lock;
  852. map[none]= 2;
  853. map[Lock]= 1;
  854. level_name[1]= "Base";
  855. level_name[2]= "Caps";
  856. };
  857. type "KEYPAD" {
  858. modifiers= Shift+NumLock;
  859. map[Shift] = Level2;
  860. map[NumLock]= 2;
  861. level_name[1]= "Base";
  862. level_name[2]= "Number";
  863. };
  864. type "FOUR_LEVEL" {
  865. modifiers= Shift+LevelThree;
  866. map[None]= 1;
  867. map[Shift]= 2;
  868. map[LevelThree]= 3;
  869. map[Shift+LevelThree] = Level4;
  870. level_name[1]= "Base";
  871. level_name[2]= "Shift";
  872. level_name[3]= "Alt Base";
  873. level_name[4]= "Shift Alt";
  874. };
  875. type "FOUR_LEVEL_ALPHABETIC" {
  876. modifiers= Shift+Lock+LevelThree;
  877. map[Shift]= 2;
  878. map[Lock]= 2;
  879. map[LevelThree]= 3;
  880. map[Shift+LevelThree]= 4;
  881. map[Lock+LevelThree]= 4;
  882. map[Shift+Lock+LevelThree]= 3;
  883. level_name[1]= "Base";
  884. level_name[2]= "Shift";
  885. level_name[3]= "Alt Base";
  886. level_name[4]= "Shift Alt";
  887. };
  888. type "FOUR_LEVEL_SEMIALPHABETIC" {
  889. modifiers= Shift+Lock+LevelThree;
  890. map[None]= 1;
  891. map[Shift]= 2;
  892. map[Lock]= 2;
  893. map[LevelThree]= 3;
  894. map[Shift+LevelThree]= 4;
  895. map[Lock+LevelThree]= 3;
  896. preserve[Lock+LevelThree]= Lock;
  897. map[Shift+Lock+LevelThree]= 4;
  898. preserve[Shift+Lock+LevelThree]= Lock;
  899. level_name[1]= "Base";
  900. level_name[2]= "Shift";
  901. level_name[3]= "Alt Base";
  902. level_name[4]= "Shift Alt";
  903. };
  904. type "XXX" {
  905. modifiers = Shift+Lock+LevelThree;
  906. map[None] = 1;
  907. map[Shift] = 2;
  908. // map[LevelThree] = 3;
  909. map[LevelThree] = 1;
  910. map[Shift+LevelThree] = 4;
  911. level_name[1] = "A";
  912. level_name[2] = "2";
  913. level_name[3] = "3";
  914. level_name[4] = "4";
  915. };
  916. type "YYY" {
  917. modifiers = None;
  918. map[None] = Level1;
  919. level_name[Level1]= "New";
  920. };
  921. """,
  922. )
  923. ################################################################################
  924. #
  925. # Compat tests
  926. #
  927. ################################################################################
  928. COMPAT_TESTS = ComponentTestTemplate(
  929. "Compat",
  930. component=Component.compat,
  931. base_template=ComponentTemplate(
  932. """
  933. ${mode}virtual_modifiers NumLock;
  934. interpret.repeat= False;
  935. setMods.clearLocks= True;
  936. latchMods.clearLocks= True;
  937. latchMods.latchToLock= True;
  938. ${mode}interpret Any + Any {
  939. action= SetMods(modifiers=modMapMods);
  940. };
  941. ${mode}interpret Caps_Lock {
  942. action = LockMods(modifiers = Lock);
  943. };
  944. ${mode}indicator "Caps Lock" {
  945. !allowExplicit;
  946. whichModState= Locked;
  947. modifiers= Lock;
  948. };
  949. ${mode}indicator "Num Lock" {
  950. !allowExplicit;
  951. whichModState= Locked;
  952. modifiers= NumLock;
  953. };
  954. """
  955. ),
  956. update_template=ComponentTemplate(
  957. """
  958. ${mode}virtual_modifiers NumLock;
  959. ${mode}interpret.repeat= False;
  960. ${mode}setMods.clearLocks= False; // Changed
  961. // Unchanged
  962. ${mode}interpret Any + Any {
  963. action= SetMods(modifiers=modMapMods);
  964. };
  965. // Changed
  966. ${mode}interpret Caps_Lock {
  967. action = LockMods(modifiers = NumLock);
  968. };
  969. // Unchanged
  970. ${mode}indicator "Caps Lock" {
  971. !allowExplicit;
  972. whichModState= Locked;
  973. modifiers= Lock;
  974. };
  975. // Changed
  976. ${mode}indicator "Num Lock" {
  977. !allowExplicit;
  978. whichModState= Base;
  979. modifiers= Lock;
  980. };
  981. // New
  982. ${mode}indicator "Kana" {
  983. !allowExplicit;
  984. whichModState= Locked;
  985. modifiers= Control;
  986. };
  987. """
  988. ),
  989. augment="""
  990. virtual_modifiers NumLock;
  991. interpret.useModMapMods= AnyLevel;
  992. interpret.repeat= False;
  993. interpret Caps_Lock+AnyOfOrNone(all) {
  994. action= LockMods(modifiers=Lock);
  995. };
  996. interpret Any+AnyOf(all) {
  997. action= SetMods(modifiers=modMapMods,clearLocks);
  998. };
  999. indicator "Caps Lock" {
  1000. whichModState= locked;
  1001. modifiers= Lock;
  1002. };
  1003. indicator "Num Lock" {
  1004. whichModState= locked;
  1005. modifiers= NumLock;
  1006. };
  1007. indicator "Kana" {
  1008. whichModState= locked;
  1009. modifiers= Control;
  1010. };
  1011. """,
  1012. override="""
  1013. virtual_modifiers NumLock;
  1014. interpret.repeat= False;
  1015. setMods.clearLocks= False;
  1016. interpret Caps_Lock+AnyOfOrNone(all) {
  1017. action= LockMods(modifiers=NumLock);
  1018. };
  1019. interpret Any+AnyOf(all) {
  1020. action= SetMods(modifiers=modMapMods);
  1021. };
  1022. indicator "Caps Lock" {
  1023. whichModState= locked;
  1024. modifiers= Lock;
  1025. };
  1026. indicator "Kana" {
  1027. whichModState= locked;
  1028. modifiers= Control;
  1029. };
  1030. indicator "Num Lock" {
  1031. whichModState= base;
  1032. modifiers= Lock;
  1033. };
  1034. """,
  1035. )
  1036. ################################################################################
  1037. #
  1038. # Symbols tests
  1039. #
  1040. ################################################################################
  1041. LINUX_EVENT_CODES = (
  1042. None,
  1043. "ESC",
  1044. "1",
  1045. "2",
  1046. "3",
  1047. "4",
  1048. "5",
  1049. "6",
  1050. "7",
  1051. "8",
  1052. "9",
  1053. "0",
  1054. "MINUS",
  1055. "EQUAL",
  1056. "BACKSPACE",
  1057. "TAB",
  1058. "Q",
  1059. "W",
  1060. "E",
  1061. "R",
  1062. "T",
  1063. "Y",
  1064. "U",
  1065. "I",
  1066. "O",
  1067. "P",
  1068. "LEFTBRACE",
  1069. "RIGHTBRACE",
  1070. "ENTER",
  1071. "LEFTCTRL",
  1072. "A",
  1073. "S",
  1074. "D",
  1075. "F",
  1076. "G",
  1077. "H",
  1078. "J",
  1079. "K",
  1080. "L",
  1081. "SEMICOLON",
  1082. "APOSTROPHE",
  1083. "GRAVE",
  1084. "LEFTSHIFT",
  1085. "BACKSLASH",
  1086. "Z",
  1087. "X",
  1088. "C",
  1089. "V",
  1090. "B",
  1091. "N",
  1092. "M",
  1093. "COMMA",
  1094. "DOT",
  1095. "SLASH",
  1096. "RIGHTSHIFT",
  1097. "KPASTERISK",
  1098. "LEFTALT",
  1099. "SPACE",
  1100. "CAPSLOCK",
  1101. "F1",
  1102. "F2",
  1103. "F3",
  1104. "F4",
  1105. "F5",
  1106. "F6",
  1107. "F7",
  1108. "F8",
  1109. "F9",
  1110. "F10",
  1111. "NUMLOCK",
  1112. "SCROLLLOCK",
  1113. "KP7",
  1114. "KP8",
  1115. "KP9",
  1116. "KPMINUS",
  1117. "KP4",
  1118. "KP5",
  1119. "KP6",
  1120. "KPPLUS",
  1121. "KP1",
  1122. "KP2",
  1123. "KP3",
  1124. "KP0",
  1125. "KPDOT",
  1126. None,
  1127. "ZENKAKUHANKAKU",
  1128. "102ND",
  1129. "F11",
  1130. "F12",
  1131. "RO",
  1132. "KATAKANA",
  1133. "HIRAGANA",
  1134. "HENKAN",
  1135. "KATAKANAHIRAGANA",
  1136. "MUHENKAN",
  1137. "KPJPCOMMA",
  1138. "KPENTER",
  1139. "RIGHTCTRL",
  1140. "KPSLASH",
  1141. "SYSRQ",
  1142. "RIGHTALT",
  1143. "LINEFEED",
  1144. "HOME",
  1145. "UP",
  1146. "PAGEUP",
  1147. "LEFT",
  1148. "RIGHT",
  1149. "END",
  1150. "DOWN",
  1151. "PAGEDOWN",
  1152. "INSERT",
  1153. "DELETE",
  1154. "MACRO",
  1155. "MUTE",
  1156. "VOLUMEDOWN",
  1157. "VOLUMEUP",
  1158. "POWER",
  1159. "KPEQUAL",
  1160. "KPPLUSMINUS",
  1161. "PAUSE",
  1162. "SCALE",
  1163. "KPCOMMA",
  1164. "HANGEUL",
  1165. "HANJA",
  1166. "YEN",
  1167. "LEFTMETA",
  1168. "RIGHTMETA",
  1169. "COMPOSE",
  1170. "STOP",
  1171. "AGAIN",
  1172. "PROPS",
  1173. "UNDO",
  1174. "FRONT",
  1175. "COPY",
  1176. "OPEN",
  1177. "PASTE",
  1178. "FIND",
  1179. "CUT",
  1180. "HELP",
  1181. "MENU",
  1182. "CALC",
  1183. "SETUP",
  1184. "SLEEP",
  1185. "WAKEUP",
  1186. "FILE",
  1187. "SENDFILE",
  1188. "DELETEFILE",
  1189. "XFER",
  1190. "PROG1",
  1191. "PROG2",
  1192. "WWW",
  1193. "MSDOS",
  1194. "COFFEE",
  1195. "DIRECTION",
  1196. "CYCLEWINDOWS",
  1197. "MAIL",
  1198. "BOOKMARKS",
  1199. "COMPUTER",
  1200. "BACK",
  1201. "FORWARD",
  1202. "CLOSECD",
  1203. "EJECTCD",
  1204. "EJECTCLOSECD",
  1205. "NEXTSONG",
  1206. "PLAYPAUSE",
  1207. "PREVIOUSSONG",
  1208. "STOPCD",
  1209. "RECORD",
  1210. "REWIND",
  1211. "PHONE",
  1212. "ISO",
  1213. "CONFIG",
  1214. "HOMEPAGE",
  1215. "REFRESH",
  1216. "EXIT",
  1217. "MOVE",
  1218. "EDIT",
  1219. "SCROLLUP",
  1220. "SCROLLDOWN",
  1221. "KPLEFTPAREN",
  1222. "KPRIGHTPAREN",
  1223. "NEW",
  1224. "REDO",
  1225. "F13",
  1226. "F14",
  1227. "F15",
  1228. "F16",
  1229. "F17",
  1230. "F18",
  1231. "F19",
  1232. "F20",
  1233. "F21",
  1234. "F22",
  1235. "F23",
  1236. "F24",
  1237. None,
  1238. None,
  1239. None,
  1240. None,
  1241. None,
  1242. "PLAYCD",
  1243. "PAUSECD",
  1244. "PROG3",
  1245. "PROG4",
  1246. "DASHBOARD",
  1247. "SUSPEND",
  1248. "CLOSE",
  1249. "PLAY",
  1250. "FASTFORWARD",
  1251. "BASSBOOST",
  1252. "PRINT",
  1253. "HP",
  1254. "CAMERA",
  1255. "SOUND",
  1256. "QUESTION",
  1257. )
  1258. Comment = NewType("Comment", str)
  1259. @dataclass(frozen=True)
  1260. class KeyCode:
  1261. _evdev: str
  1262. _xkb: str
  1263. @property
  1264. def c(self) -> str:
  1265. return f"KEY_{self._evdev}"
  1266. @property
  1267. def xkb(self) -> str:
  1268. return f"<{self._xkb}>"
  1269. class Keysym(str):
  1270. @property
  1271. def c(self) -> str:
  1272. return f"XKB_KEY_{self}"
  1273. @classmethod
  1274. def parse(cls, raw: str | None) -> Self:
  1275. if not raw:
  1276. return cls("NoSymbol")
  1277. else:
  1278. return cls(raw)
  1279. NoSymbol = Keysym("NoSymbol")
  1280. class Modifier(IntFlag):
  1281. NoModifier = 0
  1282. Shift = 1 << 0
  1283. Lock = 1 << 1
  1284. Control = 1 << 2
  1285. Mod1 = 1 << 3
  1286. Mod2 = 1 << 4
  1287. Mod3 = 1 << 5
  1288. Mod4 = 1 << 6
  1289. Mod5 = 1 << 7
  1290. LevelThree = Mod5
  1291. def __iter__(self) -> Iterator[Self]:
  1292. for m in self.__class__:
  1293. if m & self:
  1294. yield m
  1295. def __str__(self) -> str:
  1296. return "+".join(m.name for m in self)
  1297. class Action(metaclass=ABCMeta):
  1298. @abstractmethod
  1299. def __bool__(self) -> bool: ...
  1300. @classmethod
  1301. def parse(cls, raw: Any) -> Self:
  1302. if raw is None:
  1303. return GroupAction.parse(None)
  1304. elif isinstance(raw, Modifier):
  1305. return ModAction.parse(raw)
  1306. elif isinstance(raw, int):
  1307. return GroupAction.parse(raw)
  1308. else:
  1309. raise ValueError(raw)
  1310. @abstractmethod
  1311. def action_to_keysym(self, index: int, level: int) -> Keysym: ...
  1312. @dataclass
  1313. class GroupAction(Action):
  1314. """
  1315. SetGroup or NoAction
  1316. """
  1317. group: int
  1318. keysyms: ClassVar[dict[tuple[int, int, int], Keysym]] = {
  1319. (2, 0, 0): Keysym("a"),
  1320. (2, 0, 1): Keysym("A"),
  1321. (2, 1, 0): Keysym("b"),
  1322. (2, 1, 1): Keysym("B"),
  1323. (3, 0, 0): Keysym("Greek_alpha"),
  1324. (3, 0, 1): Keysym("Greek_ALPHA"),
  1325. (3, 1, 0): Keysym("Greek_beta"),
  1326. (3, 1, 1): Keysym("Greek_BETA"),
  1327. }
  1328. def __str__(self) -> str:
  1329. if self.group > 0:
  1330. return f"SetGroup(group={self.group})"
  1331. else:
  1332. return "NoAction()"
  1333. def __bool__(self) -> bool:
  1334. return bool(self.group)
  1335. @classmethod
  1336. def parse(cls, raw: int | None) -> Self:
  1337. if not raw:
  1338. return cls(0)
  1339. else:
  1340. return cls(raw)
  1341. def action_to_keysym(self, index: int, level: int) -> Keysym:
  1342. if not self.group:
  1343. return NoSymbol
  1344. else:
  1345. if (
  1346. keysym := self.keysyms.get((self.group % 4, index % 2, level % 2))
  1347. ) is None:
  1348. raise ValueError((self, index, level))
  1349. return keysym
  1350. @dataclass
  1351. class ModAction(Action):
  1352. """
  1353. SetMod or NoAction
  1354. """
  1355. mods: Modifier
  1356. keysyms: ClassVar[dict[tuple[Modifier, int, int], Keysym]] = {
  1357. (Modifier.Control, 0, 0): Keysym("x"),
  1358. (Modifier.Control, 0, 1): Keysym("X"),
  1359. (Modifier.Control, 1, 0): Keysym("y"),
  1360. (Modifier.Control, 1, 1): Keysym("Y"),
  1361. (Modifier.Mod5, 0, 0): Keysym("Greek_xi"),
  1362. (Modifier.Mod5, 0, 1): Keysym("Greek_XI"),
  1363. (Modifier.Mod5, 1, 0): Keysym("Greek_upsilon"),
  1364. (Modifier.Mod5, 1, 1): Keysym("Greek_UPSILON"),
  1365. }
  1366. def __str__(self) -> str:
  1367. if self.mods is Modifier.NoModifier:
  1368. return "NoAction()"
  1369. else:
  1370. return f"SetMods(mods={self.mods})"
  1371. def __bool__(self) -> bool:
  1372. return self.mods is Modifier.NoModifier
  1373. @classmethod
  1374. def parse(cls, raw: Modifier | None) -> Self:
  1375. if not raw:
  1376. return cls(Modifier.NoModifier)
  1377. else:
  1378. return cls(raw)
  1379. def action_to_keysym(self, index: int, level: int) -> Keysym:
  1380. if self.mods is Modifier.NoModifier:
  1381. return NoSymbol
  1382. else:
  1383. if (keysym := self.keysyms.get((self.mods, index % 2, level % 2))) is None:
  1384. raise ValueError((self, index, level))
  1385. return keysym
  1386. @dataclass
  1387. class Level:
  1388. keysyms: tuple[Keysym, ...]
  1389. actions: tuple[Action, ...]
  1390. @staticmethod
  1391. def _c(default: str, xs: Iterable[Any]) -> str:
  1392. match len(xs):
  1393. case 0:
  1394. return default
  1395. case 1:
  1396. return xs[0].c
  1397. case _:
  1398. return ", ".join(map(lambda x: x.c, xs))
  1399. @staticmethod
  1400. def _xkb(default: str, xs: Iterable[Any]) -> str:
  1401. match len(xs):
  1402. case 0:
  1403. return default
  1404. case 1:
  1405. return str(xs[0])
  1406. case _:
  1407. return "{" + ", ".join(map(str, xs)) + "}"
  1408. @classmethod
  1409. def has_empty_symbols(cls, keysyms: tuple[Keysym, ...]) -> bool:
  1410. return all(ks == NoSymbol for ks in keysyms)
  1411. @property
  1412. def empty_symbols(self) -> bool:
  1413. return self.has_empty_symbols(self.keysyms)
  1414. @property
  1415. def keysyms_c(self) -> str:
  1416. if not self.keysyms and self.actions:
  1417. return self._c(
  1418. NoSymbol.c, tuple(itertools.repeat(NoSymbol, len(self.actions)))
  1419. )
  1420. return self._c(NoSymbol.c, self.keysyms)
  1421. @property
  1422. def keysyms_xkb(self) -> str:
  1423. return self._xkb(NoSymbol, self.keysyms)
  1424. @classmethod
  1425. def has_empty_actions(cls, actions: tuple[Action, ...]) -> bool:
  1426. return not any(actions)
  1427. @property
  1428. def empty_actions(self) -> bool:
  1429. return self.has_empty_actions(self.actions)
  1430. @property
  1431. def actions_xkb(self) -> str:
  1432. return self._xkb("NoAction()", self.actions)
  1433. @classmethod
  1434. def Keysyms(cls, *keysyms: str | None) -> Self:
  1435. return cls.Mix(keysyms, ())
  1436. @classmethod
  1437. def Actions(cls, *actions: int | Modifier | None) -> Self:
  1438. return cls.Mix((), actions)
  1439. @classmethod
  1440. def Mix(
  1441. cls, keysyms: tuple[str | None, ...], actions: tuple[int | Modifier | None,]
  1442. ) -> Self:
  1443. return cls(tuple(map(Keysym.parse, keysyms)), tuple(map(Action.parse, actions)))
  1444. def add_keysyms(self, keep_actions: bool, level: int) -> Self:
  1445. return self.__class__(
  1446. keysyms=tuple(
  1447. a.action_to_keysym(index=k, level=level)
  1448. for k, a in enumerate(self.actions)
  1449. ),
  1450. actions=self.actions if keep_actions else (),
  1451. )
  1452. @property
  1453. def target_group(self) -> int:
  1454. for a in self.actions:
  1455. if isinstance(a, GroupAction) and a.group > 1:
  1456. return a.group
  1457. else:
  1458. return 0
  1459. @property
  1460. def target_level(self) -> int:
  1461. for a in self.actions:
  1462. if isinstance(a, ModAction) and a.mods:
  1463. match a.mods:
  1464. case Modifier.LevelThree:
  1465. return 2
  1466. case _:
  1467. return 0
  1468. else:
  1469. return 0
  1470. @dataclass
  1471. class KeyEntry:
  1472. levels: tuple[Level, ...]
  1473. def __init__(self, *levels: Level):
  1474. self.levels = levels
  1475. @property
  1476. def xkb(self) -> Iterator[str]:
  1477. if not self.levels:
  1478. yield ""
  1479. return
  1480. keysyms = tuple(l.keysyms for l in self.levels)
  1481. has_keysyms = any(not Level.has_empty_symbols(s) for s in keysyms)
  1482. no_keysyms = all(not s for s in keysyms)
  1483. actions = tuple(l.actions for l in self.levels)
  1484. has_actions = any(not Level.has_empty_actions(a) for a in actions)
  1485. if has_keysyms or (not no_keysyms and not has_actions):
  1486. yield "["
  1487. yield ", ".join(l.keysyms_xkb for l in self.levels)
  1488. yield "]"
  1489. if has_actions or no_keysyms:
  1490. if has_keysyms:
  1491. yield ", "
  1492. yield "["
  1493. yield ", ".join(l.actions_xkb for l in self.levels)
  1494. yield "]"
  1495. def add_keysyms(self, keep_actions: bool) -> Self:
  1496. return self.__class__(
  1497. *(
  1498. l.add_keysyms(keep_actions=keep_actions, level=k)
  1499. for k, l in enumerate(self.levels)
  1500. )
  1501. )
  1502. class TestType(IntFlag):
  1503. KeysymsOnly = auto()
  1504. ActionsOnly = auto()
  1505. KeysymsAndActions = auto()
  1506. All = ActionsOnly | KeysymsOnly | KeysymsAndActions
  1507. @dataclass
  1508. class TestId:
  1509. type: TestType
  1510. base: int = 0
  1511. _last_base: ClassVar[int] = 0
  1512. _max_type: ClassVar[int] = TestType.KeysymsAndActions >> 1
  1513. _forbidden_keys: tuple[str, ...] = ("LEFTSHIFT", "RIGHTALT")
  1514. def __post_init__(self):
  1515. if self.base == -1:
  1516. self.base = self.__class__._last_base
  1517. elif self.base < 0:
  1518. raise ValueError(self.base)
  1519. elif self.base == 0:
  1520. self.__class__._last_base += 1
  1521. self.base = self.__class__._last_base
  1522. while not self.check_linux_keys(self._base_id):
  1523. self.__class__._last_base += 1
  1524. self.base = self.__class__._last_base
  1525. else:
  1526. self.__class__._last_base = max(self.__class__._last_base, self.base)
  1527. assert self.linux_key, self
  1528. # print(self.base, self.id, self.xkb_key)
  1529. def __hash__(self) -> int:
  1530. return self.id
  1531. @property
  1532. def _base_id(self) -> int:
  1533. return (self.base - 1) * (self._max_type + 1) + 1
  1534. @property
  1535. def id(self) -> int:
  1536. # return (self.base << 2) | (self.type >> 1)
  1537. return self._base_id + (self.type >> 1)
  1538. def with_type(self, type: TestType) -> Self:
  1539. return dataclasses.replace(self, type=type)
  1540. @property
  1541. def xkb_key(self) -> str:
  1542. return f"T{self.id:0>3}"
  1543. @classmethod
  1544. def check_linux_key(cls, idx: int) -> bool:
  1545. if idx >= len(LINUX_EVENT_CODES):
  1546. raise ValueError("Not enough Linux keys available!")
  1547. key: str | None = LINUX_EVENT_CODES[idx]
  1548. return bool(key) and key not in cls._forbidden_keys
  1549. @classmethod
  1550. def check_linux_keys(cls, base_id) -> bool:
  1551. return all(
  1552. cls.check_linux_key(base_id + k) for k in range(0, cls._max_type + 1)
  1553. )
  1554. @property
  1555. def linux_key(self) -> str:
  1556. if self.id >= len(LINUX_EVENT_CODES):
  1557. raise ValueError("Not enough Linux keys available!")
  1558. return LINUX_EVENT_CODES[self.id]
  1559. @property
  1560. def key(self) -> KeyCode:
  1561. return KeyCode(self.linux_key, self.xkb_key)
  1562. @unique
  1563. class Implementation(Flag):
  1564. x11 = auto()
  1565. xkbcommon = auto()
  1566. all = x11 | xkbcommon
  1567. @dataclass
  1568. class TestEntry:
  1569. id: TestId
  1570. key: KeyCode = dataclasses.field(init=False)
  1571. base: KeyEntry
  1572. update: KeyEntry
  1573. augment: KeyEntry
  1574. override: KeyEntry
  1575. replace: KeyEntry
  1576. types: TestType
  1577. implementations: Implementation
  1578. group_keysyms: ClassVar[tuple[tuple[str, str], ...]] = (
  1579. ("Ukrainian_i", "Ukrainian_I", "Ukrainian_yi", "Ukrainian_YI"),
  1580. ("ch", "Ch", "c_h", "C_h"),
  1581. )
  1582. def __init__(
  1583. self,
  1584. id: TestId | None,
  1585. base: KeyEntry,
  1586. update: KeyEntry,
  1587. augment: KeyEntry,
  1588. override: KeyEntry,
  1589. types: TestType = TestType.All,
  1590. replace: KeyEntry | None = None,
  1591. implementations: Implementation = Implementation.all,
  1592. ):
  1593. self.id = TestId(0, 0) if id is None else id
  1594. self.key = id.key
  1595. self.base = base
  1596. self.update = update
  1597. self.augment = augment
  1598. self.override = override
  1599. self.types = types
  1600. self.replace = self.update if replace is None else replace
  1601. self.implementations = implementations
  1602. @property
  1603. def default(self) -> KeyEntry:
  1604. return self.override
  1605. def add_keysyms(self, keep_actions: bool) -> Self:
  1606. types = TestType.KeysymsAndActions if keep_actions else TestType.KeysymsOnly
  1607. return dataclasses.replace(
  1608. self,
  1609. id=self.id.with_type(types),
  1610. base=self.base.add_keysyms(keep_actions=keep_actions),
  1611. update=self.update.add_keysyms(keep_actions=keep_actions),
  1612. augment=self.augment.add_keysyms(keep_actions=keep_actions),
  1613. override=self.override.add_keysyms(keep_actions=keep_actions),
  1614. replace=self.replace.add_keysyms(keep_actions=keep_actions),
  1615. types=types,
  1616. )
  1617. @classmethod
  1618. def alt_keysym(cls, group: int, level: int) -> Keysym:
  1619. return Keysym(cls.group_keysyms[group % 2][level % 4])
  1620. @classmethod
  1621. def alt_keysyms(cls, group: int) -> Iterator[Keysym]:
  1622. for keysym in cls.group_keysyms[group % 2]:
  1623. yield Keysym(keysym)
  1624. @dataclass
  1625. class SymbolsTestGroup:
  1626. name: str
  1627. tests: tuple[TestEntry | Comment, ...]
  1628. def _with_implementation(
  1629. self, implementation: Implementation
  1630. ) -> Iterable[TestEntry | Comment]:
  1631. pending_comment: Comment | None = None
  1632. for t in self.tests:
  1633. if not isinstance(t, TestEntry):
  1634. pending_comment = t
  1635. elif t.implementations & implementation:
  1636. if pending_comment is not None:
  1637. yield pending_comment
  1638. pending_comment = None
  1639. yield t
  1640. def with_implementation(self, implementation: Implementation) -> Self:
  1641. return dataclasses.replace(
  1642. self, tests=tuple(self._with_implementation(implementation))
  1643. )
  1644. @staticmethod
  1645. def _add_keysyms(entry: TestEntry | Comment) -> Iterable[TestEntry | Comment]:
  1646. if isinstance(entry, TestEntry) and entry.id.type is TestType.ActionsOnly:
  1647. if entry.types & TestType.KeysymsOnly:
  1648. yield entry.add_keysyms(keep_actions=False)
  1649. yield entry
  1650. if entry.types & TestType.KeysymsAndActions:
  1651. yield entry.add_keysyms(keep_actions=True)
  1652. else:
  1653. yield entry
  1654. def add_keysyms(self, name: str = "") -> Self:
  1655. return dataclasses.replace(
  1656. self,
  1657. name=name or self.name,
  1658. tests=tuple(t for ts in self.tests for t in self._add_keysyms(ts)),
  1659. )
  1660. def __add__(self, other: Any) -> Self:
  1661. if isinstance(other, tuple):
  1662. return dataclasses.replace(self, tests=self.tests + other)
  1663. elif isinstance(other, self.__class__):
  1664. return dataclasses.replace(self, tests=self.tests + other.tests)
  1665. else:
  1666. return NotImplemented
  1667. def get_keycodes(self, base: ComponentTestTemplate) -> ComponentTestTemplate:
  1668. ids: set[TestId] = set(t.id for t in self.tests if isinstance(t, TestEntry))
  1669. base_template = Template(
  1670. "\n".join(f"${{mode}}<{id.xkb_key}> = {id.id + 8};" for id in ids) + "\n"
  1671. )
  1672. keycodes = base_template.substitute(mode="")
  1673. return dataclasses.replace(
  1674. base,
  1675. base_template=base_template + base.base_template,
  1676. update_template=base.update_template,
  1677. augment=keycodes + base.augment,
  1678. override=keycodes + base.override,
  1679. replace=keycodes + base.replace,
  1680. )
  1681. def _get_symbols(self, type: str, debug: bool) -> Generator[str]:
  1682. for entry in self.tests:
  1683. if isinstance(entry, str):
  1684. if type == "update":
  1685. yield f"\n////// {entry} //////"
  1686. else:
  1687. data: KeyEntry = getattr(entry, type)
  1688. if debug:
  1689. yield f"// base: {''.join(entry.base.xkb) or '(empty)'}"
  1690. yield "// key to merge / replace result"
  1691. yield f"${{mode}}key {entry.key.xkb} {{ {''.join(data.xkb)} }};"
  1692. if debug:
  1693. yield f"// override: {''.join(entry.override.xkb) or '(empty)'}"
  1694. yield f"// augment: {''.join(entry.augment.xkb) or '(empty)'}"
  1695. def get_symbols(self, debug: bool = False) -> ComponentTestTemplate:
  1696. base_template = ComponentTemplate("\n".join(self._get_symbols("base", False)))
  1697. update_template = ComponentTemplate(
  1698. "\n".join(self._get_symbols("update", debug))
  1699. )
  1700. augment = ComponentTemplate(
  1701. "\n".join(self._get_symbols("augment", False))
  1702. ).substitute(mode="")
  1703. override = ComponentTemplate(
  1704. "\n".join(self._get_symbols("override", False))
  1705. ).substitute(mode="")
  1706. replace = ComponentTemplate(
  1707. "\n".join(self._get_symbols("replace", False))
  1708. ).substitute(mode="")
  1709. return ComponentTestTemplate(
  1710. title=self.name,
  1711. component=Component.symbols,
  1712. base_template=base_template,
  1713. update_template=update_template,
  1714. augment=augment,
  1715. override=override,
  1716. replace=replace,
  1717. )
  1718. SYMBOLS_TESTS_BOTH = SymbolsTestGroup(
  1719. "",
  1720. (
  1721. Comment("Trivial cases"),
  1722. TestEntry(
  1723. TestId(TestType.ActionsOnly),
  1724. KeyEntry(),
  1725. update=KeyEntry(),
  1726. augment=KeyEntry(),
  1727. override=KeyEntry(),
  1728. ),
  1729. TestEntry(
  1730. TestId(TestType.ActionsOnly),
  1731. KeyEntry(),
  1732. update=KeyEntry(Level.Actions(3)),
  1733. augment=KeyEntry(Level.Actions(3)),
  1734. override=KeyEntry(Level.Actions(3)),
  1735. ),
  1736. TestEntry(
  1737. TestId(TestType.ActionsOnly),
  1738. KeyEntry(Level.Actions(2)),
  1739. update=KeyEntry(),
  1740. augment=KeyEntry(Level.Actions(2)),
  1741. override=KeyEntry(Level.Actions(2)),
  1742. ),
  1743. Comment("Same key"),
  1744. TestEntry(
  1745. TestId(TestType.ActionsOnly),
  1746. KeyEntry(Level.Actions(2)),
  1747. update=KeyEntry(Level.Actions(2)),
  1748. augment=KeyEntry(Level.Actions(2)),
  1749. override=KeyEntry(Level.Actions(2)),
  1750. ),
  1751. TestEntry(
  1752. TestId(TestType.ActionsOnly),
  1753. KeyEntry(Level.Actions(2), Level.Actions(2, Modifier.Control)),
  1754. update=KeyEntry(Level.Actions(2), Level.Actions(2, Modifier.Control)),
  1755. augment=KeyEntry(Level.Actions(2), Level.Actions(2, Modifier.Control)),
  1756. override=KeyEntry(Level.Actions(2), Level.Actions(2, Modifier.Control)),
  1757. implementations=Implementation.xkbcommon,
  1758. ),
  1759. Comment("Mismatch levels count"),
  1760. (
  1761. TEST_BOTH_Q := TestEntry(
  1762. TestId(TestType.ActionsOnly),
  1763. KeyEntry(Level.Actions(None), Level.Actions(2)),
  1764. update=KeyEntry(
  1765. Level.Actions(3), Level.Actions(None), Level.Actions(None)
  1766. ),
  1767. augment=KeyEntry(
  1768. Level.Actions(3), Level.Actions(2), Level.Actions(None)
  1769. ),
  1770. override=KeyEntry(
  1771. Level.Actions(3), Level.Actions(2), Level.Actions(None)
  1772. ),
  1773. # X11 and xkbcommon handle keysyms-only case differently
  1774. types=TestType.ActionsOnly | TestType.KeysymsAndActions,
  1775. )
  1776. ),
  1777. # Trailing NoSymbols are discarded in xkbcomp
  1778. dataclasses.replace(
  1779. TEST_BOTH_Q,
  1780. augment=KeyEntry(Level.Actions(3), Level.Actions(2)),
  1781. override=KeyEntry(Level.Actions(3), Level.Actions(2)),
  1782. replace=KeyEntry(Level.Actions(3)),
  1783. implementations=Implementation.x11,
  1784. ).add_keysyms(keep_actions=False),
  1785. dataclasses.replace(
  1786. TEST_BOTH_Q, implementations=Implementation.xkbcommon
  1787. ).add_keysyms(keep_actions=False),
  1788. TestEntry(
  1789. TestId(TestType.ActionsOnly),
  1790. KeyEntry(Level.Actions(None), Level.Actions(2)),
  1791. update=KeyEntry(Level.Actions(3), Level.Actions(None), Level.Actions(None)),
  1792. augment=KeyEntry(Level.Actions(3), Level.Actions(2), Level.Actions(None)),
  1793. override=KeyEntry(Level.Actions(3), Level.Actions(2), Level.Actions(None)),
  1794. # X11 and xkbcommon handle keysyms-only case differently
  1795. types=TestType.ActionsOnly | TestType.KeysymsAndActions,
  1796. ),
  1797. (
  1798. TEST_BOTH_W := TestEntry(
  1799. TestId(TestType.ActionsOnly),
  1800. KeyEntry(Level.Actions(None), Level.Actions(2), Level.Actions(None)),
  1801. update=KeyEntry(Level.Actions(3), Level.Actions(None)),
  1802. augment=KeyEntry(
  1803. Level.Actions(3), Level.Actions(2), Level.Actions(None)
  1804. ),
  1805. override=KeyEntry(
  1806. Level.Actions(3), Level.Actions(2), Level.Actions(None)
  1807. ),
  1808. # X11 and xkbcommon handle keysyms-only case differently
  1809. types=TestType.ActionsOnly | TestType.KeysymsAndActions,
  1810. )
  1811. ),
  1812. dataclasses.replace(
  1813. TEST_BOTH_W,
  1814. augment=KeyEntry(Level.Actions(3), Level.Actions(2)),
  1815. override=KeyEntry(Level.Actions(3), Level.Actions(2)),
  1816. replace=KeyEntry(Level.Actions(3)),
  1817. implementations=Implementation.x11,
  1818. ).add_keysyms(keep_actions=False),
  1819. dataclasses.replace(
  1820. TEST_BOTH_W, implementations=Implementation.xkbcommon
  1821. ).add_keysyms(keep_actions=False),
  1822. TestEntry(
  1823. TestId(TestType.ActionsOnly),
  1824. KeyEntry(Level.Actions(2), Level.Actions(2)),
  1825. update=KeyEntry(Level.Actions(3), Level.Actions(3), Level.Actions(3)),
  1826. augment=KeyEntry(Level.Actions(2), Level.Actions(2), Level.Actions(3)),
  1827. override=KeyEntry(Level.Actions(3), Level.Actions(3), Level.Actions(3)),
  1828. ),
  1829. TestEntry(
  1830. TestId(TestType.ActionsOnly),
  1831. KeyEntry(Level.Actions(2), Level.Actions(2), Level.Actions(2)),
  1832. update=KeyEntry(Level.Actions(3), Level.Actions(3)),
  1833. augment=KeyEntry(Level.Actions(2), Level.Actions(2), Level.Actions(2)),
  1834. override=KeyEntry(Level.Actions(3), Level.Actions(3), Level.Actions(2)),
  1835. ),
  1836. Comment("Single keysyms -> single keysyms"),
  1837. TestEntry(
  1838. TestId(TestType.ActionsOnly),
  1839. KeyEntry(Level.Actions(None), Level.Actions(None)),
  1840. update=KeyEntry(Level.Actions(None), Level.Actions(None)),
  1841. augment=KeyEntry(Level.Actions(None), Level.Actions(None)),
  1842. override=KeyEntry(Level.Actions(None), Level.Actions(None)),
  1843. ),
  1844. (
  1845. TEST_BOTH_Y := TestEntry(
  1846. TestId(TestType.ActionsOnly),
  1847. KeyEntry(Level.Actions(None), Level.Actions(None)),
  1848. update=KeyEntry(Level.Actions(3), Level.Actions(None)),
  1849. augment=KeyEntry(Level.Actions(3), Level.Actions(None)),
  1850. override=KeyEntry(Level.Actions(3), Level.Actions(None)),
  1851. # X11 and xkbcommon handle keysyms-only case differently
  1852. types=TestType.ActionsOnly | TestType.KeysymsAndActions,
  1853. )
  1854. ),
  1855. dataclasses.replace(
  1856. TEST_BOTH_Y,
  1857. augment=KeyEntry(Level.Actions(3)),
  1858. override=KeyEntry(Level.Actions(3)),
  1859. replace=KeyEntry(Level.Actions(3)),
  1860. implementations=Implementation.x11,
  1861. ).add_keysyms(keep_actions=False),
  1862. dataclasses.replace(
  1863. TEST_BOTH_Y, implementations=Implementation.xkbcommon
  1864. ).add_keysyms(keep_actions=False),
  1865. TestEntry(
  1866. TestId(TestType.ActionsOnly),
  1867. KeyEntry(Level.Actions(None), Level.Actions(None)),
  1868. update=KeyEntry(Level.Actions(None), Level.Actions(3)),
  1869. augment=KeyEntry(Level.Actions(None), Level.Actions(3)),
  1870. override=KeyEntry(Level.Actions(None), Level.Actions(3)),
  1871. ),
  1872. TestEntry(
  1873. TestId(TestType.ActionsOnly),
  1874. KeyEntry(Level.Actions(None), Level.Actions(None)),
  1875. update=KeyEntry(Level.Actions(3), Level.Actions(3)),
  1876. augment=KeyEntry(Level.Actions(3), Level.Actions(3)),
  1877. override=KeyEntry(Level.Actions(3), Level.Actions(3)),
  1878. ),
  1879. TestEntry(
  1880. TestId(TestType.ActionsOnly),
  1881. KeyEntry(Level.Actions(2), Level.Actions(2)),
  1882. update=KeyEntry(Level.Actions(None), Level.Actions(None)),
  1883. augment=KeyEntry(Level.Actions(2), Level.Actions(2)),
  1884. override=KeyEntry(Level.Actions(2), Level.Actions(2)),
  1885. ),
  1886. (
  1887. TEST_BOTH_P := TestEntry(
  1888. TestId(TestType.ActionsOnly),
  1889. KeyEntry(Level.Actions(2), Level.Actions(2)),
  1890. update=KeyEntry(Level.Actions(3), Level.Actions(None)),
  1891. augment=KeyEntry(Level.Actions(2), Level.Actions(2)),
  1892. override=KeyEntry(Level.Actions(3), Level.Actions(2)),
  1893. # X11 and xkbcommon handle keysyms-only case differently
  1894. types=TestType.ActionsOnly | TestType.KeysymsAndActions,
  1895. )
  1896. ),
  1897. dataclasses.replace(
  1898. TEST_BOTH_P,
  1899. augment=KeyEntry(Level.Actions(2), Level.Actions(2)),
  1900. override=KeyEntry(Level.Actions(3), Level.Actions(2)),
  1901. replace=KeyEntry(Level.Actions(3)),
  1902. implementations=Implementation.x11,
  1903. ).add_keysyms(keep_actions=False),
  1904. dataclasses.replace(
  1905. TEST_BOTH_P, implementations=Implementation.xkbcommon
  1906. ).add_keysyms(keep_actions=False),
  1907. TestEntry(
  1908. TestId(TestType.ActionsOnly),
  1909. KeyEntry(Level.Actions(2), Level.Actions(2)),
  1910. update=KeyEntry(Level.Actions(None), Level.Actions(3)),
  1911. augment=KeyEntry(Level.Actions(2), Level.Actions(2)),
  1912. override=KeyEntry(Level.Actions(2), Level.Actions(3)),
  1913. ),
  1914. TestEntry(
  1915. TestId(TestType.ActionsOnly),
  1916. KeyEntry(Level.Actions(2), Level.Actions(2)),
  1917. update=KeyEntry(Level.Actions(3), Level.Actions(3)),
  1918. augment=KeyEntry(Level.Actions(2), Level.Actions(2)),
  1919. override=KeyEntry(Level.Actions(3), Level.Actions(3)),
  1920. ),
  1921. TestEntry(
  1922. TestId(TestType.KeysymsAndActions),
  1923. KeyEntry(Level.Keysyms("a"), Level.Actions(2)),
  1924. update=KeyEntry(Level.Actions(3), Level.Keysyms("X")),
  1925. augment=KeyEntry(Level.Mix(("a"), (3,)), Level.Mix(("X",), (2,))),
  1926. override=KeyEntry(Level.Mix(("a"), (3,)), Level.Mix(("X",), (2,))),
  1927. ),
  1928. Comment("Single keysyms -> multiple keysyms"),
  1929. TestEntry(
  1930. TestId(TestType.ActionsOnly),
  1931. KeyEntry(Level.Actions(None), Level.Actions(None)),
  1932. update=KeyEntry(Level.Actions(3, None), Level.Actions(None)),
  1933. augment=KeyEntry(Level.Actions(3, None), Level.Actions(None)),
  1934. override=KeyEntry(Level.Actions(3, None), Level.Actions(None)),
  1935. implementations=Implementation.xkbcommon,
  1936. ),
  1937. TestEntry(
  1938. TestId(TestType.ActionsOnly),
  1939. KeyEntry(Level.Actions(None), Level.Actions(None)),
  1940. update=KeyEntry(Level.Actions(3, None), Level.Actions(None, None)),
  1941. augment=KeyEntry(Level.Actions(3, None), Level.Actions(None)),
  1942. override=KeyEntry(Level.Actions(3, None), Level.Actions(None)),
  1943. implementations=Implementation.xkbcommon,
  1944. ),
  1945. TestEntry(
  1946. TestId(TestType.ActionsOnly),
  1947. KeyEntry(Level.Actions(None), Level.Actions(None)),
  1948. update=KeyEntry(Level.Actions(None), Level.Actions(3, None)),
  1949. augment=KeyEntry(Level.Actions(None), Level.Actions(3, None)),
  1950. override=KeyEntry(Level.Actions(None), Level.Actions(3, None)),
  1951. implementations=Implementation.xkbcommon,
  1952. ),
  1953. TestEntry(
  1954. TestId(TestType.ActionsOnly),
  1955. KeyEntry(Level.Actions(None), Level.Actions(None)),
  1956. update=KeyEntry(Level.Actions(None, None), Level.Actions(3, None)),
  1957. augment=KeyEntry(Level.Actions(None), Level.Actions(3, None)),
  1958. override=KeyEntry(Level.Actions(None), Level.Actions(3, None)),
  1959. implementations=Implementation.xkbcommon,
  1960. ),
  1961. TestEntry(
  1962. TestId(TestType.ActionsOnly),
  1963. KeyEntry(Level.Actions(None), Level.Actions(None)),
  1964. update=KeyEntry(Level.Actions(3, None), Level.Actions(3, None)),
  1965. augment=KeyEntry(Level.Actions(3, None), Level.Actions(3, None)),
  1966. override=KeyEntry(Level.Actions(3, None), Level.Actions(3, None)),
  1967. implementations=Implementation.xkbcommon,
  1968. ),
  1969. TestEntry(
  1970. TestId(TestType.ActionsOnly),
  1971. KeyEntry(Level.Actions(None), Level.Actions(None)),
  1972. update=KeyEntry(
  1973. Level.Actions(3, Modifier.LevelThree),
  1974. Level.Actions(3, Modifier.LevelThree),
  1975. ),
  1976. augment=KeyEntry(
  1977. Level.Actions(3, Modifier.LevelThree),
  1978. Level.Actions(3, Modifier.LevelThree),
  1979. ),
  1980. override=KeyEntry(
  1981. Level.Actions(3, Modifier.LevelThree),
  1982. Level.Actions(3, Modifier.LevelThree),
  1983. ),
  1984. implementations=Implementation.xkbcommon,
  1985. ),
  1986. TestEntry(
  1987. TestId(TestType.ActionsOnly),
  1988. KeyEntry(Level.Actions(2), Level.Actions(2)),
  1989. update=KeyEntry(Level.Actions(3, None), Level.Actions(None)),
  1990. augment=KeyEntry(Level.Actions(2), Level.Actions(2)),
  1991. override=KeyEntry(Level.Actions(3, None), Level.Actions(2)),
  1992. implementations=Implementation.xkbcommon,
  1993. ),
  1994. TestEntry(
  1995. TestId(TestType.ActionsOnly),
  1996. KeyEntry(Level.Actions(2), Level.Actions(2)),
  1997. update=KeyEntry(Level.Actions(3, None), Level.Actions(None, None)),
  1998. augment=KeyEntry(Level.Actions(2), Level.Actions(2)),
  1999. override=KeyEntry(Level.Actions(3, None), Level.Actions(2)),
  2000. implementations=Implementation.xkbcommon,
  2001. ),
  2002. TestEntry(
  2003. TestId(TestType.ActionsOnly),
  2004. KeyEntry(Level.Actions(2), Level.Actions(2)),
  2005. update=KeyEntry(Level.Actions(None), Level.Actions(3, None)),
  2006. augment=KeyEntry(Level.Actions(2), Level.Actions(2)),
  2007. override=KeyEntry(Level.Actions(2), Level.Actions(3, None)),
  2008. implementations=Implementation.xkbcommon,
  2009. ),
  2010. TestEntry(
  2011. TestId(TestType.ActionsOnly),
  2012. KeyEntry(Level.Actions(2), Level.Actions(2)),
  2013. update=KeyEntry(Level.Actions(None, None), Level.Actions(3, None)),
  2014. augment=KeyEntry(Level.Actions(2), Level.Actions(2)),
  2015. override=KeyEntry(Level.Actions(2), Level.Actions(3, None)),
  2016. implementations=Implementation.xkbcommon,
  2017. ),
  2018. TestEntry(
  2019. TestId(TestType.ActionsOnly),
  2020. KeyEntry(Level.Actions(2), Level.Actions(2)),
  2021. update=KeyEntry(Level.Actions(3, None), Level.Actions(3, None)),
  2022. augment=KeyEntry(Level.Actions(2), Level.Actions(2)),
  2023. override=KeyEntry(Level.Actions(3, None), Level.Actions(3, None)),
  2024. implementations=Implementation.xkbcommon,
  2025. ),
  2026. TestEntry(
  2027. TestId(TestType.ActionsOnly),
  2028. KeyEntry(Level.Actions(2), Level.Actions(2)),
  2029. update=KeyEntry(
  2030. Level.Actions(3, Modifier.LevelThree),
  2031. Level.Actions(3, Modifier.LevelThree),
  2032. ),
  2033. augment=KeyEntry(Level.Actions(2), Level.Actions(2)),
  2034. override=KeyEntry(
  2035. Level.Actions(3, Modifier.LevelThree),
  2036. Level.Actions(3, Modifier.LevelThree),
  2037. ),
  2038. implementations=Implementation.xkbcommon,
  2039. ),
  2040. Comment("Multiple keysyms -> multiple keysyms"),
  2041. TestEntry(
  2042. TestId(TestType.ActionsOnly),
  2043. KeyEntry(Level.Actions(None, None), Level.Actions(None, None)),
  2044. update=KeyEntry(
  2045. Level.Actions(None, None), Level.Actions(3, Modifier.LevelThree)
  2046. ),
  2047. augment=KeyEntry(
  2048. Level.Actions(None, None), Level.Actions(3, Modifier.LevelThree)
  2049. ),
  2050. override=KeyEntry(
  2051. Level.Actions(None, None), Level.Actions(3, Modifier.LevelThree)
  2052. ),
  2053. implementations=Implementation.xkbcommon,
  2054. ),
  2055. TestEntry(
  2056. TestId(TestType.ActionsOnly),
  2057. KeyEntry(Level.Actions(None, None), Level.Actions(None, None)),
  2058. update=KeyEntry(Level.Actions(3, None), Level.Actions(None, 3)),
  2059. augment=KeyEntry(Level.Actions(3, None), Level.Actions(None, 3)),
  2060. override=KeyEntry(Level.Actions(3, None), Level.Actions(None, 3)),
  2061. implementations=Implementation.xkbcommon,
  2062. ),
  2063. TestEntry(
  2064. TestId(TestType.ActionsOnly),
  2065. KeyEntry(Level.Actions(None, None), Level.Actions(2, Modifier.Control)),
  2066. update=KeyEntry(
  2067. Level.Actions(3, Modifier.LevelThree),
  2068. Level.Actions(3, Modifier.LevelThree),
  2069. ),
  2070. augment=KeyEntry(
  2071. Level.Actions(3, Modifier.LevelThree),
  2072. Level.Actions(2, Modifier.Control),
  2073. ),
  2074. override=KeyEntry(
  2075. Level.Actions(3, Modifier.LevelThree),
  2076. Level.Actions(3, Modifier.LevelThree),
  2077. ),
  2078. implementations=Implementation.xkbcommon,
  2079. ),
  2080. TestEntry(
  2081. TestId(TestType.ActionsOnly),
  2082. KeyEntry(Level.Actions(2, None), Level.Actions(None, 2)),
  2083. update=KeyEntry(Level.Actions(3, None), Level.Actions(None, 3)),
  2084. augment=KeyEntry(Level.Actions(2, None), Level.Actions(None, 2)),
  2085. override=KeyEntry(Level.Actions(3, None), Level.Actions(None, 3)),
  2086. implementations=Implementation.xkbcommon,
  2087. ),
  2088. TestEntry(
  2089. TestId(TestType.ActionsOnly),
  2090. KeyEntry(Level.Actions(2, None), Level.Actions(None, 2)),
  2091. update=KeyEntry(
  2092. Level.Actions(3, Modifier.LevelThree),
  2093. Level.Actions(Modifier.LevelThree, 3),
  2094. ),
  2095. augment=KeyEntry(
  2096. Level.Actions(2, None),
  2097. Level.Actions(None, 2),
  2098. ),
  2099. override=KeyEntry(
  2100. Level.Actions(3, Modifier.LevelThree),
  2101. Level.Actions(Modifier.LevelThree, 3),
  2102. ),
  2103. implementations=Implementation.xkbcommon,
  2104. ),
  2105. TestEntry(
  2106. TestId(TestType.ActionsOnly),
  2107. KeyEntry(
  2108. Level.Actions(2, Modifier.Control), Level.Actions(2, Modifier.Control)
  2109. ),
  2110. update=KeyEntry(
  2111. Level.Actions(None, None), Level.Actions(3, Modifier.LevelThree)
  2112. ),
  2113. augment=KeyEntry(
  2114. Level.Actions(2, Modifier.Control), Level.Actions(2, Modifier.Control)
  2115. ),
  2116. override=KeyEntry(
  2117. Level.Actions(2, Modifier.Control),
  2118. Level.Actions(3, Modifier.LevelThree),
  2119. ),
  2120. implementations=Implementation.xkbcommon,
  2121. ),
  2122. TestEntry(
  2123. TestId(TestType.ActionsOnly),
  2124. KeyEntry(
  2125. Level.Actions(2, Modifier.Control), Level.Actions(Modifier.Control, 2)
  2126. ),
  2127. update=KeyEntry(Level.Actions(3, None), Level.Actions(None, 3)),
  2128. augment=KeyEntry(
  2129. Level.Actions(2, Modifier.Control), Level.Actions(Modifier.Control, 2)
  2130. ),
  2131. override=KeyEntry(Level.Actions(3, None), Level.Actions(None, 3)),
  2132. implementations=Implementation.xkbcommon,
  2133. ),
  2134. TestEntry(
  2135. TestId(TestType.ActionsOnly),
  2136. KeyEntry(Level.Actions(None, None), Level.Actions(None, None, None)),
  2137. update=KeyEntry(Level.Actions(None, None, None), Level.Actions(None, None)),
  2138. augment=KeyEntry(
  2139. Level.Actions(None, None), Level.Actions(None, None, None)
  2140. ),
  2141. override=KeyEntry(
  2142. Level.Actions(None, None), Level.Actions(None, None, None)
  2143. ),
  2144. implementations=Implementation.xkbcommon,
  2145. ),
  2146. TestEntry(
  2147. TestId(TestType.ActionsOnly),
  2148. KeyEntry(Level.Actions(None, None), Level.Actions(None, None, None)),
  2149. update=KeyEntry(
  2150. Level.Actions(3, None, Modifier.LevelThree),
  2151. Level.Actions(Modifier.LevelThree, 3),
  2152. ),
  2153. augment=KeyEntry(
  2154. Level.Actions(3, None, Modifier.LevelThree),
  2155. Level.Actions(Modifier.LevelThree, 3),
  2156. ),
  2157. override=KeyEntry(
  2158. Level.Actions(3, None, Modifier.LevelThree),
  2159. Level.Actions(Modifier.LevelThree, 3),
  2160. ),
  2161. implementations=Implementation.xkbcommon,
  2162. ),
  2163. TestEntry(
  2164. TestId(TestType.ActionsOnly),
  2165. KeyEntry(
  2166. Level.Actions(2, Modifier.Control),
  2167. Level.Actions(Modifier.Control, None, 2),
  2168. ),
  2169. update=KeyEntry(Level.Actions(None, None, None), Level.Actions(None, None)),
  2170. augment=KeyEntry(
  2171. Level.Actions(2, Modifier.Control),
  2172. Level.Actions(Modifier.Control, None, 2),
  2173. ),
  2174. override=KeyEntry(
  2175. Level.Actions(2, Modifier.Control),
  2176. Level.Actions(Modifier.Control, None, 2),
  2177. ),
  2178. implementations=Implementation.xkbcommon,
  2179. ),
  2180. TestEntry(
  2181. TestId(TestType.ActionsOnly),
  2182. KeyEntry(
  2183. Level.Actions(2, Modifier.Control),
  2184. Level.Actions(Modifier.Control, None, 2),
  2185. ),
  2186. update=KeyEntry(
  2187. Level.Actions(3, None, Modifier.LevelThree),
  2188. Level.Actions(Modifier.LevelThree, 3),
  2189. ),
  2190. augment=KeyEntry(
  2191. Level.Actions(2, Modifier.Control),
  2192. Level.Actions(Modifier.Control, None, 2),
  2193. ),
  2194. override=KeyEntry(
  2195. Level.Actions(3, None, Modifier.LevelThree),
  2196. Level.Actions(Modifier.LevelThree, 3),
  2197. ),
  2198. implementations=Implementation.xkbcommon,
  2199. ),
  2200. Comment("Multiple keysyms -> single keysyms"),
  2201. TestEntry(
  2202. TestId(TestType.ActionsOnly),
  2203. KeyEntry(Level.Actions(None, None), Level.Actions(2, Modifier.Control)),
  2204. update=KeyEntry(Level.Actions(None), Level.Actions(None)),
  2205. augment=KeyEntry(
  2206. Level.Actions(None, None), Level.Actions(2, Modifier.Control)
  2207. ),
  2208. override=KeyEntry(
  2209. Level.Actions(None, None), Level.Actions(2, Modifier.Control)
  2210. ),
  2211. implementations=Implementation.xkbcommon,
  2212. ),
  2213. TestEntry(
  2214. TestId(TestType.ActionsOnly),
  2215. KeyEntry(Level.Actions(None, None), Level.Actions(2, Modifier.Control)),
  2216. update=KeyEntry(Level.Actions(3), Level.Actions(3)),
  2217. augment=KeyEntry(Level.Actions(3), Level.Actions(2, Modifier.Control)),
  2218. override=KeyEntry(Level.Actions(3), Level.Actions(3)),
  2219. implementations=Implementation.xkbcommon,
  2220. ),
  2221. TestEntry(
  2222. TestId(TestType.ActionsOnly),
  2223. KeyEntry(Level.Actions(2, None), Level.Actions(None, 2)),
  2224. update=KeyEntry(Level.Actions(None), Level.Actions(None)),
  2225. augment=KeyEntry(Level.Actions(2, None), Level.Actions(None, 2)),
  2226. override=KeyEntry(Level.Actions(2, None), Level.Actions(None, 2)),
  2227. implementations=Implementation.xkbcommon,
  2228. ),
  2229. TestEntry(
  2230. TestId(TestType.ActionsOnly),
  2231. KeyEntry(Level.Actions(2, None), Level.Actions(None, 2)),
  2232. update=KeyEntry(Level.Actions(3), Level.Actions(3)),
  2233. augment=KeyEntry(Level.Actions(2, None), Level.Actions(None, 2)),
  2234. override=KeyEntry(Level.Actions(3), Level.Actions(3)),
  2235. implementations=Implementation.xkbcommon,
  2236. ),
  2237. Comment("Mix"),
  2238. TestEntry(
  2239. TestId(TestType.KeysymsAndActions),
  2240. KeyEntry(Level.Actions(2)),
  2241. update=KeyEntry(
  2242. Level.Actions(3, Modifier.LevelThree),
  2243. Level.Actions(3, Modifier.LevelThree),
  2244. ),
  2245. augment=KeyEntry(Level.Actions(2), Level.Actions(3, Modifier.LevelThree)),
  2246. override=KeyEntry(
  2247. Level.Actions(3, Modifier.LevelThree),
  2248. Level.Actions(3, Modifier.LevelThree),
  2249. ),
  2250. implementations=Implementation.xkbcommon,
  2251. ),
  2252. TestEntry(
  2253. TestId(TestType.KeysymsAndActions),
  2254. KeyEntry(Level.Actions(2, Modifier.Control)),
  2255. update=KeyEntry(Level.Actions(3, Modifier.LevelThree), Level.Actions(3)),
  2256. augment=KeyEntry(Level.Actions(2, Modifier.Control), Level.Actions(3)),
  2257. override=KeyEntry(Level.Actions(3, Modifier.LevelThree), Level.Actions(3)),
  2258. implementations=Implementation.xkbcommon,
  2259. ),
  2260. TestEntry(
  2261. TestId(TestType.KeysymsAndActions),
  2262. KeyEntry(Level.Actions(2), Level.Actions(2, Modifier.Control)),
  2263. update=KeyEntry(Level.Actions(3, Modifier.LevelThree), Level.Actions(3)),
  2264. augment=KeyEntry(Level.Actions(2), Level.Actions(2, Modifier.Control)),
  2265. override=KeyEntry(Level.Actions(3, Modifier.LevelThree), Level.Actions(3)),
  2266. implementations=Implementation.xkbcommon,
  2267. ),
  2268. Comment("Mix"),
  2269. TestEntry(
  2270. TestId(TestType.KeysymsAndActions),
  2271. KeyEntry(Level.Keysyms("a"), Level.Actions(2)),
  2272. update=KeyEntry(
  2273. Level.Actions(3, Modifier.LevelThree), Level.Keysyms("X", "Y")
  2274. ),
  2275. augment=KeyEntry(
  2276. Level.Mix(("a",), (3, Modifier.LevelThree)),
  2277. Level.Mix(("X", "Y"), (2,)),
  2278. ),
  2279. override=KeyEntry(
  2280. Level.Mix(("a",), (3, Modifier.LevelThree)),
  2281. Level.Mix(("X", "Y"), (2,)),
  2282. ),
  2283. implementations=Implementation.xkbcommon,
  2284. ),
  2285. Comment("Multiple keysyms/actions –> single"),
  2286. TestEntry(
  2287. TestId(TestType.KeysymsAndActions),
  2288. KeyEntry(Level.Keysyms("a", "b"), Level.Actions(2, Modifier.Control)),
  2289. update=KeyEntry(Level.Actions(3), Level.Keysyms("X")),
  2290. augment=KeyEntry(
  2291. Level.Mix(("a", "b"), (3,)),
  2292. Level.Mix(("X",), (2, Modifier.Control)),
  2293. ),
  2294. override=KeyEntry(
  2295. Level.Mix(("a", "b"), (3,)),
  2296. Level.Mix(("X",), (2, Modifier.Control)),
  2297. ),
  2298. implementations=Implementation.xkbcommon,
  2299. ),
  2300. Comment("Multiple keysyms/actions –> multiple (xor)"),
  2301. TestEntry(
  2302. TestId(TestType.KeysymsAndActions),
  2303. KeyEntry(Level.Keysyms("a", "b"), Level.Actions(2, Modifier.Control)),
  2304. update=KeyEntry(
  2305. Level.Actions(3, Modifier.LevelThree), Level.Keysyms("X", "Y")
  2306. ),
  2307. augment=KeyEntry(
  2308. Level.Mix(("a", "b"), (3, Modifier.LevelThree)),
  2309. Level.Mix(("X", "Y"), (2, Modifier.Control)),
  2310. ),
  2311. override=KeyEntry(
  2312. Level.Mix(("a", "b"), (3, Modifier.LevelThree)),
  2313. Level.Mix(("X", "Y"), (2, Modifier.Control)),
  2314. ),
  2315. implementations=Implementation.xkbcommon,
  2316. ),
  2317. Comment("Multiple keysyms/actions –> multiple (mix)"),
  2318. TestEntry(
  2319. TestId(TestType.KeysymsAndActions),
  2320. KeyEntry(Level.Keysyms("a", None), Level.Actions(2, None)),
  2321. update=KeyEntry(
  2322. Level.Mix(("x", "y"), (3, Modifier.LevelThree)),
  2323. Level.Mix(("X", "Y"), (3, Modifier.LevelThree)),
  2324. ),
  2325. augment=KeyEntry(
  2326. Level.Mix(("a", None), (3, Modifier.LevelThree)),
  2327. Level.Mix(("X", "Y"), (2, None)),
  2328. ),
  2329. override=KeyEntry(
  2330. Level.Mix(("x", "y"), (3, Modifier.LevelThree)),
  2331. Level.Mix(("X", "Y"), (3, Modifier.LevelThree)),
  2332. ),
  2333. implementations=Implementation.xkbcommon,
  2334. ),
  2335. TestEntry(
  2336. TestId(TestType.KeysymsAndActions),
  2337. KeyEntry(Level.Keysyms("a", "b"), Level.Actions(2, Modifier.Control)),
  2338. update=KeyEntry(
  2339. Level.Mix(("x", None), (3, Modifier.LevelThree)),
  2340. Level.Mix(("X", "Y"), (3, None)),
  2341. ),
  2342. augment=KeyEntry(
  2343. Level.Mix(("a", "b"), (3, Modifier.LevelThree)),
  2344. Level.Mix(("X", "Y"), (2, Modifier.Control)),
  2345. ),
  2346. override=KeyEntry(
  2347. Level.Mix(("x", None), (3, Modifier.LevelThree)),
  2348. Level.Mix(("X", "Y"), (3, None)),
  2349. ),
  2350. implementations=Implementation.xkbcommon,
  2351. ),
  2352. Comment("Multiple (mix) –> multiple keysyms/actions"),
  2353. TestEntry(
  2354. TestId(TestType.KeysymsAndActions),
  2355. KeyEntry(
  2356. Level.Mix(("a", "b"), (2, Modifier.Control)),
  2357. Level.Mix(("A", "B"), (2, Modifier.Control)),
  2358. ),
  2359. update=KeyEntry(Level.Keysyms("x", None), Level.Actions(3, None)),
  2360. augment=KeyEntry(
  2361. Level.Mix(("a", "b"), (2, Modifier.Control)),
  2362. Level.Mix(("A", "B"), (2, Modifier.Control)),
  2363. ),
  2364. override=KeyEntry(
  2365. Level.Mix(("x", None), (2, Modifier.Control)),
  2366. Level.Mix(("A", "B"), (3, None)),
  2367. ),
  2368. implementations=Implementation.xkbcommon,
  2369. ),
  2370. TestEntry(
  2371. TestId(TestType.KeysymsAndActions),
  2372. KeyEntry(
  2373. Level.Mix(("a", None), (2, Modifier.Control)),
  2374. Level.Mix(("A", "B"), (2, None)),
  2375. ),
  2376. update=KeyEntry(
  2377. Level.Keysyms("x", "y"), Level.Actions(3, Modifier.LevelThree)
  2378. ),
  2379. augment=KeyEntry(
  2380. Level.Mix(("a", None), (2, Modifier.Control)),
  2381. Level.Mix(("A", "B"), (2, None)),
  2382. ),
  2383. override=KeyEntry(
  2384. Level.Mix(("x", "y"), (2, Modifier.Control)),
  2385. Level.Mix(("A", "B"), (3, Modifier.LevelThree)),
  2386. ),
  2387. implementations=Implementation.xkbcommon,
  2388. ),
  2389. Comment("Multiple (mix) –> multiple (mix)"),
  2390. TestEntry(
  2391. TestId(TestType.KeysymsAndActions),
  2392. KeyEntry(
  2393. Level.Mix(("a", "b"), (2, Modifier.Control)),
  2394. Level.Mix((None, "B"), (2, None)),
  2395. ),
  2396. update=KeyEntry(
  2397. Level.Mix((None, "y"), (3, None)),
  2398. Level.Mix(("X", "Y"), (3, Modifier.LevelThree)),
  2399. ),
  2400. augment=KeyEntry(
  2401. Level.Mix(("a", "b"), (2, Modifier.Control)),
  2402. Level.Mix((None, "B"), (2, None)),
  2403. ),
  2404. override=KeyEntry(
  2405. Level.Mix((None, "y"), (3, None)),
  2406. Level.Mix(("X", "Y"), (3, Modifier.LevelThree)),
  2407. ),
  2408. implementations=Implementation.xkbcommon,
  2409. ),
  2410. TestEntry(
  2411. TestId(TestType.KeysymsAndActions),
  2412. KeyEntry(
  2413. Level.Mix(("a", None), (2, None)),
  2414. Level.Mix((None, "B"), (None, Modifier.Control)),
  2415. ),
  2416. update=KeyEntry(
  2417. Level.Mix((None, "y"), (None, Modifier.LevelThree)),
  2418. Level.Mix(("X", None), (3, None)),
  2419. ),
  2420. augment=KeyEntry(
  2421. Level.Mix(("a", None), (2, None)),
  2422. Level.Mix((None, "B"), (None, Modifier.Control)),
  2423. ),
  2424. override=KeyEntry(
  2425. Level.Mix((None, "y"), (None, Modifier.LevelThree)),
  2426. Level.Mix(("X", None), (3, None)),
  2427. ),
  2428. implementations=Implementation.xkbcommon,
  2429. ),
  2430. Comment("Mismatch count with mix"),
  2431. TestEntry(
  2432. TestId(TestType.KeysymsAndActions),
  2433. KeyEntry(
  2434. Level.Keysyms("a"),
  2435. Level.Keysyms("A", "B"),
  2436. ),
  2437. update=KeyEntry(
  2438. Level.Actions(3, Modifier.LevelThree),
  2439. Level.Actions(3),
  2440. ),
  2441. augment=KeyEntry(
  2442. Level.Mix(("a"), (3, Modifier.LevelThree)),
  2443. Level.Mix(("A", "B"), (3,)),
  2444. ),
  2445. override=KeyEntry(
  2446. Level.Mix(("a"), (3, Modifier.LevelThree)),
  2447. Level.Mix(("A", "B"), (3,)),
  2448. ),
  2449. implementations=Implementation.xkbcommon,
  2450. ),
  2451. TestEntry(
  2452. TestId(TestType.KeysymsAndActions),
  2453. KeyEntry(
  2454. Level.Actions(3),
  2455. Level.Actions(3, Modifier.LevelThree),
  2456. ),
  2457. update=KeyEntry(
  2458. Level.Keysyms("A", "B"),
  2459. Level.Keysyms("a"),
  2460. ),
  2461. augment=KeyEntry(
  2462. Level.Mix(("A", "B"), (3,)),
  2463. Level.Mix(("a"), (3, Modifier.LevelThree)),
  2464. ),
  2465. override=KeyEntry(
  2466. Level.Mix(("A", "B"), (3,)),
  2467. Level.Mix(("a"), (3, Modifier.LevelThree)),
  2468. ),
  2469. implementations=Implementation.xkbcommon,
  2470. ),
  2471. TestEntry(
  2472. TestId(TestType.KeysymsAndActions),
  2473. KeyEntry(
  2474. Level.Mix(("a",), (2,)),
  2475. Level.Mix(("A", "B"), (2, Modifier.Control)),
  2476. ),
  2477. update=KeyEntry(
  2478. Level.Mix(("x", "y"), (3, Modifier.LevelThree)),
  2479. Level.Mix(("X",), (3,)),
  2480. ),
  2481. augment=KeyEntry(
  2482. Level.Mix(("a",), (2,)),
  2483. Level.Mix(("A", "B"), (2, Modifier.Control)),
  2484. ),
  2485. override=KeyEntry(
  2486. Level.Mix(("x", "y"), (3, Modifier.LevelThree)),
  2487. Level.Mix(("X",), (3,)),
  2488. ),
  2489. implementations=Implementation.xkbcommon,
  2490. ),
  2491. Comment("Issue #564"),
  2492. TestEntry(
  2493. TestId(TestType.KeysymsAndActions),
  2494. KeyEntry(Level.Keysyms("A")),
  2495. update=KeyEntry(Level.Mix(("A", "A"), (3, Modifier.LevelThree))),
  2496. augment=KeyEntry(Level.Mix(("A",), (3, Modifier.LevelThree))),
  2497. override=KeyEntry(Level.Mix(("A", "A"), (3, Modifier.LevelThree))),
  2498. implementations=Implementation.xkbcommon,
  2499. ),
  2500. Comment("Drop NoSymbol/NoAction"),
  2501. TestEntry(
  2502. TestId(TestType.KeysymsAndActions),
  2503. KeyEntry(Level.Mix(("A",), (2,))),
  2504. update=KeyEntry(Level.Mix((None, "Y", None), (None, 3, None))),
  2505. augment=KeyEntry(Level.Mix(("A",), (2,))),
  2506. override=KeyEntry(Level.Mix(("Y",), (3,))),
  2507. implementations=Implementation.xkbcommon,
  2508. ),
  2509. Comment("Drop NoSymbol/NoAction and invalid keysyms"),
  2510. TestEntry(
  2511. TestId(TestType.KeysymsAndActions),
  2512. KeyEntry(Level.Mix(("notAKeysym", None, "thisEither"), (None, None))),
  2513. update=KeyEntry(Level.Mix((None, None), (None, None))),
  2514. augment=KeyEntry(Level.Keysyms(None)),
  2515. override=KeyEntry(Level.Keysyms(None)),
  2516. replace=KeyEntry(Level.Keysyms(None)),
  2517. implementations=Implementation.xkbcommon,
  2518. ),
  2519. ),
  2520. ).add_keysyms()
  2521. ################################################################################
  2522. #
  2523. # Keycodes tests
  2524. #
  2525. ################################################################################
  2526. KEYCODES_TESTS_BASE = ComponentTestTemplate(
  2527. "Keycodes",
  2528. component=Component.keycodes,
  2529. base_template=ComponentTemplate(
  2530. """
  2531. ${mode}<1> = 241;
  2532. ${mode}<2> = 242;
  2533. ${mode}alias <A> = <1>;
  2534. ${mode}alias <B> = <2>;
  2535. ${mode}indicator 1 = "Caps Lock";
  2536. ${mode}indicator 2 = "Num Lock";
  2537. ${mode}indicator 3 = "Scroll Lock";
  2538. ${mode}indicator 4 = "Compose";
  2539. ${mode}indicator 5 = "Kana";
  2540. """
  2541. ),
  2542. update_template=ComponentTemplate(
  2543. """
  2544. ${mode}<1> = 241; // Unchanged
  2545. ${mode}<2> = 244; // Changed
  2546. ${mode}<3> = 243; // New
  2547. ${mode}alias <A> = <1>; // Unchanged
  2548. ${mode}alias <B> = <3>; // Changed
  2549. ${mode}alias <C> = <3>; // New
  2550. ${mode}indicator 1 = "Caps Lock"; // Unchanged
  2551. ${mode}indicator 6 = "Num Lock"; // Changed index (free)
  2552. ${mode}indicator 5 = "Scroll Lock"; // Changed index (not free)
  2553. ${mode}indicator 4 = "XXXX"; // Changed name
  2554. ${mode}indicator 7 = "Suspend"; // New
  2555. """
  2556. ),
  2557. augment="""
  2558. <1> = 241;
  2559. <2> = 242;
  2560. <3> = 243;
  2561. alias <A> = <1>;
  2562. alias <B> = <2>;
  2563. alias <C> = <3>;
  2564. indicator 1 = "Caps Lock";
  2565. indicator 2 = "Num Lock";
  2566. indicator 3 = "Scroll Lock";
  2567. indicator 4 = "Compose";
  2568. indicator 5 = "Kana";
  2569. indicator 7 = "Suspend";
  2570. """,
  2571. override="""
  2572. <1> = 241;
  2573. <2> = 244;
  2574. <3> = 243;
  2575. alias <A> = <1>;
  2576. alias <B> = <3>;
  2577. alias <C> = <3>;
  2578. indicator 1 = "Caps Lock";
  2579. indicator 4 = "XXXX";
  2580. indicator 5 = "Scroll Lock";
  2581. indicator 6 = "Num Lock";
  2582. indicator 7 = "Suspend";
  2583. """,
  2584. )
  2585. ################################################################################
  2586. #
  2587. # Main
  2588. #
  2589. ################################################################################
  2590. if __name__ == "__main__":
  2591. # Parse commands
  2592. parser = argparse.ArgumentParser(description="Generate merge mode tests")
  2593. parser.add_argument(
  2594. "compiler",
  2595. type=XkbCompiler.parse,
  2596. nargs="?",
  2597. default="xkbcommon",
  2598. help="XKB compiler to use",
  2599. )
  2600. parser.add_argument(
  2601. "--root",
  2602. type=Path,
  2603. default=ROOT,
  2604. help="Path to the root of the project (default: %(default)s)",
  2605. )
  2606. parser.add_argument(
  2607. "--c-out",
  2608. type=Path,
  2609. # default=ROOT / TestGroup.c_template.stem,
  2610. help="Path to the output C test file (default: %(default)s)",
  2611. )
  2612. parser.add_argument("--no-xkb", action="store_true", help="Do not update XKB data")
  2613. parser.add_argument("--debug", action="store_true", help="Activate debug mode")
  2614. args = parser.parse_args()
  2615. # Prepare data
  2616. template_loader = jinja2.FileSystemLoader(args.root, encoding="utf-8")
  2617. jinja_env = jinja2.Environment(
  2618. loader=template_loader,
  2619. keep_trailing_newline=True,
  2620. trim_blocks=True,
  2621. lstrip_blocks=True,
  2622. )
  2623. def escape_quotes(s: str) -> str:
  2624. return s.replace('"', '\\"')
  2625. jinja_env.filters["escape_quotes"] = escape_quotes
  2626. compiler: XkbCompiler = args.compiler
  2627. SYMBOLS_TESTS = SYMBOLS_TESTS_BOTH.with_implementation(
  2628. Implementation.xkbcommon if compiler.extended_syntax else Implementation.x11
  2629. )
  2630. KEYCODES_TESTS = SYMBOLS_TESTS.get_keycodes(KEYCODES_TESTS_BASE)
  2631. TESTS = (
  2632. KeymapTestTemplate(
  2633. title="",
  2634. keycodes=KEYCODES_TESTS,
  2635. types=TYPES_TESTS,
  2636. compat=COMPAT_TESTS,
  2637. symbols=SYMBOLS_TESTS.get_symbols(debug=args.debug),
  2638. ),
  2639. )
  2640. # Write tests
  2641. TESTS[0].write(
  2642. root=args.root,
  2643. jinja_env=jinja_env,
  2644. c_file=args.c_out,
  2645. xkb=not args.no_xkb,
  2646. compiler=compiler,
  2647. tests=TESTS,
  2648. )