refactor(qmk): multi-target (arsenik/selenium) structure with shared code#101
refactor(qmk): multi-target (arsenik/selenium) structure with shared code#101severindupouy wants to merge 16 commits intoOneDeadKey:mainfrom
Conversation
Prepare for multi-target structure by moving all keymap files into a dedicated arsenik/ directory.
Extract reusable code into shared/: - shared/keycodes.h: generic shorthands, host layout declarations, ODK sequences, shifted numbers - shared/layouts.h: ARSENIK_LAYOUT macros for all supported keyboards - shared/keymap_ergol.h: moved from arsenik/ Arsenik-specific logic (LAFAYETTE, HRM, thumb configs) stays in arsenik/customization.h, which includes the shared headers. Rename arsenik_config.h to config.h for consistency.
The _lafayette and _symbols layers serve the same purpose (programming symbols). Use the more generic _symbols name for consistency across arsenik and selenium targets.
Use a neutral ONEDEADKEY_ prefix for the layout macro, since it is shared across multiple keymap targets (arsenik, selenium, etc.).
20b7a9b to
fc01a69
Compare
|
Dans l'idéal, il faudrait tester toutes les différentes possibilités de customisation d'arsenik et de selenium (les différentes flavor, etc) et vérifier qu'on génère bien une keymap valide que QMK arrive à compiler. Je ne suis pas sûr de pouvoir prendre le temps de faire toutes ces vérifications. En terme d'organisation des repos, on pourrait organiser les choses différemment (générer une keymap selenium dans le dépôt qui s'appelle arsenik n'est pas hyper cohérent, mais pour l'instant c'est comme ça). @Nuclear-Squid @fabi1cazenave qu'en pensez-vous ? |
|
Merci pour ta contribution ! Y’a beaucoup de choses à regarder, je vais tâcher de regarder ça dans le weekend. J’aimerai prendre le temps d’avoir une vue holistique de ton travail avant de faire une revue ^^ |
|
N'hésites pas si tu as des questions. |
b9b9bf8 to
7fbd50e
Compare
|
J'ai ajouté :
Si la partie tests / CI te sembe too much, tu me dis. Comme le repo /OneDeadKey/arsenik n'est pas configuré pour run cette CI, j'ai créé une PR jumelle sur mon fork, histoire de vérifier que cette CI passe bien. Tu peux check ici : severindupouy#4 Une fois validé, avant de merger, il faudra drop le dernier commit ci(qmk): temporarily trigger CI on qmk-restructure branch Et si tu veux qu'on envisage de ne pas merger et mettre ça dans un autre repo, on peut faire ça. |
7fbd50e to
5b1c5fa
Compare
|
a32d998 to
9192a33
Compare
Selenium is a keymap converted from the ZMK Selenium project (zmk-keyboard-quacken). It features configurable hold-tap behavior (HT_NONE, HT_THUMB_TAPS, HT_HOME_ROW_MODS, HT_TWO_THUMB_KEYS), VIM_NAVIGATION, HRM_SHIFT, and LEFT_HAND_SPACE options. Uses the shared/ headers for keycodes, layouts, and keymap_ergol.h.
Replace arsenik-qmk.sh with generator.sh supporting multiple keymap targets via the -target flag (arsenik, selenium, etc.). The generator copies shared/ files and target-specific files into a flat output directory, flattening include paths and replacing the layout placeholder automatically. Update and rename readme.md to README.md.
The sendstring_*.h headers redefine ascii_to_keycode_lut and ascii_to_dead_lut lookup tables, which conflict with the same tables in QMK's send_string.c. This causes compilation failures for AZERTY, BEPO, DVORAK, COLEMAK, and WORKMAN host layouts. These includes are only needed when using send_string() with layout-specific characters. Arsenik does not use send_string(), so removing them is safe and fixes all affected host layouts. Related QMK issues: - qmk/qmk_firmware#5139 - qmk/qmk_firmware#16826 - qmk/qmk_firmware#25696
- Rename mouse wheel keycodes KC_WH_* to MS_WHL* (renamed in QMK 0.32) - Fix BEPO keycode prefix from BE_ to BP_ (renamed in QMK 0.32)
Add a test framework that verifies all config option combinations compile successfully for each keymap target. - tests/common.sh: shared functions (generate, patch, compile) - tests/test_per_option.sh: toggle one option at a time - tests/test_exhaustive.sh: reads matrix files for all combinations - tests/matrix_arsenik.txt: 36 arsenik combinations - tests/matrix_selenium.txt: 40 selenium combinations - tests/run_all.sh: runs per-option then exhaustive
- qmk/.env: pin QMK_VERSION=0.32.3 and QMK_KEYBOARD=beekeeb/piantor - qmk/Dockerfile: QMK build environment based on qmkfm/qmk_cli - .github/workflows/qmk-test.yml: CI pipeline - Per-option compile tests on PRs (fast gate) - Exhaustive compile tests on main merges only - Both arsenik and selenium targets run in parallel
Explain how to run compile tests locally, in Docker, and in CI. Document the matrix file format for adding new test combinations.
9192a33 to
95297e8
Compare
Python tool that checks and fixes formatting of ONEDEADKEY_LAYOUT() layer blocks in keymap.c files. Supports compact (per-layer) and wide (cross-layer) column alignment modes.
- .clang-format: C formatting rules for non-layout code - .zed/tasks.json: keymap lint tasks for Zed - .zed/settings.json: C language settings, format_on_save off - .vscode/tasks.json: keymap lint tasks for VS Code
95297e8 to
54c82d5
Compare
Functional changes
Multi-target keymap architecture
Restructure
qmk/to support multiple keymap targets sharing common code:shared/customization.h,config.h,keymap.c, andrules.mkARSENIK_LAYOUT→ONEDEADKEY_LAYOUT(neutral prefix for shared use)_lafayettelayer →_symbolsfor consistency across targetsNew generator
Replace
arsenik-qmk.shwithgenerator.sh.Previous behavior (
arsenik-qmk.sh):keymap/folder into QMKarsenikkeymap only~/qmk_firmware(or$QMK_PATH)$EDITORonconfig.hafter installNew behavior (
generator.sh):-target <name>flag selects which keymap to generate (arsenik,selenium, or any future target)shared/files with the target-specific files into a flat output directory../shared/include paths so the output is self-containedkeymaps/arsenik/orkeymaps/selenium/), allowing both to coexist in QMKqmk config user.keyboard,user.keymap,user.qmk_home) instead of relying on hardcoded paths or environment variables. This means the generator works out of the box for anyone who has already set up QMK, with no extra configuration needed. Values can still be overridden via-kband-kmflags.user.keymap(typicallydefault)Selenium keymap
QMK implementation of Selenium, based on the ZMK reference implementation. Not all features are supported.
Implementation details and design decisions are documented in
selenium/IMPLEMENTATION.md.ZMK → QMK conversion details
QMK and ZMK don't offer the same features. Here's how we handled the differences.
Timing (all 3 ZMK values preserved exactly):
SHORT_TAPPING_TERMTAPPING_TERM = 150(global default)HRM_TAPPING_TERMget_tapping_term()returns 300ms for text-producing keysQUICK_TAPget_quick_tap_term()returns 200ms viaQUICK_TAP_TERM_PER_KEYQMK only has a single global
TAPPING_TERM, so we useTAPPING_TERM_PER_KEYto differentiate between hold-preferred keys (150ms) and tap-preferred keys like HRM and spacebar (300ms). ForQUICK_TAP, QMK'saction_tapping.hunconditionally redefinesQUICK_TAP_TERM = TAPPING_TERMunlessQUICK_TAP_TERM_PER_KEYis defined — we use that workaround to set our own 200ms value.Hold-tap behavior:
A single helper function
tap_keycode_used_in_text()drives both timing and hold behavior, cleanly replicating ZMK's per-behavior split:sc(hold-preferred) →get_hold_on_other_key_press()returnstruefor non-text keyslt(tap-preferred) → QMK default behavior for text-producing keysZMK feature mapping:
EZ_SK(LSHIFT)(sticky key)OSM(MOD_LSFT)EZ_SL(hold=momentary, tap=one-shot)OSL()OSL()provides both behaviors&sl { ignore-modifiers; }&sk { quick-release; }< LAYER LS(SPACE)LT()keycode as NumLock/NumNav space, making layer-specific interception impossiblesym_shift_altgr(shift→AltGr morph)OSL(_symbols)magic_backspace/magic_space(mod-morphs)QMK 0.32.x compatibility
sendstring_*.hincludes that caused compilation failures for non-QWERTY host layouts (#5139, #16826, #25696)KC_WH_*→MS_WHL*(renamed in QMK 0.32)BE_→BP_(renamed in QMK 0.32)Tooling & testing
Compile test framework (
qmk/tests/)Verifies that every valid config option combination compiles successfully:
Documentation:
qmk/tests/README.mdKeymap layout linter (
qmk/tools/)Custom Python formatter to make pretty the blocks in
keymap.cfiles:--compact(per-layer alignment) and--wide(global alignment across all layers)// clang-format off/onmarkers protect layout blocks from generic C formatters. A.clang-formatconfig handles the non-layout C code.Documentation:
qmk/tools/README.mdIDE integration
.zed/tasks.jsonand.vscode/tasks.json: keymap lint tasks (check, fix, fix wide)qmk/.clang-format: formatting rules for non-layout C codeCI/CD
qmk/.env: pinned QMK version (0.32.3) and default keyboardqmk/Dockerfile: reproducible build environment based onqmkfm/qmk_cli.github/workflows/qmk-test.yml:Test plan
./generator.sh -target arsenik -ggenerates a valid keymap./generator.sh -target selenium -ggenerates a valid keymapqmk compile -kb <keyboard> -km arsenikcompiles successfullyqmk compile -kb <keyboard> -km seleniumcompiles successfully