Jelajahi Sumber

feat: Add a generic QMK implementation for Arsenik / Selenium (#46)

* Arsenik QMK

* Renamed QMK folders

* Basic documentation.

* Removed some bloat, better docs.
Léo Cazenave 8 bulan lalu
induk
melakukan
1dc2289abd

+ 87 - 0
qmk/arsenik-qmk.sh

@@ -0,0 +1,87 @@
+!#/bin/sh
+
+set -euo pipefail
+
+if [ "$#" -lt 1 ]; then
+    echo "Usage:"
+    echo "$0 <keyboard_name> [-n] [-b,-f]"
+    echo "    # Install Arsenik for your keyboard, opens your editor to edit the config"
+    echo '    # -n: no editor: doesn’t open the config with your $EDITOR'
+    echo "    # -b: build the newly created keymap (after you edited the config)"
+    echo "    # -f: build the newly created keymap (after you edited the config) then flash"
+    exit 0
+fi
+
+if [ -z "${QMK_PATH+x}" ]; then
+    QMK_PATH="$HOME/qmk_firmware"
+fi
+
+
+function get_keymaps_folder() {
+    keyboard_name="$1"
+    while [ ! -d "$QMK_PATH/keyboards/$keyboard_name/keymaps" ]; do
+        if [ "$keyboard_name" == "." ]; then
+            echo "Couldn’t find keymap folder for your keyboard"
+            exit 1
+        fi
+        keyboard_name=$(dirname "$keyboard_name")
+    done
+
+    echo "$QMK_PATH/keyboards/$keyboard_name/keymaps"
+}
+
+function make_new_arsenik_keymap() {
+    local keyboard_name="$1"
+    local qmk_cmd="$2"
+    local no_editor="$3"
+
+    local keymap_folder=$(get_keymaps_folder "$keyboard_name")
+    local arsenik_folder="$keymap_folder/arsenik"
+    local default_keymap_folder="$keymap_folder/default"
+
+    cp -r "$default_keymap_folder" "$arsenik_folder"
+
+    local layout=""
+    case $(ls "$arsenik_folder"/keymap.* | sed 's/.*\(keymap.*\)/\1/') in
+        "keymap.c")    layout=$(grep 'LAYOUT' "$arsenik_folder"/keymap.c | sed 's/.*= \(.*\)(/\1/' | head -n 1);;
+        "keymap.json") layout=$(grep 'LAYOUT' "$arsenik_folder"/keymap.json | sed 's/ *"layout": "\(.*\)",/\1/');;
+        *) echo "Unable to find layout name, unsupported keymap format";;
+    esac
+
+    if [ "$layout" == "LAYOUT" ]; then
+        layout+="_$(echo "$keyboard_name" | sed 's,/,_,g' | sed 's/_rev[0-9]*$//')"
+    fi
+
+    layout="ARSENIK_$layout"
+
+    rm "$arsenik_folder"/keymap.*
+    cat ./arsenik_config.h >> "$arsenik_folder/config.h"
+    cat ./rules.mk >> "$arsenik_folder/rules.mk"
+    cp ./keymap.c ./arsenik.h ./keymap_ergol.h "$arsenik_folder"
+
+    sed -i "s/ARSENIK_PLACEHOLDER_LAYOUT/$layout/" "$arsenik_folder/config.h"
+
+    if [ $no_editor = false ]; then
+        eval "$EDITOR" "$arsenik_folder/config.h"
+    fi
+
+    case "$qmk_cmd" in
+        "none") ;;
+        "build") cd $QMK_PATH && make "$keyboard_name:arsenik";;
+        "flash") cd $QMK_PATH && make "$keyboard_name:arsenik:flash";;
+    esac
+}
+
+
+no_editor=false
+qmk_cmd="none"
+for arg in "${@:2}"; do
+    case "$arg" in
+        "-n") no_editor=true;;
+        "-b") qmk_cmd="build";;
+        "-f") qmk_cmd="flash";;
+        *) echo "Unknown argument $arg."; exit 1;;
+    esac
+done
+
+make_new_arsenik_keymap "$1" "$qmk_cmd" "$no_editor"

+ 312 - 0
qmk/arsenik.h

@@ -0,0 +1,312 @@
+#pragma once
+
+// ╭─────────────────────────────────────────────────────────╮
+// │         Syntaxic sugar and generic definitions          │
+// ╰─────────────────────────────────────────────────────────╯
+
+// Generic shorthand definitions
+#define AG(keycode) RALT(keycode)
+#define XX KC_NO
+#define __ KC_TRNS
+
+// Lafayette-layer-specific shorthand definitions
+#ifdef ARSENIK_ENABLE_LAFAYETTE_LAYER
+#    define LAFAYETTE MO(_lafayette)
+#    define LAFAYETTE_T(keycode) LT(_lafayette, keycode)
+#else
+#    define LAFAYETTE KC_RALT
+#    define LAFAYETTE_T(keycode) RALT_T(keycode)
+#endif
+
+// TODO: find better names for those macros ?
+#ifdef ARSENIK_MAC_MODIFIERS
+#    define _GUI_T LALT_T
+#    define _CTL_T LGUI_T
+#    define _ALT_T LCTL_T
+#    define _GUI KC_LALT
+#    define _CTL KC_LGUI
+#    define _ALT KC_LCTL
+#else
+#    define _GUI_T LGUI_T
+#    define _CTL_T LCTL_T
+#    define _ALT_T LALT_T
+#    define _GUI KC_LGUI
+#    define _CTL KC_LCTL
+#    define _ALT KC_LALT
+#endif
+
+#ifdef ARSENIK_ENABLE_HRM
+#    define KC_SS _GUI_T(KC_S)
+#    define KC_DD _CTL_T(KC_D)
+#    define KC_FF _ALT_T(KC_F)
+#    define KC_JJ _ALT_T(KC_J)
+#    define KC_KK _CTL_T(KC_K)
+#    define KC_LL _GUI_T(KC_L)
+#else
+#    define KC_SS KC_S
+#    define KC_DD KC_D
+#    define KC_FF KC_F
+#    define KC_JJ KC_J
+#    define KC_KK KC_K
+#    define KC_LL KC_L
+#endif
+
+// Extra simple config for beginners with bigger keyboards
+#if defined ARSENIK_DISABLE_THUMB_TAP_HOLDS
+#    define AS_TL_TUCK  _ALT
+#    define AS_TL_HOME  _CTL
+#    define AS_TL_REACH _GUI
+#    define AS_TR_REACH MO(_num_nav)
+#    define AS_TR_HOME  KC_SPC
+#    define AS_TR_TUCK  LAFAYETTE
+#elif defined ARSENIK_ENABLE_SELENIUM_VARIANT
+#    define AS_TL_REACH XX
+#    define AS_TR_REACH XX
+#    define AS_TL_TUCK  LT(_vim_nav, KC_ESC)
+#    define AS_TR_TUCK  LT(_num_row, KC_ENT)
+#    if defined SELENIUM_LEFT_HAND_SPACE
+#        define AS_TL_HOME  LSFT_T(KC_SPC)
+#        define AS_TR_HOME  LAFAYETTE_T(KC_BSPC)
+#    else
+#        define AS_TL_HOME  LSFT_T(KC_BSPC)
+#        define AS_TR_HOME  LAFAYETTE_T(KC_SPC)
+#    endif
+#else
+#    define AS_TL_TUCK LSFT_T(KC_BSPC)
+#    define AS_TL_HOME LT(_num_nav, KC_BSPC)
+#    define AS_TL_REACH XX
+#    define AS_TR_REACH XX
+#    define AS_TR_HOME AS_TL_HOME
+#    define AS_TR_TUCK LAFAYETTE_T(KC_ENT)
+#endif
+
+// ╭─────────────────────────────────────────────────────────╮
+// │          Keyboard layout specific declarations          │
+// ╰─────────────────────────────────────────────────────────╯
+
+#if defined ARSENIK_HOST_LAYOUT_QWERTY
+#    define AS(stripped_keycode) KC_##stripped_keycode
+#elif defined ARSENIK_HOST_LAYOUT_AZERTY
+#    define AS(stripped_keycode) FR_##stripped_keycode
+#    define SHIFTED_NUMBERS
+#    include "keymap_french.h"
+#    include "sendstring_french.h"
+#elif defined ARSENIK_HOST_LAYOUT_ERGOL
+#    define AS(stripped_keycode) EL_##stripped_keycode
+#    include "keymap_ergol.h"
+#    define ODK1_SEQUENCE tap_code(EL_ODK); tap_code(KC_1)
+#    define ODK2_SEQUENCE tap_code(EL_ODK); tap_code(KC_2)
+#    define ODK3_SEQUENCE tap_code(EL_ODK); tap_code(KC_3)
+#    define ODK4_SEQUENCE tap_code(EL_ODK); tap_code(KC_4)
+#    define ODK5_SEQUENCE tap_code(EL_ODK); tap_code(KC_5)
+#elif defined ARSENIK_HOST_LAYOUT_BEPO
+#    define AS(stripped_keycode) BE_##stripped_keycode
+#    define SHIFTED_NUMBERS
+#    include "keymap_bepo.h"
+#    include "sendstring_bepo.h"
+#elif defined ARSENIK_HOST_LAYOUT_DVORAK
+#    define AS(stripped_keycode) DV_##stripped_keycode
+#    include "keymap_dvorak.h"
+#    include "sendstring_dvorak.h"
+#elif defined ARSENIK_HOST_LAYOUT_COLEMAK
+#    define AS(stripped_keycode) CM_##stripped_keycode
+#    include "keymap_colemak.h"
+#    include "sendstring_colemak.h"
+#elif defined ARSENIK_HOST_LAYOUT_WORKMAN
+#    define AS(stripped_keycode) WK_##stripped_keycode
+#    include "keymap_workman.h"
+#    include "sendstring_workman.h"
+#else
+#    error "No `ARSENIK_HOST_LAYOUT_*` option was found or recognised"
+#endif
+
+#ifndef ODK1_SEQUENCE
+#    define ODK1_SEQUENCE tap_code(KC_NO)
+#endif
+#ifndef ODK2_SEQUENCE
+#    define ODK2_SEQUENCE tap_code(KC_NO)
+#endif
+#ifndef ODK3_SEQUENCE
+#    define ODK3_SEQUENCE tap_code(KC_NO)
+#endif
+#ifndef ODK4_SEQUENCE
+#    define ODK4_SEQUENCE tap_code(KC_NO)
+#endif
+#ifndef ODK5_SEQUENCE
+#    define ODK5_SEQUENCE tap_code(KC_NO)
+#endif
+
+
+#ifdef SHIFTED_NUMBERS
+#    define AS_S0  KC_0
+#    define AS_S1  KC_1
+#    define AS_S2  KC_2
+#    define AS_S3  KC_3
+#    define AS_S4  KC_4
+#    define AS_S5  KC_5
+#    define AS_S6  KC_6
+#    define AS_S7  KC_7
+#    define AS_S8  KC_8
+#    define AS_S9  KC_9
+#else
+#    define AS_S0  S(KC_0)
+#    define AS_S1  S(KC_1)
+#    define AS_S2  S(KC_2)
+#    define AS_S3  S(KC_3)
+#    define AS_S4  S(KC_4)
+#    define AS_S5  S(KC_5)
+#    define AS_S6  S(KC_6)
+#    define AS_S7  S(KC_7)
+#    define AS_S8  S(KC_8)
+#    define AS_S9  S(KC_9)
+#endif
+
+
+// ╭─────────────────────────────────────────────────────────╮
+// │                 QMK layouts definitions                 │
+// ╰─────────────────────────────────────────────────────────╯
+
+//  ──────────────────────────< Generic layouts >──────────────────────────
+
+#if defined ARSENIK_LAYOUT_split_3x5_2
+#define ARSENIK_LAYOUT(\
+        k11, k12, k13, k14, k15, k16,     k17, k18, k19, k1a, k1b, k1c,\
+        k21, k22, k23, k24, k25, k26,     k27, k28, k29, k2a, k2b, k2c,\
+        k31, k32, k33, k34, k35, k36,     k37, k38, k39, k3a, k3b, k3c,\
+        k41, k42, k43, k44, k45, k46,     k47, k48, k49, k4a, k4b, k4c,\
+                       k51, k52, k53,     k54, k55, k56\
+    )\
+    LAYOUT_split_3x5_2(\
+             k22, k23, k24, k25, k26,     k27, k28, k29, k2a, k2b,\
+             k32, k33, k34, k35, k36,     k37, k38, k39, k3a, k3b,\
+             k42, k43, k44, k45, k46,     k47, k48, k49, k4a, k4b,\
+                       k51, k52,               k55, k56\
+    )
+
+#elif defined ARSENIK_LAYOUT_split_3x5_3
+#define ARSENIK_LAYOUT(\
+        k11, k12, k13, k14, k15, k16,     k17, k18, k19, k1a, k1b, k1c,\
+        k21, k22, k23, k24, k25, k26,     k27, k28, k29, k2a, k2b, k2c,\
+        k31, k32, k33, k34, k35, k36,     k37, k38, k39, k3a, k3b, k3c,\
+        k41, k42, k43, k44, k45, k46,     k47, k48, k49, k4a, k4b, k4c,\
+                       k51, k52, k53,     k54, k55, k56\
+    )\
+    LAYOUT_split_3x5_3(\
+             k22, k23, k24, k25, k26,     k27, k28, k29, k2a, k2b,\
+             k32, k33, k34, k35, k36,     k37, k38, k39, k3a, k3b,\
+             k42, k43, k44, k45, k46,     k47, k48, k49, k4a, k4b,\
+                       k51, k52, k53,     k54, k55, k56\
+    )
+
+#elif defined ARSENIK_LAYOUT_split_3x6_3
+#define ARSENIK_LAYOUT(\
+        k11, k12, k13, k14, k15, k16,     k17, k18, k19, k1a, k1b, k1c,\
+        k21, k22, k23, k24, k25, k26,     k27, k28, k29, k2a, k2b, k2c,\
+        k31, k32, k33, k34, k35, k36,     k37, k38, k39, k3a, k3b, k3c,\
+        k41, k42, k43, k44, k45, k46,     k47, k48, k49, k4a, k4b, k4c,\
+                       k51, k52, k53,     k54, k55, k56\
+    )\
+    LAYOUT_split_3x6_3(\
+        k21, k22, k23, k24, k25, k26,     k27, k28, k29, k2a, k2b, k2c,\
+        k31, k32, k33, k34, k35, k36,     k37, k38, k39, k3a, k3b, k3c,\
+        k41, k42, k43, k44, k45, k46,     k47, k48, k49, k4a, k4b, k4c,\
+                       k51, k52, k53,     k54, k55, k56\
+    )
+
+#elif defined ARSENIK_LAYOUT_ortho_4x10
+#define ARSENIK_LAYOUT(\
+        k11, k12, k13, k14, k15, k16,     k17, k18, k19, k1a, k1b, k1c,\
+        k21, k22, k23, k24, k25, k26,     k27, k28, k29, k2a, k2b, k2c,\
+        k31, k32, k33, k34, k35, k36,     k37, k38, k39, k3a, k3b, k3c,\
+        k41, k42, k43, k44, k45, k46,     k47, k48, k49, k4a, k4b, k4c,\
+                       k51, k52, k53,     k54, k55, k56\
+    )\
+    LAYOUT_ortho_4x10(\
+             k22, k23, k24, k25, k26,     k27, k28, k29, k2a, k2b,\
+             k32, k33, k34, k35, k36,     k37, k38, k39, k3a, k3b,\
+             k42, k43, k44, k45, k46,     k47, k48, k49, k4a, k4b,\
+             XX,  XX,  k51, k52, k53,     k54, k55, k56, XX,  XX,\
+    )
+
+#elif defined ARSENIK_LAYOUT_ortho_4x12
+#define ARSENIK_LAYOUT(\
+        k11, k12, k13, k14, k15, k16,     k17, k18, k19, k1a, k1b, k1c,\
+        k21, k22, k23, k24, k25, k26,     k27, k28, k29, k2a, k2b, k2c,\
+        k31, k32, k33, k34, k35, k36,     k37, k38, k39, k3a, k3b, k3c,\
+        k41, k42, k43, k44, k45, k46,     k47, k48, k49, k4a, k4b, k4c,\
+                       k51, k52, k53,     k54, k55, k56\
+    )\
+    LAYOUT_ortho_4x12(\
+        k21, k22, k23, k24, k25, k26,     k27, k28, k29, k2a, k2b, k2c,\
+        k31, k32, k33, k34, k35, k36,     k37, k38, k39, k3a, k3b, k3c,\
+        k41, k42, k43, k44, k45, k46,     k47, k48, k49, k4a, k4b, k4c,\
+        XX,  XX,  XX,  k51, k52, k53,     k54, k55, k56, XX,  XX,  XX,\
+    )
+
+#elif defined ARSENIK_LAYOUT_ortho_5x10
+#define ARSENIK_LAYOUT(\
+        k11, k12, k13, k14, k15, k16,     k17, k18, k19, k1a, k1b, k1c,\
+        k21, k22, k23, k24, k25, k26,     k27, k28, k29, k2a, k2b, k2c,\
+        k31, k32, k33, k34, k35, k36,     k37, k38, k39, k3a, k3b, k3c,\
+        k41, k42, k43, k44, k45, k46,     k47, k48, k49, k4a, k4b, k4c,\
+                       k51, k52, k53,     k54, k55, k56\
+    )\
+    LAYOUT_ortho_4x10(\
+             k12, k13, k14, k15, k16,     k17, k18, k19, k1a, k1b,\
+             k22, k23, k24, k25, k26,     k27, k28, k29, k2a, k2b,\
+             k32, k33, k34, k35, k36,     k37, k38, k39, k3a, k3b,\
+             k42, k43, k44, k45, k46,     k47, k48, k49, k4a, k4b,\
+             XX,  XX,  k51, k52, k53,     k54, k55, k56, XX,  XX,\
+    )
+
+#elif defined ARSENIK_LAYOUT_ortho_5x12
+#define ARSENIK_LAYOUT(\
+        k11, k12, k13, k14, k15, k16,     k17, k18, k19, k1a, k1b, k1c,\
+        k21, k22, k23, k24, k25, k26,     k27, k28, k29, k2a, k2b, k2c,\
+        k31, k32, k33, k34, k35, k36,     k37, k38, k39, k3a, k3b, k3c,\
+        k41, k42, k43, k44, k45, k46,     k47, k48, k49, k4a, k4b, k4c,\
+                       k51, k52, k53,     k54, k55, k56\
+    )\
+    LAYOUT_ortho_5x12(\
+        k11, k12, k13, k14, k15, k16,     k17, k18, k19, k1a, k1b, k1c,\
+        k21, k22, k23, k24, k25, k26,     k27, k28, k29, k2a, k2b, k2c,\
+        k31, k32, k33, k34, k35, k36,     k37, k38, k39, k3a, k3b, k3c,\
+        k41, k42, k43, k44, k45, k46,     k47, k48, k49, k4a, k4b, k4c,\
+        XX,  XX,  XX,  k51, k52, k53,     k54, k55, k56, XX,  XX,  XX,\
+    )
+
+//  ─────────────────< Custom keyboard-specific layouts >──────────────
+
+#elif defined ARSENIK_LAYOUT_planck_grid
+#define ARSENIK_LAYOUT(\
+        k11, k12, k13, k14, k15, k16,      k17, k18, k19, k1a, k1b, k1c,\
+        k21, k22, k23, k24, k25, k26,      k27, k28, k29, k2a, k2b, k2c,\
+        k31, k32, k33, k34, k35, k36,      k37, k38, k39, k3a, k3b, k3c,\
+        k41, k42, k43, k44, k45, k46,      k47, k48, k49, k4a, k4b, k4c,\
+                       k51, k52, k53,      k54, k55, k56\
+    LAYOUT_planck_grid(\
+        k11, k12, k13, k14, k15, k16,     k17, k18, k19, k1a, k1b, k1c,\
+        k21, k22, k23, k24, k25, k26,     k27, k28, k29, k2a, k2b, k2c,\
+        k31, k32, k33, k34, k35, k36,     k37, k38, k39, k3a, k3b, k3c,\
+        k41, k42, k43, k44, k45, k46,     k47, k48, k49, k4a, k4b, k4c,\
+        XX,  XX,  XX,  k53, k51,      k55,     k56, k54, XX,  XX,  XX,\
+    )
+
+#elif defined ARSENIK_LAYOUT_keebio_iris
+#define ARSENIK_LAYOUT(\
+        k11, k12, k13, k14, k15, k16,      k17, k18, k19, k1a, k1b, k1c,\
+        k21, k22, k23, k24, k25, k26,      k27, k28, k29, k2a, k2b, k2c,\
+        k31, k32, k33, k34, k35, k36,      k37, k38, k39, k3a, k3b, k3c,\
+        k41, k42, k43, k44, k45, k46,      k47, k48, k49, k4a, k4b, k4c,\
+                       k51, k52, k53,      k54, k55, k56\
+    ) LAYOUT(\
+        k11, k12, k13, k14, k15, k16,         k17, k18, k19, k1a, k1b, k1c,\
+        k21, k22, k23, k24, k25, k26,         k27, k28, k29, k2a, k2b, k2c,\
+        k31, k32, k33, k34, k35, k36,         k37, k38, k39, k3a, k3b, k3c,\
+        k41, k42, k43, k44, k45, k46, XX, XX, k47, k48, k49, k4a, k4b, k4c,\
+                       k51, k52, k53,         k54, k55, k56\
+    )
+
+#else
+#    error "Arsenik: Unknown layout"
+#endif

+ 132 - 0
qmk/arsenik_config.h

@@ -0,0 +1,132 @@
+//  ───────────────────< Basic QMK options for Arsenik >───────────────────
+
+#undef PERMISSIVE_HOLD
+/* QMK’s `PERMISSIVE_HOLD` can be some extra comfort for experienced users, but
+ * can also be an absolute pain for beginners, especially if you are trying to
+ * learn home-row-mods, which is why we chose to deactivate this option by
+ * default.
+ */
+
+
+#define HOLD_ON_OTHER_KEY_PRESS_PER_KEY
+/* QMK considers tap-hold actions as "tap by default" when another key is
+ * pressed during the "quantum period", but some tap-holds should ideally be
+ * "hold by default" to avoid this delay or accidentally pressing keys like
+ * Enter or Escape.
+ *
+ * This option allows us to have a fine-grain controll over this behaviour.
+ *
+ * Arsenik provides a good default implementation of the required function
+ * `get_hold_on_other_key_press` in the `keymap.c` file.
+ */
+
+
+#define TAPPING_TERM_PER_KEY
+/* Tap-hold actions (especially home-row-mods) may be hard to use as a
+ * beginner, as it is common to hold those keys for too long and accidentally
+ * use the `hold-action`.
+ *
+ * This option allows us to have a fine-grain controll over the `TAPPING_TERM`
+ * for each tap-hold key, allowing for a longer delay on those sensitive keys
+ * without slowing down the safer ones.
+ *
+ * Arsenik provides a good default implementation of the required function
+ * `get_tapping_term` in the `keymap.c` file.
+ */
+
+
+#define ARSENIK_PLACEHOLDER_LAYOUT
+/* NOTE: This line gets automatically filled in by the install script, but the
+ * underlying layout may not yet exist, and keyboard specific layout may have
+ * other variants you might want to check out.
+ */
+
+
+#define ARSENIK_HRM_TAPPING_TERM 300
+/* This is the delay used by Arsenik for sensitive tap-holds, which include
+ * home-row-mods and mod-taps using the spacebar
+ */
+
+
+//  ────────────────────< Main Arsenik configuration >─────────────────
+
+// Below are a bunch of options to quickly customize the Arsenik keymap. You
+// can pick and choose them by (un)commenting the different `#define`
+// declarations.
+
+#define ARSENIK_ENABLE_LAFAYETTE_LAYER
+/* When active, gives access to the programming symbols layer used by layouts
+ * like Ergo‑L and all of the "Lafayette" familly of layouts (it’s their AltGr
+ * layer). The definition of this layer depends on the keyboard layout you are
+ * using, so make sure to select the correct one in the list bellow.
+ *
+ * When inactive, this layer is discarded and replaced by AltGr.
+ */
+
+// #define ARSENIK_ENABLE_HRM
+/* When active, adds a Meta, Ctrl and Alt home-row-mod on respectively s/l,
+ * d/k or f/j on a Qwerty keyboard. Those home-row-mods stay on those exact
+ * keys regardless of the layout being used, meaning they would be on r/i, s/e
+ * and t/n on a Colemak keyboard.
+ */
+
+// #define ARSENIK_MAC_MODIFIERS
+/* Swaps around home-row-mods from Meta, Ctrl, Alt to Alt, Meta, Ctrl, as it
+ * may make more sense on a Mac, like to keep common shortcuts accessible with
+ * the Ergo‑L layout, for instance
+ *
+ * (Requires `ARSENIK_ENABLE_HRM`)
+ */
+
+// #define ARSENIK_DISABLE_THUMB_TAP_HOLDS
+/* When active, uses an extra simple config without any tap-holds on the thumb
+ * keys. It may be a *lot* simpler to use, but requieres a keyboard with at
+ * least 6 thumb keys (so 3 per thumb) instead of 3 thumb keys total and is
+ * overall a lot less efficient (especially when combining modifiers).
+ *
+ * Base thumb config: LSFT_T(KC_ËSC)  LT(_num_nav, KC_SPC)  RALT_T(KC_ENT)
+ * When it’s active: KC_ALT  KC_CTL  KC_GUI     MO(_num_nav)  KC_SPC  KC_RALT
+ * (KC_RALT becomes the `_lafayette` layer if `ARSENIK_ENABLE_LAFAYETTE_LAYER`
+ * is active)
+ *
+ * (Prevents using `ARSENIK_ENABLE_SELENIUM_VARIANT`)
+ */
+
+// #define ARSENIK_ENABLE_SELENIUM_VARIANT
+/* Most ergonomic keyboards have at least 4 comfortable thumb keys keys (so 2
+ * per thumb). Selenium is a variant of Arsenik made to fit on 34 keys keyboard
+ * to take advantage of the extra thumb key. It does it by splitting the numbers
+ * and navigation layers to 2 distict layers, and adds an escape key.
+ *
+ * Base thumb config: LSFT_T(KC_ËSC)  LT(_num_nav, KC_SPC)  RALT_T(KC_ENT)
+ * Selenium: LSFT_T(KC_ESC) LT(_num_row, KC_BSPC) LT(_vim_nav, KC_SPC) RALT_T(KC_ENT)
+ */
+
+// #define SELENIUM_LEFT_HAND_SPACE
+/* Swaps around the backspace and space keycodes, for people who prefer using
+ * their left thunb for the space bar.
+ *
+ * (Requires `ARSENIK_ENABLE_SELENIUM_VARIANT`)
+ */
+
+#define SELENIUM_RESTORE_SPACE
+/* Having Space accessible to only one thumb may create some problems, especially
+ * when trying to type Shift + Space or Lafayette / AltGr + Space (depending if
+ * your space key is on your left or right hand). When active, backspace gets
+ * temporarily replaced by space when the original space key is held.
+ *
+ * (Requires `ARSENIK_ENABLE_SELENIUM_VARIANT`)
+ */
+
+
+// Lists of layouts supported by Arsenik. Some parts of the config are dependent
+// on keyboard layout used on your computer. If they don’t match up some
+// characters may not be correctly placed or missing entirely. If multiple
+// options are toggled at the same time, the first one is chosen.
+#define ARSENIK_HOST_LAYOUT_QWERTY
+// #define ARSENIK_HOST_LAYOUT_AZERTY
+// #define ARSENIK_HOST_LAYOUT_ERGOL
+// #define ARSENIK_HOST_LAYOUT_BEPO
+// #define ARSENIK_HOST_LAYOUT_DVORAK
+// #define ARSENIK_HOST_LAYOUT_COLEMAK
+// #define ARSENIK_HOST_LAYOUT_WORKMAN

+ 145 - 0
qmk/keymap.c

@@ -0,0 +1,145 @@
+#include QMK_KEYBOARD_H
+#include "arsenik.h"
+
+enum arsenik_layers {
+    _base,
+    _lafayette,
+    _num_row,
+    _vim_nav,
+    _num_nav,
+    _num_pad,
+    _fun_pad,
+};
+
+enum custom_keycodes {
+    ODK_1 = SAFE_RANGE,  // „
+    ODK_2,  // “
+    ODK_3,  // ”
+    ODK_4,  // ¢
+    ODK_5,  // ‰
+};
+
+// The ARSENIK_LAYOUT macro allows us to declare a config for a 4x6+3 keyboard, then truncate it
+// (or fill it with noops) depending on the size of your keyboard. Your keyboard may have extra
+// definitions for this macro or none at all (preventing you from compiling the keymap). Check
+// the `README.md` file for more information.
+//
+// A comprehensive list of QMK keycodes is available here: https://docs.qmk.fm/keycodes
+// However, we used a many aliases to automatically adapt the keymap depending on the options you
+// enabled in the `config.h` file (or just to have some syntaxic sugar). You can find all of them
+// in the `arsenik.h` file. Feel free to remove those aliases and replace them with their actual
+// value if you need something Arsenik doesn’t provide.
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+
+    [_base] = ARSENIK_LAYOUT(
+        KC_CAPS, KC_1, KC_2,  KC_3,  KC_4,  KC_5,      KC_6, KC_7,  KC_8,   KC_9,    KC_0,    KC_DEL,
+        KC_TAB,  KC_Q, KC_W,  KC_E,  KC_R,  KC_T,      KC_Y, KC_U,  KC_I,   KC_O,    KC_P,    KC_BSPC,
+        KC_ESC,  KC_A, KC_SS, KC_DD, KC_FF, KC_G,      KC_H, KC_JJ, KC_KK,  KC_LL,   KC_SCLN, KC_ENTER,
+        KC_LSFT, KC_Z, KC_X,  KC_C,  KC_V,  KC_B,      KC_N, KC_M,  KC_DOT, KC_COMM, KC_SLSH, KC_RSFT,
+         AS_TL_TUCK,   AS_TL_HOME,   AS_TL_REACH,      AS_TR_REACH,   AS_TR_HOME,   AS_TR_TUCK
+    ),
+
+    [_lafayette] = ARSENIK_LAYOUT(
+        __, AG(KC_1), AG(KC_2), AG(KC_3), AG(KC_4), AG(KC_5),      AG(KC_6), AG(KC_7), AG(KC_8), AG(KC_9), AG(KC_0), __,
+        __, AS(CIRC), AS(LT),   AS(GT),   AS(DLR),  AS(PERC),      AS(AT),   AS(AMPR), AS(ASTR), AS(QUOT), AS(GRV),  __,
+        __, AS(LCBR), AS(LPRN), AS(LPRN), AS(RCBR), AS(EQL),       AS(BSLS), AS(PLUS), AS(MINS), AS(SLSH), AS(DQUO), __,
+        __, AS(TILD), AS(LBRC), AS(RBRC), AS(UNDS), AS(HASH),      AS(PIPE), AS(EXLM), AS(SCLN), AS(COLN), AS(QUES), __,
+                                MO(_num_row),   KC_SPC,   XX,      XX,   KC_SPC,   MO(_num_row)
+    ),
+
+    // Not fully implemented yet
+    [_num_row] = ARSENIK_LAYOUT(
+        __, __,    __,    __,    __,    __,         __,    __,       __,       __,      __,       __,
+        __, AS_S1, AS_S2, AS_S3, AS_S4, AS_S5,      AS_S6, AS_S7,    AS_S8,    AS_S9,   AS_S0,    __,
+        __, AS(1), AS(2), AS(3), AS(4), AS(5),      AS(6), AS(7),    AS(8),    AS(9),   AS(0),    __,
+        __, ODK_1, ODK_2, ODK_3, ODK_4, ODK_5,      XX,    AS(MINS), AS(COMM), AS(DOT), AS(SLSH), __,
+                    LAFAYETTE,   KC_SPC,   XX,      XX,   KC_SPC,   LAFAYETTE
+    ),
+
+    [_vim_nav] = ARSENIK_LAYOUT(
+        __, G(KC_1),      G(KC_2),  G(KC_3),   G(KC_4),  G(KC_5), G(KC_6),  G(KC_7),  G(KC_8), G(KC_9), G(KC_0),      __,
+        __, MO(_num_nav), C(AS(T)), KC_WBAK,   KC_WFWD,  XX,      KC_HOME,  KC_PGDN,  KC_PGUP, KC_END,  G(AS(P)),     __,
+        __, C(AS(A)),     C(AS(S)), S(KC_TAB), KC_TAB,   XX,      KC_LEFT,  KC_DOWN,  KC_UP,   KC_RGHT, MO(_fun_pad), __,
+        __, C(AS(Z)),     C(AS(X)), C(AS(C)),  C(AS(V)), XX,      KC_WH_L,  KC_WH_D,  KC_WH_U, KC_WH_R, XX,           __,
+                                         KC_DEL,   __,   XX,      XX,   __,   KC_ESC
+    ),
+
+    [_num_nav] = ARSENIK_LAYOUT(
+        __, G(KC_1),  G(KC_2),  G(KC_3),  G(KC_4),  G(KC_5),        G(KC_6),  G(KC_7),  G(KC_8), G(KC_9), G(KC_0),  __,
+        __, KC_TAB,   KC_HOME,  KC_UP,    KC_END,   KC_PGUP,        AS(SLSH), AS(7),    AS(8),   AS(9),   G(AS(P)), __,
+        __, C(AS(A)), KC_LEFT,  KC_DOWN,  KC_RGHT,  KC_PGDN,        AS(MINS), AS(4),    AS(5),   AS(6),   AS(0),    __,
+        __, C(AS(Z)), C(AS(X)), C(AS(C)), C(AS(V)), S(KC_TAB),      AS(COMM), AS(1),    AS(2),   AS(3),   AS(DOT),  __,
+                                           KC_DEL,   __,   XX,      XX,   __,   KC_ESC
+    ),
+
+    [_fun_pad] = ARSENIK_LAYOUT(
+        __, __,    __,     __,     __,     __,      __, __,      __,      __,      __, __,
+        __, KC_F1, KC_F2,  KC_F3,  KC_F4,  XX,      XX, XX,      XX,      XX,      XX, __,
+        __, KC_F5, KC_F6,  KC_F7,  KC_F8,  XX,      XX, KC_LCTL, KC_LALT, KC_LGUI, __, __,
+        __, KC_F9, KC_F10, KC_F11, KC_F12, XX,      XX, XX,      XX,      XX,      XX, __,
+                    LAFAYETTE,   KC_SPC,   XX,      XX,   KC_SPC,   LAFAYETTE
+    ),
+
+};
+
+
+// This is where you’ll write most of your custom code for your keyborad.
+// This callback is called right before the keycode is sent to the OS.
+//
+// returning false cancels any furnther processing.
+// for instance, calling `tap_code(KC_B)` if KC_A is pressed but true is
+// returned, "ba" is sent, but if `false` is returned, it’s just "b"
+bool process_record_user(uint16_t keycode, keyrecord_t* record) {
+#   ifdef SELENIUM_RESTORE_SPACE
+    static bool thumb_mod_same_hand_as_space_held = false;
+    if ((keycode & 0xff) == KC_SPC && record->tap.count == 0)
+        thumb_mod_same_hand_as_space_held = record->event.pressed;
+#   endif
+
+    // Let QMK do its thing on key releases.
+    if (!record->event.pressed) return true;
+
+#   ifdef SELENIUM_RESTORE_SPACE
+    if ((keycode & 0xff) == KC_BSPC &&
+        !thumb_mod_same_hand_as_space_held &&
+        record->tap.count > 0
+    ) {
+        tap_code(KC_SPC);
+        return false;
+    }
+#   endif
+
+    switch (keycode) {
+        // ----------------------------------------
+        // Code for your custom keycodes goes here.
+        // ----------------------------------------
+
+        case ODK_1: ODK1_SEQUENCE; return false;
+        case ODK_2: ODK2_SEQUENCE; return false;
+        case ODK_3: ODK3_SEQUENCE; return false;
+        case ODK_4: ODK4_SEQUENCE; return false;
+        case ODK_5: ODK5_SEQUENCE; return false;
+    }
+
+    return true;
+}
+
+static inline bool tap_keycode_used_in_text(uint16_t keycode) {
+    // We can’t make assumptions on curstom keycodes
+    if (keycode >= SAFE_RANGE) return false;
+
+    // Remove "quantum" part of the keycode to get the action on tap.
+    const uint16_t tap_keycode = keycode & 0xff;
+    // `tap_keycode <= KC_0` includes all letters and numbers, but also
+    // `KC_NO` which is safer to include, since it is commonly used in the
+    // keymap as a placeholder for complex actions on tap.
+    return (tap_keycode <= KC_0) || (tap_keycode == KC_SPACE);
+}
+
+uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) {
+    return tap_keycode_used_in_text(keycode) ? ARSENIK_HRM_TAPPING_TERM : TAPPING_TERM;
+}
+
+bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) {
+    return !tap_keycode_used_in_text(keycode);
+}

+ 128 - 0
qmk/keymap_ergol.h

@@ -0,0 +1,128 @@
+#pragma once
+#include "keycodes.h"
+// clang-format off
+
+// Aliases
+#define EL_GRV  KC_GRV  // `
+#define EL_1    KC_1    // 1
+#define EL_2    KC_2    // 2
+#define EL_3    KC_3    // 3
+#define EL_4    KC_4    // 4
+#define EL_5    KC_5    // 5
+#define EL_6    KC_6    // 6
+#define EL_7    KC_7    // 7
+#define EL_8    KC_8    // 8
+#define EL_9    KC_9    // 9
+#define EL_0    KC_0    // 0
+#define EL_SLSH KC_MINS // /
+#define EL_EQL  KC_EQL  // =
+#define EL_Q    KC_Q    // Q
+#define EL_C    KC_W    // C
+#define EL_O    KC_E    // O
+#define EL_P    KC_R    // P
+#define EL_W    KC_T    // W
+#define EL_J    KC_Y    // J
+#define EL_M    KC_U    // M
+#define EL_D    KC_I    // D
+#define EL_ODK  KC_O    // odk (dead lafayette)
+#define EL_Y    KC_P    // Y
+#define EL_LBRC KC_LBRC // [
+#define EL_RBRC KC_RBRC // ]
+#define EL_A    KC_A    // A
+#define EL_S    KC_S    // S
+#define EL_E    KC_D    // E
+#define EL_N    KC_F    // N
+#define EL_F    KC_G    // F
+#define EL_L    KC_H    // L
+#define EL_R    KC_J    // R
+#define EL_T    KC_K    // R
+#define EL_I    KC_L    // I
+#define EL_U    KC_SCLN // U
+#define EL_QUOT KC_QUOT // '
+#define EL_BSLS KC_NUHS // (backslash)
+#define EL_LABK KC_NUBS // <
+#define EL_Z    KC_Z    // Z
+#define EL_X    KC_X    // X
+#define EL_MINS KC_C    // -
+#define EL_V    KC_V    // V
+#define EL_B    KC_B    // B
+#define EL_DOT  KC_N    // .
+#define EL_H    KC_M    // H
+#define EL_G    KC_COMM // G
+#define EL_COMM KC_DOT  // ,
+#define EL_K    KC_SLSH // K
+
+//SHIFTED
+#define EL_TILD S(EL_GRV)  // ~
+#define EL_EURO S(EL_1)    // €
+#define EL_LDQF S(EL_2)    // «
+#define EL_RDQF S(EL_3)    // »
+#define EL_DLR  S(EL_4)    // $
+#define EL_PERC S(EL_5)    // %
+#define EL_CIRC S(EL_6)    // ^
+#define EL_AMPR S(EL_7)    // &
+#define EL_ASTR S(EL_8)    // *
+#define EL_HASH S(EL_9)    // #
+#define EL_AT   S(EL_0)    // @
+#define EL_UNDS S(EL_SLSH) // _
+#define EL_PLUS S(EL_EQL)  // =
+#define EL_EXLM S(EL_ODK)  // !
+#define EL_LCBR S(EL_LBRC) // {
+#define EL_RCBR S(EL_RBRC) // }
+#define EL_DQUO S(EL_QUOT) // "
+#define EL_PIPE S(EL_BSLS) // |
+#define EL_RABK S(EL_LABK) // >
+#define EL_QUES S(EL_MINS) // ?
+#define EL_COLN S(EL_DOT)  // :
+#define EL_SCLN S(EL_COMM) // ;
+
+//ALTGR  //Symbol layer
+#define EL_SUB1 ALGR(EL_1)    // ₁
+#define EL_SUB2 ALGR(EL_2)    // ₂
+#define EL_SUB3 ALGR(EL_3)    // ₃
+#define EL_SUB4 ALGR(EL_4)    // ₄
+#define EL_SUB5 ALGR(EL_5)    // ₅
+#define EL_SUB6 ALGR(EL_6)    // ₆
+#define EL_SUB7 ALGR(EL_7)    // ₇
+#define EL_SUB8 ALGR(EL_8)    // ₈
+#define EL_SUB9 ALGR(EL_9)    // ₉
+#define EL_SUB0 ALGR(EL_0)    // ₀
+#define EL_LPRN ALGR(EL_S)    // (
+#define EL_RPRN ALGR(EL_E)    // )
+#define EL_LT   ALGR(EL_C)    // <
+#define EL_GT   ALGR(EL_O)    // >
+
+//ALTGR  //Symbol layer //SHIFTED
+#define EL_SUP1 ALGR(S(EL_1))    // ¹
+#define EL_SUP2 ALGR(S(EL_2))    // ²
+#define EL_SUP3 ALGR(S(EL_3))    // ³
+#define EL_SUP4 ALGR(S(EL_4))    // ⁴
+#define EL_SUP5 ALGR(S(EL_5))    // ⁵
+#define EL_SUP6 ALGR(S(EL_6))    // ⁶
+#define EL_SUP7 ALGR(S(EL_7))    // ⁷
+#define EL_SUP8 ALGR(S(EL_8))    // ⁸
+#define EL_SUP9 ALGR(S(EL_9))    // ⁹
+#define EL_SUP0 ALGR(S(EL_0))    // ⁰
+
+#define EL_DCIR ALGR(S(EL_Q))    // ^ (dead)
+#define EL_LEEQ ALGR(S(EL_C))    // <=
+#define EL_GREQ ALGR(S(EL_O))    // >=
+#define EL_CURR ALGR(S(EL_P))    // ¤ (dead)
+#define EL_PERM ALGR(S(EL_W))    // ‰
+#define EL_RNGA ALGR(S(EL_J))    // ° (dead)
+#define EL_MUL  ALGR(S(EL_D))    // ×
+#define EL_ACUT ALGR(S(EL_ODK))  // ´ (dead)
+#define EL_DGRV ALGR(S(EL_Y))    // ` (dead)
+#define EL_CARN ALGR(S(EL_A))    // ˇ (dead)
+// #define EL_RNGA ALGR(S(EL_N))    // ° (dead)
+#define EL_NEQL ALGR(S(EL_F))    // !=
+#define EL_DSLS ALGR(S(EL_L))    // TODO!! / dead
+#define EL_PLMN ALGR(S(EL_R))    // ±
+#define EL_MACR ALGR(S(EL_T))    // ¯ (dead)
+#define EL_DIV  ALGR(S(EL_I))    // ÷
+#define EL_DACU ALGR(S(EL_U))    // ˝ (dead)
+#define EL_DTIL ALGR(S(EL_Z))    // ~ (dead)
+#define EL_CEDL ALGR(S(EL_X))    // ¸ (dead)
+#define EL_OGON ALGR(S(EL_MINS)) // ˛ (dead)
+#define EL_DCLN ALGR(S(EL_G))    // cédille ronde (dead)
+#define EL_BREV ALGR(S(EL_K))    // ˘ (dead)

+ 78 - 0
qmk/readme.md

@@ -0,0 +1,78 @@
+# Arsenik QMK
+
+This is a generic implementation of the Arsenik layout for QMK keyboards.
+
+**Disclaimer** : This is still relatively new. There might be bugs and your
+keyboard might not be compatible *yet*.
+
+## How it works
+
+Arsenik-QMK will define a full qmk keymap in a dummy `ARSENIK_LAYOUT` layout
+definition. At compile time, this dummy gets is replaced by the layout
+definition your keyboard actually uses. This means that the keymap will
+naturally remove unused keys (like the number row on a keyboard with 3 rows)
+or add no-op to the keys unused by Arsenik on bigger keyboards.
+
+Ideally, you install it and it just works, but not every keyboards are
+currently supported. If the `ARSENIK_LAYOUT` isn’t defined for your keyboard,
+it needs to be added at the end of the `arsenik.h` file. PRs are welcome, but
+we will gladly help you if you open an issue ^^
+
+Here is a list of all currently supported QMK layouts :
+
+- `LAYOUT_split_3x5_2`
+- `LAYOUT_split_3x5_3`
+- `LAYOUT_split_3x6_3`
+- `LAYOUT_ortho_4x10`
+- `LAYOUT_ortho_4x12`
+- `LAYOUT_ortho_5x10`
+- `LAYOUT_ortho_5x12`
+- `LAYOUT_planck_grid`
+- `LAYOUT_keebio_iris_default`
+
+## Install
+
+You’ll need to setup your QMK environment beforhand, QMK’s cli tool does the
+job well. You’ll need to know how is your keyboard is called inside of QMK’s
+code, usually they are named `brand/model/revision` though that may vary from a
+keyboard to another. You can always run `qmk list-keyboard | grep <your
+keyboard>` to quickly find it, is case you don’t know.
+
+Once you know how your keyboard is named, installing Arsenik-QMK is as easy as
+cloning this repo locally and running the `./arsenik-qmk.sh <your keyboard>`.
+The script expects to find the QMK repo at `~/qmk_firmware`, so if you already
+have QMK setup somewhere else, you can set the `QMK_PATH` environment variable
+before running the script.
+
+The script will duplicate the default config for your keyboard, replace the
+keymap by Arsenik’s keymap and install As-QMK’s library and default config.
+Once this is done, the script will open the newly created `config.h` file with
+your `$EDITOR` to let you emmidiatly toggle the different config options you
+can choose from (see "Configuration" section).
+
+Optionnal flags can be passed to `arsenik-qmk.sh` to enable or disable certain
+features:
+
+- `-n`: “no editor” (doesn’t open the `config.h` file)
+- `-b`: “build” (immidiatlly build the keymap after installing it)
+- `-f`: “flash” (immidiatlly build the keymap and flash your keyboard with it
+    after installing it)
+
+### example:
+
+Let’s say I have a Keebio Iris Rev2, and I want to install Arsenik-QMK for it
+(with my QMK folder located in `~/Code/qmk`) then flash the keymap. First, I
+find my real keyboard name:
+
+```sh
+qmk list-keyboards | grep 'iris'
+# >> ...
+# >> keebio/iris/rev2
+# >> ...
+```
+
+Then I run the script
+
+```sh
+QMK_PATH="~/Code/qmk" ./arsenik-qmk.sh keebio/iris/rev2 -f
+```

+ 1 - 0
qmk/rules.mk

@@ -0,0 +1 @@
+MOUSEKEY_ENABLE = yes

qmk/README.md → qmk_legacy/README.md


qmk/keyboards/ferris/keymaps/1dk/config.h → qmk_legacy/keyboards/ferris/keymaps/1dk/config.h


qmk/keyboards/ferris/keymaps/1dk/keymap.c → qmk_legacy/keyboards/ferris/keymaps/1dk/keymap.c


qmk/keyboards/ferris/keymaps/1dk/rules.mk → qmk_legacy/keyboards/ferris/keymaps/1dk/rules.mk