diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000000..3c29522ad4af --- /dev/null +++ b/.clang-format @@ -0,0 +1,4 @@ +BasedOnStyle: LLVM +IndentWidth: 4 +ColumnLimit: 100 +SortIncludes: false diff --git a/.devcontainer/.bashrc b/.devcontainer/.bashrc new file mode 100644 index 000000000000..967fa144bbb0 --- /dev/null +++ b/.devcontainer/.bashrc @@ -0,0 +1,13 @@ +export LS_OPTIONS='-F --color=auto' +alias ls='ls $LS_OPTIONS' +if [ "${CODESPACES}" = "true" ]; then + export WORKSPACE_DIR="$HOME/workspace/zmk" +fi +if [ -f "$WORKSPACE_DIR/zephyr/zephyr-env.sh" ]; then + source "$WORKSPACE_DIR/zephyr/zephyr-env.sh" +fi + +if [ -d "$WORKSPACE_DIR/tools/bsim" ]; then + export BSIM_OUT_PATH="$WORKSPACE_DIR/tools/bsim/" + export BSIM_COMPONENTS_PATH="$WORKSPACE_DIR/tools/bsim/components/" +fi \ No newline at end of file diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000000..5b69e18043d5 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,4 @@ +FROM docker.io/zmkfirmware/zmk-dev-arm:3.2 + +COPY .bashrc tmp +RUN mv /tmp/.bashrc ~/.bashrc diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000000..efa8c229d9a5 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,25 @@ +{ + "name": "ZMK Development", + "dockerFile": "Dockerfile", + "runArgs": ["--security-opt", "label=disable"], + "containerEnv": { + "WORKSPACE_DIR": "${containerWorkspaceFolder}", + "PROMPT_COMMAND": "history -a" + }, + "mounts": [ + "type=volume,source=zmk-root-user,target=/root", + "type=volume,source=zmk-config,target=/workspaces/zmk-config", + "type=volume,source=zmk-zephyr,target=${containerWorkspaceFolder}/zephyr", + "type=volume,source=zmk-zephyr-modules,target=${containerWorkspaceFolder}/modules", + "type=volume,source=zmk-zephyr-tools,target=${containerWorkspaceFolder}/tools" + ], + "customizations": { + "vscode": { + "extensions": ["ms-vscode.cpptools"], + "settings": { + "terminal.integrated.shell.linux": "/bin/bash" + } + } + }, + "forwardPorts": [3000] +} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000000..3d05d86d31a6 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +* text=auto + +# Always use Unix-style line endings for Bash scripts so they work in +# Docker on Windows. +.bashrc text eol=lf +*.sh text eol=lf diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000000..1df0848cd75a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + - package-ecosystem: "npm" + directory: "/docs" + schedule: + interval: "daily" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000000..9e523a36c581 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,15 @@ + + +## Board/Shield Check-list + +- [ ] This board/shield is tested working on real hardware +- [ ] Definitions follow the general style of other shields/boards upstream ([Reference](https://zmk.dev/docs/development/new-shield)) +- [ ] `.zmk.yml` metadata file added +- [ ] Proper Copyright + License headers added to applicable files (Generally, we stick to "The ZMK Contributors" for copyrights to help avoid churn when files get edited) +- [ ] General consistent formatting of DeviceTree files +- [ ] Keymaps do not use deprecated key defines (Check using the [upgrader tool](https://zmk.dev/docs/codes/keymap-upgrader)) +- [ ] `&pro_micro` used in favor of `&pro_micro_d/a` if applicable +- [ ] If split, no name added for the right/peripheral half +- [ ] Kconfig.defconfig file correctly wraps _all_ configuration in conditional on the shield symbol +- [ ] `.conf` file has optional extra features commented out +- [ ] Keyboard/PCB is part of a shipped group buy or is generally available in stock to purchase (OSH/personal projects without general availability should create a zmk-config repo instead) diff --git a/.github/workflows/ble-test.yml b/.github/workflows/ble-test.yml new file mode 100644 index 000000000000..8f545002e73e --- /dev/null +++ b/.github/workflows/ble-test.yml @@ -0,0 +1,78 @@ +name: BLE Tests + +on: + push: + paths: + - ".github/workflows/ble-test.yml" + - "app/tests/ble/**" + - "app/src/**" + - "app/run-ble-test.sh" + pull_request: + paths: + - ".github/workflows/ble-test.yml" + - "app/tests/ble/**" + - "app/src/**" + - "app/run-ble-test.sh" + +jobs: + collect-tests: + outputs: + test-dirs: ${{ steps.test-dirs.outputs.test-dirs }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Find test directories + id: test-dirs + run: | + cd app/tests/ble + export TESTS=$(ls -d * | grep -v central | jq -R -s -c 'split("\n")[:-1]') + echo "test-dirs=${TESTS}" > $GITHUB_OUTPUT + run-tests: + needs: collect-tests + strategy: + matrix: + test: ${{ fromJSON(needs.collect-tests.outputs.test-dirs) }} + runs-on: ubuntu-latest + container: + image: docker.io/zmkfirmware/zmk-build-arm:3.2 + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Cache west modules + uses: actions/cache@v3 + env: + cache-name: cache-zephyr-modules + with: + path: | + modules/ + tools/ + zephyr/ + bootloader/ + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('app/west.yml') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + timeout-minutes: 2 + continue-on-error: true + - name: Initialize workspace (west init) + run: west init -l app + - name: Enable babblesim group filter + run: west config manifest.group-filter -- +babblesim + - name: Update modules (west update) + run: west update + - name: Export Zephyr CMake package (west zephyr-export) + run: west zephyr-export + - name: Build BabbleSim components + working-directory: tools/bsim + run: make everything + - name: Test ${{ matrix.test }} + working-directory: app + run: BSIM_COMPONENTS_PATH="${GITHUB_WORKSPACE}/tools/bsim/components/" BSIM_OUT_PATH="${GITHUB_WORKSPACE}/tools/bsim/" ./run-ble-test.sh tests/ble/${{ matrix.test }} + - name: Archive artifacts + if: ${{ always() }} + uses: actions/upload-artifact@v4 + with: + name: "${{ matrix.test }}-log-files" + path: app/build/**/*.log diff --git a/.github/workflows/build-user-config.yml b/.github/workflows/build-user-config.yml new file mode 100644 index 000000000000..7efa6425f92f --- /dev/null +++ b/.github/workflows/build-user-config.yml @@ -0,0 +1,163 @@ +name: Reusable user config build + +on: + workflow_call: + inputs: + build_matrix_path: + description: "Path to the build matrix file" + default: "build.yaml" + required: false + type: string + config_path: + description: "Path to the config directory" + default: "config" + required: false + type: string + fallback_binary: + description: "Fallback binary format, if no *.uf2 file was built" + default: "bin" + required: false + type: string + archive_name: + description: "Archive output file name" + default: "firmware" + required: false + type: string + +jobs: + matrix: + runs-on: ubuntu-latest + name: Fetch Build Keyboards + outputs: + build_matrix: ${{ env.build_matrix }} + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install yaml2json + run: python3 -m pip install remarshal + + - name: Fetch Build Matrix + run: | + echo "build_matrix=$(yaml2json '${{ inputs.build_matrix_path }}' | jq -c .)" >> $GITHUB_ENV + yaml2json "${{ inputs.build_matrix_path }}" | jq + + build: + runs-on: ubuntu-latest + container: + image: zmkfirmware/zmk-build-arm:stable + needs: matrix + name: Build + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.matrix.outputs.build_matrix) }} + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Create build directory + run: | + echo "build_dir=$(mktemp -d)" >> $GITHUB_ENV + + - name: Prepare variables + shell: sh -x {0} + env: + board: ${{ matrix.board }} + shield: ${{ matrix.shield }} + artifact_name: ${{ matrix.artifact-name }} + run: | + if [ -e zephyr/module.yml ]; then + export zmk_load_arg=" -DZMK_EXTRA_MODULES='${GITHUB_WORKSPACE}'" + export new_tmp_dir=$(mktemp -d) + echo "base_dir=${new_tmp_dir}" >> $GITHUB_ENV + else + echo "base_dir=${GITHUB_WORKSPACE}" >> $GITHUB_ENV + fi + + echo "zephyr_version=${ZEPHYR_VERSION}" >> $GITHUB_ENV + echo "extra_cmake_args=${shield:+-DSHIELD=\"$shield\"}${zmk_load_arg}" >> $GITHUB_ENV + echo "display_name=${shield:+$shield - }${board}" >> $GITHUB_ENV + echo "artifact_name=${artifact_name:-${shield:+$shield-}${board}-zmk}" >> $GITHUB_ENV + + - name: Copy config files to isolated temporary directory + run: | + if [ "${{ env.base_dir }}" != "${GITHUB_WORKSPACE}" ]; then + mkdir "${{ env.base_dir }}/${{ inputs.config_path }}" + cp -R ${{ inputs.config_path }}/* "${{ env.base_dir }}/${{ inputs.config_path }}/" + fi + + - name: Cache west modules + uses: actions/cache@v3.0.11 + continue-on-error: true + env: + cache_name: cache-zephyr-${{ env.zephyr_version }}-modules + with: + path: | + ${{ env.base_dir }}/modules/ + ${{ env.base_dir }}/tools/ + ${{ env.base_dir }}/zephyr/ + ${{ env.base_dir }}/bootloader/ + ${{ env.base_dir }}/zmk/ + key: ${{ runner.os }}-build-${{ env.cache_name }}-${{ hashFiles('**/west.yml', '**/build.yaml') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache_name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + + - name: West Init + working-directory: ${{ env.base_dir }} + run: west init -l "${{ env.base_dir }}/${{ inputs.config_path }}" + + - name: West Update + working-directory: ${{ env.base_dir }} + run: west update + + - name: West Zephyr export + working-directory: ${{ env.base_dir }} + run: west zephyr-export + + - name: West Build (${{ env.display_name }}) + working-directory: ${{ env.base_dir }} + shell: sh -x {0} + run: west build -s zmk/app -d "${{ env.build_dir }}" -b "${{ matrix.board }}" -- -DZMK_CONFIG=${{ env.base_dir }}/${{ inputs.config_path }} ${{ env.extra_cmake_args }} ${{ matrix.cmake-args }} + + - name: ${{ env.display_name }} Kconfig file + run: | + if [ -f "${{ env.build_dir }}/zephyr/.config" ] + then + grep -v -e "^#" -e "^$" "${{ env.build_dir }}/zephyr/.config" | sort + else + echo "No Kconfig output" + fi + if: ${{ !cancelled() }} + + - name: ${{ env.display_name }} Devicetree file + run: | + if [ -f "${{ env.build_dir }}/zephyr/zephyr.dts" ] + then + cat "${{ env.build_dir }}/zephyr/zephyr.dts" + elif [ -f "${{ env.build_dir }}/zephyr/zephyr.dts.pre" ] + then + cat -s "${{ env.build_dir }}/zephyr/zephyr.dts.pre" + else + echo "No Devicetree output" + fi + if: ${{ !cancelled() }} + + - name: Rename artifacts + shell: sh -x {0} + run: | + mkdir "${{ env.build_dir }}/artifacts" + if [ -f "${{ env.build_dir }}/zephyr/zmk.uf2" ] + then + cp "${{ env.build_dir }}/zephyr/zmk.uf2" "${{ env.build_dir }}/artifacts/${{ env.artifact_name }}.uf2" + elif [ -f "${{ env.build_dir }}/zephyr/zmk.${{ inputs.fallback_binary }}" ] + then + cp "${{ env.build_dir }}/zephyr/zmk.${{ inputs.fallback_binary }}" "${{ env.build_dir }}/artifacts/${{ env.artifact_name }}.${{ inputs.fallback_binary }}" + fi + + - name: Archive (${{ env.display_name }}) + uses: actions/upload-artifact@v3 + with: + name: ${{ inputs.archive_name }} + path: ${{ env.build_dir }}/artifacts diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000000..a7d0560d0420 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,409 @@ +name: Build + +on: + push: + paths: + - ".github/workflows/build.yml" + - "app/**" + pull_request: + paths: + - ".github/workflows/build.yml" + - "app/**" + schedule: + - cron: "22 4 * * *" + +jobs: + build: + if: ${{ always() }} + runs-on: ubuntu-latest + container: + image: docker.io/zmkfirmware/zmk-build-arm:3.2 + needs: compile-matrix + strategy: + matrix: + include: ${{ fromJSON(needs.compile-matrix.outputs.include-list) }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Cache west modules + uses: actions/cache@v3.0.2 + env: + cache-name: cache-zephyr-modules + with: + path: | + modules/ + tools/ + zephyr/ + bootloader/ + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('app/west.yml') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + timeout-minutes: 2 + continue-on-error: true + - name: Initialize workspace (west init) + run: west init -l app + - name: Update modules (west update) + run: west update + - name: Export Zephyr CMake package (west zephyr-export) + run: west zephyr-export + - name: Use Node.js + uses: actions/setup-node@v2 + with: + node-version: "14.x" + - name: Install @actions/artifact + run: npm install @actions/artifact + - name: Build and upload artifacts + uses: actions/github-script@v7 + id: boards-list + with: + script: | + const fs = require('fs'); + const {default: artifact} = require('@actions/artifact'); + + const execSync = require('child_process').execSync; + + const buildShieldArgs = JSON.parse(`${{ matrix.shieldArgs }}`); + + let error = false; + + for (const shieldArgs of buildShieldArgs) { + try { + const output = execSync(`west build -s app -p -b ${{ matrix.board }} -- ${shieldArgs.shield ? '-DSHIELD="' + shieldArgs.shield + '"' : ''} ${shieldArgs['cmake-args'] || ''}`); + + console.log(`::group::${{ matrix.board}} ${shieldArgs.shield} Build`) + console.log(output.toString()); + + const fileExtensions = ["hex", "uf2"]; + + const files = fileExtensions + .map(extension => "build/zephyr/zmk." + extension) + .filter(path => fs.existsSync(path)); + + const rootDirectory = 'build/zephyr'; + const options = { + continueOnError: true + } + + const cmakeName = shieldArgs['cmake-args'] ? '-' + (shieldArgs.nickname || shieldArgs['cmake-args'].split(' ').join('')) : ''; + const artifactName = `${{ matrix.board }}${shieldArgs.shield ? '-' + shieldArgs.shield : ''}${cmakeName}-zmk`; + + await artifact.uploadArtifact(artifactName, files, rootDirectory, options); + } catch (e) { + console.error(`::error::Failed to build or upload ${{ matrix.board }} ${shieldArgs.shield} ${shieldArgs['cmake-args']}`); + console.error(e); + error = true; + } finally { + console.log('::endgroup::'); + } + } + + if (error) { + throw new Error('Failed to build one or more configurations'); + } + compile-matrix: + if: ${{ always() }} + runs-on: ubuntu-latest + needs: [core-coverage, board-changes, nightly] + outputs: + include-list: ${{ steps.compile-list.outputs.result }} + steps: + - name: Join build lists + uses: actions/github-script@v7 + id: compile-list + with: + script: | + const coreCoverage = `${{ needs.core-coverage.outputs.core-include }}` || "[]"; + const boardChanges = `${{ needs.board-changes.outputs.boards-include }}` || "[]"; + const nightly = `${{ needs.nightly.outputs.nightly-include }}` || "[]"; + + const combined = [ + ...JSON.parse(coreCoverage), + ...JSON.parse(boardChanges), + ...JSON.parse(nightly) + ]; + const combinedUnique = [...new Map(combined.map(el => [JSON.stringify(el), el])).values()]; + + const perBoard = {}; + + for (const configuration of combinedUnique) { + if (!perBoard[configuration.board]) + perBoard[configuration.board] = []; + + perBoard[configuration.board].push({ + shield: configuration.shield, + 'cmake-args': configuration['cmake-args'], + nickname: configuration.nickname + }) + } + + return Object.entries(perBoard).map(([board, shieldArgs]) => ({ + board, + shieldArgs: JSON.stringify(shieldArgs), + })); + core-coverage: + if: ${{ needs.get-changed-files.outputs.core-changes == 'true' }} + runs-on: ubuntu-latest + needs: get-changed-files + outputs: + core-include: ${{ steps.core-list.outputs.result }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Use Node.js + uses: actions/setup-node@v2 + with: + node-version: "14.x" + - name: Install js-yaml + run: npm install js-yaml + - uses: actions/github-script@v7 + id: core-list + with: + script: | + const fs = require('fs'); + const yaml = require('js-yaml'); + + const coreCoverage = yaml.load(fs.readFileSync('app/core-coverage.yml', 'utf8')); + + let include = coreCoverage.board.flatMap(board => + coreCoverage.shield.map(shield => ({ board, shield })) + ); + + return [...include, ...coreCoverage.include]; + board-changes: + if: ${{ needs.get-changed-files.outputs.board-changes == 'true' }} + runs-on: ubuntu-latest + needs: [get-grouped-hardware, get-changed-files] + outputs: + boards-include: ${{ steps.boards-list.outputs.result }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Use Node.js + uses: actions/setup-node@v2 + with: + node-version: "14.x" + - name: Install js-yaml + run: npm install js-yaml + - uses: actions/github-script@v7 + id: boards-list + with: + script: | + const fs = require('fs'); + const yaml = require('js-yaml'); + + const changedFiles = JSON.parse(`${{ needs.get-changed-files.outputs.changed-files }}`); + const metadata = JSON.parse(`${{ needs.get-grouped-hardware.outputs.organized-metadata }}`); + const boardChanges = new Set(changedFiles.filter(f => f.startsWith('app/boards')).map(f => f.split('/').slice(0, 4).join('/'))); + + return (await Promise.all([...boardChanges].flatMap(async bc => { + const globber = await glob.create(bc + "/*.zmk.yml"); + const files = await globber.glob(); + + const aggregated = files.flatMap((f) => + yaml.loadAll(fs.readFileSync(f, "utf8")) + ); + + const boardAndShield = (b, s) => { + if (s.siblings) { + return s.siblings.map(shield => ({ + board: b.id, + shield, + })); + } else { + return { + board: b.id, + shield: s.id + }; + } + } + + return aggregated.flatMap(hm => { + switch (hm.type) { + case "board": + if (hm.features && hm.features.includes("keys")) { + if (hm.siblings) { + return hm.siblings.map(board => ({ + board, + })); + } else { + return { + board: hm.id + }; + } + } else if (hm.exposes) { + return hm.exposes.flatMap(i => + metadata.interconnects[i].shields.flatMap(s => boardAndShield(hm, s)) + ); + } else { + console.error("Board without keys or interconnect"); + } + break; + case "shield": + if (hm.features && hm.features.includes("keys")) { + return hm.requires.flatMap(i => + metadata.interconnects[i].boards.flatMap(b => boardAndShield(b, hm)) + ); + } else { + console.warn("Unhandled shield without keys"); + return []; + } + break; + case "interconnect": + return []; + } + }); + }))).flat(); + nightly: + if: ${{ github.event_name == 'schedule' }} + runs-on: ubuntu-latest + needs: get-grouped-hardware + outputs: + nightly-include: ${{ steps.nightly-list.outputs.result }} + steps: + - name: Create nightly list + uses: actions/github-script@v7 + id: nightly-list + with: + script: | + const metadata = JSON.parse(`${{ needs.get-grouped-hardware.outputs.organized-metadata }}`); + + let includeOnboard = metadata.onboard.flatMap(b => { + if (b.siblings) { + return b.siblings.map(board => ({ + board, + })); + } else { + return { + board: b.id, + }; + } + }); + + let includeInterconnect = Object.values(metadata.interconnects).flatMap(i => + i.boards.flatMap(b => + i.shields.flatMap(s => { + if (s.siblings) { + return s.siblings.map(shield => ({ + board: b.id, + shield, + })); + } else { + return { + board: b.id, + shield: s.id, + }; + } + }) + ) + ); + + return [...includeOnboard, ...includeInterconnect]; + get-grouped-hardware: + runs-on: ubuntu-latest + outputs: + organized-metadata: ${{ steps.organize-metadata.outputs.result }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Use Node.js + uses: actions/setup-node@v2 + with: + node-version: "14.x" + - name: Install js-yaml + run: npm install js-yaml + - name: Aggregate Metadata + uses: actions/github-script@v7 + id: aggregate-metadata + with: + script: | + const fs = require('fs'); + const yaml = require('js-yaml'); + + const globber = await glob.create("app/boards/**/*.zmk.yml"); + const files = await globber.glob(); + + const aggregated = files.flatMap((f) => + yaml.loadAll(fs.readFileSync(f, "utf8")) + ); + + return JSON.stringify(aggregated).replace(/\\/g,"\\\\").replace(/`/g,"\\`"); + result-encoding: string + + - name: Organize Metadata + uses: actions/github-script@v7 + id: organize-metadata + with: + script: | + const hardware = JSON.parse(`${{ steps.aggregate-metadata.outputs.result }}`); + + const grouped = hardware.reduce((agg, hm) => { + switch (hm.type) { + case "board": + if (hm.features && hm.features.includes("keys")) { + agg.onboard.push(hm); + } else if (hm.exposes) { + hm.exposes.forEach((element) => { + let ic = agg.interconnects[element] || { + boards: [], + shields: [], + }; + ic.boards.push(hm); + agg.interconnects[element] = ic; + }); + } else { + console.error("Board without keys or interconnect"); + } + break; + case "shield": + if (hm.features && hm.features.includes("keys")) { + hm.requires.forEach((id) => { + let ic = agg.interconnects[id] || { boards: [], shields: [] }; + ic.shields.push(hm); + agg.interconnects[id] = ic; + }); + } + break; + case "interconnect": + let ic = agg.interconnects[hm.id] || { boards: [], shields: [] }; + ic.interconnect = hm; + agg.interconnects[hm.id] = ic; + break; + } + return agg; + }, + { onboard: [], interconnects: {} }); + + return JSON.stringify(grouped).replace(/\\/g,"\\\\").replace(/`/g,"\\`"); + result-encoding: string + get-changed-files: + if: ${{ github.event_name != 'schedule' }} + runs-on: ubuntu-latest + outputs: + changed-files: ${{ steps.changed-files.outputs.all }} + board-changes: ${{ steps.board-changes.outputs.result }} + core-changes: ${{ steps.core-changes.outputs.result }} + steps: + - uses: Ana06/get-changed-files@v2.0.0 + id: changed-files + with: + format: "json" + - uses: actions/github-script@v7 + id: board-changes + with: + script: | + const changedFiles = JSON.parse(`${{ steps.changed-files.outputs.all }}`); + const boardChanges = changedFiles.filter(f => f.startsWith('app/boards')); + return boardChanges.length ? 'true' : 'false'; + result-encoding: string + - uses: actions/github-script@v7 + id: core-changes + with: + script: | + const changedFiles = JSON.parse(`${{ steps.changed-files.outputs.all }}`); + const boardChanges = changedFiles.filter(f => f.startsWith('app/boards')); + const appChanges = changedFiles.filter(f => f.startsWith('app')); + const ymlChanges = changedFiles.includes('.github/workflows/build.yml'); + return boardChanges.length < appChanges.length || ymlChanges ? 'true' : 'false'; + result-encoding: string diff --git a/.github/workflows/doc-checks.yml b/.github/workflows/doc-checks.yml new file mode 100644 index 000000000000..91e65e6d31e1 --- /dev/null +++ b/.github/workflows/doc-checks.yml @@ -0,0 +1,36 @@ +name: Docs Checks + +on: + push: + paths: + - ".github/workflows/doc-checks.yml" + - "docs/**" + pull_request: + paths: + - ".github/workflows/doc-checks.yml" + - "docs/**" + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: bahmutov/npm-install@v1 + with: + working-directory: docs + - name: ESLint + run: npm run lint + working-directory: docs + typecheck: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: bahmutov/npm-install@v1 + with: + working-directory: docs + - name: Build + run: npm run build + working-directory: docs + - name: TypeScript check + run: npm run typecheck + working-directory: docs diff --git a/.github/workflows/hardware-metadata-validation.yml b/.github/workflows/hardware-metadata-validation.yml new file mode 100644 index 000000000000..100928368e31 --- /dev/null +++ b/.github/workflows/hardware-metadata-validation.yml @@ -0,0 +1,34 @@ +name: Hardware Metadata Validation + +on: + push: + paths: + - ".github/workflows/hardware-metadata-validation.yml" + - "schema/hardware-metadata.schema.json" + - "app/boards/**/*.zmk.yml" + - "app/scripts/west_commands/metadata.py" + pull_request: + paths: + - ".github/workflows/hardware-metadata-validation.yml" + - "schema/hardware-metadata.schema.json" + - "app/boards/**/*.zmk.yml" + - "app/scripts/west_commands/metadata.py" + +jobs: + validate-metadata: + runs-on: ubuntu-latest + container: + image: docker.io/zmkfirmware/zmk-dev-arm:3.2 + steps: + - uses: actions/checkout@v3 + - name: Install dependencies + run: pip install -r app/scripts/requirements.txt + - name: West init + run: west init -l app + - name: Update modules (west update) + run: west update + - name: Export Zephyr CMake package (west zephyr-export) + run: west zephyr-export + - name: Validate Hardware Metadata + working-directory: app + run: west metadata check diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 000000000000..a6583d4f71b8 --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,15 @@ +name: pre-commit + +on: + pull_request: + push: + +jobs: + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: 3.x + - uses: pre-commit/action@v3.0.0 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 000000000000..eba4ff3a0b44 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,71 @@ +name: Tests + +on: + push: + paths: + - ".github/workflows/test.yml" + - "app/tests/**" + - "app/src/**" + pull_request: + paths: + - ".github/workflows/test.yml" + - "app/tests/**" + - "app/src/**" + +jobs: + collect-tests: + outputs: + test-dirs: ${{ steps.test-dirs.outputs.test-dirs }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Find test directories + id: test-dirs + run: | + cd app/tests/ + export TESTS=$(ls -d * | grep -v ble | jq -R -s -c 'split("\n")[:-1]') + echo "test-dirs=${TESTS}" >> $GITHUB_OUTPUT + run-tests: + needs: collect-tests + strategy: + matrix: + test: ${{ fromJSON(needs.collect-tests.outputs.test-dirs) }} + runs-on: ubuntu-latest + container: + image: docker.io/zmkfirmware/zmk-build-arm:3.2 + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Cache west modules + uses: actions/cache@v3 + env: + cache-name: cache-zephyr-modules + with: + path: | + modules/ + tools/ + zephyr/ + bootloader/ + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('app/west.yml') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + timeout-minutes: 2 + continue-on-error: true + - name: Initialize workspace (west init) + run: west init -l app + - name: Update modules (west update) + run: west update + - name: Export Zephyr CMake package (west zephyr-export) + run: west zephyr-export + - name: Test ${{ matrix.test }} + working-directory: app + run: west test tests/${{ matrix.test }} + - name: Archive artifacts + if: ${{ always() }} + uses: actions/upload-artifact@v4 + with: + name: "${{ matrix.test }}-log-files" + path: app/build/**/*.log diff --git a/.gitignore b/.gitignore index 567609b1234a..93c801d9aa9a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,9 @@ -build/ +/.west +/bootloader +/modules +/tools +/zephyr +/zmk-config +/build +*.DS_Store +__pycache__ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index c41b2432e751..000000000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "zephyr-rust"] - path = zephyr-rust - url = https://github.com/tylerwhall/zephyr-rust.git diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000000..e0666ea8d2b0 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,28 @@ +fail_fast: false +repos: + - repo: https://github.com/Lucas-C/pre-commit-hooks + rev: v1.5.1 + hooks: + - id: remove-tabs + exclude: "vendor-prefixes\\.txt$" + - repo: https://github.com/pocc/pre-commit-hooks + rev: v1.3.5 + hooks: + - id: clang-format + args: + - -i + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v2.7.1 + hooks: + - id: prettier + # Workaround for https://github.com/pre-commit/mirrors-prettier/issues/29 + additional_dependencies: + - prettier@2.8.7 + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: trailing-whitespace + - id: check-yaml + - id: check-added-large-files + - id: check-shebang-scripts-are-executable + exclude: "\\.mustache$" diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000000..0819f71e7a05 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,9 @@ +{ + "recommendations": [ + "esbenp.prettier-vscode", + "ms-python.python", + "ms-vscode.cpptools", + "plorefice.devicetree", + "twxs.cmake" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000000..924d83b1f257 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,22 @@ +{ + "files.associations": { + "*.overlay": "dts", + "*.keymap": "dts" + }, + "python.formatting.provider": "black", + "[c]": { + "editor.formatOnSave": true + }, + "[javascript][javascriptreact][typescript][typescriptreact]": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[python]": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "ms-python.python" + }, + "[css][json][jsonc][html][markdown][yaml]": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode" + } +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 000000000000..080ffea6e65e --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,28 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Build", + "type": "shell", + "command": "cd app && west build", + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "Flash", + "type": "shell", + "command": "cd app && west flash", + "group": "test" + }, + { + "label": "Debug", + "type": "shell", + "command": "cd app && west debug", + "group": "test" + } + ] +} diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000000..b748b4e65fe4 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,13 @@ +# The ZMK Project consists of many contributors. This file includes individuals +# who have contributed significant changes to the project. To be added to here, +# please submit a PR to the project repo. +Peter Johanson (@petejohanson) +Innovaker (@innovaker) +Nick Winans (@Nicell) +Okke Formsma (@okke-formsma) +Cody McGinnis (@BrainWart) +Kurtis Lew (@kurtis-lew) +Richard Jones (@bmcgavin) +Kevin Chen (@chenkevinh) +Joel Spadin (@joelspadin) +KemoNine (@mcrosson) diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 58277409462d..000000000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -# Find Zephyr. This also loads Zephyr's build system. -cmake_minimum_required(VERSION 3.13.1) -find_package(Zephyr) - -get_filename_component(ZEPHYR_RUST ${CMAKE_CURRENT_SOURCE_DIR}/zephyr-rust ABSOLUTE) -list(APPEND ZEPHYR_EXTRA_MODULES ${ZEPHYR_RUST}) - -project(zmk) - -# Add your source file to the "app" target. This must come after -# find_package(Zephyr) which defines the target. -target_sources(app PRIVATE src/main.c) - -include(ExternalProject) - -# Add rust_example as a CMake target -ExternalProject_Add( - zmk_crate - DOWNLOAD_COMMAND "" - CONFIGURE_COMMAND "" - BUILD_COMMAND cargo build --target thumbv7m-none-eabi COMMAND cargo build --release --target thumbv7m-none-eabi - BINARY_DIR "${CMAKE_SOURCE_DIR}/zmk" - INSTALL_COMMAND "" - BUILD_BYPRODUCTS "${CMAKE_SOURCE_DIR}/zmk/target/thumbv7m-none-eabi/release/libzmk.a" - LOG_BUILD ON) - -# Create a wrapper CMake library that our app can link with -add_library(zmk_lib STATIC IMPORTED GLOBAL) -add_dependencies( - zmk_lib - zmk_crate - ) - -set_target_properties(zmk_lib PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/zmk/target/thumbv7m-none-eabi/release/libzmk.a) -# target_link_libraries(zmk_lib -# debug "${CMAKE_SOURCE_DIR}/target/debug/zmk.a" -# optimized "${CMAKE_SOURCE_DIR}/target/release/zmk.a") - -target_link_libraries(app PUBLIC zmk_lib) - diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 000000000000..d9bf0d44bb0e --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,5 @@ +* @zmkfirmware/core + +/app/boards @zmkfirmware/boards-shields + +/docs @zmkfirmware/docs \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000000..2f8c597b8165 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +- Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery, and sexual attention or + advances of any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email + address, without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +conduct@zmk.dev. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000000..fe7292a8feec --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,127 @@ +# Contributing To ZMK + +Thanks for taking an interest in contributing to ZMK! After reading through the documentation, if +you have any questions, please come join us on the +[ZMK Discord Server][discord-invite]. + +## Code of Conduct + +All community members are expected to abide by the [Code of Conduct][code-of-conduct]. +For any and all conduct inquiries or concerns, please contact conduct@zmk.dev. + +[code-of-conduct]: https://github.com/zmkfirmware/zmk/blob/main/CODE_OF_CONDUCT.md + +## How Can I Contribute + +There are many different ways that you can contribute to ZMK, several of which require no coding +abilities. These include: + +- Chat Support +- Issue Reporting/Commenting +- Testing +- Documentation +- Code Contributions + +## Chat Support + +Providing user support on the [ZMK Discord Server][discord-invite] is a great way to help the +project. In particular, answering questions in the [#help](https://discord.com/channels/719497620560543766/719909884769992755) channel is incredibly appreciated. + +## Issue Reporting/Commenting + +Often, you might encounter unexpected behavior when building, flashing, or running the ZMK +firmware. Submitting or commenting on issues on GitHub is a great way to contribute to the +ZMK project. + +### Before Submitting a Report + +- Review the [Frequently Asked Questions](https://zmk.dev/docs/faq). +- Check the [Troubleshooting Guide](https://zmk.dev/docs/troubleshooting) for answers. +- Search the [open issues](https://github.com/zmkfirmware/zmk/issues) for an existing report that + matches your problem. + +### Opening A Report + +To open a report: + +- Head to https://github.com/zmkfirmware/zmk/issues/new +- Provide an accurate summary of the issue in the title. +- Provide as much detail as you can about the issue including: + - What [board/shield](https://zmk.dev/docs/faq#what-is-a-board) you are using. + - A link to the user repository, if you used it to build your firmware. + - Exact steps to reproduce the problem. + - Any relevant screenshots or [logs](https://zmk.dev/docs/dev-guide-usb-logging) + +## Testing + +The `help wanted` label will be added to any [pull requests](https://github.com/zmkfirmware/zmk/pulls?q=is%3Aopen+is%3Apr+label%3A%22help+wanted%22) +or [issues](https://github.com/zmkfirmware/zmk/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) +where user testing can assist the ZMK contributors to verify fixes, confirm +bugs, etc. + +When providing testing feedback, please provide: + +- Exact steps used to test +- Any hardware details relevant to testing +- Pass/fail summary for testing. +- Full details of any failures, including: + - Logs + - Screenshots + +## Documentation + +Quality documentation is a huge part of what makes a successful project. Contributions to add +documentation to areas not currently covered are greatly appreciated. + +### Contributing + +- The documentation site can be found in the main ZMK repo, in the + [docs/](https://github.com/zmkfirmware/zmk/tree/main/docs) subdirectory. +- The documentation is maintained using [Docusaurus V2](https://v2.docusaurus.io/docs/). +- To get started, from the `docs/` directory, run `npm ci` and then `npm start`. +- Enhancements should be submitted as pull requests to the `main` branch of ZMK. + +### Formatting + +ZMK uses `prettier` to format documentation files. You can run prettier with `npm run prettier:format`. +You can setup git to run prettier automatically when you commit by installing the pre-commit hooks: `pip3 install pre-commit`, `pre-commit install`. + +## Code Contributions + +### Development Setup + +To get your development environment setup going, start at the +[basic setup](https://zmk.dev/docs/development/setup/) docs, and make sure you can build and flash +your own locally built firmware. + +### Formatting + +ZMK uses `clang-format` to ensure consist formatting for our source code. Before submitting your +changes, make sure you've manually run `clang-format`, or have your IDE configured to auto-format +on save. + +You can setup git to run `clang-format` automatically when you commit by installing the pre-commit hooks: `pip3 install pre-commit`, `pre-commit install`. + +### Commit Messages + +The ZMK project is working towards, but not yet enforcing, the use of +[conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) for commit messages. + +Further documentation and details will be provided here soon. + +### Pull Requests + +When opening a pull request with your changes, please: + +- Submit the PR to the `main` branch of the + [`zmkfirmware/zmk`](https://github.com/zmkfirmware/zmk) repository. +- Use a descriptive title that summarizes the change. +- In the description, include: + - References to any open issues fixed by the PR. + - Feature added by the PR + - Bugs fixed by the PR. + - Testing you've performed locally. + - Requested testing by reviewers or testers. + - Screenshots or logs that support understanding the change. + +[discord-invite]: https://zmk.dev/community/discord/invite diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000000..213e73406b00 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 The ZMK Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 000000000000..f112b0f97056 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# Zephyr™ Mechanical Keyboard (ZMK) Firmware + +[![Discord](https://img.shields.io/discord/719497620560543766)](https://zmk.dev/community/discord/invite) +[![Build](https://github.com/zmkfirmware/zmk/workflows/Build/badge.svg)](https://github.com/zmkfirmware/zmk/actions) +[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg)](CODE_OF_CONDUCT.md) + +[ZMK Firmware](https://zmk.dev/) is an open source ([MIT](LICENSE)) keyboard firmware built on the [Zephyr™ Project](https://www.zephyrproject.org/) Real Time Operating System (RTOS). ZMK's goal is to provide a modern, wireless, and powerful firmware free of licensing issues. + +Check out the website to learn more: https://zmk.dev/. + +You can also come join our [ZMK Discord Server](https://zmk.dev/community/discord/invite). + +To review features, check out the [feature overview](https://zmk.dev/docs/). ZMK is under active development, and new features are listed with the [enhancement label](https://github.com/zmkfirmware/zmk/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) in GitHub. Please feel free to add 👍 to the issue description of any requests to upvote the feature. diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 000000000000..3e2e84b087a7 --- /dev/null +++ b/app/.gitignore @@ -0,0 +1,2 @@ +build/ +node_modules/ diff --git a/app/.prettierrc.js b/app/.prettierrc.js new file mode 100644 index 000000000000..2a1f0b48af9e --- /dev/null +++ b/app/.prettierrc.js @@ -0,0 +1,3 @@ +module.exports = { + endOfLine: "auto", +}; diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt new file mode 100644 index 000000000000..e5f489765e86 --- /dev/null +++ b/app/CMakeLists.txt @@ -0,0 +1,96 @@ +cmake_minimum_required(VERSION 3.13.1) + +set(CONFIG_APPLICATION_DEFINED_SYSCALL true) + +set(ZEPHYR_EXTRA_MODULES "${ZMK_EXTRA_MODULES};${CMAKE_CURRENT_SOURCE_DIR}/module;${CMAKE_CURRENT_SOURCE_DIR}/keymap-module") + +# Find Zephyr. This also loads Zephyr's build system. +find_package(Zephyr REQUIRED HINTS ../zephyr) +project(zmk) + +zephyr_linker_sources(SECTIONS include/linker/zmk-behaviors.ld) +zephyr_linker_sources(RODATA include/linker/zmk-events.ld) + +# Add your source file to the "app" target. This must come after +# find_package(Zephyr) which defines the target. +target_include_directories(app PRIVATE include) +target_sources(app PRIVATE src/stdlib.c) +target_sources(app PRIVATE src/activity.c) +target_sources(app PRIVATE src/behavior.c) +target_sources(app PRIVATE src/kscan.c) +target_sources(app PRIVATE src/matrix_transform.c) +target_sources(app PRIVATE src/sensors.c) +target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/wpm.c) +target_sources(app PRIVATE src/event_manager.c) +target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/ext_power_generic.c) +target_sources(app PRIVATE src/events/activity_state_changed.c) +target_sources(app PRIVATE src/events/position_state_changed.c) +target_sources(app PRIVATE src/events/sensor_event.c) +target_sources(app PRIVATE src/events/mouse_button_state_changed.c) +target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/events/wpm_state_changed.c) +target_sources_ifdef(CONFIG_USB_DEVICE_STACK app PRIVATE src/events/usb_conn_state_changed.c) +target_sources(app PRIVATE src/behaviors/behavior_reset.c) +target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext_power.c) +if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL) + target_sources(app PRIVATE src/hid.c) + target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse.c) + target_sources(app PRIVATE src/behaviors/behavior_key_press.c) + target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_KEY_TOGGLE app PRIVATE src/behaviors/behavior_key_toggle.c) + target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c) + target_sources(app PRIVATE src/behaviors/behavior_sticky_key.c) + target_sources(app PRIVATE src/behaviors/behavior_caps_word.c) + target_sources(app PRIVATE src/behaviors/behavior_key_repeat.c) + target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_MACRO app PRIVATE src/behaviors/behavior_macro.c) + target_sources(app PRIVATE src/behaviors/behavior_momentary_layer.c) + target_sources(app PRIVATE src/behaviors/behavior_mod_morph.c) + target_sources(app PRIVATE src/behaviors/behavior_outputs.c) + target_sources(app PRIVATE src/behaviors/behavior_toggle_layer.c) + target_sources(app PRIVATE src/behaviors/behavior_to_layer.c) + target_sources(app PRIVATE src/behaviors/behavior_transparent.c) + target_sources(app PRIVATE src/behaviors/behavior_none.c) + target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE app PRIVATE src/behaviors/behavior_sensor_rotate.c) + target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE_VAR app PRIVATE src/behaviors/behavior_sensor_rotate_var.c) + target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON app PRIVATE src/behaviors/behavior_sensor_rotate_common.c) + target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_MOUSE_KEY_PRESS app PRIVATE src/behaviors/behavior_mouse_key_press.c) + target_sources(app PRIVATE src/combo.c) + target_sources(app PRIVATE src/behaviors/behavior_tap_dance.c) + target_sources(app PRIVATE src/behavior_queue.c) + target_sources(app PRIVATE src/conditional_layer.c) + target_sources(app PRIVATE src/endpoints.c) + target_sources(app PRIVATE src/events/endpoint_changed.c) + target_sources(app PRIVATE src/hid_listener.c) + target_sources(app PRIVATE src/keymap.c) + target_sources(app PRIVATE src/events/layer_state_changed.c) + target_sources(app PRIVATE src/events/modifiers_state_changed.c) + target_sources(app PRIVATE src/events/keycode_state_changed.c) + target_sources_ifdef(CONFIG_ZMK_HID_INDICATORS app PRIVATE src/hid_indicators.c) + + if (CONFIG_ZMK_BLE) + target_sources(app PRIVATE src/events/ble_active_profile_changed.c) + target_sources(app PRIVATE src/behaviors/behavior_bt.c) + target_sources(app PRIVATE src/ble.c) + target_sources(app PRIVATE src/hog.c) + endif() +endif() + +target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/behaviors/behavior_rgb_underglow.c) +target_sources_ifdef(CONFIG_ZMK_BACKLIGHT app PRIVATE src/behaviors/behavior_backlight.c) + +target_sources_ifdef(CONFIG_ZMK_BATTERY_REPORTING app PRIVATE src/events/battery_state_changed.c) +target_sources_ifdef(CONFIG_ZMK_BATTERY_REPORTING app PRIVATE src/battery.c) + +target_sources_ifdef(CONFIG_ZMK_HID_INDICATORS app PRIVATE src/events/hid_indicators_changed.c) + +target_sources_ifdef(CONFIG_ZMK_SPLIT app PRIVATE src/events/split_peripheral_status_changed.c) +add_subdirectory(src/split) + +target_sources_ifdef(CONFIG_USB_DEVICE_STACK app PRIVATE src/usb.c) +target_sources_ifdef(CONFIG_ZMK_USB app PRIVATE src/usb_hid.c) +target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/rgb_underglow.c) +target_sources_ifdef(CONFIG_ZMK_BACKLIGHT app PRIVATE src/backlight.c) +target_sources_ifdef(CONFIG_ZMK_LOW_PRIORITY_WORK_QUEUE app PRIVATE src/workqueue.c) +target_sources(app PRIVATE src/main.c) + +add_subdirectory(src/display/) + +zephyr_cc_option(-Wfatal-errors) diff --git a/app/Kconfig b/app/Kconfig new file mode 100644 index 000000000000..a5fa54f614be --- /dev/null +++ b/app/Kconfig @@ -0,0 +1,650 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +mainmenu "ZMK Firmware" + +menu "ZMK" + +menu "Basic Keyboard Setup" + +config ZMK_KEYBOARD_NAME + string "Keyboard Name" + +config USB_DEVICE_PRODUCT + default ZMK_KEYBOARD_NAME + +config BT_DEVICE_NAME + default ZMK_KEYBOARD_NAME + +config USB_DEVICE_VID + default 0x1D50 + +config USB_DEVICE_PID + default 0x615E + +config USB_DEVICE_MANUFACTURER + default "ZMK Project" + +config BT_DIS_PNP_VID + default 0x1D50 + +config BT_DIS_PNP_PID + default 0x615E + +config BT_DIS_MODEL + default ZMK_KEYBOARD_NAME + +config BT_DIS_MANUF + default "ZMK Project" + +menu "HID" + +choice ZMK_HID_REPORT_TYPE + prompt "HID Report Type" + +config ZMK_HID_REPORT_TYPE_HKRO + bool "#-Key Roll Over (HKRO) HID Report" + help + Enable # key roll over for HID report. This selection is "boot keyboard" compatible + but limits the total number of possible keys to report as held to #. + +config ZMK_HID_REPORT_TYPE_NKRO + bool "Full N-Key Roll Over (NKRO) HID Report" + help + Enable full N-Key Roll Over for HID output. This selection will prevent the keyboard + from working with some BIOS/UEFI versions that only support "boot keyboard" support. + This option also prevents using some infrequently used higher range HID usages (notably F13-F24 and INTL1-9) + These usages can be re enabled with ZMK_HID_KEYBOARD_NKRO_EXTENDED_REPORT. + +endchoice + +config ZMK_HID_KEYBOARD_NKRO_EXTENDED_REPORT + bool "Enable extended NKRO reporting" + depends on ZMK_HID_REPORT_TYPE_NKRO + help + Enables higher usage range for NKRO (F13-F24 and INTL1-9). + Please note this is not compatible with Android currently and you will get no input + + +if ZMK_HID_REPORT_TYPE_HKRO + +config ZMK_HID_KEYBOARD_REPORT_SIZE + int "# Keyboard Keys Reportable" + default 6 + +endif + +config ZMK_HID_CONSUMER_REPORT_SIZE + int "# Consumer Keys Reportable" + default 6 + + +choice ZMK_HID_CONSUMER_REPORT_USAGES + prompt "HID Report Type" + +config ZMK_HID_CONSUMER_REPORT_USAGES_FULL + bool "Full Consumer HID Usage Support" + help + Enable full Consumer usage ID values to be sent to hosts. Allows for less + frequently used usages, but has compatibability issues with some host OSes. + +config ZMK_HID_CONSUMER_REPORT_USAGES_BASIC + bool "Basic Consumer HID Usage Support" + help + Enable Consumer usage ID values up to "Playback Speed - Slow" to be sent to + hosts. Allows for broader compatibability with more host OSes. + +endchoice + +config ZMK_HID_INDICATORS + bool "HID Indicators" + help + Enable HID indicators, used for detecting state of Caps/Scroll/Num Lock, + Kata, and Compose. + +menu "Output Types" + +config ZMK_USB + bool "USB" + depends on (!ZMK_SPLIT || (ZMK_SPLIT && ZMK_SPLIT_ROLE_CENTRAL)) + select USB + select USB_DEVICE_STACK + select USB_DEVICE_HID + +config ZMK_USB_BOOT + bool "USB Boot Protocol Support" + depends on ZMK_USB + select USB_HID_BOOT_PROTOCOL + select USB_DEVICE_SOF + +if ZMK_USB + +config USB_NUMOF_EP_WRITE_RETRIES + default 10 + +config USB_HID_POLL_INTERVAL_MS + default 1 + +#ZMK_USB +endif + +menuconfig ZMK_BLE + bool "BLE (HID over GATT)" + select BT + select BT_SMP + select BT_SMP_SC_PAIR_ONLY + select BT_SMP_APP_PAIRING_ACCEPT + select BT_PERIPHERAL + select BT_DIS + imply BT_SETTINGS if !ARCH_POSIX + imply SETTINGS if !ARCH_POSIX + imply ZMK_BATTERY_REPORTING if !ARCH_POSIX + +if ZMK_BLE + +config ZMK_BLE_EXPERIMENTAL_CONN + bool "Experimental BLE connection changes" + imply BT_GATT_AUTO_SEC_REQ + help + Enables a combination of settings that are planned to be default in future versions of ZMK + to improve connection stability. This includes changes to timing on BLE pairing initation, + restores use of the updated/new LLCP implementation, and disables 2M PHY support. + +config ZMK_BLE_EXPERIMENTAL_SEC + bool "Experimental BLE security changes" + imply BT_SMP_ALLOW_UNAUTH_OVERWRITE + help + Enables a combination of settings that are planned to be officially supported in the future. + This includes enabling BT Secure Connection passkey entry, and allows overwrite of keys from + previously paired hosts. + +config ZMK_BLE_EXPERIMENTAL_FEATURES + bool "Experimental BLE connection and security settings/features" + select ZMK_BLE_EXPERIMENTAL_CONN + select ZMK_BLE_EXPERIMENTAL_SEC + help + Enables experimental connection changes and security features. + +config ZMK_BLE_PASSKEY_ENTRY + bool "Require passkey entry on the keyboard to complete pairing" + default n + select RING_BUFFER + +config BT_SMP_ALLOW_UNAUTH_OVERWRITE + imply ZMK_BLE_PASSKEY_ENTRY + +choice BT_LL_SW_LLCP_IMPL + default BT_LL_SW_LLCP_LEGACY if !ZMK_BLE_EXPERIMENTAL_CONN + +endchoice + +config BT_CTLR_PHY_2M + default n if ZMK_BLE_EXPERIMENTAL_CONN + +# BT_TINYCRYPT_ECC is required for BT_SMP_SC_PAIR_ONLY when using HCI +config BT_TINYCRYPT_ECC + default y if BT_HCI && !BT_CTLR + +config SYSTEM_WORKQUEUE_STACK_SIZE + default 4096 if SOC_RP2040 + default 2048 + +config ZMK_BLE_THREAD_STACK_SIZE + int "BLE notify thread stack size" + default 768 + +config ZMK_BLE_THREAD_PRIORITY + int "BLE notify thread priority" + default 5 + +config ZMK_BLE_KEYBOARD_REPORT_QUEUE_SIZE + int "Max number of keyboard HID reports to queue for sending over BLE" + default 20 + +config ZMK_BLE_CONSUMER_REPORT_QUEUE_SIZE + int "Max number of consumer HID reports to queue for sending over BLE" + default 5 + +config ZMK_BLE_MOUSE_REPORT_QUEUE_SIZE + int "Max number of mouse HID reports to queue for sending over BLE" + default 20 + +config ZMK_BLE_CLEAR_BONDS_ON_START + bool "Configuration that clears all bond information from the keyboard on startup." + default n + +# HID GATT notifications sent this way are *not* picked up by Linux, and possibly others. +config BT_GATT_NOTIFY_MULTIPLE + default n + +config BT_GATT_AUTO_SEC_REQ + default n + +config BT_DEVICE_APPEARANCE + default 961 + +config BT_PERIPHERAL_PREF_MIN_INT + default 6 + +config BT_PERIPHERAL_PREF_MAX_INT + default 12 + +config BT_PERIPHERAL_PREF_LATENCY + default 30 + +config BT_PERIPHERAL_PREF_TIMEOUT + default 400 + +#ZMK_BLE +endif + +#Output Types +endmenu + +# HID +endmenu + +rsource "src/split/Kconfig" + +#Basic Keyboard Setup +endmenu + +menu "Display/LED Options" + +rsource "src/display/Kconfig" + +menuconfig ZMK_RGB_UNDERGLOW + bool "RGB Adressable LED Underglow" + select LED_STRIP + select ZMK_LOW_PRIORITY_WORK_QUEUE + +if ZMK_RGB_UNDERGLOW + +# This default value cuts down on tons of excess .conf files, if you're using GPIO, manually disable this +config SPI + default y + +config ZMK_RGB_UNDERGLOW_EXT_POWER + bool "RGB underglow toggling also controls external power" + default y + +config ZMK_RGB_UNDERGLOW_BRT_MIN + int "RGB underglow minimum brightness in percent" + range 0 100 + default 0 + +config ZMK_RGB_UNDERGLOW_BRT_MAX + int "RGB underglow maximum brightness in percent" + range ZMK_RGB_UNDERGLOW_BRT_MIN 100 + default 100 + +config ZMK_RGB_UNDERGLOW_HUE_STEP + int "RGB underglow hue step in degrees" + range 0 359 + default 10 + +config ZMK_RGB_UNDERGLOW_SAT_STEP + int "RGB underglow saturation step in percent" + range 0 100 + default 10 + +config ZMK_RGB_UNDERGLOW_BRT_STEP + int "RGB underglow brightness step in percent" + range 0 100 + default 10 + +config ZMK_RGB_UNDERGLOW_HUE_START + int "RGB underglow start hue value in degrees" + range 0 359 + default 0 + +config ZMK_RGB_UNDERGLOW_SAT_START + int "RGB underglow start saturations value in percent" + range 0 100 + default 100 + +config ZMK_RGB_UNDERGLOW_BRT_START + int "RGB underglow start brightness value in percent" + range ZMK_RGB_UNDERGLOW_BRT_MIN ZMK_RGB_UNDERGLOW_BRT_MAX + default ZMK_RGB_UNDERGLOW_BRT_MAX + +config ZMK_RGB_UNDERGLOW_SPD_START + int "RGB underglow start animation speed value" + range 1 5 + default 3 + +config ZMK_RGB_UNDERGLOW_EFF_START + int "RGB underglow start effect int value related to the effect enum list" + range 0 3 + default 0 + +config ZMK_RGB_UNDERGLOW_ON_START + bool "RGB underglow starts on by default" + default y + +config ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE + bool "Turn off RGB underglow when keyboard goes into idle state" + +config ZMK_RGB_UNDERGLOW_AUTO_OFF_USB + bool "Turn off RGB underglow when USB is disconnected" + depends on USB_DEVICE_STACK + +#ZMK_RGB_UNDERGLOW +endif + +menuconfig ZMK_BACKLIGHT + bool "LED backlight" + select LED + +if ZMK_BACKLIGHT + +config ZMK_BACKLIGHT_BRT_STEP + int "Brightness step in percent" + range 1 100 + default 20 + +config ZMK_BACKLIGHT_BRT_START + int "Default brightness in percent" + range 1 100 + default 40 + +config ZMK_BACKLIGHT_ON_START + bool "Default backlight state" + default y + +config ZMK_BACKLIGHT_AUTO_OFF_IDLE + bool "Turn off backlight when keyboard goes into idle state" + +config ZMK_BACKLIGHT_AUTO_OFF_USB + bool "Turn off backlight when USB is disconnected" + +#ZMK_BACKLIGHT +endif + +#Display/LED Options +endmenu + +menu "Mouse Options" + +config ZMK_MOUSE + bool "Enable ZMK mouse emulation" + default n + +#Mouse Options +endmenu + +menu "Power Management" + +config ZMK_BATTERY_REPORTING + bool "Battery level detection/reporting" + default n + select SENSOR + select ZMK_LOW_PRIORITY_WORK_QUEUE + imply BT_BAS if ZMK_BLE + +config ZMK_IDLE_TIMEOUT + int "Milliseconds of inactivity before entering idle state (OLED shutoff, etc)" + default 30000 + +config ZMK_SLEEP + bool "Enable deep sleep support" + imply USB + +if ZMK_SLEEP + +config PM_DEVICE + default y + +config ZMK_IDLE_SLEEP_TIMEOUT + int "Milliseconds of inactivity before entering deep sleep" + default 900000 + +#ZMK_SLEEP +endif + +config ZMK_EXT_POWER + bool "Enable support to control external power output" + default y + +#Power Management +endmenu + +menu "Combo options" + +config ZMK_COMBO_MAX_PRESSED_COMBOS + int "Maximum number of currently pressed combos" + default 4 + +config ZMK_COMBO_MAX_COMBOS_PER_KEY + int "Maximum number of combos per key" + default 5 + +config ZMK_COMBO_MAX_KEYS_PER_COMBO + int "Maximum number of keys per combo" + default 4 + +#Combo options +endmenu + +menu "Behavior Options" + +config ZMK_BEHAVIORS_QUEUE_SIZE + int "Maximum number of behaviors to allow queueing from a macro or other complex behavior" + default 64 + +rsource "Kconfig.behaviors" + +config ZMK_MACRO_DEFAULT_WAIT_MS + int "Default time to wait (in milliseconds) before triggering the next behavior in macros" + default 15 + +config ZMK_MACRO_DEFAULT_TAP_MS + int "Default time to wait (in milliseconds) between the press and release events of a tapped behavior in macros" + default 30 + +endmenu + +menu "Advanced" + +menu "Initialization Priorities" + +if USB_DEVICE_STACK + +config ZMK_USB_INIT_PRIORITY + int "USB Init Priority" + default 50 + +#USB +endif + +if ZMK_BLE || ZMK_SPLIT_BLE + +config ZMK_BLE_INIT_PRIORITY + int "BLE Init Priority" + default 50 + +#ZMK_BLE || ZMK_SPLIT_BLE +endif + +#Initialization Priorities +endmenu + +menuconfig ZMK_KSCAN + bool "ZMK KScan Integration" + default y + select KSCAN + +if ZMK_KSCAN + +config ZMK_KSCAN_EVENT_QUEUE_SIZE + int "Size of the event queue for KSCAN events to buffer events" + default 4 + +endif # ZMK_KSCAN + +menu "Logging" + +config ZMK_LOGGING_MINIMAL + bool "Suppress all ZMK debug log messages" + default false + +if !ZMK_LOGGING_MINIMAL + +config ZMK_LOG_LEVEL + default 4 + +endif + +config ZMK_USB_LOGGING + bool "Enable USB CDC ACM logging to help debug" + select LOG + select USB + select USB_DEVICE_STACK + select USB_CDC_ACM + select SERIAL + select CONSOLE + select UART_INTERRUPT_DRIVEN + select UART_LINE_CTRL + select UART_CONSOLE + select USB_UART_CONSOLE + +if ZMK_USB_LOGGING + +choice USB_CDC_ACM_LOG_LEVEL_CHOICE + default USB_CDC_ACM_LOG_LEVEL_OFF +endchoice + +choice USB_DRIVER_LOG_LEVEL_CHOICE + default USB_DRIVER_LOG_LEVEL_OFF +endchoice + +# We do this to avoid log loop where logging to USB generates more log messages. + +config USB_CDC_ACM_RINGBUF_SIZE + default 1024 + +config LOG_PROCESS_THREAD_STARTUP_DELAY_MS + default 1000 + +#ZMK_USB_LOGGING +endif + +config ZMK_RTT_LOGGING + bool "Enable RTT logging to help debug" + select LOG + select DEBUG + select ASSERT + select USE_SEGGER_RTT + select CONSOLE + select RTT_CONSOLE + +if ZMK_RTT_LOGGING + +config SEGGER_RTT_BUFFER_SIZE_UP + default 8192 + +#ZMK_RTT_LOGGING +endif + +if ZMK_USB_LOGGING || ZMK_RTT_LOGGING + +config LOG_BUFFER_SIZE + default 8192 + +config LOG_PROCESS_THREAD_SLEEP_MS + default 100 + +#ZMK_USB_LOGGING || ZMK_RTT_LOGGING +endif + +#Logging +endmenu + +if SETTINGS + +config ZMK_SETTINGS_SAVE_DEBOUNCE + int "Milliseconds to debounce settings saves" + default 60000 + +#SETTINGS +endif + +config ZMK_BATTERY_REPORT_INTERVAL + depends on ZMK_BATTERY_REPORTING + int "Battery level report interval in seconds" + default 60 + +config ZMK_LOW_PRIORITY_WORK_QUEUE + bool "Work queue for low priority items" + +if ZMK_LOW_PRIORITY_WORK_QUEUE + +config ZMK_LOW_PRIORITY_THREAD_STACK_SIZE + int "Low priority thread stack size" + default 768 + +config ZMK_LOW_PRIORITY_THREAD_PRIORITY + int "Low priority thread priority" + default 10 + +endif + +#Advanced +endmenu + +#ZMK +endmenu + +config HEAP_MEM_POOL_SIZE + default 8192 + +config KERNEL_BIN_NAME + default "zmk" + +config REBOOT + default y + +config USB_DEVICE_STACK + default y if HAS_HW_NRF_USBD + +config ZMK_WPM + bool "Calculate WPM" + default n + +config ZMK_KEYMAP_SENSORS + bool "Enable Keymap Sensors support" + default y + depends on DT_HAS_ZMK_KEYMAP_SENSORS_ENABLED + select SENSOR + +if ZMK_KEYMAP_SENSORS + +config ZMK_KEYMAP_SENSORS_DEFAULT_TRIGGERS_PER_ROTATION + int "Default triggers per rotation" + help + Unless overridden for a sensor in the board/shield/devicetree, this value + determines how many times to trigger the bound behavior per full rotation. + For tactile encoders with detents, this usually should match the number of + detents per rotation of the encoder. + default 20 + +endif # ZMK_KEYMAP_SENSORS + +choice CBPRINTF_IMPLEMENTATION + default CBPRINTF_NANO + +endchoice + +module = ZMK +module-str = zmk +source "subsys/logging/Kconfig.template.log_config" + +rsource "boards/Kconfig" +rsource "boards/shields/*/Kconfig.defconfig" +rsource "boards/shields/*/Kconfig.shield" + +osource "$(ZMK_CONFIG)/boards/shields/*/Kconfig.defconfig" +osource "$(ZMK_CONFIG)/boards/shields/*/Kconfig.shield" + + +source "Kconfig.zephyr" diff --git a/app/Kconfig.behaviors b/app/Kconfig.behaviors new file mode 100644 index 000000000000..11bc8c5900f1 --- /dev/null +++ b/app/Kconfig.behaviors @@ -0,0 +1,34 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config ZMK_BEHAVIOR_KEY_TOGGLE + bool + default y + depends on DT_HAS_ZMK_BEHAVIOR_KEY_TOGGLE_ENABLED + +config ZMK_BEHAVIOR_MOUSE_KEY_PRESS + bool + default y + depends on DT_HAS_ZMK_BEHAVIOR_MOUSE_KEY_PRESS_ENABLED + imply ZMK_MOUSE + +config ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON + bool + default n + +config ZMK_BEHAVIOR_SENSOR_ROTATE + bool + default y + depends on DT_HAS_ZMK_BEHAVIOR_SENSOR_ROTATE_ENABLED + select ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON + +config ZMK_BEHAVIOR_SENSOR_ROTATE_VAR + bool + default y + depends on DT_HAS_ZMK_BEHAVIOR_SENSOR_ROTATE_VAR_ENABLED + select ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON + +config ZMK_BEHAVIOR_MACRO + bool + default y + depends on DT_HAS_ZMK_BEHAVIOR_MACRO_ENABLED || DT_HAS_ZMK_BEHAVIOR_MACRO_ONE_PARAM_ENABLED || DT_HAS_ZMK_BEHAVIOR_MACRO_TWO_PARAM_ENABLED \ No newline at end of file diff --git a/app/boards/01space_rp2040_042lcd.conf b/app/boards/01space_rp2040_042lcd.conf new file mode 100644 index 000000000000..c520a3b73392 --- /dev/null +++ b/app/boards/01space_rp2040_042lcd.conf @@ -0,0 +1,6 @@ +CONFIG_ZMK_DISPLAY=y +CONFIG_LV_FONT_UNSCII_8=n +CONFIG_ZMK_USB=y +CONFIG_I2C=y +CONFIG_I2C_DW=y +CONFIG_LV_Z_VDB_SIZE=50 diff --git a/app/boards/01space_rp2040_042lcd.overlay b/app/boards/01space_rp2040_042lcd.overlay new file mode 100644 index 000000000000..d89e53f4a8e5 --- /dev/null +++ b/app/boards/01space_rp2040_042lcd.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "usb_console.dtsi" + +&xiao_serial { status = "disabled"; }; diff --git a/app/boards/Kconfig b/app/boards/Kconfig new file mode 100644 index 000000000000..fe841c487106 --- /dev/null +++ b/app/boards/Kconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +rsource "shields/*/Kconfig.shield" diff --git a/app/boards/adafruit_kb2040.conf b/app/boards/adafruit_kb2040.conf new file mode 100644 index 000000000000..21c1893d91f4 --- /dev/null +++ b/app/boards/adafruit_kb2040.conf @@ -0,0 +1,4 @@ +CONFIG_CONSOLE=n +CONFIG_SERIAL=n +CONFIG_UART_CONSOLE=n +CONFIG_ZMK_USB=y diff --git a/app/boards/adafruit_kb2040.overlay b/app/boards/adafruit_kb2040.overlay new file mode 100644 index 000000000000..b14e0d04d478 --- /dev/null +++ b/app/boards/adafruit_kb2040.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "usb_console.dtsi" + +&pro_micro_serial { status = "disabled"; }; diff --git a/app/boards/adafruit_qt_py_rp2040.conf b/app/boards/adafruit_qt_py_rp2040.conf new file mode 100644 index 000000000000..21c1893d91f4 --- /dev/null +++ b/app/boards/adafruit_qt_py_rp2040.conf @@ -0,0 +1,4 @@ +CONFIG_CONSOLE=n +CONFIG_SERIAL=n +CONFIG_UART_CONSOLE=n +CONFIG_ZMK_USB=y diff --git a/app/boards/adafruit_qt_py_rp2040.overlay b/app/boards/adafruit_qt_py_rp2040.overlay new file mode 100644 index 000000000000..d89e53f4a8e5 --- /dev/null +++ b/app/boards/adafruit_qt_py_rp2040.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "usb_console.dtsi" + +&xiao_serial { status = "disabled"; }; diff --git a/app/boards/arm/adafruit_kb2040/adafruit_kb2040.zmk.yml b/app/boards/arm/adafruit_kb2040/adafruit_kb2040.zmk.yml new file mode 100644 index 000000000000..c8973f5c2941 --- /dev/null +++ b/app/boards/arm/adafruit_kb2040/adafruit_kb2040.zmk.yml @@ -0,0 +1,9 @@ +file_format: "1" +id: adafruit_kb2040 +name: Adafruit KB2040 +type: board +arch: arm +outputs: + - usb +url: https://www.adafruit.com/product/5302 +exposes: [pro_micro] diff --git a/app/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.zmk.yml b/app/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.zmk.yml new file mode 100644 index 000000000000..9b9c1450d327 --- /dev/null +++ b/app/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.zmk.yml @@ -0,0 +1,9 @@ +file_format: "1" +id: adafruit_qt_py_rp2040 +name: Adafruit QT Py RP2040 +type: board +arch: arm +outputs: + - usb +url: https://www.adafruit.com/product/4900 +exposes: [seeed_xiao] diff --git a/app/boards/arm/adv360pro/Kconfig b/app/boards/arm/adv360pro/Kconfig new file mode 100644 index 000000000000..1840851c2bb5 --- /dev/null +++ b/app/boards/arm/adv360pro/Kconfig @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT + +config BOARD_ENABLE_DCDC + bool "Enable DCDC mode" + select SOC_DCDC_NRF52X + default y + depends on BOARD_ADV360PRO_LEFT || BOARD_ADV360PRO_RIGHT diff --git a/app/boards/arm/adv360pro/Kconfig.board b/app/boards/arm/adv360pro/Kconfig.board new file mode 100644 index 000000000000..51ebaec07916 --- /dev/null +++ b/app/boards/arm/adv360pro/Kconfig.board @@ -0,0 +1,12 @@ +# +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT +# + +config BOARD_ADV360PRO_LEFT + bool "adv360pro_left" + depends on SOC_NRF52840_QIAA + +config BOARD_ADV360PRO_RIGHT + bool "adv360pro_right" + depends on SOC_NRF52840_QIAA diff --git a/app/boards/arm/adv360pro/Kconfig.defconfig b/app/boards/arm/adv360pro/Kconfig.defconfig new file mode 100644 index 000000000000..0c4abacfbfae --- /dev/null +++ b/app/boards/arm/adv360pro/Kconfig.defconfig @@ -0,0 +1,55 @@ +# +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT +# + +if BOARD_ADV360PRO_LEFT + +config ZMK_KEYBOARD_NAME + default "Adv360 Pro" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif # BOARD_ADV360PRO_LEFT + +if BOARD_ADV360PRO_RIGHT + +config ZMK_KEYBOARD_NAME + default "Adv360 Pro rt" + +endif # BOARD_ADV360PRO_RIGHT + + +if BOARD_ADV360PRO_LEFT || BOARD_ADV360PRO_RIGHT + +config BOARD + default "adv360pro" + +config ZMK_SPLIT + default y + +config SPI + bool + default y + +config BT_CTLR + default BT + +if USB + +config USB_NRFX + default y + +config USB_DEVICE_STACK + default y + +endif # USB + +config ZMK_BATTERY_VOLTAGE_DIVIDER + default y + +config SPI + default y + +endif # BOARD_ADV360PRO_LEFT || BOARD_ADV360PRO_RIGHT diff --git a/app/boards/arm/adv360pro/README.md b/app/boards/arm/adv360pro/README.md new file mode 100755 index 000000000000..89fa1da51521 --- /dev/null +++ b/app/boards/arm/adv360pro/README.md @@ -0,0 +1,7 @@ +# Kinesis Advantage 360 Professional + +This board definition provides upstream support for the [Kinesis Advantage 360 Professional](https://kinesis-ergo.com/keyboards/advantage360/) + +Kinesis offer a specific [custom configuration](https://github.com/KinesisCorporation/Adv360-Pro-ZMK/) for the 360 Pro that references [a customised version of ZMK](https://github.com/ReFil/zmk/tree/adv360-z3.2-2) with Advantage 360 Pro specific functionality and changes over base ZMK. The Kinesis fork is regularly updated to bring the latest updates and changes from base ZMK however will not always be completely up to date, some features such as new keycodes will not be immediately available on the 360 Pro after they are implemented in base ZMK. + +When using this board definition some of the more advanced features (the indicator RGB leds) will not work, and Kinesis cannot provide customer service for usage of base ZMK. Likewise the ZMK community cannot provide support for either the Kinesis keymap editor, nor any usage of the Kinesis custom fork. diff --git a/app/boards/arm/adv360pro/adv360pro-pinctrl.dtsi b/app/boards/arm/adv360pro/adv360pro-pinctrl.dtsi new file mode 100644 index 000000000000..7dafcdcecf42 --- /dev/null +++ b/app/boards/arm/adv360pro/adv360pro-pinctrl.dtsi @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; + pwm0_default: pwm0_default { + group1 { + psels = ; + }; + }; + pwm0_sleep: pwm0_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/arm/adv360pro/adv360pro.dtsi b/app/boards/arm/adv360pro/adv360pro.dtsi new file mode 100644 index 000000000000..c837e518458a --- /dev/null +++ b/app/boards/arm/adv360pro/adv360pro.dtsi @@ -0,0 +1,157 @@ +/* +* +* Copyright (c) 2023 The ZMK Contributors +* SPDX-License-Identifier: MIT +* +*/ + +/dts-v1/; +#include + +#include +#include + +#include "adv360pro-pinctrl.dtsi" + +/ { + model = "Adv360 Pro"; + compatible = "kinesis,adv360pro"; + + chosen { + zephyr,code-partition = &code_partition; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + zmk,kscan = &kscan0; + zmk,backlight = &backlight; + zmk,battery = &vbatt; + zmk,matrix_transform = &default_transform; + zmk,underglow = &led_strip; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <20>; + rows = <5>; + + + map = < + RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,13) RC(4,14) RC(4,15) RC(4,16) RC(4,17) RC(4,18) RC(4,19) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,13) RC(3,14) RC(3,15) RC(3,16) RC(3,17) RC(3,18) RC(3,19) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,13) RC(2,14) RC(2,15) RC(2,16) RC(2,17) RC(2,18) RC(2,19) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,9) RC(1,10) RC(1,14) RC(1,15) RC(1,16) RC(1,17) RC(1,18) RC(1,19) + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,15) RC(0,16) RC(0,17) RC(0,18) RC(0,19) + + >; + }; + ext-power { + compatible = "zmk,ext-power-generic"; + control-gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>; + }; + + vbatt: vbatt { + compatible = "zmk,battery-voltage-divider"; + io-channels = <&adc 2>; + output-ohms = <100000>; + full-ohms = <(100000 + 100000)>; + }; + + backlight: pwmleds { + compatible = "pwm-leds"; + pwm_led_0 { + pwms = <&pwm0 0 10000 PWM_POLARITY_NORMAL>; + }; + }; + +}; + +&pwm0 { + status = "okay"; + pinctrl-0 = <&pwm0_default>; + pinctrl-1 = <&pwm0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + sd_partition: partition@0 { + reg = <0x00000000 0x00026000>; + }; + code_partition: partition@26000 { + reg = <0x00026000 0x000c6000>; + }; + + /* + * The flash starting at 0x000ec000 and ending at + * 0x000f3fff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@ec000 { + reg = <0x000ec000 0x00008000>; + }; + + boot_partition: partition@f4000 { + reg = <0x000f4000 0x0000c000>; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <3>; /* number of LEDs */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; diff --git a/app/boards/arm/adv360pro/adv360pro.keymap b/app/boards/arm/adv360pro/adv360pro.keymap new file mode 100644 index 000000000000..999781e437ff --- /dev/null +++ b/app/boards/arm/adv360pro/adv360pro.keymap @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp EQUAL &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &tog 1 &mo 3 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS + &kp TAB &kp Q &kp W &kp E &kp R &kp T &none &none &kp Y &kp U &kp I &kp O &kp P &kp BSLH + &kp ESC &kp A &kp S &kp D &kp F &kp G &none &kp LCTRL &kp LALT &kp LGUI &kp RCTRL &none &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp HOME &kp PG_UP &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &mo 2 &kp GRAVE &kp CAPS &kp LEFT &kp RIGHT &kp BSPC &kp DEL &kp END &kp PG_DN &kp ENTER &kp SPACE &kp UP &kp DOWN &kp LBKT &kp RBKT &mo 2 + >; + }; + keypad { + bindings = < + &kp EQUAL &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &trans &mo 3 &kp N6 &kp KP_NUM &kp KP_EQUAL &kp KP_DIVIDE &kp KP_MULTIPLY &kp MINUS + &kp TAB &kp Q &kp W &kp E &kp R &kp T &none &none &kp Y &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_MINUS &kp BSLH + &kp ESC &kp A &kp S &kp D &kp F &kp G &none &kp LCTRL &kp LALT &kp LGUI &kp RCTRL &none &kp H &kp KP_N4 &kp KP_N5 &kp KP_N6 &kp KP_PLUS &kp SQT + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp HOME &kp PG_UP &kp N &kp KP_N1 &kp KP_N2 &kp KP_N3 &kp KP_ENTER &kp RSHFT + &mo 2 &kp GRAVE &kp CAPS &kp LEFT &kp RIGHT &kp BSPC &kp DEL &kp END &kp PG_DN &kp ENTER &kp KP_N0 &kp UP &kp DOWN &kp KP_DOT &kp RBKT &mo 2 + >; + }; + fn { + bindings = < + &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &tog 1 &mo 3 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 + &trans &trans &trans &trans &trans &trans &none &none &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &none &trans &trans &trans &trans &none &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + }; + mod { + bindings = < + &none &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &none &trans &none &none &none &none &none &none + &none &none &none &none &none &none &bootloader &bootloader &none &none &none &none &none &none + &none &none &none &none &none &none &none &none &none &bt BT_CLR &none &none &none &none &none &none &none &none + &none &none &none &none &none &none &none &none &none &none &none &none &none &none + &none &none &none &none &none &none &none &none &none &bl BL_TOG &rgb_ug RGB_TOG &bl BL_INC &bl BL_DEC &none &none &none + >; + }; + }; +}; diff --git a/app/boards/arm/adv360pro/adv360pro.yaml b/app/boards/arm/adv360pro/adv360pro.yaml new file mode 100644 index 000000000000..2d555d4e20ce --- /dev/null +++ b/app/boards/arm/adv360pro/adv360pro.yaml @@ -0,0 +1,19 @@ +identifier: adv360pro +name: Advantage 360 Pro +type: keyboard +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - gpio + - i2c + - counter + - spi + - usb_device + - nvs + - can + - kscan + - ble + - pwm diff --git a/app/boards/arm/adv360pro/adv360pro.zmk.yml b/app/boards/arm/adv360pro/adv360pro.zmk.yml new file mode 100644 index 000000000000..7d4a4b44495f --- /dev/null +++ b/app/boards/arm/adv360pro/adv360pro.zmk.yml @@ -0,0 +1,16 @@ +file_format: "1" +id: adv360pro +name: Advantage 360 Pro +type: board +url: https://kinesis-ergo.com/keyboards/advantage360 +arch: arm +features: + - keys + - underglow + - backlight +outputs: + - usb + - ble +siblings: + - adv360pro_left + - adv360pro_right diff --git a/app/boards/arm/adv360pro/adv360pro_left.dts b/app/boards/arm/adv360pro/adv360pro_left.dts new file mode 100644 index 000000000000..6ef5f59071b3 --- /dev/null +++ b/app/boards/arm/adv360pro/adv360pro_left.dts @@ -0,0 +1,36 @@ +/* +* +* Copyright (c) 2023 The ZMK Contributors +* SPDX-License-Identifier: MIT +* +*/ + +#include "adv360pro.dtsi" + +/{ + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&gpio1 11 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 12 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + col-gpios + = <&gpio0 25 GPIO_ACTIVE_HIGH> + , <&gpio0 11 GPIO_ACTIVE_HIGH> + , <&gpio0 2 GPIO_ACTIVE_HIGH> + , <&gpio0 28 GPIO_ACTIVE_HIGH> + , <&gpio0 29 GPIO_ACTIVE_HIGH> + , <&gpio0 30 GPIO_ACTIVE_HIGH> + , <&gpio0 31 GPIO_ACTIVE_HIGH> + , <&gpio1 9 GPIO_ACTIVE_HIGH> + , <&gpio0 12 GPIO_ACTIVE_HIGH> + , <&gpio0 7 GPIO_ACTIVE_HIGH> + ; + }; +}; diff --git a/app/boards/arm/adv360pro/adv360pro_left_defconfig b/app/boards/arm/adv360pro/adv360pro_left_defconfig new file mode 100644 index 000000000000..6eb5a8d042af --- /dev/null +++ b/app/boards/arm/adv360pro/adv360pro_left_defconfig @@ -0,0 +1,55 @@ +# +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT +# + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_ADV360PRO_LEFT=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable SPI for LEDS +CONFIG_PINCTRL=y +CONFIG_SPI=y +CONFIG_SPI_NRFX=y + +# Enable writing to flash +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +# Enable 32kHz crystal +CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_150PPM=y + +#RGB leds config +CONFIG_WS2812_STRIP=y +CONFIG_ZMK_RGB_UNDERGLOW=y +CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER=y +CONFIG_ZMK_RGB_UNDERGLOW_ON_START=n +CONFIG_ZMK_RGB_UNDERGLOW_EFF_START=0 +CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE=y + +#Backlighting configuration +CONFIG_PWM=y +CONFIG_LED_PWM=y +CONFIG_ZMK_BACKLIGHT=y +CONFIG_ZMK_BACKLIGHT_BRT_START=20 +CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE=y + +#Misc configuration +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y +CONFIG_ZMK_HID_REPORT_TYPE_NKRO=y +CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_BASIC=y +CONFIG_BUILD_OUTPUT_UF2=y +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y diff --git a/app/boards/arm/adv360pro/adv360pro_right.dts b/app/boards/arm/adv360pro/adv360pro_right.dts new file mode 100644 index 000000000000..97d846f855cd --- /dev/null +++ b/app/boards/arm/adv360pro/adv360pro_right.dts @@ -0,0 +1,40 @@ +/* +* +* Copyright (c) 2023 The ZMK Contributors +* SPDX-License-Identifier: MIT +* +*/ + +#include "adv360pro.dtsi" + +/{ + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&gpio0 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 31 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 30 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 29 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + col-gpios + = <&gpio0 12 GPIO_ACTIVE_HIGH> + , <&gpio1 9 GPIO_ACTIVE_HIGH> + , <&gpio0 7 GPIO_ACTIVE_HIGH> + , <&gpio1 11 GPIO_ACTIVE_HIGH> + , <&gpio1 10 GPIO_ACTIVE_HIGH> + , <&gpio1 13 GPIO_ACTIVE_HIGH> + , <&gpio1 15 GPIO_ACTIVE_HIGH> + , <&gpio0 3 GPIO_ACTIVE_HIGH> + , <&gpio0 2 GPIO_ACTIVE_HIGH> + , <&gpio0 28 GPIO_ACTIVE_HIGH> + ; + }; +}; + +&default_transform { + col-offset = <10>; +}; diff --git a/app/boards/arm/adv360pro/adv360pro_right_defconfig b/app/boards/arm/adv360pro/adv360pro_right_defconfig new file mode 100644 index 000000000000..b5174549ea47 --- /dev/null +++ b/app/boards/arm/adv360pro/adv360pro_right_defconfig @@ -0,0 +1,54 @@ +# +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT +# + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_ADV360PRO_RIGHT=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable SPI for LEDS +CONFIG_PINCTRL=y +CONFIG_SPI=y +CONFIG_SPI_NRFX=y + +# Enable writing to flash +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +# Enable 32kHz crystal +CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_150PPM=y + +#RGB leds config +CONFIG_WS2812_STRIP=y +CONFIG_ZMK_RGB_UNDERGLOW=y +CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER=y +CONFIG_ZMK_RGB_UNDERGLOW_ON_START=n +CONFIG_ZMK_RGB_UNDERGLOW_EFF_START=0 +CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE=y + +#Backlighting configuration +CONFIG_PWM=y +CONFIG_LED_PWM=y +CONFIG_ZMK_BACKLIGHT=y +CONFIG_ZMK_BACKLIGHT_BRT_START=20 +CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE=y + +#Misc configuration +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y +CONFIG_ZMK_HID_REPORT_TYPE_NKRO=y +CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_BASIC=y +CONFIG_BUILD_OUTPUT_UF2=y +CONFIG_ZMK_BLE=y diff --git a/app/boards/arm/adv360pro/board.cmake b/app/boards/arm/adv360pro/board.cmake new file mode 100644 index 000000000000..6d62a8a16bf0 --- /dev/null +++ b/app/boards/arm/adv360pro/board.cmake @@ -0,0 +1,8 @@ +# +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT +# + +board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") + +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) diff --git a/app/boards/arm/bdn9/Kconfig.board b/app/boards/arm/bdn9/Kconfig.board new file mode 100644 index 000000000000..76a204cc41a5 --- /dev/null +++ b/app/boards/arm/bdn9/Kconfig.board @@ -0,0 +1,8 @@ +# keeb.io BDN9 board configuration + +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_BDN9 + bool "BDN9 rev2" + depends on SOC_STM32F072XB diff --git a/app/boards/arm/bdn9/Kconfig.defconfig b/app/boards/arm/bdn9/Kconfig.defconfig new file mode 100644 index 000000000000..96b7fe55329f --- /dev/null +++ b/app/boards/arm/bdn9/Kconfig.defconfig @@ -0,0 +1,18 @@ +# keeb.io BDN9 board configuration + +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if BOARD_BDN9 + +config BOARD + default "bdn9_rev2" + +config ZMK_KEYBOARD_NAME + default "BDN9 Rev2" + +config ZMK_RGB_UNDERGLOW + select SPI + select WS2812_STRIP + +endif # BOARD_BDN9 diff --git a/app/boards/arm/bdn9/README.md b/app/boards/arm/bdn9/README.md new file mode 100644 index 000000000000..7b4ef4417bda --- /dev/null +++ b/app/boards/arm/bdn9/README.md @@ -0,0 +1,37 @@ +# Building ZMK for the BDN9 + +Some general notes/commands for building standard BDN9 layouts from the assembly documentation. + +## Standard Build + +``` +west build -p -d build/bdn9 --board bdn9_rev2 +``` + +## Encoder Notes + +If you built your BDN9 with encoders, you'll need to change the following in your local BDN9 config or add them to the end of the file. + +``` +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y +``` + +Then, you'll want to uncomment the necessary encoder lines in your `bdn9_rev2.keymap`: + +``` +&sensors { + status = "okay"; + sensors = <&left_encoder &mid_encoder &right_encoder>; +}; + +&left_encoder { status = "okay"; }; +&mid_encoder { status = "okay"; }; +&right_encoder { status = "okay"; }; +``` + +And then add the correct `sensor-bindings` array to each keymap layer, e.g.: + +``` +sensor-bindings = <&inc_dec_kp PG_UP PG_DN &inc_dec_kp M_VOLU M_VOLD &inc_dec_kp C_PREV C_NEXT>; +``` diff --git a/app/boards/arm/bdn9/bdn9_rev2.conf b/app/boards/arm/bdn9/bdn9_rev2.conf new file mode 100644 index 000000000000..f6506a065d0f --- /dev/null +++ b/app/boards/arm/bdn9/bdn9_rev2.conf @@ -0,0 +1,9 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Uncomment these lines below to enable encoders. +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# Uncomment the line below to enable RGB. +# CONFIG_ZMK_RGB_UNDERGLOW=y diff --git a/app/boards/arm/bdn9/bdn9_rev2.dts b/app/boards/arm/bdn9/bdn9_rev2.dts new file mode 100644 index 000000000000..6e15408a2cd0 --- /dev/null +++ b/app/boards/arm/bdn9/bdn9_rev2.dts @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include +#include +#include + +/ { + model = "Keeb.io BDN9 rev2"; + compatible = "keebio,bdn9", "st,stm32f072"; + + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + zmk,kscan = &kscan; + zmk,underglow = &led_strip; + }; + + kscan: kscan { + compatible = "zmk,kscan-gpio-direct"; + + input-gpios + = <&gpiob 12 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpiob 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpiob 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpiob 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpiob 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpiob 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpioa 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpiof 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpiof 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; + }; + + left_encoder: encoder_left { + compatible = "alps,ec11"; + a-gpios = <&gpioa 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&gpioa 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + mid_encoder: encoder_mid { + compatible = "alps,ec11"; + a-gpios = <&gpioa 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&gpioa 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + right_encoder: encoder_right { + compatible = "alps,ec11"; + a-gpios = <&gpioa 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&gpiob 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + sensors: sensors { + compatible = "zmk,keymap-sensors"; + status = "disabled"; + sensors = <>; + triggers-per-rotation = <20>; + }; +}; + +&spi2 { + status = "okay"; + pinctrl-0 = <&spi2_sck_pb13 &spi2_mosi_pb15>; + pinctrl-names = "default"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <9>; + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +&clk_hsi { + status = "okay"; +}; + +&pll { + status = "okay"; + prediv = <1>; + mul = <6>; + clocks = <&clk_hsi>; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <1>; +}; + +&usb { + status = "okay"; + pinctrl-0 = <&usb_dm_pa11 &usb_dp_pa12>; + pinctrl-names = "default"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + +&rtc { + status = "okay"; +}; + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/guides/dts/index.html#flash-partitions + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Set 6Kb of storage at the end of the 128Kb of flash */ + storage_partition: partition@1e800 { + reg = <0x0001e800 0x00001800>; + }; + }; +}; diff --git a/app/boards/arm/bdn9/bdn9_rev2.keymap b/app/boards/arm/bdn9/bdn9_rev2.keymap new file mode 100644 index 000000000000..1e2c192dd6f8 --- /dev/null +++ b/app/boards/arm/bdn9/bdn9_rev2.keymap @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +/* Uncomment and keep whatever encoders are on your BDN9 +&sensors { + status = "okay"; + sensors = <&left_encoder &mid_encoder &right_encoder>; +}; +*/ + +// Uncomment each encoder installed on your BDN9 +// &left_encoder { status = "okay"; }; +// &mid_encoder { status = "okay"; }; +// &right_encoder { status = "okay"; }; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp HOME &kp K_PP &kp END + &kp PG_UP &kp UP &kp PG_DN + &kp LEFT &kp DOWN &kp RIGHT + >; + /* Uncomment and add necessary bindings. This examples is for one encoder + sensor-bindings = <&inc_dec_kp PG_UP PG_DN>; + */ + }; + }; +}; + diff --git a/app/boards/arm/bdn9/bdn9_rev2.yaml b/app/boards/arm/bdn9/bdn9_rev2.yaml new file mode 100644 index 000000000000..bbae8833031e --- /dev/null +++ b/app/boards/arm/bdn9/bdn9_rev2.yaml @@ -0,0 +1,14 @@ +identifier: bdn9 +name: keeb.io BDN9 +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 40 +supported: + - encoders + - switches + - underglow + - per_key diff --git a/app/boards/arm/bdn9/bdn9_rev2.yml b/app/boards/arm/bdn9/bdn9_rev2.yml new file mode 100644 index 000000000000..01ebd3e0b5cc --- /dev/null +++ b/app/boards/arm/bdn9/bdn9_rev2.yml @@ -0,0 +1,11 @@ +file_format: "1" +id: bdn9_rev2 +name: BDN9 Rev2 +type: board +arch: arm +features: + - keys + - encoder +outputs: + - usb +url: https://keeb.io/products/bdn9-rev-2-3x3-9-key-macropad-rotary-encoder-and-rgb diff --git a/app/boards/arm/bdn9/bdn9_rev2.zmk.yml b/app/boards/arm/bdn9/bdn9_rev2.zmk.yml new file mode 100644 index 000000000000..4680746f22d9 --- /dev/null +++ b/app/boards/arm/bdn9/bdn9_rev2.zmk.yml @@ -0,0 +1,11 @@ +file_format: "1" +id: bdn9_rev2 +name: BDN9 Rev2 +type: board +arch: arm +outputs: + - usb +features: + - keys + - encoder +url: https://keeb.io/collections/bdn9-collection/products/bdn9-rev-2-3x3-9-key-macropad-rotary-encoder-and-rgb diff --git a/app/boards/arm/bdn9/bdn9_rev2_defconfig b/app/boards/arm/bdn9/bdn9_rev2_defconfig new file mode 100644 index 000000000000..05087eeb4c65 --- /dev/null +++ b/app/boards/arm/bdn9/bdn9_rev2_defconfig @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_STM32F0X=y +CONFIG_SOC_STM32F072XB=y +# 72MHz system clock +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=72000000 + +# Floating Point Options +CONFIG_FPU=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable pinctrl +CONFIG_PINCTRL=y + +# Poll to avoid interrupt overlap issues +CONFIG_ZMK_KSCAN_DIRECT_POLLING=y + +# Needed to reduce this to size that will fit on F072 +CONFIG_HEAP_MEM_POOL_SIZE=1024 + +# clock configuration +CONFIG_CLOCK_CONTROL=y + +CONFIG_ZMK_USB=y \ No newline at end of file diff --git a/app/boards/arm/bdn9/board.cmake b/app/boards/arm/bdn9/board.cmake new file mode 100644 index 000000000000..4f430e12b0ea --- /dev/null +++ b/app/boards/arm/bdn9/board.cmake @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT + +board_runner_args(dfu-util "--pid=0483:df11" "--alt=0" "--dfuse") +board_runner_args(jlink "--device=STM32F072CB" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/dfu-util.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/app/boards/arm/blackpill_f401ce/blackpill_f401ce.zmk.yml b/app/boards/arm/blackpill_f401ce/blackpill_f401ce.zmk.yml new file mode 100644 index 000000000000..251d2c27231d --- /dev/null +++ b/app/boards/arm/blackpill_f401ce/blackpill_f401ce.zmk.yml @@ -0,0 +1,9 @@ +file_format: "1" +id: blackpill_f401ce +name: BlackPill F401CE +type: board +arch: arm +outputs: + - usb +url: https://github.com/WeActStudio/WeActStudio.MiniSTM32F4x1 +exposes: [blackpill] diff --git a/app/boards/arm/blackpill_f411ce/blackpill_f411ce.zmk.yml b/app/boards/arm/blackpill_f411ce/blackpill_f411ce.zmk.yml new file mode 100644 index 000000000000..eaa714d69af4 --- /dev/null +++ b/app/boards/arm/blackpill_f411ce/blackpill_f411ce.zmk.yml @@ -0,0 +1,9 @@ +file_format: "1" +id: blackpill_f411ce +name: BlackPill F411CE +type: board +arch: arm +outputs: + - usb +url: https://github.com/WeActStudio/WeActStudio.MiniSTM32F4x1 +exposes: [blackpill] diff --git a/app/boards/arm/bluemicro840/Kconfig b/app/boards/arm/bluemicro840/Kconfig new file mode 100644 index 000000000000..ca060885f16c --- /dev/null +++ b/app/boards/arm/bluemicro840/Kconfig @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: MIT + +config BOARD_ENABLE_DCDC + bool "Enable DCDC mode" + select SOC_DCDC_NRF52X + default y + depends on BOARD_BLUEMICRO840_V1 + diff --git a/app/boards/arm/bluemicro840/Kconfig.board b/app/boards/arm/bluemicro840/Kconfig.board new file mode 100644 index 000000000000..e27940157b21 --- /dev/null +++ b/app/boards/arm/bluemicro840/Kconfig.board @@ -0,0 +1,8 @@ +# BlueMicro840 board configuration + +# Copyright (c) 2020 Pete Johanson, Derek Schmell +# SPDX-License-Identifier: MIT + +config BOARD_BLUEMICRO840_V1 + bool "BlueMicro840_V1" + depends on SOC_NRF52840_QIAA diff --git a/app/boards/arm/bluemicro840/Kconfig.defconfig b/app/boards/arm/bluemicro840/Kconfig.defconfig new file mode 100644 index 000000000000..ff61ec92f81b --- /dev/null +++ b/app/boards/arm/bluemicro840/Kconfig.defconfig @@ -0,0 +1,21 @@ +# BlueMicro840 board configuration + +# Copyright (c) 2020 Pete Johanson, Derek Schmell +# SPDX-License-Identifier: MIT + +if BOARD_BLUEMICRO840_V1 + +config BOARD + default "bluemicro840_v1" + +if USB_DEVICE_STACK + +config USB_NRFX + default y + +endif # USB_DEVICE_STACK + +config BT_CTLR + default BT + +endif # BOARD_BLUEMICRO840_V1 diff --git a/app/boards/arm/bluemicro840/arduino_pro_micro_pins.dtsi b/app/boards/arm/bluemicro840/arduino_pro_micro_pins.dtsi new file mode 100644 index 000000000000..cdb8fcdd3fd0 --- /dev/null +++ b/app/boards/arm/bluemicro840/arduino_pro_micro_pins.dtsi @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 Derek Schmell + * + * SPDX-License-Identifier: MIT + */ + +/ { + pro_micro: connector { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &gpio0 8 0> /* D0 D2 */ + , <1 0 &gpio0 6 0> /* D1 D3*/ + , <2 0 &gpio0 15 0> /* D2 D1*/ + , <3 0 &gpio0 17 0> /* D3 D0*/ + , <4 0 &gpio0 20 0> /* D4/A6 D4*/ + , <5 0 &gpio0 13 0> /* D5 C6*/ + , <6 0 &gpio0 24 0> /* D6/A7 D7*/ + , <7 0 &gpio0 9 0> /* D7 E6*/ + , <8 0 &gpio0 10 0> /* D8/A8 B4*/ + , <9 0 &gpio1 6 0> /* D9/A9 B5*/ + , <10 0 &gpio1 11 0> /* D10/A10 B6*/ + , <16 0 &gpio0 28 0> /* D16 B2*/ + , <14 0 &gpio0 3 0> /* D14 B3*/ + , <15 0 &gpio1 13 0> /* D15 B1*/ + , <18 0 &gpio0 2 0> /* D18/A0 F7*/ + , <19 0 &gpio0 29 0> /* D19/A1 F6*/ + , <20 0 &gpio0 26 0> /* D20/A2 F5*/ + , <21 0 &gpio0 30 0> /* D21/A3 F4*/ + ; + }; + + pro_micro_a: connector_a { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &gpio0 2 0> /* D18/A0 F7*/ + , <1 0 &gpio0 29 0> /* D19/A1 F6*/ + , <2 0 &gpio0 26 0> /* D20/A2 F5*/ + , <3 0 &gpio0 30 0> /* D21/A3 F4*/ + , <6 0 &gpio0 20 0> /* D4/A6 D4*/ + , <7 0 &gpio0 24 0> /* D6/A7 D7*/ + , <8 0 &gpio0 10 0> /* D8/A8 B4*/ + , <9 0 &gpio1 6 0> /* D9/A9 B5*/ + , <10 0 &gpio1 11 0> /* D10/A10 B6*/ + ; + }; +}; + +pro_micro_d: &pro_micro {}; +pro_micro_i2c: &i2c0 {}; +pro_micro_spi: &spi0 {}; +pro_micro_serial: &uart0 {}; diff --git a/app/boards/arm/bluemicro840/bluemicro840_v1-pinctrl.dtsi b/app/boards/arm/bluemicro840/bluemicro840_v1-pinctrl.dtsi new file mode 100644 index 000000000000..868d3c27ad70 --- /dev/null +++ b/app/boards/arm/bluemicro840/bluemicro840_v1-pinctrl.dtsi @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = ; + bias-pull-up; + }; + group2 { + psels = ; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + i2c0_default: i2c0_default { + group1 { + psels = , + ; + }; + }; + + i2c0_sleep: i2c0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; diff --git a/app/boards/arm/bluemicro840/bluemicro840_v1.dts b/app/boards/arm/bluemicro840/bluemicro840_v1.dts new file mode 100644 index 000000000000..408cca3be76e --- /dev/null +++ b/app/boards/arm/bluemicro840/bluemicro840_v1.dts @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2020 Pete Johanson, Derek Schmell + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include +#include "arduino_pro_micro_pins.dtsi" +#include "bluemicro840_v1-pinctrl.dtsi" + +/ { + model = "BlueMicro840_V1"; + compatible = "bluemicro840,v1"; + + chosen { + zephyr,code-partition = &code_partition; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + zmk,battery = &vbatt; + }; + + leds { + compatible = "gpio-leds"; + blue_led: led_0 { + gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + }; + }; + + // Node name must match original "EXT_POWER" label to preserve user settings. + EXT_POWER { + compatible = "zmk,ext-power-generic"; + init-delay-ms = <20>; + control-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>; + }; + + vbatt: vbatt { + compatible = "zmk,battery-voltage-divider"; + io-channels = <&adc 7>; + output-ohms = <2000000>; + full-ohms = <(2000000 + 806000)>; + }; + +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&i2c0 { + compatible = "nordic,nrf-twi"; + pinctrl-0 = <&i2c0_default>; + pinctrl-1 = <&i2c0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart0 { + compatible = "nordic,nrf-uarte"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + sd_partition: partition@0 { + reg = <0x00000000 0x00026000>; + }; + code_partition: partition@26000 { + reg = <0x00026000 0x000c6000>; + }; + + /* + * The flash starting at 0x000ec000 and ending at + * 0x000f3fff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@ec000 { + reg = <0x000ec000 0x00008000>; + }; + + boot_partition: partition@f4000 { + reg = <0x000f4000 0x0000c000>; + }; + }; +}; diff --git a/app/boards/arm/bluemicro840/bluemicro840_v1.yaml b/app/boards/arm/bluemicro840/bluemicro840_v1.yaml new file mode 100644 index 000000000000..9e1dd54c29c7 --- /dev/null +++ b/app/boards/arm/bluemicro840/bluemicro840_v1.yaml @@ -0,0 +1,15 @@ +identifier: bluemicro840_v1 +name: BlueMicro840_V1 +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog diff --git a/app/boards/arm/bluemicro840/bluemicro840_v1.zmk.yml b/app/boards/arm/bluemicro840/bluemicro840_v1.zmk.yml new file mode 100644 index 000000000000..c1d3c6b94632 --- /dev/null +++ b/app/boards/arm/bluemicro840/bluemicro840_v1.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: bluemicro840_v1 +name: BlueMicro840 v1 +type: board +arch: arm +outputs: + - usb + - ble +url: https://nrf52.jpconstantineau.com/docs/bluemicro840_v1/ +exposes: [pro_micro] diff --git a/app/boards/arm/bluemicro840/bluemicro840_v1_defconfig b/app/boards/arm/bluemicro840/bluemicro840_v1_defconfig new file mode 100644 index 000000000000..3e13e77d0b5e --- /dev/null +++ b/app/boards/arm/bluemicro840/bluemicro840_v1_defconfig @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_BLUEMICRO840_V1=y + +# Enable MPU +CONFIG_ARM_MPU=y + +CONFIG_PINCTRL=y + +# enable GPIO +CONFIG_GPIO=y + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y diff --git a/app/boards/arm/bluemicro840/board.cmake b/app/boards/arm/bluemicro840/board.cmake new file mode 100644 index 000000000000..fa847d505952 --- /dev/null +++ b/app/boards/arm/bluemicro840/board.cmake @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: MIT + +board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") +include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) diff --git a/app/boards/arm/boardsource_blok/boardsource_blok.zmk.yml b/app/boards/arm/boardsource_blok/boardsource_blok.zmk.yml new file mode 100644 index 000000000000..a6e91afd703a --- /dev/null +++ b/app/boards/arm/boardsource_blok/boardsource_blok.zmk.yml @@ -0,0 +1,9 @@ +file_format: "1" +id: boardsource_blok +name: BoardSource blok +type: board +arch: arm +outputs: + - usb +url: https://peg.software/docs/blok +exposes: [pro_micro] diff --git a/app/boards/arm/bt60/Kconfig b/app/boards/arm/bt60/Kconfig new file mode 100644 index 000000000000..d57a6b7efe30 --- /dev/null +++ b/app/boards/arm/bt60/Kconfig @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT + +config BOARD_ENABLE_DCDC + bool "Enable DCDC mode" + select SOC_DCDC_NRF52X + default y + depends on (BOARD_BT60_V1_HS || BOARD_BT60_V1) diff --git a/app/boards/arm/bt60/Kconfig.board b/app/boards/arm/bt60/Kconfig.board new file mode 100644 index 000000000000..24c0a8b5b0c3 --- /dev/null +++ b/app/boards/arm/bt60/Kconfig.board @@ -0,0 +1,12 @@ +# BT60 board configuration + +# Copyright (c) 2021 Polarity Works +# SPDX-License-Identifier: MIT + +config BOARD_BT60_V1 + bool "bt60" + depends on SOC_NRF52840_QIAA + +config BOARD_BT60_V1_HS + bool "bt60 hotswap" + depends on SOC_NRF52840_QIAA diff --git a/app/boards/arm/bt60/Kconfig.defconfig b/app/boards/arm/bt60/Kconfig.defconfig new file mode 100644 index 000000000000..c44901bd8d42 --- /dev/null +++ b/app/boards/arm/bt60/Kconfig.defconfig @@ -0,0 +1,25 @@ +# Copyright (c) 2021 Polarity Works +# SPDX-License-Identifier: MIT + +if BOARD_BT60_V1_HS || BOARD_BT60_V1 + +config BOARD + default "bt60" + +if USB + +config USB_NRFX + default y + +config USB_DEVICE_STACK + default y + +endif # USB + +config BT_CTLR + default BT + +config ZMK_KEYBOARD_NAME + default "BT60" + +endif # BOARD_BT60 diff --git a/app/boards/arm/bt60/board.cmake b/app/boards/arm/bt60/board.cmake new file mode 100644 index 000000000000..fa847d505952 --- /dev/null +++ b/app/boards/arm/bt60/board.cmake @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: MIT + +board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") +include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) diff --git a/app/boards/arm/bt60/bt60.dtsi b/app/boards/arm/bt60/bt60.dtsi new file mode 100644 index 000000000000..68d817ea9c75 --- /dev/null +++ b/app/boards/arm/bt60/bt60.dtsi @@ -0,0 +1,127 @@ +/* +* Copyright (c) 2021 Polarity Works +* +* SPDX-License-Identifier: MIT +*/ + +/dts-v1/; +#include +#include + +/ { + model = "BT60"; + compatible = "polarityworks,bt60"; + + chosen { + zephyr,code-partition = &code_partition; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + zmk,battery = &vbatt; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + sensors: sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder>; + triggers-per-rotation = <20>; + }; + + + + left_encoder: encoder_left { + compatible = "alps,ec11"; + a-gpios = <&gpio1 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&gpio1 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + status = "okay"; + }; + + + leds { + compatible = "gpio-leds"; + blue_led: led_0 { + gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; + }; + }; + + vbatt: vbatt { + compatible = "zmk,battery-voltage-divider"; + io-channels = <&adc 2>; + output-ohms = <2000000>; + full-ohms = <(2000000 + 806000)>; + }; +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&i2c0 { + compatible = "nordic,nrf-twi"; + sda-pin = <17>; + scl-pin = <20>; +}; + +&uart0 { + compatible = "nordic,nrf-uarte"; + tx-pin = <6>; + rx-pin = <8>; +}; + +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + sd_partition: partition@0 { + reg = <0x00000000 0x00026000>; + }; + code_partition: partition@26000 { + reg = <0x00026000 0x000c6000>; + }; + + /* + * The flash starting at 0x000ec000 and ending at + * 0x000f3fff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@ec000 { + reg = <0x000ec000 0x00008000>; + }; + + boot_partition: partition@f4000 { + reg = <0x000f4000 0x0000c000>; + }; + }; +}; diff --git a/app/boards/arm/bt60/bt60_v1.dts b/app/boards/arm/bt60/bt60_v1.dts new file mode 100644 index 000000000000..4f66a0c20e3e --- /dev/null +++ b/app/boards/arm/bt60/bt60_v1.dts @@ -0,0 +1,112 @@ +/* +* Copyright (c) 2021 Polarity Works +* +* SPDX-License-Identifier: MIT +*/ + +/dts-v1/; +#include "bt60.dtsi" + + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &ansi_transform; + }; + + ansi_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <15>; + rows = <5>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,13) + RC(3,0) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) + RC(4,0) RC(4,1) RC(4,2) RC(4,6) RC(4,10) RC(4,11) RC(4,12) RC(4,13) RC(4,14) + >; + }; + + hhkb_transform: keymap_transform_1 { + compatible = "zmk,matrix-transform"; + columns = <15>; + rows = <5>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,13) + RC(3,0) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) RC(3,14) + RC(4,0) RC(4,1) RC(4,2) RC(4,6) RC(4,10) RC(4,11) RC(4,12) RC(4,13) + >; + }; + + iso_transform: keymap_transform_2 { + compatible = "zmk,matrix-transform"; + columns = <15>; + rows = <5>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) + RC(4,0) RC(4,1) RC(4,2) RC(4,6) RC(4,10) RC(4,11) RC(4,12) RC(4,13) + >; + }; + + all_1u_transform: keymap_transform_3 { + compatible = "zmk,matrix-transform"; + columns = <15>; + rows = <5>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,13) + RC(3,0) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) RC(3,13) RC(3,14) + RC(4,0) RC(4,1) RC(4,2) RC(4,6) RC(4,10) RC(4,11) RC(4,12) RC(4,13) RC(4,14) + >; + }; + + split_transform: keymap_transform_4 { + compatible = "zmk,matrix-transform"; + columns = <15>; + rows = <5>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,13) + RC(3,0) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) RC(3,14) + RC(4,0) RC(4,1) RC(4,2) RC(4,6) RC(4,10) RC(4,11) RC(4,12) RC(4,13) + >; + }; + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + col-gpios + = <&gpio1 13 GPIO_ACTIVE_HIGH> + , <&gpio1 10 GPIO_ACTIVE_HIGH> + , <&gpio1 11 GPIO_ACTIVE_HIGH> + , <&gpio1 15 GPIO_ACTIVE_HIGH> + , <&gpio0 3 GPIO_ACTIVE_HIGH> + , <&gpio0 2 GPIO_ACTIVE_HIGH> + , <&gpio0 28 GPIO_ACTIVE_HIGH> + , <&gpio0 29 GPIO_ACTIVE_HIGH> + , <&gpio0 30 GPIO_ACTIVE_HIGH> + , <&gpio0 31 GPIO_ACTIVE_HIGH> + , <&gpio0 5 GPIO_ACTIVE_HIGH> + , <&gpio0 7 GPIO_ACTIVE_HIGH> + , <&gpio1 9 GPIO_ACTIVE_HIGH> + , <&gpio0 12 GPIO_ACTIVE_HIGH> + , <&gpio0 23 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&gpio1 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 22 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; diff --git a/app/boards/arm/bt60/bt60_v1.keymap b/app/boards/arm/bt60/bt60_v1.keymap new file mode 100644 index 000000000000..25ae269d306d --- /dev/null +++ b/app/boards/arm/bt60/bt60_v1.keymap @@ -0,0 +1,180 @@ +#include +#include +#include + +#define ANSI true +//#define HHKB true +//#define ISO true +//#define ALL_1U true +//#define SPLIT_BKSP_RSHFT true + + + +/ { + chosen { + #ifdef ANSI + zmk,matrix_transform = &ansi_transform; + #elif defined(HHKB) + zmk,matrix_transform = &hhkb_transform; + #elif defined(ISO) + zmk,matrix_transform = &iso_transform; + #elif defined(ALL_1U) + zmk,matrix_transform = &all_1u_transform; + #else + zmk,matrix_transform = &split_transform; + #endif + }; + + + keymap { + compatible = "zmk,keymap"; + #ifdef ANSI + default_layer { + // ------------------------------------------------------------------------------------------ + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | + // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | | | + // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | + // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | + // | CTL | WIN | ALT | SPACE | ALT | 1 | MENU | CTRL | + // ------------------------------------------------------------------------------------------ + bindings = < + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &mo 1 &kp K_CMENU &kp RCTRL &bt BT_CLR + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + raise { + // ------------------------------------------------------------------------------------------ + // |GRAVE| F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | DEL | + // | TAB | Q | UP | E | R | T | Y | U | INS | O |PSCRN|SLCK |PSEBRK| RESET | + // | CAPS |LEFT |DOWN |RIGHT| F | G | H | J | K | L |HOME |PGUP | BOOTLOADER | + // | PREV |VOLUP |VOLDN|MUTE | V | B | N | M | , | END | PGDN | NEXT | + // | CTL | WIN | ALT | SPACE | ALT | 1 | MENU | BT_CLR | + // ------------------------------------------------------------------------------------------ + bindings = < + &kp GRAVE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp DEL + &trans &trans &kp UP &trans &trans &trans &trans &trans &kp INS &trans &kp PSCRN &kp SLCK &kp PAUSE_BREAK &sys_reset + &trans &kp LEFT &kp DOWN &kp RIGHT &trans &trans &trans &trans &trans &trans &kp HOME &kp PG_UP &bootloader + &kp C_PREV &kp C_VOL_DN &kp C_VOL_UP &kp C_MUTE &trans &trans &trans &trans &trans &kp END &kp PG_DN &kp C_NEXT + &bt BT_PRV &bt BT_NXT &trans &trans &trans &trans &trans &bt BT_CLR &trans + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + #elif defined(HHKB) + default_layer { + // ------------------------------------------------------------------------------------------ + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | \ | ` | + // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | BSPC | + // | CTRL | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | + // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | 1 | + // | CAPS | ALT | WIN | SPACE | WIN | ALT | CTRL | + // ------------------------------------------------------------------------------------------ + bindings = < + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSLH &kp GRAVE + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSPC + &kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &mo 1 + &kp LCTRL &kp LALT &kp LGUI &kp SPACE &kp RGUI &kp RALT &kp RCTRL + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + raise { + bindings = < + &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp INS &kp DEL + &kp CLCK &bt BT_PRV &bt BT_NXT &bt BT_CLR &trans &trans &trans &trans &trans &trans &trans &kp UP &trans &sys_reset + &trans &kp C_VOL_DN &kp C_VOL_UP &kp C_MUTE &trans &trans &trans &trans &trans &trans &kp LEFT &kp RIGHT &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp DOWN &trans &trans + &trans &trans &trans &bootloader &trans &trans &trans + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + #elif defined(ISO) + default_layer { + // ------------------------------------------------------------------------------------------ + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | + // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | | + // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | # | ENTER | + // | SHIFT | | | Z | X | C | V | B | N | M | , | . | / | SHIFT | + // | CTL | WIN | ALT | SPACE | ALT | 1 | MENU | CTRL | + // ------------------------------------------------------------------------------------------ + bindings = < + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp NON_US_HASH &kp RET + &kp LSHFT &kp NON_US_BSLH &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &mo 1 &kp K_CMENU &kp RCTRL + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + raise { + bindings = < + &kp GRAVE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp DEL + &sys_reset &trans &kp UP &trans &trans &trans &trans &trans &kp INS &trans &kp PSCRN &kp SLCK &kp PAUSE_BREAK + &trans &kp LEFT &kp DOWN &kp RIGHT &trans &trans &trans &trans &trans &trans &kp HOME &kp PG_UP &trans &bootloader + &kp C_PREV &kp C_VOL_DN &kp C_VOL_UP &kp C_MUTE &trans &trans &trans &trans &trans &trans &kp END &kp PG_DN &kp C_NEXT + &bt BT_PRV &bt BT_NXT &trans &trans &trans &trans &trans &bt BT_CLR + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + #elif defined(ALL_1U) + default_layer { + // ------------------------------------------------------------------------------------------ + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | + // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | "|" | + // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | + // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHFT | UP | 1 | + // | CTL | WIN | ALT | SPACE | ALT | CTRL | LEFT | DOWN | RIGHT | + // ------------------------------------------------------------------------------------------ + bindings = < + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &mo 1 + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + raise { + bindings = < + &kp GRAVE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp F1 + &trans &trans &kp UP &trans &trans &trans &trans &trans &kp INS &trans &kp PSCRN &kp SLCK &kp PAUSE_BREAK &sys_reset + &trans &kp LEFT &kp DOWN &kp RIGHT &trans &trans &trans &trans &trans &trans &kp HOME &kp PG_UP &bootloader + &kp C_PREV &kp C_VOL_DN &kp C_VOL_UP &kp C_MUTE &trans &trans &trans &trans &trans &trans &trans &kp END &kp PG_DN &kp C_NEXT + &bt BT_PRV &bt BT_NXT &trans &trans &trans &trans &trans &trans &bt BT_CLR + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + #else + default_layer { + // ------------------------------------------------------------------------------------------ + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = |BKSP| DEL | + // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | + // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | + // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | 1 | + // | CTL | WIN | ALT | SPACE | ALT | 1 | CTRL | + // ------------------------------------------------------------------------------------------ + bindings = < + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp DEL + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &mo 1 + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &kp RGUI &kp C_MENU &kp RCTRL + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + raise { + bindings = < + &kp GRAVE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp DEL &trans + &trans &trans &kp UP &trans &trans &trans &trans &trans &kp INS &trans &kp PSCRN &kp SLCK &kp PAUSE_BREAK &sys_reset + &trans &kp LEFT &kp DOWN &kp RIGHT &trans &trans &trans &trans &trans &trans &kp HOME &kp PG_UP &bootloader + &kp C_PREV &kp C_VOL_DN &kp C_VOL_UP &kp C_MUTE &trans &trans &trans &trans &trans &kp END &kp PG_DN &kp C_NEXT &trans + &bt BT_PRV &bt BT_NXT &trans &trans &trans &trans &trans &bt BT_CLR + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + #endif + }; +}; diff --git a/app/boards/arm/bt60/bt60_v1.yaml b/app/boards/arm/bt60/bt60_v1.yaml new file mode 100644 index 000000000000..41fd7e409453 --- /dev/null +++ b/app/boards/arm/bt60/bt60_v1.yaml @@ -0,0 +1,15 @@ +identifier: bt60_v1 +name: BT60 V1 Soldered +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog diff --git a/app/boards/arm/bt60/bt60_v1.zmk.yml b/app/boards/arm/bt60/bt60_v1.zmk.yml new file mode 100644 index 000000000000..9909f1912340 --- /dev/null +++ b/app/boards/arm/bt60/bt60_v1.zmk.yml @@ -0,0 +1,12 @@ +file_format: "1" +id: bt60_v1 +name: BT60 V1 Soldered +type: board +arch: arm +features: + - keys + - encoder +outputs: + - usb + - ble +url: https://polarityworks.com diff --git a/app/boards/arm/bt60/bt60_v1_defconfig b/app/boards/arm/bt60/bt60_v1_defconfig new file mode 100644 index 000000000000..04adb8a3cd81 --- /dev/null +++ b/app/boards/arm/bt60/bt60_v1_defconfig @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_BT60_V1=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# enable GPIO +CONFIG_GPIO=y + +# encoder +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/bt60/bt60_v1_hs.dts b/app/boards/arm/bt60/bt60_v1_hs.dts new file mode 100644 index 000000000000..155d626cc278 --- /dev/null +++ b/app/boards/arm/bt60/bt60_v1_hs.dts @@ -0,0 +1,60 @@ +/* +* Copyright (c) 2021 Polarity Works +* +* SPDX-License-Identifier: MIT +*/ + +/dts-v1/; +#include "bt60.dtsi" + + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <15>; + rows = <5>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(2,13) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) + RC(4,0) RC(4,1) RC(4,2) RC(4,5) RC(4,8) RC(4,9) RC(4,10) RC(4,11) + >; + }; + + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + col-gpios + = <&gpio1 11 GPIO_ACTIVE_HIGH> + , <&gpio1 10 GPIO_ACTIVE_HIGH> + , <&gpio1 13 GPIO_ACTIVE_HIGH> + , <&gpio1 15 GPIO_ACTIVE_HIGH> + , <&gpio0 3 GPIO_ACTIVE_HIGH> + , <&gpio0 2 GPIO_ACTIVE_HIGH> + , <&gpio0 28 GPIO_ACTIVE_HIGH> + , <&gpio0 29 GPIO_ACTIVE_HIGH> + , <&gpio0 30 GPIO_ACTIVE_HIGH> + , <&gpio0 31 GPIO_ACTIVE_HIGH> + , <&gpio0 5 GPIO_ACTIVE_HIGH> + , <&gpio0 7 GPIO_ACTIVE_HIGH> + , <&gpio1 9 GPIO_ACTIVE_HIGH> + , <&gpio0 12 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&gpio1 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 22 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 23 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; diff --git a/app/boards/arm/bt60/bt60_v1_hs.keymap b/app/boards/arm/bt60/bt60_v1_hs.keymap new file mode 100644 index 000000000000..6c26756e35ad --- /dev/null +++ b/app/boards/arm/bt60/bt60_v1_hs.keymap @@ -0,0 +1,37 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + // ------------------------------------------------------------------------------------------ + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | DEL + // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | | | + // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | + // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | + // | CTL | WIN | ALT | SPACE | ALT | 1 | MENU | CTRL | + // ------------------------------------------------------------------------------------------ + bindings = < + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &bt BT_CLR + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &mo 1 &kp K_CMENU &kp RCTRL + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + raise { + bindings = < + &kp GRAVE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp DEL &trans + &trans &trans &kp UP &trans &trans &trans &trans &trans &kp INS &trans &kp PSCRN &kp SLCK &kp PAUSE_BREAK &sys_reset + &trans &kp LEFT &kp DOWN &kp RIGHT &trans &trans &trans &trans &trans &trans &kp HOME &kp PG_UP &bootloader + &kp C_PREV &kp C_VOL_DN &kp C_VOL_UP &kp C_MUTE &trans &trans &trans &trans &trans &kp END &kp PG_DN &kp C_NEXT + &bt BT_PRV &bt BT_NXT &trans &trans &trans &trans &trans &bt BT_CLR + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + }; +}; diff --git a/app/boards/arm/bt60/bt60_v1_hs.yaml b/app/boards/arm/bt60/bt60_v1_hs.yaml new file mode 100644 index 000000000000..5a73753b5e29 --- /dev/null +++ b/app/boards/arm/bt60/bt60_v1_hs.yaml @@ -0,0 +1,15 @@ +identifier: bt60_v1_hs +name: BT60 V1 Hotswap +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog diff --git a/app/boards/arm/bt60/bt60_v1_hs.zmk.yml b/app/boards/arm/bt60/bt60_v1_hs.zmk.yml new file mode 100644 index 000000000000..bc9acea46a73 --- /dev/null +++ b/app/boards/arm/bt60/bt60_v1_hs.zmk.yml @@ -0,0 +1,12 @@ +file_format: "1" +id: bt60_v1_hs +name: BT60 V1 Hotswap +type: board +arch: arm +features: + - keys + - encoder +outputs: + - usb + - ble +url: https://polarityworks.com diff --git a/app/boards/arm/bt60/bt60_v1_hs_defconfig b/app/boards/arm/bt60/bt60_v1_hs_defconfig new file mode 100644 index 000000000000..f16d82ac41d7 --- /dev/null +++ b/app/boards/arm/bt60/bt60_v1_hs_defconfig @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_BT60_V1_HS=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# enable GPIO +CONFIG_GPIO=y + +# encoder +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/ckp/Kconfig b/app/boards/arm/ckp/Kconfig new file mode 100644 index 000000000000..7baf14861025 --- /dev/null +++ b/app/boards/arm/ckp/Kconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_ENABLE_DCDC + bool "Enable DCDC mode" + select SOC_DCDC_NRF52X + default y + depends on BOARD_BT60_V2 || BOARD_BT65_V1 || BOARD_BT75_V1 diff --git a/app/boards/arm/ckp/Kconfig.board b/app/boards/arm/ckp/Kconfig.board new file mode 100644 index 000000000000..a98a31673f41 --- /dev/null +++ b/app/boards/arm/ckp/Kconfig.board @@ -0,0 +1,16 @@ +# CKP boards configuration + +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_BT60_V2 + bool "bt60_v2" + depends on SOC_NRF52840_QIAA + +config BOARD_BT65_V1 + bool "bt65_v1" + depends on SOC_NRF52840_QIAA + +config BOARD_BT75_V1 + bool "bt75_v1" + depends on SOC_NRF52840_QIAA diff --git a/app/boards/arm/ckp/Kconfig.defconfig b/app/boards/arm/ckp/Kconfig.defconfig new file mode 100644 index 000000000000..376d4619fde8 --- /dev/null +++ b/app/boards/arm/ckp/Kconfig.defconfig @@ -0,0 +1,28 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD + default "bt60_v2" if BOARD_BT60_V2 + default "bt65_v1" if BOARD_BT65_V1 + default "bt75_v1" if BOARD_BT75_V1 +config ZMK_KEYBOARD_NAME + default "BT60 V2" if BOARD_BT60_V2 + default "BT65" if BOARD_BT65_V1 + default "BT75" if BOARD_BT75_V1 + +if BOARD_BT60_V2 || BOARD_BT65_V1 || BOARD_BT75_V1 + +if USB + +config USB_NRFX + default y + +config USB_DEVICE_STACK + default y + +endif # USB + +config BT_CTLR + default BT + +endif # BOARD_BT60_V2 || BOARD_BT65_V1 || BOARD_BT75_V1 diff --git a/app/boards/arm/ckp/board.cmake b/app/boards/arm/ckp/board.cmake new file mode 100644 index 000000000000..b7feee2ee9e7 --- /dev/null +++ b/app/boards/arm/ckp/board.cmake @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: MIT + +board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) diff --git a/app/boards/arm/ckp/bt60_v2.dts b/app/boards/arm/ckp/bt60_v2.dts new file mode 100644 index 000000000000..19f92287e3f5 --- /dev/null +++ b/app/boards/arm/ckp/bt60_v2.dts @@ -0,0 +1,71 @@ +/* +* Copyright (c) 2022 The ZMK Contributors +* +* SPDX-License-Identifier: MIT +*/ + +/dts-v1/; +#include "ckp.dtsi" + + +/ { + model = "BT60_V2"; + compatible = "polarityworks,bt60_v2"; + + chosen { + zmk,matrix_transform = &ansi_transform; + }; + + + ansi_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <15>; + rows = <5>; + map = < + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,13) + RC(4,0) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,12) + RC(5,0) RC(5,1) RC(5,2) RC(5,6) RC(5,10) RC(5,11) RC(5,12) RC(5,13) + >; + }; + + iso_transform: keymap_transform_1 { + compatible = "zmk,matrix-transform"; + columns = <15>; + rows = <5>; + map = < + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) RC(3,13) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,12) + RC(5,0) RC(5,1) RC(5,2) RC(5,6) RC(5,10) RC(5,11) RC(5,12) RC(5,13) + >; + }; + + all_1u_transform: keymap_transform_2 { + compatible = "zmk,matrix-transform"; + columns = <15>; + rows = <5>; + map = < + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) RC(1,14) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,13) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,13) RC(4,14) + RC(5,0) RC(5,1) RC(5,2) RC(5,6) RC(5,10) RC(5,11) RC(5,12) RC(5,13) RC(5,14) + >; + }; + + hhkb_transform: keymap_transform_3 { + compatible = "zmk,matrix-transform"; + columns = <15>; + rows = <5>; + map = < + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,13) + RC(4,0) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,12) + RC(5,0) RC(5,1) RC(5,2) RC(5,6) RC(5,11) RC(5,12) RC(5,13) + >; + }; +}; diff --git a/app/boards/arm/ckp/bt60_v2.keymap b/app/boards/arm/ckp/bt60_v2.keymap new file mode 100644 index 000000000000..eeb5c96e3738 --- /dev/null +++ b/app/boards/arm/ckp/bt60_v2.keymap @@ -0,0 +1,177 @@ +#include +#include +#include +#include +#include + +#define ANSI +//#define ISO +//#define ALL_1U +//#define HHKB + +/ { + chosen { + #ifdef ANSI + zmk,matrix_transform = &ansi_transform; + #elif defined(ISO) + zmk,matrix_transform = &iso_transform; + #elif defined(ALL_1U) + zmk,matrix_transform = &all_1u_transform; + #elif defined(HHKB) + zmk,matrix_transform = &hhkb_transform; + #else + #error "Layout not defined, please define a layout by uncommenting the appropriate line in bt60_v2.keymap" + #endif + }; + + keymap { + compatible = "zmk,keymap"; + #ifdef ANSI + default_layer { + // ------------------------------------------------------------------------------------------ + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | + // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | + // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | + // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | + // | CTL | WIN | ALT | SPACE | ALT | 1 | MENU | CTRL | + // ------------------------------------------------------------------------------------------ + bindings = < + + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH + &kp CAPS &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &mo 1 &kp K_CMENU &kp RCTRL + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + raise { + // ------------------------------------------------------------------------------------------ + // |GRAVE| F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | DEL | + // | TAB | Q | UP | E | HUI | HUD | Y | U | INS | O |PSCRN| SLCK| P_B | RGB_TOG| + // | CAPS | LEFT| DOWN|RIGHT| BRI | BRD | H | J | K | L | HOME| PGUP| BOOT | + // | SHIFT |VOLDN|VOLUP| MUTE|BLINC|BLDEC| N | M | , | END | PGDN | BL_TOG | + // | BT_PRV| BT_NXT| ALT | SPACE | ALT | 1 | RESET | BT_CLR | + // ------------------------------------------------------------------------------------------ + bindings = < + &kp GRAVE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp DEL + &trans &trans &kp UP &trans &rgb_ug RGB_HUI &rgb_ug RGB_HUD &trans &trans &kp INS &trans &kp PSCRN &kp SLCK &kp PAUSE_BREAK &rgb_ug RGB_TOG + &trans &kp LEFT &kp DOWN &kp RIGHT &rgb_ug RGB_BRI &rgb_ug RGB_BRD &trans &trans &trans &trans &kp HOME &kp PG_UP &bootloader + &trans &kp C_VOL_DN &kp C_VOL_UP &kp C_MUTE &bl BL_INC &bl BL_DEC &trans &trans &trans &kp END &kp PG_DN &bl BL_TOG + &bt BT_PRV &bt BT_NXT &trans &trans &trans &trans &sys_reset &bt BT_CLR + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + #elif defined(ISO) + default_layer { + // ------------------------------------------------------------------------------------------ + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | + // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | | + // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | # | ENTER | + // | SHIFT | \ | Z | X | C | V | B | N | M | , | . | / | SHIFT | + // | CTL | WIN | ALT | SPACE | ALT | 1 | MENU | CTRL | + // ------------------------------------------------------------------------------------------ + bindings = < + + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT + &kp CAPS &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp NON_US_HASH &kp RET + &kp LSHFT &kp NON_US_BSLH &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &mo 1 &kp K_CMENU &kp RCTRL + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + raise { + // ------------------------------------------------------------------------------------------ + // |GRAVE| F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | DEL | + // | TAB | Q | UP | E | HUI | HUD | Y | U | INS | O |PSCRN| SLCK| P_B | | + // | CAPS | LEFT| DOWN|RIGHT| BRI | BRD | H | J | K | L | HOME| PGUP|RGB_TOG| BOOT | + // | SHIFT |VOLDN|VOLUP| MUTE|BLINC|BLDEC| B | N | M | , | END | PGDN | BL_TOG | + // | BT_PRV| BT_NXT| ALT | SPACE | ALT | 1 | RESET |BT_CLR | + // ------------------------------------------------------------------------------------------ + bindings = < + &kp GRAVE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp DEL + &trans &trans &kp UP &trans &rgb_ug RGB_HUI &rgb_ug RGB_HUD &trans &trans &kp INS &trans &kp PSCRN &kp SLCK &kp PAUSE_BREAK + &trans &kp LEFT &kp DOWN &kp RIGHT &rgb_ug RGB_BRI &rgb_ug RGB_BRD &trans &trans &trans &trans &kp HOME &kp PG_UP &rgb_ug RGB_TOG &bootloader + &trans &kp C_VOL_DN &kp C_VOL_UP &kp C_MUTE &bl BL_INC &bl BL_DEC &trans &trans &trans &trans &kp END &kp PG_DN &bl BL_TOG + &bt BT_PRV &bt BT_NXT &trans &trans &trans &trans &sys_reset &bt BT_CLR + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + #elif defined(ALL_1U) + default_layer { + // ------------------------------------------------------------------------------------------ + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = |BKSP | DEL | + // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | + // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | + // | SHFT |NONE| Z | X | C | V | B | N | M | , | . | / | SHFT | UP | 1 | + // | CTL | WIN | ALT | SPACE | RALT| CTRL | LEFT | DOWN | RIGHT | + // ------------------------------------------------------------------------------------------ + bindings = < + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp DEL + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET + &kp LSHFT &none &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &mo 1 + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + raise { + // ------------------------------------------------------------------------------------------ + // |GRAVE| F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 |BKSP | DEL | + // | TAB | Q | W | E | HUI | HUD | Y | U | INS | O |PSCRN| SLCK| P_B | RGB_TOG | + // | CAPS | A | S | D | BRI | BRD | H | J | K | L | HOME| PGUP| BOOT | + // | SHFT |NONE|VOLDN|VOLUP|MUTE|BLINC|BLDEC| N | M | , | END | PGDN | SHFT|BL_TOG| 1 | + // | BT_PRV| BT_NXT| ALT | SPACE | RALT| CTRL | LEFT |RESET| BT_CLR | + // ------------------------------------------------------------------------------------------ + bindings = < + &kp GRAVE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &trans &trans + &trans &trans &trans &trans &rgb_ug RGB_HUI &rgb_ug RGB_HUD &trans &trans &kp INS &trans &kp PSCRN &kp SLCK &kp PAUSE_BREAK &rgb_ug RGB_TOG + &trans &trans &trans &trans &rgb_ug RGB_BRI &rgb_ug RGB_BRD &trans &trans &trans &trans &kp HOME &kp PG_UP &bootloader + &trans &none &kp C_VOL_DN &kp C_VOL_UP &kp C_MUTE &bl BL_INC &bl BL_DEC &trans &trans &trans &kp END &kp PG_DN &trans &bl BL_TOG &trans + &bt BT_PRV &bt BT_NXT &trans &trans &trans &trans &trans &sys_reset &bt BT_CLR + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + #elif defined(HHKB) + default_layer { + // ------------------------------------------------------------------------------------------ + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | + // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | + // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | + // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | + // | CTL | WIN | ALT | SPACE | ALT | 1 | CTRL | + // ------------------------------------------------------------------------------------------ + bindings = < + + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH + &kp CAPS &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &mo 1 &kp RCTRL + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + raise { + // ------------------------------------------------------------------------------------------ + // |GRAVE| F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | DEL | + // | TAB | Q | UP | E | HUI | HUD | Y | U | INS | O |PSCRN| SLCK| P_B | RGB_TOG| + // | CAPS | LEFT| DOWN|RIGHT| BRI | BRD | H | J | K | L | HOME| PGUP| BOOT | + // | SHFT |VOLDN|VOLUP| MUTE|BLINC|BLDEC| N | M | , | END | PGDN | BL_TOG | + // | BT_PRV | BT_NXT | ALT | SPACE | RESET | 1 | BT_CLR | + // ------------------------------------------------------------------------------------------ + bindings = < + &kp GRAVE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp DEL + &trans &trans &kp UP &trans &rgb_ug RGB_HUI &rgb_ug RGB_HUD &trans &trans &kp INS &trans &kp PSCRN &kp SLCK &kp PAUSE_BREAK &rgb_ug RGB_TOG + &trans &kp LEFT &kp DOWN &kp RIGHT &rgb_ug RGB_BRI &rgb_ug RGB_BRD &trans &trans &trans &trans &kp HOME &kp PG_UP &bootloader + &trans &kp C_VOL_DN &kp C_VOL_UP &kp C_MUTE &bl BL_INC &bl BL_DEC &trans &trans &trans &kp END &kp PG_DN &bl BL_TOG + &bt BT_PRV &bt BT_NXT &trans &trans &sys_reset &trans &bt BT_CLR + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + #else + #error "Layout not defined, please define a layout by uncommenting the appropriate line in bt60_v2.keymap" + #endif + + }; +}; diff --git a/app/boards/arm/ckp/bt60_v2.yaml b/app/boards/arm/ckp/bt60_v2.yaml new file mode 100644 index 000000000000..2a3f3b47a475 --- /dev/null +++ b/app/boards/arm/ckp/bt60_v2.yaml @@ -0,0 +1,15 @@ +identifier: bt60_v2 +name: BT60 V2 +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog diff --git a/app/boards/arm/ckp/bt60_v2.zmk.yml b/app/boards/arm/ckp/bt60_v2.zmk.yml new file mode 100644 index 000000000000..faf64205da10 --- /dev/null +++ b/app/boards/arm/ckp/bt60_v2.zmk.yml @@ -0,0 +1,14 @@ +file_format: "1" +id: bt60_v2 +name: BT60 V2 +type: board +arch: arm +features: + - keys + - encoder + - underglow + - backlight +outputs: + - usb + - ble +url: https://polarityworks.com/btckp diff --git a/app/boards/arm/ckp/bt60_v2_defconfig b/app/boards/arm/ckp/bt60_v2_defconfig new file mode 100644 index 000000000000..fd1ae985995c --- /dev/null +++ b/app/boards/arm/ckp/bt60_v2_defconfig @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_BT60_V2=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# enable GPIO +CONFIG_GPIO=y +CONFIG_PINCTRL=y + +# encoder +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_PWM=y +CONFIG_LED_PWM=y +CONFIG_ZMK_BACKLIGHT=y +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +CONFIG_ZMK_RGB_UNDERGLOW=y +CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER=y +CONFIG_ZMK_RGB_UNDERGLOW_ON_START=y +CONFIG_ZMK_RGB_UNDERGLOW_HUE_START=262 +CONFIG_WS2812_STRIP=y +CONFIG_SPI=y + +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y diff --git a/app/boards/arm/ckp/bt65_v1.dts b/app/boards/arm/ckp/bt65_v1.dts new file mode 100644 index 000000000000..97d80da2fb14 --- /dev/null +++ b/app/boards/arm/ckp/bt65_v1.dts @@ -0,0 +1,71 @@ +/* +* Copyright (c) 2022 The ZMK Contributors +* +* SPDX-License-Identifier: MIT +*/ + +/dts-v1/; +#include "ckp.dtsi" + + +/ { + model = "BT65_V1"; + compatible = "polarityworks,bt65_v1"; + + chosen { + zmk,matrix_transform = &ansi_transform; + }; + + + ansi_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <16>; + rows = <5>; + map = < + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) RC(1,15) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) RC(2,15) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,13) RC(3,15) + RC(4,0) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,14) RC(4,15) + RC(5,0) RC(5,1) RC(5,2) RC(5,6) RC(5,10) RC(5,11) RC(5,12) RC(5,13) RC(5,14) RC(5,15) + >; + }; + + iso_transform: keymap_transform_1 { + compatible = "zmk,matrix-transform"; + columns = <16>; + rows = <5>; + map = < + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) RC(1,15) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,15) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) RC(3,13) RC(3,15) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,14) RC(4,15) + RC(5,0) RC(5,1) RC(5,2) RC(5,6) RC(5,10) RC(5,11) RC(5,12) RC(5,13) RC(5,14) RC(5,15) + >; + }; + + all_1u_transform: keymap_transform_2 { + compatible = "zmk,matrix-transform"; + columns = <16>; + rows = <5>; + map = < + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) RC(1,14) RC(1,15) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) RC(2,15) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,13) RC(3,15) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,13) RC(4,14) RC(4,15) + RC(5,0) RC(5,1) RC(5,2) RC(5,6) RC(5,10) RC(5,11) RC(5,12) RC(5,13) RC(5,14) RC(5,15) + >; + }; + + hhkb_transform: keymap_transform_3 { + compatible = "zmk,matrix-transform"; + columns = <16>; + rows = <5>; + map = < + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) RC(1,15) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) RC(2,15) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,13) RC(3,15) + RC(4,0) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,15) + RC(5,0) RC(5,1) RC(5,2) RC(5,6) RC(5,11) RC(5,12) RC(5,13) RC(5,15) + >; + }; +}; diff --git a/app/boards/arm/ckp/bt65_v1.keymap b/app/boards/arm/ckp/bt65_v1.keymap new file mode 100644 index 000000000000..27411a71c216 --- /dev/null +++ b/app/boards/arm/ckp/bt65_v1.keymap @@ -0,0 +1,177 @@ +#include +#include +#include +#include +#include + +#define ANSI +//#define ISO +//#define ALL_1U +//#define HHKB + +/ { + chosen { + #ifdef ANSI + zmk,matrix_transform = &ansi_transform; + #elif defined(ISO) + zmk,matrix_transform = &iso_transform; + #elif defined(ALL_1U) + zmk,matrix_transform = &all_1u_transform; + #elif defined(HHKB) + zmk,matrix_transform = &hhkb_transform; + #else + #error "Layout not defined, please define a layout by uncommenting the appropriate line in bt65_v1.keymap" + #endif + }; + + keymap { + compatible = "zmk,keymap"; + #ifdef ANSI + default_layer { + // ------------------------------------------------------------------------------------------------ + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | DEL | + // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | INS | + // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | PGUP| + // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | UP | PGDN| + // | CTL | WIN | ALT | SPACE | ALT | 1 |RCTRL| LEFT| DOWN|RIGHT| + // ------------------------------------------------------------------------------------------------ + bindings = < + + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BKSP &kp DEL + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp INS + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET &kp PG_UP + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp PG_DN + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &mo 1 &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + raise { + // -------------------------------------------------------------------------------------------------- + // |GRAVE| F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | BL_TOG |RGB_TOG| + // | TAB | Q | W | E | HUI | HUD | Y | U | I | O | P | SLCK| ] | RESET | PSCRN| + // | CAPS | A | S | D | BRI | BRD | H | J | K | L | ; | ' | BOOT | P_BRK| + // | SHIFT |VOLDN|VOLUP| MUTE|BLINC|BLDEC| N | M | , | . | / | SHIFT | HOME | END | + // | BT_PRV| BT_NXT| ALT | SPACE | ALT | 1 | CTRL | LEFT | DOWN |BT_CLR| + // -------------------------------------------------------------------------------------------------- + bindings = < + &kp GRAVE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &bl BL_TOG &rgb_ug RGB_TOG + &trans &trans &trans &trans &rgb_ug RGB_HUI &rgb_ug RGB_HUD &trans &trans &trans &trans &trans &kp SLCK &trans &sys_reset &kp PSCRN + &trans &trans &trans &trans &rgb_ug RGB_BRI &rgb_ug RGB_BRD &trans &trans &trans &trans &trans &trans &bootloader &kp PAUSE_BREAK + &trans &kp C_VOL_DN &kp C_VOL_UP &kp C_MUTE &bl BL_INC &bl BL_DEC &trans &trans &trans &trans &trans &trans &kp HOME &kp END + &bt BT_PRV &bt BT_NXT &trans &trans &trans &trans &trans &trans &trans &bt BT_CLR + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + #elif defined(ISO) + default_layer { + // ------------------------------------------------------------------------------------------------ + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | DEL | + // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | | INS | + // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | # | ENTER | PGUP| + // |SHIFT | \ | Z | X | C | V | B | N | M | , | . | / | SHIFT | UP | PGDN| + // | CTL | WIN | ALT | SPACE | ALT | 1 |RCTRL| LEFT| DOWN|RIGHT| + // ------------------------------------------------------------------------------------------------ + bindings = < + + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BKSP &kp DEL + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp INS + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp NON_US_HASH &kp RET &kp PG_UP + &kp LSHFT &kp NON_US_BSLH &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp PG_DN + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &mo 1 &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + raise { + // -------------------------------------------------------------------------------------------------- + // |GRAVE| F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | BL_TOG |RGB_TOG| + // | TAB | Q | W | E | HUI | HUD | Y | U | I | O | P | SLCK| ] | | PSCRN| + // | CAPS | A | S | D | BRI | BRD | H | J | K | L | ; | ' |RESET| BOOT | P_BRK| + // |SHIFT |VOLDN|VOLUP| MUTE|BLINC|BLDEC| B | N | M | , | . | / | SHIFT | HOME | END | + // | BT_PRV| BT_NXT| ALT | SPACE | ALT | 1 | CTRL | LEFT | DOWN |BT_CLR| + // -------------------------------------------------------------------------------------------------- + bindings = < + &kp GRAVE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &bl BL_TOG &rgb_ug RGB_TOG + &trans &trans &trans &trans &rgb_ug RGB_HUI &rgb_ug RGB_HUD &trans &trans &trans &trans &trans &kp SLCK &trans &kp PSCRN + &trans &trans &trans &trans &rgb_ug RGB_BRI &rgb_ug RGB_BRD &trans &trans &trans &trans &trans &trans &sys_reset &bootloader &kp PAUSE_BREAK + &trans &kp C_VOL_DN &kp C_VOL_UP &kp C_MUTE &bl BL_INC &bl BL_DEC &trans &trans &trans &trans &trans &trans &trans &kp HOME &kp END + &bt BT_PRV &bt BT_NXT &trans &trans &trans &trans &trans &trans &trans &bt BT_CLR + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + #elif defined(ALL_1U) + default_layer { + // ------------------------------------------------------------------------------------------------- + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = |BKSP | DEL | HOME| + // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | END | + // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | PGUP| + // |SHIFT|NONE | Z | X | C | V | B | N | M | , | . | / |SHIFT|NONE | UP | PGDN| + // | CTL | WIN | ALT | SPACE | ALT | 1 |RCTRL| LEFT| DOWN|RIGHT| + // ------------------------------------------------------------------------------------------------- + bindings = < + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp DEL &kp HOME + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp END + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET &kp PG_UP + &kp LSHFT &none &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &none &kp UP &kp PG_DN + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp LALT &mo 1 &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + raise { + // -------------------------------------------------------------------------------------------------- + // |GRAVE| F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 |BL_TOG|RGB_TOG|HOME| + // | TAB | Q | W | E | HUI | HUD | Y | U | I | O | P | SLCK| ] | RESET | PSCRN| + // | CAPS | A | S | D | BRI | BRD | H | J | K | L | ; | ' | BOOT | P_BRK| + // |SHIFT| NONE|VOLDN|VOLUP| MUTE|BLINC|BLDEC| N | M | , | . | / |SHIFT| NONE| UP | INS | + // | BT_PRV| BT_NXT| ALT | SPACE | ALT | 1 | CTRL| LEFT| DOWN |BT_CLR| + // -------------------------------------------------------------------------------------------------- + bindings = < + &kp GRAVE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &bl BL_TOG &rgb_ug RGB_TOG &trans + &trans &trans &trans &trans &rgb_ug RGB_HUI &rgb_ug RGB_HUD &trans &trans &trans &trans &trans &kp SLCK &trans &sys_reset &kp PSCRN + &trans &trans &trans &trans &rgb_ug RGB_BRI &rgb_ug RGB_BRD &trans &trans &trans &trans &trans &trans &bootloader &kp PAUSE_BREAK + &trans &none &kp C_VOL_DN &kp C_VOL_UP &kp C_MUTE &bl BL_INC &bl BL_DEC &trans &trans &trans &trans &trans &trans &trans &trans &kp INS + &bt BT_PRV &bt BT_NXT &trans &trans &trans &trans &trans &trans &trans &bt BT_CLR + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + #elif defined(HHKB) + default_layer { + // ------------------------------------------------------------------------------------------------ + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | DEL | + // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | HOME| + // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | END | + // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | PGUP| + // | CTL | WIN | ALT | SPACE | ALT | 1 | CTRL | PGDN| + // ------------------------------------------------------------------------------------------------ + bindings = < + + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BKSP &kp DEL + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp HOME + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET &kp END + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp PG_UP + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &mo 1 &kp RCTRL &kp PG_DN + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + raise { + // -------------------------------------------------------------------------------------------------- + // |GRAVE| F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | BL_TOG |RGB_TOG| + // | TAB | Q | UP | E | HUI | HUD | Y | U | I | O | P | SLCK| ] | RESET | PSCRN| + // | CAPS | LEFT| DOWN|RIGHT| BRI | BRD | H | J | K | L | ; | ' | BOOT | P_BRK| + // | SHIFT |VOLDN|VOLUP| MUTE|BLINC|BLDEC| N | M | , | . | / | SHIFT | INS | + // | BT_PRV | BT_NXT | ALT | SPACE | ALT | 1 | CTRL |BT_CLR| + // -------------------------------------------------------------------------------------------------- + bindings = < + &kp GRAVE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &bl BL_TOG &rgb_ug RGB_TOG + &trans &trans &kp UP &trans &rgb_ug RGB_HUI &rgb_ug RGB_HUD &trans &trans &trans &trans &trans &kp SLCK &trans &sys_reset &kp PSCRN + &trans &kp LEFT &kp DOWN &kp RIGHT &rgb_ug RGB_BRI &rgb_ug RGB_BRD &trans &trans &trans &trans &trans &trans &bootloader &kp PAUSE_BREAK + &trans &kp C_VOL_DN &kp C_VOL_UP &kp C_MUTE &bl BL_INC &bl BL_DEC &trans &trans &trans &trans &trans &trans &kp INS + &bt BT_PRV &bt BT_NXT &trans &trans &trans &trans &trans &bt BT_CLR + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + #else + #error "Layout not defined, please define a layout by uncommenting the appropriate line in bt65_v1.keymap" + #endif + + }; +}; diff --git a/app/boards/arm/ckp/bt65_v1.yaml b/app/boards/arm/ckp/bt65_v1.yaml new file mode 100644 index 000000000000..61edacce6c24 --- /dev/null +++ b/app/boards/arm/ckp/bt65_v1.yaml @@ -0,0 +1,15 @@ +identifier: bt65_v1 +name: BT65_V1 +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog diff --git a/app/boards/arm/ckp/bt65_v1.zmk.yml b/app/boards/arm/ckp/bt65_v1.zmk.yml new file mode 100644 index 000000000000..f82253b094c5 --- /dev/null +++ b/app/boards/arm/ckp/bt65_v1.zmk.yml @@ -0,0 +1,14 @@ +file_format: "1" +id: bt65_v1 +name: BT65 +type: board +arch: arm +features: + - keys + - encoder + - underglow + - backlight +outputs: + - usb + - ble +url: https://polarityworks.com/btckp diff --git a/app/boards/arm/ckp/bt65_v1_defconfig b/app/boards/arm/ckp/bt65_v1_defconfig new file mode 100644 index 000000000000..be5f17eb54fe --- /dev/null +++ b/app/boards/arm/ckp/bt65_v1_defconfig @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_BT65_V1=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# enable GPIO +CONFIG_GPIO=y +CONFIG_PINCTRL=y + +# encoder +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_PWM=y +CONFIG_LED_PWM=y +CONFIG_ZMK_BACKLIGHT=y +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +CONFIG_ZMK_RGB_UNDERGLOW=y +CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER=y +CONFIG_ZMK_RGB_UNDERGLOW_ON_START=y +CONFIG_ZMK_RGB_UNDERGLOW_HUE_START=262 +CONFIG_WS2812_STRIP=y +CONFIG_SPI=y + +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/ckp/bt75_v1.dts b/app/boards/arm/ckp/bt75_v1.dts new file mode 100644 index 000000000000..42aaf351bb79 --- /dev/null +++ b/app/boards/arm/ckp/bt75_v1.dts @@ -0,0 +1,61 @@ +/* +* Copyright (c) 2022 The ZMK Contributors +* +* SPDX-License-Identifier: MIT +*/ + +/dts-v1/; +#include "ckp.dtsi" + + +/ { + model = "BT75_V1"; + compatible = "polarityworks,bt75_v1"; + + chosen { + zmk,matrix_transform = &ansi_transform; + }; + + + ansi_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <16>; + rows = <6>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,15) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) RC(1,15) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) RC(2,15) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,13) RC(3,15) + RC(4,0) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,14) RC(4,15) + RC(5,0) RC(5,1) RC(5,2) RC(5,6) RC(5,10) RC(5,11) RC(5,12) RC(5,13) RC(5,14) RC(5,15) + >; + }; + + iso_transform: keymap_transform_1 { + compatible = "zmk,matrix-transform"; + columns = <16>; + rows = <6>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,15) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) RC(1,15) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,15) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) RC(3,13) RC(3,15) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,14) RC(4,15) + RC(5,0) RC(5,1) RC(5,2) RC(5,6) RC(5,10) RC(5,11) RC(5,12) RC(5,13) RC(5,14) RC(5,15) + >; + }; + + all_1u_transform: keymap_transform_2 { + compatible = "zmk,matrix-transform"; + columns = <16>; + rows = <6>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,15) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) RC(1,14) RC(1,15) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) RC(2,15) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,13) RC(3,15) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,13) RC(4,14) RC(4,15) + RC(5,0) RC(5,1) RC(5,2) RC(5,6) RC(5,10) RC(5,11) RC(5,12) RC(5,13) RC(5,14) RC(5,15) + >; + }; +}; diff --git a/app/boards/arm/ckp/bt75_v1.keymap b/app/boards/arm/ckp/bt75_v1.keymap new file mode 100644 index 000000000000..5c95387adab2 --- /dev/null +++ b/app/boards/arm/ckp/bt75_v1.keymap @@ -0,0 +1,148 @@ +#include +#include +#include +#include +#include + +#define ANSI +//#define ISO +//#define ALL_1U + +/ { + chosen { + #ifdef ANSI + zmk,matrix_transform = &ansi_transform; + #elif defined(ISO) + zmk,matrix_transform = &iso_transform; + #elif defined(ALL_1U) + zmk,matrix_transform = &all_1u_transform; + #else + #error "Layout not defined, please define a layout using by uncommenting the appropriate line in bt75_v1.keymap" + #endif + }; + + keymap { + compatible = "zmk,keymap"; + #ifdef ANSI + default_layer { + // ------------------------------------------------------------------------------------------------ + // | ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F9 | F9 | F10 | F11 | F12 |PSCRN|HOME| END | + // |GRAVE| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | DEL | + // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | INS | + // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | PGUP| + // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | UP | PGDN| + // | CTL | WIN | ALT | SPACE | ALT | 1 |RCTRL| LEFT| DOWN|RIGHT| + // ------------------------------------------------------------------------------------------------ + bindings = < + &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp PSCRN &kp HOME &kp END + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BKSP &kp DEL + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp INS + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET &kp PG_UP + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp PG_DN + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &mo 1 &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + raise { + // -------------------------------------------------------------------------------------------------- + // | ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F9 | F9 | F10 | F11 | F12 |PSCRN| HOME| END | + // |GRAVE| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BL_TOG |RGB_TOG| + // | TAB | Q | W | E | HUI | HUD | Y | U | I | O | P | SLCK| ] | RESET | P_BRK| + // | CAPS | A | S | D | BRI | BRD | H | J | K | L | ; | ' | BOOT | PG_UP| + // | SHIFT |VOLDN|VOLUP| MUTE|BLINC|BLDEC| N | M | , | . | / | SHIFT | UP | PG_DN| + // | BT_PRV| BT_NXT| ALT | SPACE | ALT | 1 | CTRL | LEFT | DOWN |BT_CLR| + // -------------------------------------------------------------------------------------------------- + bindings = < + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &bl BL_TOG &rgb_ug RGB_TOG + &trans &trans &trans &trans &rgb_ug RGB_HUI &rgb_ug RGB_HUD &trans &trans &trans &trans &trans &kp SLCK &trans &sys_reset &kp PAUSE_BREAK + &trans &trans &trans &trans &rgb_ug RGB_BRI &rgb_ug RGB_BRD &trans &trans &trans &trans &trans &trans &bootloader &trans + &trans &kp C_VOL_DN &kp C_VOL_UP &kp C_MUTE &bl BL_INC &bl BL_DEC &trans &trans &trans &trans &trans &trans &trans &trans + &bt BT_PRV &bt BT_NXT &trans &trans &trans &trans &trans &trans &trans &bt BT_CLR + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + #elif defined(ISO) + default_layer { + // ------------------------------------------------------------------------------------------------ + // | ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F9 | F9 | F10 | F11 | F12 |PSCRN|HOME| END | + // |GRAVE| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | DEL | + // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | | INS | + // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | # | ENTER | PGUP| + // |SHIFT | \ | Z | X | C | V | B | N | M | , | . | / | SHIFT | UP | PGDN| + // | CTL | WIN | ALT | SPACE | ALT | 1 |RCTRL| LEFT| DOWN|RIGHT| + // ------------------------------------------------------------------------------------------------ + bindings = < + &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp PSCRN &kp HOME &kp END + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BKSP &kp DEL + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp INS + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp NON_US_HASH &kp RET &kp PG_UP + &kp LSHFT &kp NON_US_BSLH &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp PG_DN + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &mo 1 &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + raise { + // -------------------------------------------------------------------------------------------------- + // | ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F9 | F9 | F10 | F11 | F12 |PSCRN|HOME| END | + // |GRAVE| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BL_TOG |RGB_TOG| + // | TAB | Q | W | E | HUI | HUD | Y | U | I | O | P | SLCK| ] | | P_BRK| + // | CAPS | A | S | D | BRI | BRD | H | J | K | L | ; | ' |RESET| BOOT | PG_UP| + // |SHIFT | \ |VOLDN|VOLUP| MUTE|BLINC|BLDEC| N | M | , | . | / | SHIFT | UP | PG_DN| + // | BT_PRV| BT_NXT| ALT | SPACE | ALT | 1 | CTRL | LEFT | DOWN |BT_CLR| + // -------------------------------------------------------------------------------------------------- + bindings = < + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &bl BL_TOG &rgb_ug RGB_TOG + &trans &trans &trans &trans &rgb_ug RGB_HUI &rgb_ug RGB_HUD &trans &trans &trans &trans &trans &kp SLCK &trans &kp PAUSE_BREAK + &trans &trans &trans &trans &rgb_ug RGB_BRI &rgb_ug RGB_BRD &trans &trans &trans &trans &trans &trans &sys_reset &bootloader &trans + &trans &trans &kp C_VOL_DN &kp C_VOL_UP &kp C_MUTE &bl BL_INC &bl BL_DEC &trans &trans &trans &trans &trans &trans &trans &trans + &bt BT_PRV &bt BT_NXT &trans &trans &trans &trans &trans &trans &trans &bt BT_CLR + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + #elif defined(ALL_1U) + default_layer { + // ------------------------------------------------------------------------------------------------- + // | ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F9 | F9 | F10 | F11 | F12 |PSCRN| P_B | INS | + // |GRAVE| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = |BKSP | DEL | HOME| + // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | END | + // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | PGUP| + // |SHIFT|NONE | Z | X | C | V | B | N | M | , | . | / |SHIFT|NONE | UP | PGDN| + // | CTL | WIN | ALT | SPACE | ALT | 1 |RCTRL| LEFT| DOWN|RIGHT| + // ------------------------------------------------------------------------------------------------- + bindings = < + &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp PSCRN &kp PAUSE_BREAK &kp INS + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp DEL &kp HOME + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp END + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET &kp PG_UP + &kp LSHFT &none &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &none &kp UP &kp PG_DN + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp LALT &mo 1 &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + raise { + // -------------------------------------------------------------------------------------------------- + // | ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F9 | F9 | F10 | F11 | F12 |PSCRN| P_B | INS | + // |GRAVE| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = |BL_TOG|RGB_TOG|HOME| + // | TAB | Q | W | E | HUI | HUD | Y | U | I | O | P | SLCK| ] | RESET | END | + // | CAPS | A | S | D | BRI | BRD | H | J | K | L | ; | ' | BOOT | PGUP | + // |SHIFT| NONE|VOLDN|VOLUP| MUTE|BLINC|BLDEC| N | M | , | . | / |SHIFT| NONE| UP | PGDN | + // | BT_PRV| BT_NXT| ALT | SPACE | ALT | 1 | CTRL| LEFT| DOWN |BT_CLR| + // -------------------------------------------------------------------------------------------------- + bindings = < + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &bl BL_TOG &rgb_ug RGB_TOG &trans + &trans &trans &trans &trans &rgb_ug RGB_HUI &rgb_ug RGB_HUD &trans &trans &trans &trans &trans &kp SLCK &trans &sys_reset &trans + &trans &trans &trans &trans &rgb_ug RGB_BRI &rgb_ug RGB_BRD &trans &trans &trans &trans &trans &trans &bootloader &trans + &trans &trans &kp C_VOL_DN &kp C_VOL_UP &kp C_MUTE &bl BL_INC &bl BL_DEC &trans &trans &trans &trans &trans &trans &trans &trans &trans + &bt BT_PRV &bt BT_NXT &trans &trans &trans &trans &trans &trans &trans &bt BT_CLR + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + #else + #error "Layout not defined, please define a layout by uncommenting the appropriate line in bt75.keymap" + #endif + + }; +}; diff --git a/app/boards/arm/ckp/bt75_v1.yaml b/app/boards/arm/ckp/bt75_v1.yaml new file mode 100644 index 000000000000..e4faa09f52c1 --- /dev/null +++ b/app/boards/arm/ckp/bt75_v1.yaml @@ -0,0 +1,15 @@ +identifier: bt75_v1 +name: BT75_V1 +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog diff --git a/app/boards/arm/ckp/bt75_v1.zmk.yml b/app/boards/arm/ckp/bt75_v1.zmk.yml new file mode 100644 index 000000000000..76e300476fa5 --- /dev/null +++ b/app/boards/arm/ckp/bt75_v1.zmk.yml @@ -0,0 +1,14 @@ +file_format: "1" +id: bt75_v1 +name: BT75_V1 +type: board +arch: arm +features: + - keys + - encoder + - underglow + - backlight +outputs: + - usb + - ble +url: https://polarityworks.com/btckp diff --git a/app/boards/arm/ckp/bt75_v1_defconfig b/app/boards/arm/ckp/bt75_v1_defconfig new file mode 100644 index 000000000000..b4d85338aec0 --- /dev/null +++ b/app/boards/arm/ckp/bt75_v1_defconfig @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_BT75_V1=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# enable GPIO +CONFIG_GPIO=y +CONFIG_PINCTRL=y + +# encoder +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_PWM=y +CONFIG_LED_PWM=y +CONFIG_ZMK_BACKLIGHT=y +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +CONFIG_ZMK_RGB_UNDERGLOW=y +CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER=y +CONFIG_ZMK_RGB_UNDERGLOW_ON_START=y +CONFIG_ZMK_RGB_UNDERGLOW_HUE_START=262 +CONFIG_WS2812_STRIP=y +CONFIG_SPI=y + +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/ckp/ckp-pinctrl.dtsi b/app/boards/arm/ckp/ckp-pinctrl.dtsi new file mode 100644 index 000000000000..87a8edc55efd --- /dev/null +++ b/app/boards/arm/ckp/ckp-pinctrl.dtsi @@ -0,0 +1,31 @@ + +/* + * Copyright (c) 2022 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; + pwm0_default: pwm0_default { + group1 { + psels = ; + }; + }; + pwm0_sleep: pwm0_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; diff --git a/app/boards/arm/ckp/ckp.dtsi b/app/boards/arm/ckp/ckp.dtsi new file mode 100644 index 000000000000..6bbbbdd74fba --- /dev/null +++ b/app/boards/arm/ckp/ckp.dtsi @@ -0,0 +1,206 @@ +/* +* Copyright (c) 2022 The ZMK Contributors +* +* SPDX-License-Identifier: MIT +*/ + +/dts-v1/; +#include + +#include +#include + +#include "ckp-pinctrl.dtsi" + +/ { + model = "CKP"; + compatible = "polarityworks,ckp"; + + chosen { + zephyr,code-partition = &code_partition; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zmk,kscan = &kscan0; + zmk,underglow = &led_strip; + zmk,backlight = &backlight; + zmk,battery = &vbatt; + }; + + sensors: sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&encoder_1>; + triggers-per-rotation = <20>; + }; + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + col-gpios + = <&gpio1 11 GPIO_ACTIVE_HIGH> + , <&gpio1 10 GPIO_ACTIVE_HIGH> + , <&gpio1 13 GPIO_ACTIVE_HIGH> + , <&gpio1 15 GPIO_ACTIVE_HIGH> + , <&gpio0 3 GPIO_ACTIVE_HIGH> + , <&gpio0 2 GPIO_ACTIVE_HIGH> + , <&gpio0 28 GPIO_ACTIVE_HIGH> + , <&gpio0 29 GPIO_ACTIVE_HIGH> + , <&gpio0 30 GPIO_ACTIVE_HIGH> + , <&gpio0 31 GPIO_ACTIVE_HIGH> + , <&gpio0 5 GPIO_ACTIVE_HIGH> + , <&gpio0 7 GPIO_ACTIVE_HIGH> + , <&gpio1 9 GPIO_ACTIVE_HIGH> + , <&gpio0 12 GPIO_ACTIVE_HIGH> + , <&gpio0 23 GPIO_ACTIVE_HIGH> + , <&gpio1 6 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&gpio0 22 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; + + // Node name must match original "EXT_POWER" label to preserve user settings. + EXT_POWER { + compatible = "zmk,ext-power-generic"; + control-gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>; + }; + + encoder_1: encoder_1 { + compatible = "alps,ec11"; + a-gpios = <&gpio0 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&gpio0 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + status = "okay"; + }; + + encoder_2: encoder_2 { + compatible = "alps,ec11"; + a-gpios = <&gpio0 26 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&gpio0 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + status = "okay"; + }; + + encoder_3: encoder_3 { + compatible = "alps,ec11"; + a-gpios = <&gpio0 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&gpio0 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + status = "okay"; + }; + + backlight: pwmleds { + compatible = "pwm-leds"; + pwm_led_0 { + pwms = <&pwm0 0 10000 PWM_POLARITY_NORMAL>; + }; + }; + + leds { + compatible = "gpio-leds"; + blue_led: led_0 { + gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; + }; + }; + + vbatt: vbatt { + compatible = "zmk,battery-voltage-divider"; + io-channels = <&adc 2>; + output-ohms = <100000>; + full-ohms = <(100000 + 100000)>; + }; +}; + +&adc { + status = "okay"; +}; + +&pwm0 { + status = "okay"; + pinctrl-0 = <&pwm0_default>; + pinctrl-1 = <&pwm0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&usbd { + status = "okay"; +}; + + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + sd_partition: partition@0 { + reg = <0x00000000 0x00026000>; + }; + code_partition: partition@26000 { + reg = <0x00026000 0x000c6000>; + }; + + /* + * The flash starting at 0x000ec000 and ending at + * 0x000f3fff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@ec000 { + reg = <0x000ec000 0x00008000>; + }; + + boot_partition: partition@f4000 { + reg = <0x000f4000 0x0000c000>; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <12>; /* number of LEDs */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + color-mapping = ; + }; +}; diff --git a/app/boards/arm/corneish_zen/CMakeLists.txt b/app/boards/arm/corneish_zen/CMakeLists.txt new file mode 100644 index 000000000000..afaaf6bf19be --- /dev/null +++ b/app/boards/arm/corneish_zen/CMakeLists.txt @@ -0,0 +1,60 @@ +if(CONFIG_ZMK_DISPLAY) + target_sources_ifdef(CONFIG_CUSTOM_WIDGET_BATTERY_STATUS app PRIVATE widgets/battery_status.c) + target_sources_ifdef(CONFIG_CUSTOM_WIDGET_OUTPUT_STATUS app PRIVATE widgets/output_status.c) + target_sources_ifdef(CONFIG_CUSTOM_WIDGET_LAYER_STATUS app PRIVATE widgets/layer_status.c) + target_sources_ifdef(CONFIG_CUSTOM_WIDGET_PERIPHERAL_STATUS app PRIVATE widgets/peripheral_status.c) + + add_subdirectory_ifdef(CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM widgets/icons) +endif() + +zephyr_library() + +if(CONFIG_ZMK_DISPLAY) + if(CONFIG_CUSTOM_WIDGET_BATTERY_STATUS) + zephyr_library_sources(widgets/icons/batt_100.c) + zephyr_library_sources(widgets/icons/batt_100_chg.c) + zephyr_library_sources(widgets/icons/batt_75.c) + zephyr_library_sources(widgets/icons/batt_75_chg.c) + zephyr_library_sources(widgets/icons/batt_50.c) + zephyr_library_sources(widgets/icons/batt_50_chg.c) + zephyr_library_sources(widgets/icons/batt_25.c) + zephyr_library_sources(widgets/icons/batt_25_chg.c) + zephyr_library_sources(widgets/icons/batt_5.c) + zephyr_library_sources(widgets/icons/batt_5_chg.c) + zephyr_library_sources(widgets/icons/batt_0.c) + zephyr_library_sources(widgets/icons/batt_0_chg.c) + endif() + if(CONFIG_CUSTOM_WIDGET_PERIPHERAL_STATUS) + zephyr_library_sources(widgets/icons/bluetooth_advertising.c) + zephyr_library_sources(widgets/icons/bluetooth_connected_right.c) + zephyr_library_sources(widgets/icons/bluetooth_disconnected_right.c) + endif() + if(CONFIG_CUSTOM_WIDGET_OUTPUT_STATUS) + zephyr_library_sources(widgets/icons/USB_connected.c) + zephyr_library_sources(widgets/icons/bluetooth_connected_1.c) + zephyr_library_sources(widgets/icons/bluetooth_connected_2.c) + zephyr_library_sources(widgets/icons/bluetooth_connected_3.c) + zephyr_library_sources(widgets/icons/bluetooth_connected_4.c) + zephyr_library_sources(widgets/icons/bluetooth_connected_5.c) + zephyr_library_sources(widgets/icons/bluetooth_advertising_1.c) + zephyr_library_sources(widgets/icons/bluetooth_advertising_2.c) + zephyr_library_sources(widgets/icons/bluetooth_advertising_3.c) + zephyr_library_sources(widgets/icons/bluetooth_advertising_4.c) + zephyr_library_sources(widgets/icons/bluetooth_advertising_5.c) + zephyr_library_sources(widgets/icons/bluetooth_disconnected_right.c) + endif() + if(CONFIG_CUSTOM_WIDGET_LAYER_STATUS) + zephyr_library_sources(widgets/icons/layers.c) + zephyr_library_sources(widgets/icons/layers2.c) + endif() + if(NOT CONFIG_ZMK_SPLIT_ROLE_CENTRAL) + zephyr_library_sources(widgets/icons/zenlogo.c) + endif() +endif() + +zephyr_library_include_directories(${ZEPHYR_LVGL_MODULE_DIR}) +zephyr_library_include_directories(${ZEPHYR_BASE}/lib/gui/lvgl/) +zephyr_library_sources_ifdef(CONFIG_ZMK_DISPLAY custom_status_screen.c) +zephyr_library_sources(${ZEPHYR_BASE}/misc/empty_file.c) +zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/include) +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) diff --git a/app/boards/arm/corneish_zen/Kconfig b/app/boards/arm/corneish_zen/Kconfig new file mode 100644 index 000000000000..33d926092eeb --- /dev/null +++ b/app/boards/arm/corneish_zen/Kconfig @@ -0,0 +1,10 @@ +# +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT +# + +config BOARD_CORNEISH_ZEN_LEFT + bool + +config BOARD_CORNEISH_ZEN_RIGHT + bool diff --git a/app/boards/arm/corneish_zen/Kconfig.board b/app/boards/arm/corneish_zen/Kconfig.board new file mode 100644 index 000000000000..ffb3ab1f4d5d --- /dev/null +++ b/app/boards/arm/corneish_zen/Kconfig.board @@ -0,0 +1,24 @@ +# +# Copyright (c) 2022 Darryl deHaan +# SPDX-License-Identifier: MIT +# + +config BOARD_CORNEISH_ZEN_V1_LEFT + bool "corneish zen left v1" + depends on SOC_NRF52840_QIAA + select BOARD_CORNEISH_ZEN_LEFT + +config BOARD_CORNEISH_ZEN_V1_RIGHT + bool "corneish zen right v1" + depends on SOC_NRF52840_QIAA + select BOARD_CORNEISH_ZEN_RIGHT + +config BOARD_CORNEISH_ZEN_V2_LEFT + bool "corneish zen left v2" + depends on SOC_NRF52840_QIAA + select BOARD_CORNEISH_ZEN_LEFT + +config BOARD_CORNEISH_ZEN_V2_RIGHT + bool "corneish zen right v2" + depends on SOC_NRF52840_QIAA + select BOARD_CORNEISH_ZEN_RIGHT diff --git a/app/boards/arm/corneish_zen/Kconfig.defconfig b/app/boards/arm/corneish_zen/Kconfig.defconfig new file mode 100644 index 000000000000..f3cc959edd01 --- /dev/null +++ b/app/boards/arm/corneish_zen/Kconfig.defconfig @@ -0,0 +1,81 @@ +# +# Copyright (c) 2022 Darryl deHaan +# SPDX-License-Identifier: MIT +# + +if BOARD_CORNEISH_ZEN_LEFT + +config ZMK_KEYBOARD_NAME + default "Corne-ish Zen" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif # BOARD_CORNEISH_ZEN_LEFT + + +if BOARD_CORNEISH_ZEN_LEFT || BOARD_CORNEISH_ZEN_RIGHT + +config BOARD + default "corneish_zen" + +config ZMK_SPLIT + default y + +config BT_CTLR + default BT + +if USB + +config USB_NRFX + default y + +config USB_DEVICE_STACK + default y + +endif # USB + +config ZMK_DISPLAY + select LV_USE_CONT + select LV_FONT_MONTSERRAT_26 + select LV_FONT_MONTSERRAT_16 + select LV_USE_LABEL + select LV_USE_IMG + +choice ZMK_DISPLAY_STATUS_SCREEN + default ZMK_DISPLAY_STATUS_SCREEN_CUSTOM +endchoice + +if ZMK_DISPLAY + +config SPI + default y + +config IL0323 + default y + +config ZMK_DISPLAY_BLANK_ON_IDLE + default n + +endif # ZMK_DISPLAY + +menuconfig CUSTOM_WIDGET_BATTERY_STATUS + bool "custom battery status widget" + +menuconfig CUSTOM_WIDGET_OUTPUT_STATUS + bool "custom output status widget" + +menuconfig CUSTOM_WIDGET_LAYER_STATUS + bool "custom layer status widget" + +menuconfig CUSTOM_WIDGET_PERIPHERAL_STATUS + bool "custom peripheral status widget" + +endif # BOARD_CORNEISH_ZEN_LEFT || BOARD_CORNEISH_ZEN_RIGHT + +if BOARD_CORNEISH_ZEN_V1_LEFT || BOARD_CORNEISH_ZEN_V1_RIGHT + +config BQ274XX + default y + +endif # BOARD_CORNEISH_ZEN_V1_LEFT || BOARD_CORNEISH_ZEN_V1_RIGHT diff --git a/app/boards/arm/corneish_zen/board.cmake b/app/boards/arm/corneish_zen/board.cmake new file mode 100644 index 000000000000..fa847d505952 --- /dev/null +++ b/app/boards/arm/corneish_zen/board.cmake @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: MIT + +board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") +include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) diff --git a/app/boards/arm/corneish_zen/corneish_zen.conf b/app/boards/arm/corneish_zen/corneish_zen.conf new file mode 100644 index 000000000000..a2e1fbe63c1b --- /dev/null +++ b/app/boards/arm/corneish_zen/corneish_zen.conf @@ -0,0 +1,5 @@ +# Go to sleep after one hour (1*60*60*1000ms) +CONFIG_ZMK_IDLE_SLEEP_TIMEOUT=3600000 + +# Turn on logging, and set ZMK logging to debug output +# CONFIG_ZMK_USB_LOGGING=y diff --git a/app/boards/arm/corneish_zen/corneish_zen.dtsi b/app/boards/arm/corneish_zen/corneish_zen.dtsi new file mode 100644 index 000000000000..c6f2b630cbe8 --- /dev/null +++ b/app/boards/arm/corneish_zen/corneish_zen.dtsi @@ -0,0 +1,120 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +/dts-v1/; +#include + +#include + +/ { + model = "Corne-ish Zen"; + compatible = "corneish_zen"; + + chosen { + zephyr,code-partition = &code_partition; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zmk,kscan = &kscan0; + zmk,display = &epd; + zephyr,console = &cdc_acm_uart; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <12>; + rows = <4>; + + // | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | + // | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | + // | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | + // | SW19 | SW20 | SW21 | | SW21 | SW20 | SW19 | + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) + RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) + >; + }; + + five_column_transform: keymap_transform_1 { + compatible = "zmk,matrix-transform"; + columns = <10>; + rows = <4>; + + // | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | + // | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | + // | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | + // | SW19 | SW20 | SW21 | | SW21 | SW20 | SW19 | + map = < + RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) + RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) + RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) + RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) + >; + }; + +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + sd_partition: partition@0 { + reg = <0x00000000 0x00026000>; + }; + code_partition: partition@26000 { + reg = <0x00026000 0x000c6000>; + }; + + /* + * The flash starting at 0x000ec000 and ending at + * 0x000f3fff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@ec000 { + reg = <0x000ec000 0x00008000>; + }; + + boot_partition: partition@f4000 { + reg = <0x000f4000 0x0000c000>; + }; + }; +}; diff --git a/app/boards/arm/corneish_zen/corneish_zen.keymap b/app/boards/arm/corneish_zen/corneish_zen.keymap new file mode 100644 index 000000000000..d2549819c03e --- /dev/null +++ b/app/boards/arm/corneish_zen/corneish_zen.keymap @@ -0,0 +1,68 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include +#include +#include + +/ { + chosen { + zmk,matrix_transform = &default_transform; + // zmk,matrix_transform = &five_column_transform; + }; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + display-name = "QWERTY"; +// -------------------------------------------------------------------------------- +// | TAB | Q | W | E | R | T | | Y | U | I | O | P | BKSP | +// | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | +// | SHFT | Z | X | C | V | B | | N | M | , | . | / | ESC | +// | GUI | LWR | SPC | | ENT | RSE | ALT | + bindings = < +&kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSPC +&kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT +&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp ESC + &kp LGUI &mo 1 &kp SPACE &kp RET &mo 2 &kp RALT + >; + }; + + lower_layer { + display-name = "NUMBER"; +// ----------------------------------------------------------------------------------------- +// | TAB | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | BKSP | +// | BTCLR| BT1 | BT2 | BT3 | BT4 | BT5 | | LFT | DWN | UP | RGT | | | +// | SHFT | | | | | | | | | | | | | +// | GUI | | SPC | | ENT | | ALT | + bindings = < +&kp TAB &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp BSPC +&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &kp LEFT &kp DOWN &kp UP &kp RIGHT &trans &trans +&kp LSHFT &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &kp LGUI &trans &kp SPACE &kp RET &trans &kp RALT + >; + }; + + raise_layer { + display-name = "SYMBOL"; +// ----------------------------------------------------------------------------------------- +// | TAB | ! | @ | # | $ | % | | ^ | & | * | ( | ) | BKSP | +// | CTRL | | | | | | | - | = | [ | ] | \ | ` | +// | SHFT | | | | | | | _ | + | { | } | "|" | ~ | +// | GUI | | SPC | | ENT | | ALT | + bindings = < +&kp TAB &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp KP_MULTIPLY &kp LPAR &kp RPAR &kp BSPC +&kp LCTRL &trans &trans &trans &trans &trans &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH &kp GRAVE +&kp LSHFT &trans &trans &trans &trans &trans &kp UNDER &kp PLUS &kp LBRC &kp RBRC &kp PIPE &kp TILDE + &kp LGUI &trans &kp SPACE &kp RET &trans &kp RALT + >; + }; + }; +}; diff --git a/app/boards/arm/corneish_zen/corneish_zen.yaml b/app/boards/arm/corneish_zen/corneish_zen.yaml new file mode 100644 index 000000000000..7975b262af1c --- /dev/null +++ b/app/boards/arm/corneish_zen/corneish_zen.yaml @@ -0,0 +1,20 @@ +identifier: corne-ish_zen_v2 +name: Corne-ish Zen v2 +url: https://lowprokb.ca/collections/keyboards/products/corne-ish-zen +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 40 +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog + - gpio + - i2c + - spi diff --git a/app/boards/arm/corneish_zen/corneish_zen_v1.zmk.yml b/app/boards/arm/corneish_zen/corneish_zen_v1.zmk.yml new file mode 100644 index 000000000000..1f6be20d36c6 --- /dev/null +++ b/app/boards/arm/corneish_zen/corneish_zen_v1.zmk.yml @@ -0,0 +1,15 @@ +file_format: "1" +id: corneish_zen_v1 +name: Corneish Zen v1 +url: https://lowprokb.ca/collections/keyboards/products/corne-ish-zen +type: board +arch: arm +features: + - keys + - display +outputs: + - usb + - ble +siblings: + - corneish_zen_v1_left + - corneish_zen_v1_right diff --git a/app/boards/arm/corneish_zen/corneish_zen_v1_left.dts b/app/boards/arm/corneish_zen/corneish_zen_v1_left.dts new file mode 100644 index 000000000000..6683b1b2408b --- /dev/null +++ b/app/boards/arm/corneish_zen/corneish_zen_v1_left.dts @@ -0,0 +1,119 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include "corneish_zen.dtsi" + +/{ + chosen { + zephyr,display = &epd; + zmk,battery = &fuelgauge; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&gpio0 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 31 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 30 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + col-gpios + = <&gpio0 21 GPIO_ACTIVE_HIGH> + , <&gpio0 23 GPIO_ACTIVE_HIGH> + , <&gpio0 12 GPIO_ACTIVE_HIGH> + , <&gpio1 9 GPIO_ACTIVE_HIGH> + , <&gpio0 7 GPIO_ACTIVE_HIGH> + , <&gpio0 5 GPIO_ACTIVE_HIGH> + ; + }; + + leds { + compatible = "gpio-leds"; + blue_led: led_0 { + gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&pinctrl { + spi2_default: spi2_default { + group1 { + psels = , + , + ; + }; + }; + + spi2_sleep: spi2_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; + + i2c0_default: i2c0_default { + group1 { + psels = , + ; + }; + }; + + i2c0_sleep: i2c0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +&i2c0 { + status = "okay"; + compatible = "nordic,nrf-twim"; + pinctrl-0 = <&i2c0_default>; + pinctrl-1 = <&i2c0_sleep>; + pinctrl-names = "default", "sleep"; + clock-frequency = <100000>; + + fuelgauge: bq274xx@55 { + compatible = "ti,bq274xx"; + reg = <0x55>; + design-voltage = <3700>; //Battery Design Volatge in mV + design-capacity = <180>; //Battery Design Capacity in mAh + taper-current = <2>; //Battery Taper current in mAh + terminate-voltage = <2750>; //Battery Terminate Voltage in mV + int-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; + }; +}; + +&spi2 { + status = "okay"; + compatible = "nordic,nrf-spim"; + pinctrl-0 = <&spi2_default>; + pinctrl-1 = <&spi2_sleep>; + pinctrl-names = "default", "sleep"; + cs-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; + + epd: il0323@0 { + compatible = "gooddisplay,il0323"; + reg = <0>; + width = <80>; + height = <128>; + spi-max-frequency = <4000000>; + dc-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>; + busy-gpios = <&gpio0 25 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio0 24 GPIO_ACTIVE_LOW>; + pwr = [03 00 26 26]; + cdi = <0xd2>; + tcon = <0x22>; + }; +}; diff --git a/app/boards/arm/corneish_zen/corneish_zen_v1_left_defconfig b/app/boards/arm/corneish_zen/corneish_zen_v1_left_defconfig new file mode 100644 index 000000000000..d738255601bb --- /dev/null +++ b/app/boards/arm/corneish_zen/corneish_zen_v1_left_defconfig @@ -0,0 +1,79 @@ +# +# Copyright (c) 2022 Darryl deHaan +# SPDX-License-Identifier: MIT +# + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_CORNEISH_ZEN_V1_LEFT=y +CONFIG_ZMK_SLEEP=y +CONFIG_ZMK_DISPLAY=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# enable pinctrl +CONFIG_PINCTRL=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable I2C +CONFIG_I2C=y +CONFIG_I2C_NRFX=y + +# Enable SPI +CONFIG_SPI_NRFX=y + +# Enable writing to flash +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +# Enable 32kHz crystal +CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_30PPM=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y + +# enable display drivers +CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED=y +CONFIG_ZMK_DISPLAY_DEDICATED_THREAD_STACK_SIZE=2048 +CONFIG_LV_Z_BITS_PER_PIXEL=1 +CONFIG_LV_COLOR_DEPTH_1=y +CONFIG_LV_DPI_DEF=145 +CONFIG_LV_Z_VDB_SIZE=100 +CONFIG_LV_USE_THEME_MONO=y +CONFIG_LV_COLOR_CHROMA_KEY_HEX=0x00FF00 +CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_16=y +CONFIG_LV_FONT_MONTSERRAT_26=y +CONFIG_LV_FONT_DEFAULT_MONTSERRAT_26=y + +# custom status screens +CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM=y +CONFIG_ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN=n +CONFIG_CUSTOM_WIDGET_BATTERY_STATUS=y +CONFIG_ZMK_WIDGET_BATTERY_STATUS=n +CONFIG_CUSTOM_WIDGET_OUTPUT_STATUS=y +CONFIG_ZMK_WIDGET_OUTPUT_STATUS=n +CONFIG_CUSTOM_WIDGET_LAYER_STATUS=y +CONFIG_ZMK_WIDGET_LAYER_STATUS=n + +# Turn on logging, and set ZMK logging to debug output +#CONFIG_LOG=y +#CONFIG_ZMK_USB_LOGGING=y +#CONFIG_ZMK_LOG_LEVEL_DBG=y +#CONFIG_LOG_BUFFER_SIZE=65536 +#CONFIG_LOG_STRDUP_BUF_COUNT=160 +#CONFIG_I2C_LOG_LEVEL_DBG=y +#CONFIG_SPI_LOG_LEVEL_DBG=y +#CONFIG_DISPLAY_LOG_LEVEL_DBG=y +#CONFIG_LVGL_LOG_LEVEL_DBG=y +#CONFIG_LVGL_USE_DEBUG=y +#CONFIG_SENSOR_LOG_LEVEL_DBG=y diff --git a/app/boards/arm/corneish_zen/corneish_zen_v1_right.dts b/app/boards/arm/corneish_zen/corneish_zen_v1_right.dts new file mode 100644 index 000000000000..492c79fa1084 --- /dev/null +++ b/app/boards/arm/corneish_zen/corneish_zen_v1_right.dts @@ -0,0 +1,127 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include "corneish_zen.dtsi" + +/{ + chosen { + zephyr,display = &epd; + zmk,battery = &fuelgauge; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&gpio0 22 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + col-gpios + = <&gpio0 19 GPIO_ACTIVE_HIGH> + , <&gpio0 21 GPIO_ACTIVE_HIGH> + , <&gpio0 23 GPIO_ACTIVE_HIGH> + , <&gpio0 12 GPIO_ACTIVE_HIGH> + , <&gpio1 9 GPIO_ACTIVE_HIGH> + , <&gpio0 7 GPIO_ACTIVE_HIGH> + ; + }; + + leds { + compatible = "gpio-leds"; + blue_led: led_0 { + gpios = <&gpio0 26 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&default_transform { + col-offset = <6>; +}; + +&five_column_transform { + col-offset = <6>; +}; + +&pinctrl { + spi2_default: spi2_default { + group1 { + psels = , + , + ; + }; + }; + + spi2_sleep: spi2_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; + + i2c0_default: i2c0_default { + group1 { + psels = , + ; + }; + }; + + i2c0_sleep: i2c0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +&i2c0 { + status = "okay"; + compatible = "nordic,nrf-twim"; + pinctrl-0 = <&i2c0_default>; + pinctrl-1 = <&i2c0_sleep>; + pinctrl-names = "default", "sleep"; + clock-frequency = <100000>; + + fuelgauge: bq274xx@55 { + compatible = "ti,bq274xx"; + reg = <0x55>; + design-voltage = <3700>; //Battery Design Volatge in mV + design-capacity = <180>; //Battery Design Capacity in mAh + taper-current = <2>; //Battery Taper current in mAh 2.1 + terminate-voltage = <2750>; //Battery Terminate Voltage in mV + int-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; + }; +}; + +&spi2 { + status = "okay"; + compatible = "nordic,nrf-spim"; + pinctrl-0 = <&spi2_default>; + pinctrl-1 = <&spi2_sleep>; + pinctrl-names = "default", "sleep"; + cs-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>; + + epd: il0323@0 { + compatible = "gooddisplay,il0323"; + reg = <0>; + width = <80>; + height = <128>; + spi-max-frequency = <4000000>; + dc-gpios = <&gpio0 15 GPIO_ACTIVE_LOW>; + busy-gpios = <&gpio0 14 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio0 25 GPIO_ACTIVE_LOW>; + pwr = [03 00 26 26]; + cdi = <0xd2>; + tcon = <0x22>; + }; +}; diff --git a/app/boards/arm/corneish_zen/corneish_zen_v1_right_defconfig b/app/boards/arm/corneish_zen/corneish_zen_v1_right_defconfig new file mode 100644 index 000000000000..5284159d83ff --- /dev/null +++ b/app/boards/arm/corneish_zen/corneish_zen_v1_right_defconfig @@ -0,0 +1,78 @@ +# +# Copyright (c) 2022 Darryl deHaan +# SPDX-License-Identifier: MIT +# + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_CORNEISH_ZEN_V1_RIGHT=y +CONFIG_ZMK_SLEEP=y +CONFIG_ZMK_DISPLAY=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# enable pinctrl +CONFIG_PINCTRL=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable I2C +CONFIG_I2C=y +CONFIG_I2C_NRFX=y + +# Enable SPI +CONFIG_SPI_NRFX=y + +# Enable writing to flash +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +# Enable 32kHz crystal +CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_30PPM=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y + +# enable display drivers +CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED=y +CONFIG_ZMK_DISPLAY_DEDICATED_THREAD_STACK_SIZE=2048 +CONFIG_LV_Z_BITS_PER_PIXEL=1 +CONFIG_LV_COLOR_DEPTH_1=y +CONFIG_LV_DPI_DEF=145 +CONFIG_LV_Z_VDB_SIZE=100 +CONFIG_LV_USE_THEME_MONO=y +CONFIG_LV_COLOR_CHROMA_KEY_HEX=0x00FF00 +CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_16=y +CONFIG_LV_FONT_MONTSERRAT_26=y +CONFIG_LV_FONT_DEFAULT_MONTSERRAT_26=y + +# custom status screens +CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM=y +CONFIG_ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN=n +CONFIG_CUSTOM_WIDGET_BATTERY_STATUS=y +CONFIG_ZMK_WIDGET_BATTERY_STATUS=n +CONFIG_CUSTOM_WIDGET_PERIPHERAL_STATUS=y +CONFIG_ZMK_WIDGET_PERIPHERAL_STATUS=n + +# Turn on logging, and set ZMK logging to debug output +#CONFIG_LOG=y +#CONFIG_LOG_PROCESS_THREAD_STARTUP_DELAY_MS=8000 +#CONFIG_ZMK_USB_LOGGING=y +#CONFIG_ZMK_LOG_LEVEL_DBG=y +#CONFIG_LOG_BUFFER_SIZE=20000 +#CONFIG_LOG_STRDUP_BUF_COUNT=60 +#CONFIG_I2C_LOG_LEVEL_DBG=y +#CONFIG_SPI_LOG_LEVEL_DBG=y +#CONFIG_DISPLAY_LOG_LEVEL_DBG=y +#CONFIG_LVGL_LOG_LEVEL_DBG=y +#CONFIG_LVGL_USE_DEBUG=y +#CONFIG_SENSOR_LOG_LEVEL_DBG=y diff --git a/app/boards/arm/corneish_zen/corneish_zen_v2.yaml b/app/boards/arm/corneish_zen/corneish_zen_v2.yaml new file mode 100644 index 000000000000..46a213d9c602 --- /dev/null +++ b/app/boards/arm/corneish_zen/corneish_zen_v2.yaml @@ -0,0 +1,20 @@ +identifier: corneish_zen_v2 +name: Corne-ish Zen v2 +type: keyboard +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - gpio + - i2c + - counter + - spi + - usb_device + - lsm303dlhc + - nvs + - can + - kscan + - ble + - adc diff --git a/app/boards/arm/corneish_zen/corneish_zen_v2.zmk.yml b/app/boards/arm/corneish_zen/corneish_zen_v2.zmk.yml new file mode 100644 index 000000000000..37c1cef4828d --- /dev/null +++ b/app/boards/arm/corneish_zen/corneish_zen_v2.zmk.yml @@ -0,0 +1,15 @@ +file_format: "1" +id: corneish_zen_v2 +name: Corneish Zen v2 +url: https://lowprokb.ca/collections/keyboards/products/corne-ish-zen +type: board +arch: arm +features: + - keys + - display +outputs: + - usb + - ble +siblings: + - corneish_zen_v2_left + - corneish_zen_v2_right diff --git a/app/boards/arm/corneish_zen/corneish_zen_v2_left.dts b/app/boards/arm/corneish_zen/corneish_zen_v2_left.dts new file mode 100644 index 000000000000..dacb24c3a247 --- /dev/null +++ b/app/boards/arm/corneish_zen/corneish_zen_v2_left.dts @@ -0,0 +1,93 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include "corneish_zen.dtsi" + +/{ + chosen { + zephyr,display = &epd; + zmk,battery = &vbatt; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&gpio0 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 31 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 30 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + col-gpios + = <&gpio0 21 GPIO_ACTIVE_HIGH> + , <&gpio0 23 GPIO_ACTIVE_HIGH> + , <&gpio0 12 GPIO_ACTIVE_HIGH> + , <&gpio1 9 GPIO_ACTIVE_HIGH> + , <&gpio0 7 GPIO_ACTIVE_HIGH> + , <&gpio0 5 GPIO_ACTIVE_HIGH> + ; + }; + + leds { + compatible = "gpio-leds"; + blue_led: led_0 { + gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>; + }; + }; + + vbatt: vbatt { + compatible = "zmk,battery-voltage-divider"; + io-channels = <&adc 0>; + output-ohms = <1960000>; + full-ohms = <(1960000 + 810000)>; + }; + +}; + +&pinctrl { + spi0_default: spi0_default { + group1 { + psels = , + , + ; + }; + }; + + spi0_sleep: spi0_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; + +&spi0 { + status = "okay"; + compatible = "nordic,nrf-spim"; + pinctrl-0 = <&spi0_default>; + pinctrl-1 = <&spi0_sleep>; + pinctrl-names = "default", "sleep"; + cs-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; + + epd: il0323@0 { + compatible = "gooddisplay,il0323"; + reg = <0>; + width = <80>; + height = <128>; + spi-max-frequency = <4000000>; + dc-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>; + busy-gpios = <&gpio0 25 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio0 24 GPIO_ACTIVE_LOW>; + pwr = [03 00 26 26]; + cdi = <0xd2>; + tcon = <0x22>; + }; +}; diff --git a/app/boards/arm/corneish_zen/corneish_zen_v2_left_defconfig b/app/boards/arm/corneish_zen/corneish_zen_v2_left_defconfig new file mode 100644 index 000000000000..29a5f878ac24 --- /dev/null +++ b/app/boards/arm/corneish_zen/corneish_zen_v2_left_defconfig @@ -0,0 +1,75 @@ +# +# Copyright (c) 2022 Darryl deHaan +# SPDX-License-Identifier: MIT +# + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_CORNEISH_ZEN_V2_LEFT=y +CONFIG_ZMK_SLEEP=y +CONFIG_ZMK_DISPLAY=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# enable pinctrl +CONFIG_PINCTRL=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable SPI +CONFIG_SPI_NRFX=y + +# Enable writing to flash +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +# Enable 32kHz crystal +CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_30PPM=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y + +# enable display drivers +CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED=y +CONFIG_ZMK_DISPLAY_DEDICATED_THREAD_STACK_SIZE=2048 +CONFIG_LV_Z_BITS_PER_PIXEL=1 +CONFIG_LV_COLOR_DEPTH_1=y +CONFIG_LV_DPI_DEF=145 +CONFIG_LV_Z_VDB_SIZE=100 +CONFIG_LV_USE_THEME_MONO=y +CONFIG_LV_COLOR_CHROMA_KEY_HEX=0x00FF00 +CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_16=y +CONFIG_LV_FONT_MONTSERRAT_26=y +CONFIG_LV_FONT_DEFAULT_MONTSERRAT_26=y + +# custom status screens +CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM=y +CONFIG_ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN=n +CONFIG_CUSTOM_WIDGET_BATTERY_STATUS=y +CONFIG_ZMK_WIDGET_BATTERY_STATUS=n +CONFIG_CUSTOM_WIDGET_OUTPUT_STATUS=y +CONFIG_ZMK_WIDGET_OUTPUT_STATUS=n +CONFIG_CUSTOM_WIDGET_LAYER_STATUS=y +CONFIG_ZMK_WIDGET_LAYER_STATUS=n + +# Turn on logging, and set ZMK logging to debug output +#CONFIG_LOG=y +#CONFIG_ZMK_USB_LOGGING=y +#CONFIG_ZMK_LOG_LEVEL_DBG=y +#CONFIG_LOG_BUFFER_SIZE=65536 +#CONFIG_LOG_STRDUP_BUF_COUNT=160 +#CONFIG_I2C_LOG_LEVEL_DBG=y +#CONFIG_SPI_LOG_LEVEL_DBG=y +#CONFIG_DISPLAY_LOG_LEVEL_DBG=y +#CONFIG_LVGL_LOG_LEVEL_DBG=y +#CONFIG_LVGL_USE_DEBUG=y +#CONFIG_SENSOR_LOG_LEVEL_DBG=y diff --git a/app/boards/arm/corneish_zen/corneish_zen_v2_right.dts b/app/boards/arm/corneish_zen/corneish_zen_v2_right.dts new file mode 100644 index 000000000000..f1baea426561 --- /dev/null +++ b/app/boards/arm/corneish_zen/corneish_zen_v2_right.dts @@ -0,0 +1,100 @@ +/* +* +* Copyright (c) 2021 Darryl deHaan +* SPDX-License-Identifier: MIT +* +*/ + +#include "corneish_zen.dtsi" + +/{ + chosen { + zephyr,display = &epd; + zmk,battery = &vbatt; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&gpio0 22 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + col-gpios + = <&gpio0 19 GPIO_ACTIVE_HIGH> + , <&gpio0 21 GPIO_ACTIVE_HIGH> + , <&gpio0 23 GPIO_ACTIVE_HIGH> + , <&gpio0 12 GPIO_ACTIVE_HIGH> + , <&gpio1 9 GPIO_ACTIVE_HIGH> + , <&gpio0 7 GPIO_ACTIVE_HIGH> + ; + }; + + leds { + compatible = "gpio-leds"; + blue_led: led_0 { + gpios = <&gpio0 26 GPIO_ACTIVE_HIGH>; + }; + }; + + vbatt: vbatt { + compatible = "zmk,battery-voltage-divider"; + io-channels = <&adc 0>; + output-ohms = <1960000>; + full-ohms = <(1960000 + 810000)>; + }; +}; + +&default_transform { + col-offset = <6>; +}; + +&five_column_transform { + col-offset = <6>; +}; + +&pinctrl { + spi0_default: spi0_default { + group1 { + psels = , + , + ; + }; + }; + + spi0_sleep: spi0_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; + +&spi0 { + status = "okay"; + compatible = "nordic,nrf-spim"; + pinctrl-0 = <&spi0_default>; + pinctrl-1 = <&spi0_sleep>; + pinctrl-names = "default", "sleep"; + cs-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>; + + epd: il0323@0 { + compatible = "gooddisplay,il0323"; + reg = <0>; + width = <80>; + height = <128>; + spi-max-frequency = <4000000>; + dc-gpios = <&gpio0 15 GPIO_ACTIVE_LOW>; + busy-gpios = <&gpio0 14 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio0 25 GPIO_ACTIVE_LOW>; + pwr = [03 00 26 26]; + cdi = <0xd2>; + tcon = <0x22>; + }; +}; diff --git a/app/boards/arm/corneish_zen/corneish_zen_v2_right_defconfig b/app/boards/arm/corneish_zen/corneish_zen_v2_right_defconfig new file mode 100644 index 000000000000..506aa67e1b12 --- /dev/null +++ b/app/boards/arm/corneish_zen/corneish_zen_v2_right_defconfig @@ -0,0 +1,74 @@ +# +# Copyright (c) 2022 Darryl deHaan +# SPDX-License-Identifier: MIT +# + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_CORNEISH_ZEN_V2_RIGHT=y +CONFIG_ZMK_SLEEP=y +CONFIG_ZMK_DISPLAY=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# enable pinctrl +CONFIG_PINCTRL=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable SPI +CONFIG_SPI_NRFX=y + +# Enable writing to flash +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +# Enable 32kHz crystal +CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_30PPM=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y + +# enable display drivers +CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED=y +CONFIG_ZMK_DISPLAY_DEDICATED_THREAD_STACK_SIZE=2048 +CONFIG_LV_Z_BITS_PER_PIXEL=1 +CONFIG_LV_COLOR_DEPTH_1=y +CONFIG_LV_DPI_DEF=145 +CONFIG_LV_Z_VDB_SIZE=100 +CONFIG_LV_USE_THEME_MONO=y +CONFIG_LV_COLOR_CHROMA_KEY_HEX=0x00FF00 +CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_16=y +CONFIG_LV_FONT_MONTSERRAT_26=y +CONFIG_LV_FONT_DEFAULT_MONTSERRAT_26=y + +# custom status screens +CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM=y +CONFIG_ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN=n +CONFIG_CUSTOM_WIDGET_BATTERY_STATUS=y +CONFIG_ZMK_WIDGET_BATTERY_STATUS=n +CONFIG_CUSTOM_WIDGET_PERIPHERAL_STATUS=y +CONFIG_ZMK_WIDGET_PERIPHERAL_STATUS=n + +# Turn on logging, and set ZMK logging to debug output +#CONFIG_LOG=y +#CONFIG_LOG_PROCESS_THREAD_STARTUP_DELAY_MS=8000 +#CONFIG_ZMK_USB_LOGGING=y +#CONFIG_ZMK_LOG_LEVEL_DBG=y +#CONFIG_LOG_BUFFER_SIZE=20000 +#CONFIG_LOG_STRDUP_BUF_COUNT=60 +#CONFIG_I2C_LOG_LEVEL_DBG=y +#CONFIG_SPI_LOG_LEVEL_DBG=y +#CONFIG_DISPLAY_LOG_LEVEL_DBG=y +#CONFIG_LVGL_LOG_LEVEL_DBG=y +#CONFIG_LVGL_USE_DEBUG=y +#CONFIG_SENSOR_LOG_LEVEL_DBG=y diff --git a/app/boards/arm/corneish_zen/custom_status_screen.c b/app/boards/arm/corneish_zen/custom_status_screen.c new file mode 100644 index 000000000000..492239c8a57b --- /dev/null +++ b/app/boards/arm/corneish_zen/custom_status_screen.c @@ -0,0 +1,77 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include "widgets/battery_status.h" +#include "widgets/peripheral_status.h" +#include "widgets/output_status.h" +#include "widgets/layer_status.h" +#include "custom_status_screen.h" + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +LV_IMG_DECLARE(zenlogo); +LV_IMG_DECLARE(layers2); + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_BATTERY_STATUS) +static struct zmk_widget_battery_status battery_status_widget; +#endif + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_OUTPUT_STATUS) +static struct zmk_widget_output_status output_status_widget; +#endif + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_PERIPHERAL_STATUS) +static struct zmk_widget_peripheral_status peripheral_status_widget; +#endif + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_LAYER_STATUS) +static struct zmk_widget_layer_status layer_status_widget; +#endif + +lv_obj_t *zmk_display_status_screen() { + + lv_obj_t *screen; + screen = lv_obj_create(NULL); + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_BATTERY_STATUS) + zmk_widget_battery_status_init(&battery_status_widget, screen); + lv_obj_align(zmk_widget_battery_status_obj(&battery_status_widget), LV_ALIGN_TOP_MID, 0, 2); +#endif + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_OUTPUT_STATUS) + zmk_widget_output_status_init(&output_status_widget, screen); + lv_obj_align(zmk_widget_output_status_obj(&output_status_widget), LV_ALIGN_TOP_MID, 0, 41); +#endif + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_PERIPHERAL_STATUS) + zmk_widget_peripheral_status_init(&peripheral_status_widget, screen); + lv_obj_align(zmk_widget_peripheral_status_obj(&peripheral_status_widget), LV_ALIGN_TOP_MID, 0, + 41); +#endif + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_LAYER_STATUS) + lv_obj_t *LayersHeading; + LayersHeading = lv_img_create(screen); + lv_obj_align(LayersHeading, LV_ALIGN_BOTTOM_MID, 0, -30); + lv_img_set_src(LayersHeading, &layers2); + + zmk_widget_layer_status_init(&layer_status_widget, screen); + lv_obj_set_style_text_font(zmk_widget_layer_status_obj(&layer_status_widget), + &lv_font_montserrat_16, LV_PART_MAIN); + lv_obj_align(zmk_widget_layer_status_obj(&layer_status_widget), LV_ALIGN_BOTTOM_MID, 0, -5); +#endif + +#if !IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) + lv_obj_t *zenlogo_icon; + zenlogo_icon = lv_img_create(screen); + lv_img_set_src(zenlogo_icon, &zenlogo); + lv_obj_align(zenlogo_icon, LV_ALIGN_BOTTOM_MID, 0, -5); +#endif + + return screen; +} diff --git a/app/boards/arm/corneish_zen/custom_status_screen.h b/app/boards/arm/corneish_zen/custom_status_screen.h new file mode 100644 index 000000000000..8da1510de056 --- /dev/null +++ b/app/boards/arm/corneish_zen/custom_status_screen.h @@ -0,0 +1,12 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include + +lv_obj_t *zmk_display_status_screen(); \ No newline at end of file diff --git a/app/boards/arm/corneish_zen/widgets/battery_status.c b/app/boards/arm/corneish_zen/widgets/battery_status.c new file mode 100644 index 000000000000..9a2189d1e2f4 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/battery_status.c @@ -0,0 +1,96 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include "battery_status.h" +#include +#include +#include +#include + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); + +struct battery_status_state { + uint8_t level; +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + bool usb_present; +#endif +}; + +LV_IMG_DECLARE(batt_100); +LV_IMG_DECLARE(batt_100_chg); +LV_IMG_DECLARE(batt_75); +LV_IMG_DECLARE(batt_75_chg); +LV_IMG_DECLARE(batt_50); +LV_IMG_DECLARE(batt_50_chg); +LV_IMG_DECLARE(batt_25); +LV_IMG_DECLARE(batt_25_chg); +LV_IMG_DECLARE(batt_5); +LV_IMG_DECLARE(batt_5_chg); +LV_IMG_DECLARE(batt_0); +LV_IMG_DECLARE(batt_0_chg); + +static void set_battery_symbol(lv_obj_t *icon, struct battery_status_state state) { + uint8_t level = state.level; + +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + if (level > 95) { + lv_img_set_src(icon, state.usb_present ? &batt_100_chg : &batt_100); + } else if (level > 74) { + lv_img_set_src(icon, state.usb_present ? &batt_75_chg : &batt_75); + } else if (level > 49) { + lv_img_set_src(icon, state.usb_present ? &batt_50_chg : &batt_50); + } else if (level > 24) { + lv_img_set_src(icon, state.usb_present ? &batt_25_chg : &batt_25); + } else if (level > 5) { + lv_img_set_src(icon, state.usb_present ? &batt_5_chg : &batt_5); + } else { + lv_img_set_src(icon, state.usb_present ? &batt_0_chg : &batt_0); + } +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ +} + +void battery_status_update_cb(struct battery_status_state state) { + struct zmk_widget_battery_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_battery_symbol(widget->obj, state); } +} + +static struct battery_status_state battery_status_get_state(const zmk_event_t *eh) { + return (struct battery_status_state) { + .level = bt_bas_get_battery_level(), +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + .usb_present = zmk_usb_is_powered(), +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + }; +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_battery_status, struct battery_status_state, + battery_status_update_cb, battery_status_get_state) + +ZMK_SUBSCRIPTION(widget_battery_status, zmk_battery_state_changed); +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) +ZMK_SUBSCRIPTION(widget_battery_status, zmk_usb_conn_state_changed); +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + +int zmk_widget_battery_status_init(struct zmk_widget_battery_status *widget, lv_obj_t *parent) { + widget->obj = lv_img_create(parent); + + sys_slist_append(&widgets, &widget->node); + widget_battery_status_init(); + + return 0; +} + +lv_obj_t *zmk_widget_battery_status_obj(struct zmk_widget_battery_status *widget) { + return widget->obj; +} diff --git a/app/boards/arm/corneish_zen/widgets/battery_status.h b/app/boards/arm/corneish_zen/widgets/battery_status.h new file mode 100644 index 000000000000..d493c582b32b --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/battery_status.h @@ -0,0 +1,20 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include + +#include + +struct zmk_widget_battery_status { + sys_snode_t node; + lv_obj_t *obj; +}; + +int zmk_widget_battery_status_init(struct zmk_widget_battery_status *widget, lv_obj_t *parent); +lv_obj_t *zmk_widget_battery_status_obj(struct zmk_widget_battery_status *widget); diff --git a/app/boards/arm/corneish_zen/widgets/icons/CMakeLists.txt b/app/boards/arm/corneish_zen/widgets/icons/CMakeLists.txt new file mode 100644 index 000000000000..eee750bf8c55 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/CMakeLists.txt @@ -0,0 +1,4 @@ +# +# Copyright (c) 2022 Darryl deHaan +# SPDX-License-Identifier: MIT +# \ No newline at end of file diff --git a/app/boards/arm/corneish_zen/widgets/icons/USB_connected.c b/app/boards/arm/corneish_zen/widgets/icons/USB_connected.c new file mode 100644 index 000000000000..b3b60422257b --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/USB_connected.c @@ -0,0 +1,41 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_USB_CONNECTED +#define LV_ATTRIBUTE_IMG_USB_CONNECTED +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_USB_CONNECTED uint8_t USB_connected_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, 0x00, 0x3f, + 0xff, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, + 0xff, 0xfe, 0x07, 0xff, 0xff, 0xff, 0xff, 0x07, 0x1e, 0x30, 0x38, 0x07, 0x0f, 0x1c, 0x20, 0x38, + 0x07, 0x0f, 0x1c, 0x47, 0x10, 0xc3, 0x3e, 0x1c, 0x43, 0xf1, 0xc7, 0x7e, 0x3c, 0x60, 0x70, 0x0e, + 0x7e, 0x3c, 0x70, 0x30, 0x0e, 0x7e, 0x38, 0xfc, 0x33, 0xc7, 0xfe, 0x18, 0x8f, 0x23, 0x87, 0x0e, + 0x00, 0xc6, 0x20, 0x07, 0x0f, 0x01, 0xe0, 0x60, 0x0e, 0x0f, 0x87, 0xf0, 0xe0, 0x3e, 0x07, 0xff, + 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xfe, 0x00, 0x01, 0xff, 0xff, + 0xfc, 0x00, 0x00, 0x7f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t USB_connected = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 164, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = USB_connected_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/batt_0.c b/app/boards/arm/corneish_zen/widgets/icons/batt_0.c new file mode 100644 index 000000000000..a6066b95aac8 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/batt_0.c @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_0 +#define LV_ATTRIBUTE_IMG_BATT_0 +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_0 uint8_t + batt_0_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x7f, 0xfd, 0xff, 0x7f, 0xf8, + 0xff, 0xfd, 0xff, 0x7f, 0xfc, 0xff, 0xfd, 0xff, 0x7f, 0xfc, 0xff, 0xfc, 0xfe, 0x7f, 0xfc, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, 0xf0, 0x00, 0xfe, 0x00, 0x3f, 0xf0, 0x00, 0xfe, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, 0xf0, 0x00, 0xfe, 0x00, 0x0f, 0xf0, 0x00, 0x7c, 0x00, 0x0f, + 0xf0, 0x00, 0x7c, 0x00, 0x0f, 0xf0, 0x00, 0x7c, 0x00, 0x0f, 0xf0, 0x00, 0x7c, 0x00, 0x3f, + 0xf0, 0x00, 0x7c, 0x00, 0x3f, 0xf0, 0x00, 0x7c, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0x01, 0xff, 0xfc, 0xff, 0xff, 0x01, 0xff, 0xfc, 0xff, 0xfe, 0x7c, 0xff, 0xfc, + 0x7f, 0xfc, 0xfe, 0x7f, 0xf8, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, + 0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_0 = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_0_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/batt_0_chg.c b/app/boards/arm/corneish_zen/widgets/icons/batt_0_chg.c new file mode 100644 index 000000000000..368ba288d345 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/batt_0_chg.c @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_0_CHG +#define LV_ATTRIBUTE_IMG_BATT_0_CHG +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_0_CHG uint8_t + batt_0_chg_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x7f, 0xff, 0xf7, 0xbf, 0xf8, + 0xff, 0xff, 0xef, 0xbf, 0xfc, 0xff, 0xff, 0xdf, 0x7f, 0xfc, 0xff, 0xff, 0xbf, 0x7f, 0xfc, + 0xf0, 0x00, 0x7e, 0x00, 0x3f, 0xf0, 0x00, 0xfe, 0x00, 0x3f, 0xf0, 0x01, 0xfe, 0x00, 0x3f, + 0xf0, 0x03, 0xfc, 0x00, 0x3f, 0xf0, 0x07, 0xfc, 0x00, 0x0f, 0xf0, 0x0f, 0xff, 0xe0, 0x0f, + 0xf0, 0x1f, 0xff, 0xc0, 0x0f, 0xf0, 0x00, 0x7f, 0x80, 0x0f, 0xf0, 0x00, 0x7f, 0x00, 0x3f, + 0xf0, 0x00, 0xfe, 0x00, 0x3f, 0xf0, 0x00, 0xfc, 0x00, 0x3f, 0xf0, 0x01, 0xf8, 0x00, 0x3f, + 0xff, 0xfd, 0xf7, 0xff, 0xfc, 0xff, 0xfb, 0xef, 0xff, 0xfc, 0xff, 0xfb, 0xdf, 0xff, 0xfc, + 0x7f, 0xfb, 0xbf, 0xff, 0xf8, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_0_chg = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_0_chg_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/batt_100.c b/app/boards/arm/corneish_zen/widgets/icons/batt_100.c new file mode 100644 index 000000000000..e6aa27bab2f4 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/batt_100.c @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_100 +#define LV_ATTRIBUTE_IMG_BATT_100 +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_100 uint8_t + batt_100_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xf3, 0xff, 0xff, 0xff, 0x3f, + 0xf3, 0xff, 0xff, 0xff, 0x3f, 0xf3, 0xff, 0xff, 0xff, 0x0f, 0xf3, 0xff, 0xff, 0xff, 0x0f, + 0xf3, 0xff, 0xff, 0xff, 0x0f, 0xf3, 0xff, 0xff, 0xff, 0x0f, 0xf3, 0xff, 0xff, 0xff, 0x3f, + 0xf3, 0xff, 0xff, 0xff, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x7f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_100 = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_100_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/batt_100_chg.c b/app/boards/arm/corneish_zen/widgets/icons/batt_100_chg.c new file mode 100644 index 000000000000..9b2c18d4c8ea --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/batt_100_chg.c @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_100_CHG +#define LV_ATTRIBUTE_IMG_BATT_100_CHG +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_100_CHG uint8_t + batt_100_chg_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x7f, 0xff, 0xf7, 0xbf, 0xf8, + 0xff, 0xff, 0xef, 0xbf, 0xfc, 0xff, 0xff, 0xdf, 0x7f, 0xfc, 0xff, 0xff, 0xbf, 0x7f, 0xfc, + 0xf0, 0x00, 0x7e, 0x00, 0x3f, 0xf0, 0x00, 0xfe, 0x00, 0x3f, 0xf3, 0xfd, 0xfe, 0xff, 0x3f, + 0xf3, 0xfb, 0xfd, 0xff, 0x3f, 0xf3, 0xf7, 0xfc, 0x07, 0x0f, 0xf3, 0xef, 0xff, 0xef, 0x0f, + 0xf3, 0xdf, 0xff, 0xdf, 0x0f, 0xf3, 0x80, 0x7f, 0xbf, 0x0f, 0xf3, 0xff, 0x7f, 0x7f, 0x3f, + 0xf3, 0xfe, 0xfe, 0xff, 0x3f, 0xf0, 0x00, 0xfc, 0x00, 0x3f, 0xf0, 0x01, 0xf8, 0x00, 0x3f, + 0xff, 0xfd, 0xf7, 0xff, 0xfc, 0xff, 0xfb, 0xef, 0xff, 0xfc, 0xff, 0xfb, 0xdf, 0xff, 0xfc, + 0x7f, 0xfb, 0xbf, 0xff, 0xf8, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_100_chg = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_100_chg_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/batt_25.c b/app/boards/arm/corneish_zen/widgets/icons/batt_25.c new file mode 100644 index 000000000000..2445ef39516a --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/batt_25.c @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_25 +#define LV_ATTRIBUTE_IMG_BATT_25 +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_25 uint8_t + batt_25_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xf3, 0xfc, 0x00, 0x00, 0x3f, + 0xf3, 0xfc, 0x00, 0x00, 0x3f, 0xf3, 0xfc, 0x00, 0x00, 0x0f, 0xf3, 0xfc, 0x00, 0x00, 0x0f, + 0xf3, 0xfc, 0x00, 0x00, 0x0f, 0xf3, 0xfc, 0x00, 0x00, 0x0f, 0xf3, 0xfc, 0x00, 0x00, 0x3f, + 0xf3, 0xfc, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x7f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_25 = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_25_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/batt_25_chg.c b/app/boards/arm/corneish_zen/widgets/icons/batt_25_chg.c new file mode 100644 index 000000000000..37c30812fd1d --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/batt_25_chg.c @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_25_CHG +#define LV_ATTRIBUTE_IMG_BATT_25_CHG +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_25_CHG uint8_t + batt_25_chg_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x7f, 0xff, 0xf7, 0xbf, 0xf8, + 0xff, 0xff, 0xef, 0xbf, 0xfc, 0xff, 0xff, 0xdf, 0x7f, 0xfc, 0xff, 0xff, 0xbf, 0x7f, 0xfc, + 0xf0, 0x00, 0x7e, 0x00, 0x3f, 0xf0, 0x00, 0xfe, 0x00, 0x3f, 0xf3, 0xf9, 0xfe, 0x00, 0x3f, + 0xf3, 0xfb, 0xfc, 0x00, 0x3f, 0xf3, 0xf7, 0xfc, 0x00, 0x0f, 0xf3, 0xef, 0xff, 0xe0, 0x0f, + 0xf3, 0xdf, 0xff, 0xc0, 0x0f, 0xf3, 0x80, 0x7f, 0x80, 0x0f, 0xf3, 0xf8, 0x7f, 0x00, 0x3f, + 0xf3, 0xf8, 0xfe, 0x00, 0x3f, 0xf0, 0x00, 0xfc, 0x00, 0x3f, 0xf0, 0x01, 0xf8, 0x00, 0x3f, + 0xff, 0xfd, 0xf7, 0xff, 0xfc, 0xff, 0xfb, 0xef, 0xff, 0xfc, 0xff, 0xfb, 0xdf, 0xff, 0xfc, + 0x7f, 0xfb, 0xbf, 0xff, 0xf8, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_25_chg = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_25_chg_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/batt_5.c b/app/boards/arm/corneish_zen/widgets/icons/batt_5.c new file mode 100644 index 000000000000..e9824572f6f0 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/batt_5.c @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_5 +#define LV_ATTRIBUTE_IMG_BATT_5 +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_5 uint8_t + batt_5_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xf3, 0x00, 0x00, 0x00, 0x3f, + 0xf3, 0x00, 0x00, 0x00, 0x3f, 0xf3, 0x00, 0x00, 0x00, 0x0f, 0xf3, 0x00, 0x00, 0x00, 0x0f, + 0xf3, 0x00, 0x00, 0x00, 0x0f, 0xf3, 0x00, 0x00, 0x00, 0x0f, 0xf3, 0x00, 0x00, 0x00, 0x3f, + 0xf3, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x7f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_5 = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_5_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/batt_50.c b/app/boards/arm/corneish_zen/widgets/icons/batt_50.c new file mode 100644 index 000000000000..bbb0af485550 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/batt_50.c @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_50 +#define LV_ATTRIBUTE_IMG_BATT_50 +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_50 uint8_t + batt_50_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xf3, 0xff, 0xf0, 0x00, 0x3f, + 0xf3, 0xff, 0xf0, 0x00, 0x3f, 0xf3, 0xff, 0xf0, 0x00, 0x0f, 0xf3, 0xff, 0xf0, 0x00, 0x0f, + 0xf3, 0xff, 0xf0, 0x00, 0x0f, 0xf3, 0xff, 0xf0, 0x00, 0x0f, 0xf3, 0xff, 0xf0, 0x00, 0x3f, + 0xf3, 0xff, 0xf0, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x7f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_50 = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_50_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/batt_50_chg.c b/app/boards/arm/corneish_zen/widgets/icons/batt_50_chg.c new file mode 100644 index 000000000000..c2ced92e6ab9 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/batt_50_chg.c @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_50_CHG +#define LV_ATTRIBUTE_IMG_BATT_50_CHG +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_50_CHG uint8_t + batt_50_chg_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x7f, 0xff, 0xf7, 0xbf, 0xf8, + 0xff, 0xff, 0xef, 0xbf, 0xfc, 0xff, 0xff, 0xdf, 0x7f, 0xfc, 0xff, 0xff, 0xbf, 0x7f, 0xfc, + 0xf0, 0x00, 0x7e, 0x00, 0x3f, 0xf0, 0x00, 0xfe, 0x00, 0x3f, 0xf3, 0xfd, 0xfe, 0x00, 0x3f, + 0xf3, 0xfb, 0xfc, 0x00, 0x3f, 0xf3, 0xf7, 0xfc, 0x00, 0x0f, 0xf3, 0xef, 0xff, 0xe0, 0x0f, + 0xf3, 0xdf, 0xff, 0xc0, 0x0f, 0xf3, 0x80, 0x7f, 0x80, 0x0f, 0xf3, 0xff, 0x7f, 0x00, 0x3f, + 0xf3, 0xfe, 0xfe, 0x00, 0x3f, 0xf0, 0x00, 0xfc, 0x00, 0x3f, 0xf0, 0x01, 0xf8, 0x00, 0x3f, + 0xff, 0xfd, 0xf7, 0xff, 0xfc, 0xff, 0xfb, 0xef, 0xff, 0xfc, 0xff, 0xfb, 0xdf, 0xff, 0xfc, + 0x7f, 0xfb, 0xbf, 0xff, 0xf8, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_50_chg = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_50_chg_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/batt_5_chg.c b/app/boards/arm/corneish_zen/widgets/icons/batt_5_chg.c new file mode 100644 index 000000000000..6a6d9d44604a --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/batt_5_chg.c @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_5_CHG +#define LV_ATTRIBUTE_IMG_BATT_5_CHG +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_5_CHG uint8_t + batt_5_chg_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x7f, 0xff, 0xf7, 0xbf, 0xf8, + 0xff, 0xff, 0xef, 0xbf, 0xfc, 0xff, 0xff, 0xdf, 0x7f, 0xfc, 0xff, 0xff, 0xbf, 0x7f, 0xfc, + 0xf0, 0x00, 0x7e, 0x00, 0x3f, 0xf0, 0x00, 0xfe, 0x00, 0x3f, 0xf3, 0x01, 0xfe, 0x00, 0x3f, + 0xf3, 0x03, 0xfc, 0x00, 0x3f, 0xf3, 0x07, 0xfc, 0x00, 0x0f, 0xf3, 0x0f, 0xff, 0xe0, 0x0f, + 0xf3, 0x1f, 0xff, 0xc0, 0x0f, 0xf3, 0x00, 0x7f, 0x80, 0x0f, 0xf3, 0x00, 0x7f, 0x00, 0x3f, + 0xf3, 0x00, 0xfe, 0x00, 0x3f, 0xf0, 0x00, 0xfc, 0x00, 0x3f, 0xf0, 0x01, 0xf8, 0x00, 0x3f, + 0xff, 0xfd, 0xf7, 0xff, 0xfc, 0xff, 0xfb, 0xef, 0xff, 0xfc, 0xff, 0xfb, 0xdf, 0xff, 0xfc, + 0x7f, 0xfb, 0xbf, 0xff, 0xf8, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_5_chg = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_5_chg_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/batt_75.c b/app/boards/arm/corneish_zen/widgets/icons/batt_75.c new file mode 100644 index 000000000000..9918386d0253 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/batt_75.c @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_75 +#define LV_ATTRIBUTE_IMG_BATT_75 +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_75 uint8_t + batt_75_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xf3, 0xff, 0xff, 0xe0, 0x3f, + 0xf3, 0xff, 0xff, 0xe0, 0x3f, 0xf3, 0xff, 0xff, 0xe0, 0x0f, 0xf3, 0xff, 0xff, 0xe0, 0x0f, + 0xf3, 0xff, 0xff, 0xe0, 0x0f, 0xf3, 0xff, 0xff, 0xe0, 0x0f, 0xf3, 0xff, 0xff, 0xe0, 0x3f, + 0xf3, 0xff, 0xff, 0xe0, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x7f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_75 = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_75_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/batt_75_chg.c b/app/boards/arm/corneish_zen/widgets/icons/batt_75_chg.c new file mode 100644 index 000000000000..422aaabc7b49 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/batt_75_chg.c @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BATT_75_CHG +#define LV_ATTRIBUTE_IMG_BATT_75_CHG +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BATT_75_CHG uint8_t + batt_75_chg_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x7f, 0xff, 0xf7, 0xbf, 0xf8, + 0xff, 0xff, 0xef, 0xbf, 0xfc, 0xff, 0xff, 0xdf, 0x7f, 0xfc, 0xff, 0xff, 0xbf, 0x7f, 0xfc, + 0xf0, 0x00, 0x7e, 0x00, 0x3f, 0xf0, 0x00, 0xfe, 0x00, 0x3f, 0xf3, 0xfd, 0xfe, 0xe0, 0x3f, + 0xf3, 0xfb, 0xfd, 0xe0, 0x3f, 0xf3, 0xf7, 0xfc, 0x00, 0x0f, 0xf3, 0xef, 0xff, 0xe0, 0x0f, + 0xf3, 0xdf, 0xff, 0xc0, 0x0f, 0xf3, 0x80, 0x7f, 0xa0, 0x0f, 0xf3, 0xff, 0x7f, 0x60, 0x3f, + 0xf3, 0xfe, 0xfe, 0xe0, 0x3f, 0xf0, 0x00, 0xfc, 0x00, 0x3f, 0xf0, 0x01, 0xf8, 0x00, 0x3f, + 0xff, 0xfd, 0xf7, 0xff, 0xfc, 0xff, 0xfb, 0xef, 0xff, 0xfc, 0xff, 0xfb, 0xdf, 0xff, 0xfc, + 0x7f, 0xfb, 0xbf, 0xff, 0xf8, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t batt_75_chg = { + .header.always_zero = 0, + .header.w = 40, + .header.h = 31, + .data_size = 163, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = batt_75_chg_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/bluetooth_advertising.c b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_advertising.c new file mode 100644 index 000000000000..daeee223a924 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_advertising.c @@ -0,0 +1,42 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING +#define LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING uint8_t + bluetooth_advertising_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x40, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x78, + 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, + 0x20, 0x7f, 0x80, 0x00, 0x70, 0x77, 0xc0, 0x00, 0xf8, 0x73, 0xe0, 0xc0, 0x7c, 0x71, + 0xe0, 0xe0, 0x3e, 0x73, 0xc0, 0x70, 0x1f, 0x77, 0x86, 0x30, 0x0f, 0xff, 0x07, 0x30, + 0x07, 0xfe, 0x07, 0x38, 0x03, 0xfc, 0x23, 0x38, 0x01, 0xf8, 0x63, 0x18, 0x01, 0xf8, + 0x63, 0x18, 0x03, 0xfc, 0x23, 0x38, 0x07, 0xfe, 0x07, 0x38, 0x0f, 0xff, 0x07, 0x30, + 0x1f, 0x77, 0x86, 0x70, 0x3e, 0x73, 0xc0, 0x70, 0x7c, 0x71, 0xe0, 0xe0, 0xf8, 0x73, + 0xe0, 0xc0, 0x70, 0x77, 0xc0, 0x00, 0x20, 0x7f, 0x80, 0x00, 0x00, 0x7f, 0x00, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_advertising = { + .header.always_zero = 0, + .header.w = 29, + .header.h = 35, + .data_size = 148, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_advertising_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/bluetooth_advertising_1.c b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_advertising_1.c new file mode 100644 index 000000000000..cf5b81974541 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_advertising_1.c @@ -0,0 +1,47 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_1 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_1 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_1 uint8_t + bluetooth_advertising_1_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00, 0xfe, 0x00, + 0x00, 0x0f, 0xff, 0x00, 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0x70, 0xf7, 0x80, 0x00, + 0x3f, 0xff, 0xe0, 0xf8, 0xf3, 0xc1, 0xc0, 0x7f, 0xff, 0xe0, 0x7c, 0xf3, 0xe0, 0xc0, 0xff, + 0xff, 0xf0, 0x3e, 0xf7, 0xc0, 0xe0, 0xff, 0x8f, 0xf8, 0x1f, 0xff, 0x84, 0x61, 0xfe, 0x0f, + 0xf8, 0x0f, 0xff, 0x0e, 0x71, 0xfe, 0x0f, 0xf8, 0x07, 0xfe, 0x06, 0x31, 0xff, 0xcf, 0xfc, + 0x03, 0xfc, 0x27, 0x33, 0xff, 0xcf, 0xfc, 0x01, 0xf8, 0x67, 0x33, 0xff, 0xcf, 0xfc, 0x01, + 0xf8, 0x67, 0x33, 0xff, 0xcf, 0xfc, 0x03, 0xfc, 0x27, 0x33, 0xff, 0xcf, 0xfc, 0x07, 0xfe, + 0x06, 0x31, 0xff, 0xcf, 0xfc, 0x0f, 0xff, 0x0e, 0x71, 0xff, 0xcf, 0xf8, 0x1f, 0xff, 0x84, + 0x61, 0xff, 0xcf, 0xf8, 0x3e, 0xf7, 0xc0, 0xe0, 0xff, 0xcf, 0xf8, 0x7c, 0xf3, 0xe1, 0xc0, + 0xff, 0xff, 0xf0, 0xf8, 0xf3, 0xc0, 0xc0, 0x7f, 0xff, 0xe0, 0x70, 0xf7, 0x80, 0x00, 0x3f, + 0xff, 0xe0, 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0x80, 0x00, 0xfe, 0x00, 0x00, 0x0f, 0xff, + 0x00, 0x00, 0xfc, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_advertising_1 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_advertising_1_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/bluetooth_advertising_2.c b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_advertising_2.c new file mode 100644 index 000000000000..184a5ce856bd --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_advertising_2.c @@ -0,0 +1,47 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_2 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_2 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_2 uint8_t + bluetooth_advertising_2_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0xff, 0x00, 0x60, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xc0, 0xf0, 0xf7, 0xc0, 0x80, + 0x7f, 0xff, 0xe0, 0x78, 0xf3, 0xe1, 0xc0, 0x7f, 0xff, 0xf0, 0x3c, 0xf3, 0xc0, 0xe0, 0xff, + 0x0f, 0xf0, 0x1e, 0xf7, 0x84, 0xe1, 0xfe, 0x07, 0xf8, 0x0f, 0xff, 0x0e, 0x71, 0xfc, 0x63, + 0xf8, 0x07, 0xfe, 0x0e, 0x71, 0xff, 0xf3, 0xfc, 0x03, 0xfc, 0x06, 0x33, 0xff, 0xe3, 0xfc, + 0x01, 0xf8, 0x67, 0x33, 0xff, 0xe7, 0xfc, 0x01, 0xf8, 0xe7, 0x33, 0xff, 0xc7, 0xfc, 0x01, + 0xfc, 0x67, 0x33, 0xff, 0x8f, 0xfc, 0x03, 0xfe, 0x06, 0x33, 0xff, 0x1f, 0xfc, 0x07, 0xff, + 0x0e, 0x71, 0xfe, 0x3f, 0xfc, 0x0f, 0xff, 0x8e, 0x61, 0xfc, 0x03, 0xf8, 0x1e, 0xf7, 0xc0, + 0xe1, 0xfc, 0x03, 0xf8, 0x3c, 0xf3, 0xe0, 0xc0, 0xff, 0xff, 0xf0, 0x78, 0xf3, 0xe1, 0xc0, + 0x7f, 0xff, 0xf0, 0xf0, 0xf7, 0xc0, 0x80, 0x7f, 0xff, 0xe0, 0x60, 0xff, 0x80, 0x00, 0x1f, + 0xff, 0xc0, 0x00, 0xff, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x03, 0xfc, + 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_advertising_2 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_advertising_2_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/bluetooth_advertising_3.c b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_advertising_3.c new file mode 100644 index 000000000000..e9665ff91cb9 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_advertising_3.c @@ -0,0 +1,47 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_3 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_3 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_3 uint8_t + bluetooth_advertising_3_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00, 0xfe, 0x00, + 0x00, 0x0f, 0xff, 0x00, 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0x70, 0xf7, 0x80, 0x00, + 0x3f, 0xff, 0xe0, 0xf8, 0xf3, 0xc1, 0xc0, 0x7f, 0xff, 0xf0, 0x7c, 0xf3, 0xe0, 0xc0, 0xff, + 0x9f, 0xf0, 0x3e, 0xf7, 0xc0, 0xe0, 0xfe, 0x07, 0xf8, 0x1f, 0xff, 0x84, 0x61, 0xfe, 0x03, + 0xf8, 0x0f, 0xff, 0x0e, 0x71, 0xfe, 0xe3, 0xfc, 0x07, 0xfe, 0x06, 0x31, 0xff, 0xe3, 0xfc, + 0x03, 0xfc, 0x27, 0x33, 0xff, 0x87, 0xfc, 0x01, 0xf8, 0x67, 0x33, 0xff, 0x87, 0xfc, 0x01, + 0xf8, 0x67, 0x33, 0xff, 0x83, 0xfc, 0x03, 0xfc, 0x27, 0x33, 0xff, 0xf3, 0xfc, 0x07, 0xfe, + 0x06, 0x31, 0xfe, 0xf3, 0xfc, 0x0f, 0xff, 0x0e, 0x71, 0xfc, 0x63, 0xfc, 0x1f, 0xff, 0x84, + 0x61, 0xfe, 0x03, 0xf8, 0x3e, 0xf7, 0xc0, 0xe0, 0xff, 0x0f, 0xf8, 0x7c, 0xf3, 0xe1, 0xc0, + 0xff, 0xff, 0xf0, 0xf8, 0xf3, 0xc0, 0xc0, 0x7f, 0xff, 0xf0, 0x70, 0xf7, 0x80, 0x00, 0x3f, + 0xff, 0xe0, 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0x00, 0xfe, 0x00, 0x00, 0x0f, 0xff, + 0x00, 0x00, 0xfc, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_advertising_3 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_advertising_3_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/bluetooth_advertising_4.c b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_advertising_4.c new file mode 100644 index 000000000000..d591f17f316d --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_advertising_4.c @@ -0,0 +1,47 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_4 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_4 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_4 uint8_t + bluetooth_advertising_4_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00, 0xfe, 0x00, + 0x00, 0x0f, 0xff, 0x00, 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0x70, 0xf7, 0x80, 0x00, + 0x3f, 0xff, 0xe0, 0xf8, 0xf3, 0xc0, 0xc0, 0x7f, 0xff, 0xe0, 0x7c, 0xf3, 0xe0, 0xc0, 0xff, + 0xff, 0xf0, 0x3e, 0xf7, 0xc0, 0xe0, 0xff, 0xcf, 0xf8, 0x1f, 0xff, 0x84, 0x61, 0xff, 0x8f, + 0xf8, 0x0f, 0xff, 0x0e, 0x71, 0xff, 0x0f, 0xf8, 0x07, 0xfe, 0x06, 0x31, 0xff, 0x0f, 0xfc, + 0x03, 0xfc, 0x27, 0x31, 0xfe, 0x4f, 0xfc, 0x01, 0xf8, 0x67, 0x31, 0xfc, 0x4f, 0xfc, 0x01, + 0xf8, 0x67, 0x33, 0xfc, 0xcf, 0xfc, 0x03, 0xfc, 0x27, 0x31, 0xf8, 0x07, 0xfc, 0x07, 0xfe, + 0x06, 0x31, 0xf8, 0x03, 0xfc, 0x0f, 0xff, 0x0e, 0x71, 0xf8, 0x07, 0xf8, 0x1f, 0xff, 0x84, + 0x61, 0xff, 0xcf, 0xf8, 0x3e, 0xf7, 0xc0, 0xe0, 0xff, 0xcf, 0xf8, 0x7c, 0xf3, 0xe1, 0xc0, + 0xff, 0xff, 0xf0, 0xf8, 0xf3, 0xc0, 0xc0, 0x7f, 0xff, 0xe0, 0x70, 0xf7, 0x80, 0x00, 0x3f, + 0xff, 0xc0, 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0x80, 0x00, 0xfe, 0x00, 0x00, 0x07, 0xff, + 0x00, 0x00, 0xfc, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_advertising_4 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_advertising_4_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/bluetooth_advertising_5.c b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_advertising_5.c new file mode 100644 index 000000000000..882131581972 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_advertising_5.c @@ -0,0 +1,47 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_5 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_5 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_ADVERTISING_5 uint8_t + bluetooth_advertising_5_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00, 0xfe, 0x00, + 0x00, 0x0f, 0xff, 0x00, 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0x80, 0x70, 0xf7, 0x80, 0x00, + 0x3f, 0xff, 0xe0, 0xf8, 0xf3, 0xc0, 0xc0, 0x7f, 0xff, 0xe0, 0x7c, 0xf3, 0xe0, 0xe0, 0xff, + 0xff, 0xf0, 0x3e, 0xf7, 0xc0, 0xe1, 0xfe, 0x07, 0xf8, 0x1f, 0xff, 0x84, 0x61, 0xfe, 0x07, + 0xf8, 0x0f, 0xff, 0x0e, 0x71, 0xfc, 0x7f, 0xf8, 0x07, 0xfe, 0x06, 0x33, 0xfc, 0x7f, 0xfc, + 0x03, 0xfc, 0x27, 0x33, 0xfc, 0x07, 0xfc, 0x01, 0xf8, 0x67, 0x33, 0xfc, 0x03, 0xfc, 0x01, + 0xf8, 0x67, 0x33, 0xff, 0x63, 0xfc, 0x03, 0xfc, 0x27, 0x33, 0xff, 0xf3, 0xfc, 0x07, 0xfe, + 0x06, 0x33, 0xfe, 0xf3, 0xfc, 0x0f, 0xff, 0x0e, 0x71, 0xfc, 0x63, 0xf8, 0x1f, 0xff, 0x84, + 0x61, 0xfe, 0x07, 0xf8, 0x3e, 0xf7, 0xc0, 0xe0, 0xff, 0x0f, 0xf8, 0x7c, 0xf3, 0xe1, 0xc0, + 0xff, 0xff, 0xf0, 0xf8, 0xf3, 0xc0, 0xc0, 0x7f, 0xff, 0xe0, 0x70, 0xf7, 0x80, 0x00, 0x3f, + 0xff, 0xc0, 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0x80, 0x00, 0xfe, 0x00, 0x00, 0x0f, 0xff, + 0x00, 0x00, 0xfc, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_advertising_5 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_advertising_5_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/bluetooth_connected_1.c b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_connected_1.c new file mode 100644 index 000000000000..a3cb5a2cd2df --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_connected_1.c @@ -0,0 +1,47 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_1 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_1 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_1 uint8_t + bluetooth_connected_1_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x7f, 0x00, + 0x00, 0x0f, 0xff, 0x00, 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0xc0, 0x78, 0x77, 0xc0, 0x00, + 0x3f, 0xff, 0xe0, 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, 0x3e, 0x71, 0xe0, 0x00, 0xff, + 0xff, 0xf0, 0x1f, 0x73, 0xc0, 0x00, 0xff, 0x8f, 0xf8, 0x0f, 0xff, 0x80, 0x01, 0xfe, 0x0f, + 0xf8, 0x87, 0xff, 0x08, 0x01, 0xfe, 0x0f, 0xf8, 0xc3, 0xfe, 0x18, 0x01, 0xff, 0xcf, 0xfc, + 0xe1, 0xfc, 0x38, 0x03, 0xff, 0xcf, 0xfc, 0xf0, 0xf8, 0x78, 0x03, 0xff, 0xcf, 0xfc, 0xf0, + 0xfc, 0x78, 0x03, 0xff, 0xcf, 0xfc, 0xe1, 0xfc, 0x38, 0x03, 0xff, 0xcf, 0xfc, 0xc3, 0xfe, + 0x18, 0x01, 0xff, 0xcf, 0xfc, 0x87, 0xff, 0x08, 0x01, 0xff, 0xcf, 0xf8, 0x0f, 0xff, 0x80, + 0x01, 0xff, 0xcf, 0xf8, 0x1e, 0x73, 0xc0, 0x00, 0xff, 0xcf, 0xf8, 0x3c, 0x71, 0xe0, 0x00, + 0xff, 0xff, 0xf0, 0x78, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, 0x78, 0x77, 0xc0, 0x00, 0x3f, + 0xff, 0xe0, 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, + 0x00, 0x00, 0x7e, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_connected_1 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_connected_1_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/bluetooth_connected_2.c b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_connected_2.c new file mode 100644 index 000000000000..2ce5b9394256 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_connected_2.c @@ -0,0 +1,47 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_2 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_2 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_2 uint8_t + bluetooth_connected_2_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x7f, 0x00, + 0x00, 0x0f, 0xff, 0x00, 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0xc0, 0x78, 0x73, 0xc0, 0x00, + 0x7f, 0xff, 0xe0, 0x7c, 0x71, 0xe0, 0x00, 0x7f, 0xff, 0xf0, 0x3e, 0x73, 0xe0, 0x00, 0xff, + 0x0f, 0xf0, 0x1f, 0x77, 0xc0, 0x01, 0xfe, 0x07, 0xf8, 0x0f, 0xff, 0x80, 0x01, 0xfc, 0x63, + 0xf8, 0x87, 0xff, 0x08, 0x01, 0xff, 0xf3, 0xfc, 0xc3, 0xfe, 0x18, 0x03, 0xff, 0xe3, 0xfc, + 0xe1, 0xfc, 0x38, 0x03, 0xff, 0xe7, 0xfc, 0xf0, 0xf8, 0x78, 0x03, 0xff, 0xc7, 0xfc, 0xe1, + 0xfc, 0x38, 0x03, 0xff, 0x8f, 0xfc, 0xc3, 0xfe, 0x18, 0x03, 0xff, 0x1f, 0xfc, 0x87, 0xff, + 0x08, 0x01, 0xfe, 0x3f, 0xfc, 0x0f, 0xff, 0x80, 0x01, 0xfc, 0x03, 0xf8, 0x1f, 0x77, 0xc0, + 0x01, 0xfc, 0x03, 0xf8, 0x3e, 0x73, 0xe0, 0x00, 0xff, 0xff, 0xf0, 0x7c, 0x71, 0xe0, 0x00, + 0x7f, 0xff, 0xf0, 0x78, 0x73, 0xc0, 0x00, 0x7f, 0xff, 0xe0, 0x30, 0x7f, 0x80, 0x00, 0x1f, + 0xff, 0xc0, 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x03, 0xfc, + 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_connected_2 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_connected_2_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/bluetooth_connected_3.c b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_connected_3.c new file mode 100644 index 000000000000..edac091f6180 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_connected_3.c @@ -0,0 +1,47 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_3 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_3 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_3 uint8_t + bluetooth_connected_3_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x7f, 0x00, + 0x00, 0x0f, 0xff, 0x00, 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0xc0, 0x78, 0x77, 0xc0, 0x00, + 0x7f, 0xff, 0xe0, 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xf0, 0x3e, 0x71, 0xe0, 0x00, 0xff, + 0x9f, 0xf0, 0x1f, 0x73, 0xc0, 0x01, 0xfe, 0x07, 0xf8, 0x0f, 0xff, 0x80, 0x01, 0xfc, 0x03, + 0xf8, 0x87, 0xff, 0x08, 0x01, 0xfe, 0xe3, 0xfc, 0xc3, 0xfe, 0x18, 0x03, 0xff, 0xe3, 0xfc, + 0xe1, 0xfc, 0x38, 0x03, 0xff, 0x87, 0xfc, 0xf0, 0xf8, 0x78, 0x03, 0xff, 0x87, 0xfc, 0xf0, + 0xfc, 0x78, 0x03, 0xff, 0x83, 0xfc, 0xe1, 0xfe, 0x38, 0x03, 0xff, 0xf3, 0xfc, 0xc3, 0xff, + 0x18, 0x03, 0xfe, 0xf3, 0xfc, 0x87, 0xff, 0x88, 0x01, 0xfc, 0x63, 0xf8, 0x0f, 0xf7, 0xc0, + 0x01, 0xfe, 0x03, 0xf8, 0x1f, 0x73, 0xe0, 0x01, 0xff, 0x0f, 0xf8, 0x3e, 0x71, 0xe0, 0x00, + 0xff, 0xff, 0xf0, 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, 0x78, 0x77, 0xc0, 0x00, 0x3f, + 0xff, 0xe0, 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, + 0x00, 0x00, 0x7e, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_connected_3 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_connected_3_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/bluetooth_connected_4.c b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_connected_4.c new file mode 100644 index 000000000000..e79d6cb6d6c7 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_connected_4.c @@ -0,0 +1,47 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_4 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_4 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_4 uint8_t + bluetooth_connected_4_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x7f, 0x00, + 0x00, 0x07, 0xff, 0x00, 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0x80, 0x78, 0x77, 0xc0, 0x00, + 0x3f, 0xff, 0xe0, 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, 0x3e, 0x71, 0xe0, 0x00, 0xff, + 0xff, 0xf0, 0x1f, 0x73, 0xc0, 0x00, 0xff, 0xcf, 0xf8, 0x0f, 0xff, 0x80, 0x01, 0xff, 0x8f, + 0xf8, 0x87, 0xff, 0x08, 0x01, 0xff, 0x0f, 0xf8, 0xc3, 0xfe, 0x18, 0x01, 0xff, 0x0f, 0xfc, + 0xe1, 0xfc, 0x38, 0x03, 0xfe, 0x4f, 0xfc, 0xf0, 0xf8, 0x78, 0x03, 0xfc, 0x4f, 0xfc, 0xf0, + 0xfc, 0x78, 0x03, 0xfc, 0xcf, 0xfc, 0xe1, 0xfe, 0x38, 0x03, 0xf8, 0xc7, 0xfc, 0xc3, 0xff, + 0x18, 0x01, 0xf8, 0x03, 0xfc, 0x87, 0xff, 0x88, 0x01, 0xf8, 0x03, 0xf8, 0x0f, 0xf7, 0xc0, + 0x01, 0xff, 0xcf, 0xf8, 0x1f, 0x73, 0xe0, 0x00, 0xff, 0xcf, 0xf8, 0x3e, 0x71, 0xe0, 0x00, + 0xff, 0xff, 0xf0, 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, 0x78, 0x77, 0xc0, 0x00, 0x3f, + 0xff, 0xe0, 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, + 0x00, 0x00, 0x7e, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_connected_4 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_connected_4_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/bluetooth_connected_5.c b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_connected_5.c new file mode 100644 index 000000000000..b567aa2dfe01 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_connected_5.c @@ -0,0 +1,47 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_5 +#define LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_5 +#endif +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_5 uint8_t + bluetooth_connected_5_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x7f, 0x00, + 0x00, 0x0f, 0xff, 0x00, 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0x80, 0x78, 0x77, 0xc0, 0x00, + 0x3f, 0xff, 0xe0, 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, 0x3e, 0x71, 0xe0, 0x00, 0xff, + 0xff, 0xf0, 0x1f, 0x73, 0xc0, 0x01, 0xfe, 0x07, 0xf8, 0x0f, 0xff, 0x80, 0x01, 0xfe, 0x07, + 0xf8, 0x87, 0xff, 0x08, 0x01, 0xfc, 0x7f, 0xf8, 0xc3, 0xfe, 0x18, 0x03, 0xfc, 0x7f, 0xfc, + 0xe1, 0xfc, 0x38, 0x03, 0xfc, 0x07, 0xfc, 0xf0, 0xf8, 0x78, 0x03, 0xfc, 0x03, 0xfc, 0xf0, + 0xfc, 0x78, 0x03, 0xff, 0x63, 0xfc, 0xe1, 0xfe, 0x38, 0x03, 0xff, 0xf3, 0xfc, 0xc3, 0xff, + 0x18, 0x03, 0xfe, 0xf3, 0xfc, 0x87, 0xff, 0x88, 0x01, 0xfc, 0x63, 0xf8, 0x0f, 0xf7, 0xc0, + 0x01, 0xfe, 0x07, 0xf8, 0x1e, 0x73, 0xc0, 0x00, 0xff, 0x0f, 0xf8, 0x3c, 0x71, 0xe0, 0x00, + 0xff, 0xff, 0xf0, 0x7c, 0x73, 0xe0, 0x00, 0x7f, 0xff, 0xe0, 0x78, 0x77, 0xc0, 0x00, 0x3f, + 0xff, 0xc0, 0x30, 0x7f, 0x80, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x7f, 0x00, 0x00, 0x0f, 0xff, + 0x00, 0x00, 0x7e, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_connected_5 = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 254, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_connected_5_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/bluetooth_connected_right.c b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_connected_right.c new file mode 100644 index 000000000000..2a28a9039a53 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_connected_right.c @@ -0,0 +1,49 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_RIGHT +#define LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_RIGHT +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BLUETOOTH_CONNECTED_RIGHT + uint8_t bluetooth_connected_right_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x3f, 0x80, + 0x00, 0x0f, 0xfe, 0x00, 0x10, 0x3f, 0xc0, 0x00, 0x3f, 0xff, 0x80, 0x38, 0x3b, 0xe0, 0x00, + 0x7f, 0xff, 0xc0, 0x7c, 0x39, 0xf0, 0x00, 0xff, 0xff, 0xe0, 0x3e, 0x38, 0xf0, 0x01, 0xff, + 0xff, 0xf0, 0x1f, 0x39, 0xe0, 0x01, 0xff, 0xfe, 0x30, 0x0f, 0xbb, 0xc0, 0x03, 0xff, 0xfc, + 0x38, 0x87, 0xff, 0x84, 0x03, 0xff, 0xf8, 0x38, 0xc3, 0xff, 0x0c, 0x07, 0xff, 0xf0, 0x3c, + 0xe1, 0xfe, 0x1c, 0x07, 0xcf, 0xe0, 0x7c, 0xf0, 0xfc, 0x3c, 0x07, 0x87, 0xc0, 0xfc, 0xf0, + 0xfc, 0x3c, 0x07, 0x83, 0x81, 0xfc, 0xe1, 0xfe, 0x1c, 0x07, 0x81, 0x03, 0xfc, 0xc3, 0xff, + 0x0c, 0x07, 0xc0, 0x07, 0xfc, 0x87, 0xff, 0x84, 0x07, 0xe0, 0x0f, 0xfc, 0x0f, 0xbb, 0xc0, + 0x03, 0xf0, 0x1f, 0xf8, 0x1f, 0x39, 0xe0, 0x03, 0xf8, 0x3f, 0xf8, 0x3e, 0x38, 0xf0, 0x01, + 0xfc, 0xff, 0xf0, 0x7c, 0x39, 0xf0, 0x01, 0xff, 0xff, 0xf0, 0x38, 0x3b, 0xe0, 0x00, 0xff, + 0xff, 0xe0, 0x10, 0x3f, 0xc0, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x3f, 0x80, 0x00, 0x3f, 0xff, + 0x80, 0x00, 0x3f, 0x00, 0x00, 0x0f, 0xfe, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x03, 0xf8, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_connected_right = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 253, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_connected_right_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/bluetooth_disconnected_right.c b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_disconnected_right.c new file mode 100644 index 000000000000..37974d698f6a --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/bluetooth_disconnected_right.c @@ -0,0 +1,49 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BLUETOOTH_DISCONNECTED_RIGHT +#define LV_ATTRIBUTE_IMG_BLUETOOTH_DISCONNECTED_RIGHT +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BLUETOOTH_DISCONNECTED_RIGHT + uint8_t bluetooth_disconnected_right_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x3f, 0x80, + 0x00, 0x0f, 0xfe, 0x00, 0x10, 0x3f, 0xc0, 0x00, 0x3f, 0xff, 0x80, 0x38, 0x3b, 0xe0, 0x00, + 0x7f, 0xff, 0xc0, 0x7c, 0x39, 0xf0, 0x00, 0xff, 0xff, 0xe0, 0x3e, 0x38, 0xf0, 0x01, 0xff, + 0xff, 0xf0, 0x1f, 0x39, 0xe0, 0x01, 0xe3, 0xf8, 0xf0, 0x0f, 0xbb, 0xc0, 0x03, 0xe1, 0xf0, + 0xf8, 0x07, 0xff, 0x80, 0x03, 0xe0, 0xe0, 0xf8, 0x03, 0xff, 0x00, 0x07, 0xf0, 0x01, 0xfc, + 0x01, 0xfe, 0x00, 0x07, 0xf8, 0x03, 0xfc, 0x00, 0xfc, 0x00, 0x07, 0xfc, 0x07, 0xfc, 0x00, + 0xfc, 0x00, 0x07, 0xfc, 0x07, 0xfc, 0x01, 0xfe, 0x00, 0x07, 0xfc, 0x07, 0xfc, 0x03, 0xff, + 0x00, 0x07, 0xf8, 0x03, 0xfc, 0x07, 0xff, 0x80, 0x07, 0xf0, 0x01, 0xfc, 0x0f, 0xbb, 0xc0, + 0x03, 0xe0, 0xe0, 0xf8, 0x1f, 0x39, 0xe0, 0x03, 0xe1, 0xf0, 0xf8, 0x3e, 0x38, 0xf0, 0x01, + 0xe3, 0xf8, 0xf0, 0x7c, 0x39, 0xf0, 0x01, 0xff, 0xff, 0xf0, 0x38, 0x3b, 0xe0, 0x00, 0xff, + 0xff, 0xe0, 0x10, 0x3f, 0xc0, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x3f, 0x80, 0x00, 0x3f, 0xff, + 0x80, 0x00, 0x3f, 0x00, 0x00, 0x0f, 0xfe, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x03, 0xf8, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t bluetooth_disconnected_right = { + .header.always_zero = 0, + .header.w = 54, + .header.h = 35, + .data_size = 253, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = bluetooth_disconnected_right_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/layers.c b/app/boards/arm/corneish_zen/widgets/icons/layers.c new file mode 100644 index 000000000000..86bc8dfcfe82 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/layers.c @@ -0,0 +1,44 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_LAYERS +#define LV_ATTRIBUTE_IMG_LAYERS +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_LAYERS uint8_t + layers_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, + 0x00, 0x07, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xc0, 0x00, + 0x01, 0xff, 0xff, 0xf0, 0x00, 0x07, 0xff, 0xff, 0xfc, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x00, + 0x3f, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xfe, 0x00, + 0x01, 0xff, 0xff, 0xf0, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x00, 0x07, 0x9f, 0xff, 0x3c, 0x00, + 0x1e, 0x07, 0xfc, 0x0f, 0x00, 0x38, 0x01, 0xe0, 0x03, 0x80, 0x30, 0x00, 0x00, 0x01, 0x80, + 0x38, 0x00, 0x00, 0x03, 0x80, 0x0e, 0x00, 0x00, 0x0e, 0x00, 0x03, 0xc0, 0x00, 0x78, 0x00, + 0x01, 0xf0, 0x01, 0xf0, 0x00, 0x07, 0xfc, 0x07, 0xfc, 0x00, 0x1f, 0xff, 0x1f, 0xff, 0x00, + 0x3f, 0xff, 0xff, 0xff, 0x80, 0x3f, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xff, 0x00, + 0x07, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0x80, 0x00, + 0x00, 0x0f, 0xfe, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t layers = { + .header.always_zero = 0, + .header.w = 35, + .header.h = 35, + .data_size = 183, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = layers_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/layers2.c b/app/boards/arm/corneish_zen/widgets/icons/layers2.c new file mode 100644 index 000000000000..068b07576aec --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/layers2.c @@ -0,0 +1,40 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_LAYERS2 +#define LV_ATTRIBUTE_IMG_LAYERS2 +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_LAYERS2 uint8_t + layers2_map[] = { + 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ + 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x30, 0x0f, 0x18, 0xdf, 0xdf, 0xc0, 0x04, 0x00, + 0x00, 0x80, 0x30, 0x19, 0x98, 0xd8, 0x18, 0xe0, 0x0e, 0x00, 0x00, 0x80, 0x30, 0x30, 0xd8, + 0xd8, 0x18, 0xe0, 0x1f, 0x00, 0x00, 0x80, 0x30, 0x30, 0xcf, 0x9f, 0xd9, 0xc0, 0x04, 0x00, + 0x00, 0x80, 0x30, 0x3f, 0xc7, 0x18, 0x1f, 0x80, 0x04, 0x00, 0x03, 0xe0, 0x30, 0x39, 0xc6, + 0x18, 0x1b, 0x80, 0x04, 0x00, 0x01, 0xc0, 0x3f, 0xb0, 0xc6, 0x1f, 0xd9, 0xc0, 0x04, 0x00, + 0x00, 0x80, 0x3f, 0xb0, 0xc6, 0x1f, 0xd8, 0xe0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t layers2 = { + .header.always_zero = 0, + .header.w = 78, + .header.h = 12, + .data_size = 128, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = layers2_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/icons/zenlogo.c b/app/boards/arm/corneish_zen/widgets/icons/zenlogo.c new file mode 100644 index 000000000000..cc4240416457 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/icons/zenlogo.c @@ -0,0 +1,58 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_ZENLOGO +#define LV_ATTRIBUTE_IMG_ZENLOGO +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_ZENLOGO uint8_t + zenlogo_map[] = { + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0xe3, 0xe3, 0x9e, + 0x3e, 0x02, 0x72, 0xe0, 0x00, 0x00, 0x06, 0x36, 0x36, 0x33, 0x63, 0x02, 0x8b, 0x10, 0x00, + 0x00, 0x04, 0x14, 0x14, 0x21, 0x41, 0x02, 0x82, 0x10, 0x00, 0x00, 0x04, 0x04, 0x14, 0x21, + 0x7f, 0x7a, 0x72, 0x10, 0x00, 0x00, 0x04, 0x04, 0x14, 0x21, 0x40, 0x02, 0x0a, 0x10, 0x00, + 0x00, 0x04, 0x14, 0x14, 0x21, 0x41, 0x02, 0x0a, 0x10, 0x00, 0x00, 0x06, 0x36, 0x34, 0x21, + 0x63, 0x02, 0x8a, 0x10, 0x00, 0x00, 0x03, 0xe3, 0xe4, 0x21, 0x3e, 0x02, 0x72, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x03, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0xff, 0xf1, + 0xf8, 0x00, 0x60, 0x0f, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0xfb, 0xff, 0xe0, 0xf8, 0x1f, 0x80, + 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc1, 0xfc, 0x1f, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xc1, 0xfc, 0x1f, 0x00, 0x7f, 0xc0, 0x1f, 0xff, 0xff, 0xe0, 0x01, 0xfc, 0x3e, 0x00, + 0x40, 0x1f, 0xff, 0xe0, 0xff, 0xc0, 0x07, 0xfc, 0xfc, 0x00, 0xdf, 0xff, 0x80, 0x01, 0xff, + 0xc0, 0x0f, 0xdc, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x8f, 0x1f, 0x9f, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x1f, 0xef, 0xff, 0x1f, 0x9f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x8f, + 0xff, 0x3f, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0xfe, 0x3f, 0x0f, 0xf0, 0x00, + 0x00, 0x00, 0x03, 0xf8, 0x1f, 0x80, 0x7e, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x3e, + 0x00, 0x7e, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x3c, 0x00, 0x7e, 0x0f, 0xc0, 0x00, + 0x00, 0x00, 0x1f, 0xf8, 0x3c, 0x00, 0x78, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xbc, + 0x00, 0x78, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xfc, 0x00, 0xf8, 0x0f, 0xc0, 0x00, + 0x00, 0x00, 0x1f, 0xff, 0xfc, 0x0f, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, + 0xff, 0xf8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const lv_img_dsc_t zenlogo = { + .header.always_zero = 0, + .header.w = 80, + .header.h = 38, + .data_size = 388, + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .data = zenlogo_map, +}; diff --git a/app/boards/arm/corneish_zen/widgets/layer_status.c b/app/boards/arm/corneish_zen/widgets/layer_status.c new file mode 100644 index 000000000000..864183180928 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/layer_status.c @@ -0,0 +1,67 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include "layer_status.h" +#include +#include +#include +#include + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); + +struct layer_status_state { + uint8_t index; + const char *label; +}; + +static void set_layer_symbol(lv_obj_t *label, struct layer_status_state state) { + const char *layer_label = state.label; + uint8_t active_layer_index = state.index; + + if (layer_label == NULL) { + char text[6] = {}; + + sprintf(text, " %i", active_layer_index); + + lv_label_set_text(label, text); + } else { + lv_label_set_text(label, layer_label); + } +} + +static void layer_status_update_cb(struct layer_status_state state) { + struct zmk_widget_layer_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_layer_symbol(widget->obj, state); } +} + +static struct layer_status_state layer_status_get_state(const zmk_event_t *eh) { + uint8_t index = zmk_keymap_highest_layer_active(); + return (struct layer_status_state){.index = index, .label = zmk_keymap_layer_name(index)}; +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_layer_status, struct layer_status_state, layer_status_update_cb, + layer_status_get_state) + +ZMK_SUBSCRIPTION(widget_layer_status, zmk_layer_state_changed); + +int zmk_widget_layer_status_init(struct zmk_widget_layer_status *widget, lv_obj_t *parent) { + widget->obj = lv_label_create(parent); + + sys_slist_append(&widgets, &widget->node); + + widget_layer_status_init(); + return 0; +} + +lv_obj_t *zmk_widget_layer_status_obj(struct zmk_widget_layer_status *widget) { + return widget->obj; +} diff --git a/app/boards/arm/corneish_zen/widgets/layer_status.h b/app/boards/arm/corneish_zen/widgets/layer_status.h new file mode 100644 index 000000000000..c03433c56baf --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/layer_status.h @@ -0,0 +1,19 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include +#include + +struct zmk_widget_layer_status { + sys_snode_t node; + lv_obj_t *obj; +}; + +int zmk_widget_layer_status_init(struct zmk_widget_layer_status *widget, lv_obj_t *parent); +lv_obj_t *zmk_widget_layer_status_obj(struct zmk_widget_layer_status *widget); diff --git a/app/boards/arm/corneish_zen/widgets/output_status.c b/app/boards/arm/corneish_zen/widgets/output_status.c new file mode 100644 index 000000000000..8e9457ebefee --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/output_status.c @@ -0,0 +1,131 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include "output_status.h" +#include +#include +#include +#include +#include +#include + +LV_IMG_DECLARE(bluetooth_advertising); +LV_IMG_DECLARE(bluetooth_connected_right); +LV_IMG_DECLARE(bluetooth_disconnected_right); +LV_IMG_DECLARE(bluetooth_connected_1); +LV_IMG_DECLARE(bluetooth_connected_2); +LV_IMG_DECLARE(bluetooth_connected_3); +LV_IMG_DECLARE(bluetooth_connected_4); +LV_IMG_DECLARE(bluetooth_connected_5); +LV_IMG_DECLARE(bluetooth_advertising_1); +LV_IMG_DECLARE(bluetooth_advertising_2); +LV_IMG_DECLARE(bluetooth_advertising_3); +LV_IMG_DECLARE(bluetooth_advertising_4); +LV_IMG_DECLARE(bluetooth_advertising_5); +LV_IMG_DECLARE(USB_connected); + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); + +struct output_status_state { + struct zmk_endpoint_instance selected_endpoint; + bool active_profile_connected; + bool active_profile_bonded; +}; + +static struct output_status_state get_state(const zmk_event_t *_eh) { + return (struct output_status_state){ + .selected_endpoint = zmk_endpoints_selected(), + .active_profile_connected = zmk_ble_active_profile_is_connected(), + .active_profile_bonded = !zmk_ble_active_profile_is_open(), + }; +} + +static void set_status_symbol(lv_obj_t *icon, struct output_status_state state) { + switch (state.selected_endpoint.transport) { + case ZMK_TRANSPORT_USB: + lv_img_set_src(icon, &USB_connected); + break; + case ZMK_TRANSPORT_BLE: + if (state.active_profile_bonded) { + if (state.active_profile_connected) { + // sprintf(text, LV_SYMBOL_BLUETOOTH "%i " LV_SYMBOL_OK, active_profile_index); + switch (state.selected_endpoint.ble.profile_index) { + case 0: + lv_img_set_src(icon, &bluetooth_connected_1); + break; + case 1: + lv_img_set_src(icon, &bluetooth_connected_2); + break; + case 2: + lv_img_set_src(icon, &bluetooth_connected_3); + break; + case 3: + lv_img_set_src(icon, &bluetooth_connected_4); + break; + case 4: + lv_img_set_src(icon, &bluetooth_connected_5); + break; + } + } else { + lv_img_set_src(icon, &bluetooth_disconnected_right); + } + } else { + switch (state.selected_endpoint.ble.profile_index) { + case 0: + lv_img_set_src(icon, &bluetooth_advertising_1); + break; + case 1: + lv_img_set_src(icon, &bluetooth_advertising_2); + break; + case 2: + lv_img_set_src(icon, &bluetooth_advertising_3); + break; + case 3: + lv_img_set_src(icon, &bluetooth_advertising_4); + break; + case 4: + lv_img_set_src(icon, &bluetooth_advertising_5); + break; + } + } + break; + } +} + +static void output_status_update_cb(struct output_status_state state) { + struct zmk_widget_output_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_status_symbol(widget->obj, state); } +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_output_status, struct output_status_state, + output_status_update_cb, get_state) +ZMK_SUBSCRIPTION(widget_output_status, zmk_endpoint_changed); +// We don't get an endpoint changed event when the active profile connects/disconnects +// but there wasn't another endpoint to switch from/to, so update on BLE events too. +#if defined(CONFIG_ZMK_BLE) +ZMK_SUBSCRIPTION(widget_output_status, zmk_ble_active_profile_changed); +#endif + +int zmk_widget_output_status_init(struct zmk_widget_output_status *widget, lv_obj_t *parent) { + widget->obj = lv_img_create(parent); + + sys_slist_append(&widgets, &widget->node); + + widget_output_status_init(); + return 0; +} + +lv_obj_t *zmk_widget_output_status_obj(struct zmk_widget_output_status *widget) { + return widget->obj; +} diff --git a/app/boards/arm/corneish_zen/widgets/output_status.h b/app/boards/arm/corneish_zen/widgets/output_status.h new file mode 100644 index 000000000000..ba92f893ac3d --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/output_status.h @@ -0,0 +1,19 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include +#include + +struct zmk_widget_output_status { + sys_snode_t node; + lv_obj_t *obj; +}; + +int zmk_widget_output_status_init(struct zmk_widget_output_status *widget, lv_obj_t *parent); +lv_obj_t *zmk_widget_output_status_obj(struct zmk_widget_output_status *widget); diff --git a/app/boards/arm/corneish_zen/widgets/peripheral_status.c b/app/boards/arm/corneish_zen/widgets/peripheral_status.c new file mode 100644 index 000000000000..39b62fde05a3 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/peripheral_status.c @@ -0,0 +1,61 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include "peripheral_status.h" +#include +#include +#include + +LV_IMG_DECLARE(bluetooth_connected_right); +LV_IMG_DECLARE(bluetooth_disconnected_right); + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); + +struct peripheral_status_state { + bool connected; +}; + +static struct peripheral_status_state get_state(const zmk_event_t *_eh) { + return (struct peripheral_status_state){.connected = zmk_split_bt_peripheral_is_connected()}; +} + +static void set_status_symbol(lv_obj_t *icon, struct peripheral_status_state state) { + LOG_DBG("halves connected? %s", state.connected ? "true" : "false"); + + lv_img_set_src(icon, + state.connected ? &bluetooth_connected_right : &bluetooth_disconnected_right); +} + +static void output_status_update_cb(struct peripheral_status_state state) { + struct zmk_widget_peripheral_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_status_symbol(widget->obj, state); } +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_peripheral_status, struct peripheral_status_state, + output_status_update_cb, get_state) +ZMK_SUBSCRIPTION(widget_peripheral_status, zmk_split_peripheral_status_changed); + +int zmk_widget_peripheral_status_init(struct zmk_widget_peripheral_status *widget, + lv_obj_t *parent) { + widget->obj = lv_img_create(parent); + + sys_slist_append(&widgets, &widget->node); + + widget_peripheral_status_init(); + return 0; +} + +lv_obj_t *zmk_widget_peripheral_status_obj(struct zmk_widget_peripheral_status *widget) { + return widget->obj; +} diff --git a/app/boards/arm/corneish_zen/widgets/peripheral_status.h b/app/boards/arm/corneish_zen/widgets/peripheral_status.h new file mode 100644 index 000000000000..82fe2105ea19 --- /dev/null +++ b/app/boards/arm/corneish_zen/widgets/peripheral_status.h @@ -0,0 +1,20 @@ +/* + * + * Copyright (c) 2021 Darryl deHaan + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include +#include + +struct zmk_widget_peripheral_status { + sys_snode_t node; + lv_obj_t *obj; +}; + +int zmk_widget_peripheral_status_init(struct zmk_widget_peripheral_status *widget, + lv_obj_t *parent); +lv_obj_t *zmk_widget_peripheral_status_obj(struct zmk_widget_peripheral_status *widget); diff --git a/app/boards/arm/dz60rgb/Kconfig.board b/app/boards/arm/dz60rgb/Kconfig.board new file mode 100644 index 000000000000..ba09e2dd43e6 --- /dev/null +++ b/app/boards/arm/dz60rgb/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_DZ60RGB_REV1 + bool "DZ60RGB Keyboard" + depends on SOC_STM32F303XC diff --git a/app/boards/arm/dz60rgb/Kconfig.defconfig b/app/boards/arm/dz60rgb/Kconfig.defconfig new file mode 100644 index 000000000000..6e0592569def --- /dev/null +++ b/app/boards/arm/dz60rgb/Kconfig.defconfig @@ -0,0 +1,11 @@ +# DZ60RGB keyboard configuration + +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if BOARD_DZ60RGB_REV1 + +config ZMK_KEYBOARD_NAME + default "DZ60RGB Rev 1" + +endif # BOARD_DZ60RGB_REV1 diff --git a/app/boards/arm/dz60rgb/board.cmake b/app/boards/arm/dz60rgb/board.cmake new file mode 100644 index 000000000000..9da8ea911229 --- /dev/null +++ b/app/boards/arm/dz60rgb/board.cmake @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT + +board_runner_args(dfu-util "--pid=0483:df11" "--alt=0" "--dfuse") +board_runner_args(jlink "--device=STM32F303CC" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/dfu-util.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/app/boards/arm/dz60rgb/dz60rgb_rev1.dts b/app/boards/arm/dz60rgb/dz60rgb_rev1.dts new file mode 100644 index 000000000000..25c95ddf8ee1 --- /dev/null +++ b/app/boards/arm/dz60rgb/dz60rgb_rev1.dts @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include + +#include + +/ { + model = "DZ60RGB, Rev 1"; + compatible = "dz60rgb,rev1", "st,stm32f303"; + + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <14>; + rows = <5>; + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,13) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,13) +RC(4,0) RC(4,1) RC(4,2) RC(4,5) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,13) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&gpioa 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpiob 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpiob 11 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpiob 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpiob 12 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + col-gpios + = <&gpioa 6 GPIO_ACTIVE_HIGH> + , <&gpioa 7 GPIO_ACTIVE_HIGH> + , <&gpiob 0 GPIO_ACTIVE_HIGH> + , <&gpiob 13 GPIO_ACTIVE_HIGH> + , <&gpiob 15 GPIO_ACTIVE_HIGH> + , <&gpioa 8 GPIO_ACTIVE_HIGH> + , <&gpioa 15 GPIO_ACTIVE_HIGH> + , <&gpiob 3 GPIO_ACTIVE_HIGH> + , <&gpiob 4 GPIO_ACTIVE_HIGH> + , <&gpiob 5 GPIO_ACTIVE_HIGH> + , <&gpiob 8 GPIO_ACTIVE_HIGH> + , <&gpiob 9 GPIO_ACTIVE_HIGH> + , <&gpioc 13 GPIO_ACTIVE_HIGH> + , <&gpioc 14 GPIO_ACTIVE_HIGH> + ; + }; + +}; + +&usb { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/guides/dts/index.html#flash-partitions + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Set 6Kb of storage at the end of the 256Kb of flash */ + storage_partition: partition@3e800 { + reg = <0x0003e800 0x00001800>; + }; + }; +}; diff --git a/app/boards/arm/dz60rgb/dz60rgb_rev1.keymap b/app/boards/arm/dz60rgb/dz60rgb_rev1.keymap new file mode 100644 index 000000000000..e8cc6a7a8845 --- /dev/null +++ b/app/boards/arm/dz60rgb/dz60rgb_rev1.keymap @@ -0,0 +1,25 @@ +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ------------------------------------------------------------------------------------------ +// | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | +// | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | "|" | +// | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | +// | SHIFT | Z | X | C | V | B | N | M | , | . | SHIFT(/) | ^ | DEL | +// | CTL | WIN | ALT | SPACE | ALT | MO(1) | <- | v | -> | +// ------------------------------------------------------------------------------------------ + bindings = < + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &mt RSHFT FSLH &kp UP &kp DEL + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &mo 1 &kp LEFT &kp DOWN &kp RIGHT + >; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/arm/dz60rgb/dz60rgb_rev1.yaml b/app/boards/arm/dz60rgb/dz60rgb_rev1.yaml new file mode 100644 index 000000000000..d2836218a78e --- /dev/null +++ b/app/boards/arm/dz60rgb/dz60rgb_rev1.yaml @@ -0,0 +1,19 @@ +identifier: DZ60RGB_rev1 +name: DZ60RGBREV1 +type: keyboard +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 40 +supported: + - gpio + - i2c + - counter + - spi + - usb_device + - lsm303dlhc + - nvs + - can + - kscan diff --git a/app/boards/arm/dz60rgb/dz60rgb_rev1_defconfig b/app/boards/arm/dz60rgb/dz60rgb_rev1_defconfig new file mode 100644 index 000000000000..53bc0e110345 --- /dev/null +++ b/app/boards/arm/dz60rgb/dz60rgb_rev1_defconfig @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_STM32F3X=y +CONFIG_SOC_STM32F303XC=y +# 72MHz system clock +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=72000000 + +# enable pinmux +CONFIG_PINMUX=y + +# enable GPIO +CONFIG_GPIO=y + +# clock configuration +CONFIG_CLOCK_CONTROL=y + +# Clock configuration for Cube Clock control driver +CONFIG_CLOCK_STM32_HSE_CLOCK=8000000 +CONFIG_CLOCK_STM32_SYSCLK_SRC_PLL=y +# use HSE as PLL input +CONFIG_CLOCK_STM32_PLL_SRC_HSE=y +# produce 72MHz clock at PLL output +CONFIG_CLOCK_STM32_PLL_PREDIV=1 +CONFIG_CLOCK_STM32_PLL_MULTIPLIER=9 +CONFIG_CLOCK_STM32_AHB_PRESCALER=1 +CONFIG_CLOCK_STM32_APB1_PRESCALER=2 +CONFIG_CLOCK_STM32_APB2_PRESCALER=1 + +CONFIG_ZMK_USB=y \ No newline at end of file diff --git a/app/boards/arm/ferris/Kconfig.board b/app/boards/arm/ferris/Kconfig.board new file mode 100644 index 000000000000..70ee895d8ddb --- /dev/null +++ b/app/boards/arm/ferris/Kconfig.board @@ -0,0 +1,8 @@ +# Ferris board configuration + +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_FERRIS + bool "Ferris rev 0.2" + depends on SOC_STM32F072XB diff --git a/app/boards/arm/ferris/Kconfig.defconfig b/app/boards/arm/ferris/Kconfig.defconfig new file mode 100644 index 000000000000..420ea01fab92 --- /dev/null +++ b/app/boards/arm/ferris/Kconfig.defconfig @@ -0,0 +1,17 @@ +# Ferris board configuration + +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if BOARD_FERRIS + +config BOARD + default "ferris_rev02" + +config ZMK_KEYBOARD_NAME + default "Ferris rev 0.2" + +config ZMK_KSCAN_MATRIX_POLLING + default y + +endif # BOARD_FERRIS diff --git a/app/boards/arm/ferris/README.md b/app/boards/arm/ferris/README.md new file mode 100644 index 000000000000..b6fdcdf26ae3 --- /dev/null +++ b/app/boards/arm/ferris/README.md @@ -0,0 +1,15 @@ +# Building ZMK for the Ferris 0.2 + +## Standard Build + +``` +west build -p -d build/ferris --board ferris_rev02 +``` + +## Flashing + +`west` can be used to flash the board directly. Press the reset button once, and run: + +``` +west flash -d build/ferris +``` diff --git a/app/boards/arm/ferris/board.cmake b/app/boards/arm/ferris/board.cmake new file mode 100644 index 000000000000..4f430e12b0ea --- /dev/null +++ b/app/boards/arm/ferris/board.cmake @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT + +board_runner_args(dfu-util "--pid=0483:df11" "--alt=0" "--dfuse") +board_runner_args(jlink "--device=STM32F072CB" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/dfu-util.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/app/boards/arm/ferris/ferris_rev02.dts b/app/boards/arm/ferris/ferris_rev02.dts new file mode 100644 index 000000000000..1b9408d2d9b4 --- /dev/null +++ b/app/boards/arm/ferris/ferris_rev02.dts @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include +#include + +#include + +/ { + model = "Ferris rev0.2"; + compatible = "ferris,rev02", "st,stm32f072"; + + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + zmk,kscan = &kscan; + zmk,matrix_transform = &transform; + /* TODO: Enable once we support the IC for underglow + zmk,underglow = &led_strip; + */ + }; + + transform: transform { + compatible = "zmk,matrix-transform"; + rows = <4>; + columns = <10>; + + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) + RC(3,3) RC(3,4) RC(3,5) RC(3,6) + >; + }; + + kscan: kscan { + compatible = "zmk,kscan-composite"; + rows = <4>; + columns = <10>; + + left { + kscan = <&kscan_left>; + }; + + right { + kscan = <&kscan_right>; + column-offset = <5>; + }; + }; + + kscan_left: kscan_left { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + + col-gpios + = <&gpiob 8 (GPIO_ACTIVE_HIGH)> + , <&gpiob 4 (GPIO_ACTIVE_HIGH)> + , <&gpiob 3 (GPIO_ACTIVE_HIGH)> + , <&gpioa 15 (GPIO_ACTIVE_HIGH)> + , <&gpioa 14 (GPIO_ACTIVE_HIGH)> + ; + row-gpios + = <&gpiob 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpiob 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpiob 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpioa 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; + + kscan_right: kscan_right { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "row2col"; + + col-gpios + = <&right_io 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&right_io 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&right_io 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&right_io 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&right_io 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; + row-gpios + = <&right_io 8 (GPIO_ACTIVE_LOW)> + , <&right_io 9 (GPIO_ACTIVE_LOW)> + , <&right_io 10 (GPIO_ACTIVE_LOW)> + , <&right_io 11 (GPIO_ACTIVE_LOW)> + ; + }; +}; + +&i2c2 { + pinctrl-0 = <&i2c2_scl_pb10 &i2c2_sda_pb11>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; + + right_io: mcp23017@20 { + compatible = "microchip,mcp230xx"; + status = "okay"; + gpio-controller; + reg = <0x20>; + #gpio-cells = <2>; + ngpios = <16>; + }; +}; + +&usb { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + +&clk_hsi { + status = "okay"; +}; + +&pll { + prediv = <1>; + mul = <6>; + clocks = <&clk_hsi>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <1>; +}; + + +&rtc { + status = "okay"; +}; + +&flash0 { + /* + * For more information, see: + * http: //docs.zephyrproject.org/latest/guides/dts/index.html#flash-partitions + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Set 6Kb of storage at the end of the 128Kb of flash */ + storage_partition: partition@3e800 { + reg = <0x0001e800 0x00001800>; + }; + }; +}; diff --git a/app/boards/arm/ferris/ferris_rev02.keymap b/app/boards/arm/ferris/ferris_rev02.keymap new file mode 100644 index 000000000000..dc298ec8d52e --- /dev/null +++ b/app/boards/arm/ferris/ferris_rev02.keymap @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +#define NAV_L 1 +#define OTHER_L 2 +#define NUM_L 3 +#define SYM_L 4 + +// Using layer taps on thumbs, having quick tap as well helps w/ repeating space/backspace +< { quick_tap_ms = <200>; }; + +/ { + behaviors { + hm: homerow_mods { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + tapping_term_ms = <200>; + flavor = "tap-preferred"; + bindings = <&kp>, <&kp>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P + &hm LGUI A &hm LALT S &hm LCTRL D &hm LSHFT F &kp G &kp H &hm RSHFT J &hm RCTRL K &hm LALT L &hm LGUI QUOT + &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH + < NAV_L TAB &kp ENTER < NUM_L SPACE < SYM_L BKSP + >; + }; + + nav_layer { + bindings = < + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &kp LARW &kp DARW &kp UARW &kp RARW + &trans &trans &trans &trans &trans &trans &kp HOME &kp PG_DN &kp PG_UP &kp END + &trans &trans &kp ESC &kp DEL + >; + }; + + other_layer { + bindings = < + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &kp HOME &trans &trans &trans + &trans &trans &trans &trans + >; + }; + + num_layer { + bindings = < + &kp LBKT &kp N7 &kp N8 &kp N9 &kp RBKT &trans &trans &trans &trans &trans + &kp SEMI &kp N4 &kp N5 &kp N6 &kp EQUAL &trans &trans &trans &trans &trans + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp BSLH &trans &trans &trans &trans &trans + &kp N0 &kp MINUS &trans &trans + >; + }; + + sym_layer { + bindings = < + &kp LBRC &kp LS(N7) &kp LS(N8) &kp LS(N9) &kp RBRC &trans &trans &trans &trans &trans + &kp COLON &kp LS(N4) &kp LS(N5) &kp LS(N6) &kp PLUS &trans &trans &trans &trans &trans + &kp TILDE &kp LS(N1) &kp LS(N2) &kp LS(N3) &kp LS(BSLH) &trans &trans &trans &trans &trans + &kp LS(N0) &kp UNDER &trans &trans + >; + }; + }; +}; diff --git a/app/boards/arm/ferris/ferris_rev02.yaml b/app/boards/arm/ferris/ferris_rev02.yaml new file mode 100644 index 000000000000..f4cbdcaf72c0 --- /dev/null +++ b/app/boards/arm/ferris/ferris_rev02.yaml @@ -0,0 +1,12 @@ +identifier: ferris_rev02 +name: Ferris 0.2 +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 40 +supported: + - switches + - underglow diff --git a/app/boards/arm/ferris/ferris_rev02.zmk.yml b/app/boards/arm/ferris/ferris_rev02.zmk.yml new file mode 100644 index 000000000000..da3a7f534693 --- /dev/null +++ b/app/boards/arm/ferris/ferris_rev02.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: ferris_rev02 +name: Ferris 0.2 +type: board +arch: arm +features: + - keys +outputs: + - usb +url: https://github.com/pierrechevalier83/ferris/tree/main/0.2 diff --git a/app/boards/arm/ferris/ferris_rev02_defconfig b/app/boards/arm/ferris/ferris_rev02_defconfig new file mode 100644 index 000000000000..267035c9fb11 --- /dev/null +++ b/app/boards/arm/ferris/ferris_rev02_defconfig @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: MIT + +CONFIG_BOARD_FERRIS=y +CONFIG_SOC_SERIES_STM32F0X=y +CONFIG_SOC_STM32F072XB=y +# 48MHz system clock +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=48000000 + +# enable PINMUX +CONFIG_PINCTRL=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable i2c +CONFIG_I2C=y + +# ZMK Settings +CONFIG_ZMK_USB=y +CONFIG_ZMK_KSCAN_MATRIX_POLLING=y +CONFIG_USB_SELF_POWERED=n + +# Needed to reduce this to size that will fit on F072 +CONFIG_HEAP_MEM_POOL_SIZE=1024 + +# clock configuration +CONFIG_CLOCK_CONTROL=y + diff --git a/app/boards/arm/glove80/CMakeLists.txt b/app/boards/arm/glove80/CMakeLists.txt new file mode 100644 index 000000000000..3eb2cd276ea7 --- /dev/null +++ b/app/boards/arm/glove80/CMakeLists.txt @@ -0,0 +1,3 @@ +zephyr_library() +zephyr_library_sources(usb_serial_number.c) +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) diff --git a/app/boards/arm/glove80/Kconfig b/app/boards/arm/glove80/Kconfig new file mode 100644 index 000000000000..f1c12e7e3147 --- /dev/null +++ b/app/boards/arm/glove80/Kconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_ENABLE_DCDC + bool "Enable DCDC mode" + select SOC_DCDC_NRF52X + default y + depends on (BOARD_GLOVE80_LH || BOARD_GLOVE80_RH) diff --git a/app/boards/arm/glove80/Kconfig.board b/app/boards/arm/glove80/Kconfig.board new file mode 100644 index 000000000000..f689103710f1 --- /dev/null +++ b/app/boards/arm/glove80/Kconfig.board @@ -0,0 +1,10 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_GLOVE80_LH + bool "Glove80 LH" + depends on SOC_NRF52840_QIAA + +config BOARD_GLOVE80_RH + bool "Glove80 RH" + depends on SOC_NRF52840_QIAA diff --git a/app/boards/arm/glove80/Kconfig.defconfig b/app/boards/arm/glove80/Kconfig.defconfig new file mode 100644 index 000000000000..e1c452a54448 --- /dev/null +++ b/app/boards/arm/glove80/Kconfig.defconfig @@ -0,0 +1,65 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if BOARD_GLOVE80_LH + +config BOARD + default "glove80 lh" + +config ZMK_SPLIT_BLE_ROLE_CENTRAL + default y + +endif # BOARD_GLOVE80_LH + +if BOARD_GLOVE80_RH + +config BOARD + default "glove80 rh" + +endif # BOARD_GLOVE80_RH + +if BOARD_GLOVE80_LH || BOARD_GLOVE80_RH + +config ZMK_SPLIT + default y + +config BT_CTLR + default BT + +config ZMK_KSCAN_MATRIX_WAIT_BETWEEN_OUTPUTS + default 5 + +config PINCTRL + default y + +if USB + +config USB_NRFX + default y + +config USB_DEVICE_STACK + default y + +endif # USB + +if ZMK_BACKLIGHT + +config PWM + default y + +config LED_PWM + default y + +endif # ZMK_BACKLIGHT + +if ZMK_RGB_UNDERGLOW + +config SPI + default y + +config WS2812_STRIP + default y + +endif # ZMK_RGB_UNDERGLOW + +endif # BOARD_GLOVE80_LH || BOARD_GLOVE80_RH diff --git a/app/boards/arm/glove80/board.cmake b/app/boards/arm/glove80/board.cmake new file mode 100644 index 000000000000..36030db7b101 --- /dev/null +++ b/app/boards/arm/glove80/board.cmake @@ -0,0 +1,6 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") +include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) diff --git a/app/boards/arm/glove80/glove80.dtsi b/app/boards/arm/glove80/glove80.dtsi new file mode 100644 index 000000000000..3e3a6233b8d0 --- /dev/null +++ b/app/boards/arm/glove80/glove80.dtsi @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + zephyr,code-partition = &code_partition; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <14>; + rows = <6>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) RC(3,13) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(0,6) RC(1,6) RC(2,6) RC(2,7) RC(1,7) RC(0,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,13) + RC(5,0) RC(5,1) RC(5,2) RC(5,3) RC(5,4) RC(3,6) RC(4,6) RC(5,6) RC(5,7) RC(4,7) RC(3,7) RC(5,9) RC(5,10) RC(5,11) RC(5,12) RC(5,13) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + debounce-press-ms = <4>; + debounce-release-ms = <20>; + }; + +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + sd_partition: partition@0 { + reg = <0x00000000 0x00026000>; + }; + code_partition: partition@26000 { + reg = <0x00026000 0x000c6000>; + }; + + /* + * The flash starting at 0x000ec000 and ending at + * 0x000f3fff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@ec000 { + reg = <0x000ec000 0x00008000>; + }; + + boot_partition: partition@f4000 { + reg = <0x000f4000 0x0000c000>; + }; + }; +}; diff --git a/app/boards/arm/glove80/glove80.keymap b/app/boards/arm/glove80/glove80.keymap new file mode 100644 index 000000000000..60129bd94e91 --- /dev/null +++ b/app/boards/arm/glove80/glove80.keymap @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include +#include + +// layers +#define DEFAULT 0 +#define LOWER 1 +#define MAGIC 2 + +/ { + behaviors { + // For the "layer" key, it'd nice to be able to use it as either a shift or a toggle. + // Configure it as a tap dance, so the first tap (or hold) is a &mo and the second tap is a &to + layer_td: tap_dance_0 { + compatible = "zmk,behavior-tap-dance"; + #binding-cells = <0>; + tapping-term-ms = <200>; + bindings = <&mo LOWER>, <&to LOWER>; + }; + }; + + macros { + bt_0: bt_profile_macro_0 { + compatible = "zmk,behavior-macro"; + #binding-cells = <0>; + bindings + = <&out OUT_BLE>, + <&bt BT_SEL 0>; + }; + + bt_1: bt_profile_macro_1 { + compatible = "zmk,behavior-macro"; + #binding-cells = <0>; + bindings + = <&out OUT_BLE>, + <&bt BT_SEL 1>; + }; + + bt_2: bt_profile_macro_2 { + compatible = "zmk,behavior-macro"; + #binding-cells = <0>; + bindings + = <&out OUT_BLE>, + <&bt BT_SEL 2>; + }; + + bt_3: bt_profile_macro_3 { + compatible = "zmk,behavior-macro"; + #binding-cells = <0>; + bindings + = <&out OUT_BLE>, + <&bt BT_SEL 3>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + // --------------------------------------------------------------------------------------------------------------------------------- + // | F1 | F2 | F3 | F4 | F5 | | F6 | F7 | F8 | F9 | F10 | + // | = | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | - | + // | TAB | Q | W | E | R | T | | Y | U | I | O | P | \ | + // | ESC | A | S | D | F | G | | H | J | K | L | ; | ' | + // | ` | Z | X | C | V | B | LSHFT | LCTRL | LOWER | | LGUI | RCTRL | RSHFT | N | M | , | . | / | PGUP | + // | MAGIC | HOME| END | LEFT | RIGHT| | BSPC | DEL | LALT | | RALT | RET | SPACE | | UP | DOWN | [ | ] | PGDN | + + bindings = < + &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 + &kp EQUAL &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSLH + &kp ESC &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp GRAVE &kp Z &kp X &kp C &kp V &kp B &kp LSHFT &kp LCTRL &layer_td &kp LGUI &kp RCTRL &kp RSHFT &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp PG_UP + &mo MAGIC &kp HOME &kp END &kp LEFT &kp RIGHT &kp BSPC &kp DEL &kp LALT &kp RALT &kp RET &kp SPACE &kp UP &kp DOWN &kp LBKT &kp RBKT &kp PG_DN + >; + }; + + lower_layer { + bindings = < + &kp C_BRI_DN &kp C_BRI_UP &kp C_PREV &kp C_NEXT &kp C_PP &kp C_MUTE &kp C_VOL_DN &kp C_VOL_UP &none &kp PAUSE_BREAK + &trans &none &none &none &none &kp HOME &kp LPAR &kp KP_NUM &kp KP_EQUAL &kp KP_DIVIDE &kp KP_MULTIPLY &kp PSCRN + &trans &none &none &kp UP &none &kp END &kp RPAR &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_MINUS &kp SLCK + &trans &none &kp LEFT &kp DOWN &kp RIGHT &kp PG_UP &kp PRCNT &kp KP_N4 &kp KP_N5 &kp KP_N6 &kp KP_PLUS &none + &trans &kp K_CMENU &none &kp F11 &kp F12 &kp PG_DN &trans &trans &to DEFAULT &trans &trans &trans &kp COMMA &kp KP_N1 &kp KP_N2 &kp KP_N3 &kp KP_ENTER &trans + &trans &kp CAPS &kp INS &kp F11 &kp F12 &trans &trans &trans &trans &trans &trans &kp KP_N0 &kp KP_N0 &kp KP_DOT &kp KP_ENTER &trans + >; + }; + + magic_layer { + bindings = < + &bt BT_CLR &none &none &none &none &none &none &none &none &none + &none &none &none &none &none &none &none &none &none &none &none &none + &none &rgb_ug RGB_SPI &rgb_ug RGB_SAI &rgb_ug RGB_HUI &rgb_ug RGB_BRI &rgb_ug RGB_TOG &none &none &none &none &none &none + &bootloader &rgb_ug RGB_SPD &rgb_ug RGB_SAD &rgb_ug RGB_HUD &rgb_ug RGB_BRD &rgb_ug RGB_EFF &none &none &none &none &none &bootloader + &sys_reset &none &none &none &none &none &bt_2 &bt_3 &none &none &none &none &none &none &none &none &none &sys_reset + &none &none &none &none &none &bt_0 &bt_1 &out OUT_USB &none &none &none &none &none &none &none &none + >; + }; + }; +}; diff --git a/app/boards/arm/glove80/glove80.yaml b/app/boards/arm/glove80/glove80.yaml new file mode 100644 index 000000000000..90a5e13307f0 --- /dev/null +++ b/app/boards/arm/glove80/glove80.yaml @@ -0,0 +1,19 @@ +identifier: glove80 +name: Glove80 +url: https://www.moergo.com/ +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog + - gpio + - i2c + - spi diff --git a/app/boards/arm/glove80/glove80.zmk.yml b/app/boards/arm/glove80/glove80.zmk.yml new file mode 100644 index 000000000000..ca70b7d6acfe --- /dev/null +++ b/app/boards/arm/glove80/glove80.zmk.yml @@ -0,0 +1,16 @@ +file_format: "1" +id: glove80 +name: Glove80 +type: board +arch: arm +url: https://www.moergo.com/ +features: + - keys + - underglow + - backlight +outputs: + - usb + - ble +siblings: + - glove80_lh + - glove80_rh diff --git a/app/boards/arm/glove80/glove80_lh-pinctrl.dtsi b/app/boards/arm/glove80/glove80_lh-pinctrl.dtsi new file mode 100644 index 000000000000..3dbf3d7e1a14 --- /dev/null +++ b/app/boards/arm/glove80/glove80_lh-pinctrl.dtsi @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; // WS2812_VEXT_DATA + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; + + pwm0_default: pwm0_default { + group1 { + psels = ; // rear LED + }; + }; + + pwm0_sleep: pwm0_sleep { + group1 { + psels = ; + bias-pull-down; + }; + }; + + uart0_default: uart0_default { + group1 { + psels = , // EXT1 + ; // EXT2 + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; diff --git a/app/boards/arm/glove80/glove80_lh.dts b/app/boards/arm/glove80/glove80_lh.dts new file mode 100644 index 000000000000..5ef54207127b --- /dev/null +++ b/app/boards/arm/glove80/glove80_lh.dts @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "glove80.dtsi" +#include "glove80_lh-pinctrl.dtsi" + +#include + +/ { + model = "glove80_lh"; + compatible = "glove80_lh"; + + chosen { + zmk,underglow = &led_strip; + zmk,backlight = &back_led_backlight; + zmk,battery = &vbatt; + }; + + back_led_backlight: pwmleds { + compatible = "pwm-leds"; + pwm_led_0 { + pwms = <&pwm0 0 PWM_USEC(20) PWM_POLARITY_NORMAL>; + }; + }; + + // Node name must match original "EXT_POWER" label to preserve user settings. + EXT_POWER { + compatible = "zmk,ext-power-generic"; + control-gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>; /* WS2812_CE */ + init-delay-ms = <100>; + }; + + vbatt: vbatt { + compatible = "zmk,battery-nrf-vddh"; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <40>; /* 40 keys have underglow at the moment */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +&pwm0 { + status = "okay"; + pinctrl-0 = <&pwm0_default>; + pinctrl-1 = <&pwm0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart0 { + compatible = "nordic,nrf-uarte"; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&kscan0 { + row-gpios + = <&gpio0 26 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // LH ROW1 + , <&gpio0 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // LH ROW2 + , <&gpio0 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // LH ROW3 + , <&gpio0 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // LH ROW4 + , <&gpio0 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // LH ROW5 + , <&gpio1 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // LH ROW6 + ; + col-gpios + = <&gpio1 8 GPIO_ACTIVE_HIGH> // LH COL6 + , <&gpio1 4 GPIO_ACTIVE_HIGH> // LH COL5 + , <&gpio1 6 GPIO_ACTIVE_HIGH> // LH COL4 + , <&gpio1 7 GPIO_ACTIVE_HIGH> // LH COL3 + , <&gpio1 5 GPIO_ACTIVE_HIGH> // LH COL2 + , <&gpio1 3 GPIO_ACTIVE_HIGH> // LH COL1 + , <&gpio1 1 GPIO_ACTIVE_HIGH> // LH Thumb + ; +}; diff --git a/app/boards/arm/glove80/glove80_lh.keymap b/app/boards/arm/glove80/glove80_lh.keymap new file mode 100644 index 000000000000..dd4c2d6a01fb --- /dev/null +++ b/app/boards/arm/glove80/glove80_lh.keymap @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "glove80.keymap" diff --git a/app/boards/arm/glove80/glove80_lh_defconfig b/app/boards/arm/glove80/glove80_lh_defconfig new file mode 100644 index 000000000000..a93f27cd8f22 --- /dev/null +++ b/app/boards/arm/glove80/glove80_lh_defconfig @@ -0,0 +1,92 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_GLOVE80_LH=y + +# Enable both USB and BLE +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y + +# Keyboard IDs +CONFIG_ZMK_KEYBOARD_NAME="Glove80 Left" +CONFIG_USB_DEVICE_PID=0x27db +CONFIG_USB_DEVICE_VID=0x16c0 +CONFIG_USB_DEVICE_MANUFACTURER="MoErgo" +CONFIG_USB_DEVICE_SN="moergo.com:GLV80-0123456789ABCDEF" + +CONFIG_BT_DIS_PNP_PID=0x27db +CONFIG_BT_DIS_PNP_VID=0x16c0 +CONFIG_BT_DIS_MANUF="MoErgo" +CONFIG_BT_DIS_MODEL="Glove80" + +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y + +# Work-around for Windows bug with battery notifications +CONFIG_BT_GATT_ENFORCE_SUBSCRIPTION=n + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable GPIO +CONFIG_GPIO=y + +# Build configurations +CONFIG_BUILD_OUTPUT_UF2=y +CONFIG_BUILD_OUTPUT_UF2_FAMILY_ID="0x9807B007" +CONFIG_USE_DT_CODE_PARTITION=y + +# Flash configuration +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +# Enable 32kHz crystal +CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y + +# Enable RGB underglow +CONFIG_ZMK_RGB_UNDERGLOW=y + +CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER=y +CONFIG_ZMK_RGB_UNDERGLOW_ON_START=n +CONFIG_ZMK_RGB_UNDERGLOW_BRT_STEP=4 +CONFIG_ZMK_RGB_UNDERGLOW_BRT_MIN=4 + +# DO NOT CHANGE CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX TO ABOVE 80. Configuring +# BRT_MAX above 80% will draw additional current and can potentially damage your +# computer. WARRANTY IS VOID IF BRT_MAX SET ABOVE 80. +CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX=80 + +CONFIG_ZMK_RGB_UNDERGLOW_EFF_START=3 +CONFIG_ZMK_RGB_UNDERGLOW_HUE_START=285 +CONFIG_ZMK_RGB_UNDERGLOW_SAT_START=75 +CONFIG_ZMK_RGB_UNDERGLOW_BRT_START=16 + +# The power LED is implemented as a backlight +# For now, the power LED is acting as a "USB connected" indicator +CONFIG_ZMK_BACKLIGHT=y +CONFIG_ZMK_BACKLIGHT_ON_START=y +CONFIG_ZMK_BACKLIGHT_BRT_START=5 +CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE=y +CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB=y + +# The full two-byte consumer report space has compatibility issues with some +# operating systems, most notably macOS. Use the more basic single-byte usage +# space. +CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_BASIC=y + +# Turn on debugging to disable optimization. Debug messages can result in larger +# stacks, so enable stack protection and particularly a larger BLE peripheral stack. +# CONFIG_DEBUG=y +# CONFIG_DEBUG_THREAD_INFO=y +# CONFIG_EXCEPTION_STACK_TRACE=y +# CONFIG_HW_STACK_PROTECTION=y +# CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_STACK_SIZE=1300 + +# Log via USB or Segger RTT +CONFIG_ZMK_USB_LOGGING=n +CONFIG_ZMK_RTT_LOGGING=n diff --git a/app/boards/arm/glove80/glove80_rh-pinctrl.dtsi b/app/boards/arm/glove80/glove80_rh-pinctrl.dtsi new file mode 100644 index 000000000000..454a2621051e --- /dev/null +++ b/app/boards/arm/glove80/glove80_rh-pinctrl.dtsi @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; // WS2812_VEXT_DATA + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; + + pwm0_default: pwm0_default { + group1 { + psels = ; // Rear LED + }; + }; + + pwm0_sleep: pwm0_sleep { + group1 { + psels = ; + bias-pull-down; + }; + }; + + uart0_default: uart0_default { + group1 { + psels = , // EXT1 + ; // EXT2 + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + +}; diff --git a/app/boards/arm/glove80/glove80_rh.dts b/app/boards/arm/glove80/glove80_rh.dts new file mode 100644 index 000000000000..6f108d747632 --- /dev/null +++ b/app/boards/arm/glove80/glove80_rh.dts @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + +#include "glove80.dtsi" +#include "glove80_rh-pinctrl.dtsi" + +#include + +/ { + model = "glove80_rh"; + compatible = "glove80_rh"; + + chosen { + zmk,underglow = &led_strip; + zmk,backlight = &back_led_backlight; + zmk,battery = &vbatt; + }; + + back_led_backlight: pwmleds { + compatible = "pwm-leds"; + pwm_led_0 { + pwms = <&pwm0 0 PWM_USEC(20) PWM_POLARITY_NORMAL>; + }; + }; + + // Node name must match original "EXT_POWER" label to preserve user settings. + EXT_POWER { + compatible = "zmk,ext-power-generic"; + control-gpios = <&gpio0 19 GPIO_ACTIVE_HIGH>; /* WS2812_CE */ + init-delay-ms = <100>; + }; + + vbatt: vbatt { + compatible = "zmk,battery-nrf-vddh"; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <40>; /* 40 keys have underglow at the moment */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +&pwm0 { + status = "okay"; + pinctrl-0 = <&pwm0_default>; + pinctrl-1 = <&pwm0_sleep>; + pinctrl-names = "default", "sleep"; +}; + + +&uart0 { + compatible = "nordic,nrf-uarte"; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +/* For right hand, the columns are offset by 7 */ +&default_transform { + col-offset = <7>; +}; + +&kscan0 { + row-gpios + = <&gpio0 26 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // RH ROW1 + , <&gpio0 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // RH ROW2 + , <&gpio0 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // RH ROW3 + , <&gpio1 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // RH ROW4 + , <&gpio0 11 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // RH ROW5 + , <&gpio0 12 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // RH ROW6 + ; + col-gpios + = <&gpio1 6 GPIO_ACTIVE_HIGH> // RH Thumb + , <&gpio1 4 GPIO_ACTIVE_HIGH> // RH COL1 + , <&gpio0 2 GPIO_ACTIVE_HIGH> // RH COL2 + , <&gpio1 7 GPIO_ACTIVE_HIGH> // RH COL3 + , <&gpio1 5 GPIO_ACTIVE_HIGH> // RH COL4 + , <&gpio1 3 GPIO_ACTIVE_HIGH> // RH COL5 + , <&gpio1 1 GPIO_ACTIVE_HIGH> // RH COL6 + ; +}; diff --git a/app/boards/arm/glove80/glove80_rh.keymap b/app/boards/arm/glove80/glove80_rh.keymap new file mode 100644 index 000000000000..dd4c2d6a01fb --- /dev/null +++ b/app/boards/arm/glove80/glove80_rh.keymap @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "glove80.keymap" diff --git a/app/boards/arm/glove80/glove80_rh_defconfig b/app/boards/arm/glove80/glove80_rh_defconfig new file mode 100644 index 000000000000..ef29d682a54a --- /dev/null +++ b/app/boards/arm/glove80/glove80_rh_defconfig @@ -0,0 +1,89 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_GLOVE80_RH=y + +# Enable both USB and BLE +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y + +# Keyboard IDs +CONFIG_ZMK_KEYBOARD_NAME="Glove80 Right" +CONFIG_USB_DEVICE_PID=0x27d9 +CONFIG_USB_DEVICE_VID=0x16c0 +CONFIG_USB_DEVICE_MANUFACTURER="MoErgo" +CONFIG_USB_DEVICE_SN="moergo.com:GLV80-0123456789ABCDEF" + +CONFIG_BT_DIS_PNP_PID=0x27d9 +CONFIG_BT_DIS_PNP_VID=0x16c0 +CONFIG_BT_DIS_MANUF="MoErgo" +CONFIG_BT_DIS_MODEL="Glove80 Right" + +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable GPIO +CONFIG_GPIO=y + +# Build configurations +CONFIG_BUILD_OUTPUT_UF2=y +CONFIG_BUILD_OUTPUT_UF2_FAMILY_ID="0x9808B007" +CONFIG_USE_DT_CODE_PARTITION=y + +# Flash configuration +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +# Enable 32kHz crystal +CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y + +# Enable RGB underglow +CONFIG_ZMK_RGB_UNDERGLOW=y + +CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER=y +CONFIG_ZMK_RGB_UNDERGLOW_ON_START=n +CONFIG_ZMK_RGB_UNDERGLOW_BRT_STEP=4 +CONFIG_ZMK_RGB_UNDERGLOW_BRT_MIN=4 + +# DO NOT CHANGE CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX TO ABOVE 80. Configuring +# BRT_MAX above 80% will draw additional current and can potentially damage your +# computer. WARRANTY IS VOID IF BRT_MAX SET ABOVE 80. +CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX=80 + +CONFIG_ZMK_RGB_UNDERGLOW_EFF_START=3 +CONFIG_ZMK_RGB_UNDERGLOW_HUE_START=285 +CONFIG_ZMK_RGB_UNDERGLOW_SAT_START=75 +CONFIG_ZMK_RGB_UNDERGLOW_BRT_START=16 + +# The power LED is implemented as a backlight +# For now, the power LED is acting as a "USB connected" indicator +CONFIG_ZMK_BACKLIGHT=y +CONFIG_ZMK_BACKLIGHT_ON_START=y +CONFIG_ZMK_BACKLIGHT_BRT_START=5 +CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE=y +CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB=y + +# The full two-byte consumer report space has compatibility issues with some +# operating systems, most notably macOS. Use the more basic single-byte usage +# space. +CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_BASIC=y + +# Turn on debugging to disable optimization. Debug messages can result in larger +# stacks, so enable stack protection and particularly a larger BLE peripheral stack. +# CONFIG_DEBUG=y +# CONFIG_DEBUG_THREAD_INFO=y +# CONFIG_EXCEPTION_STACK_TRACE=y +# CONFIG_HW_STACK_PROTECTION=y +# CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_STACK_SIZE=1300 + +# Log via USB or Segger RTT +CONFIG_ZMK_USB_LOGGING=n +CONFIG_ZMK_RTT_LOGGING=n diff --git a/app/boards/arm/glove80/readme.md b/app/boards/arm/glove80/readme.md new file mode 100644 index 000000000000..2c770376116e --- /dev/null +++ b/app/boards/arm/glove80/readme.md @@ -0,0 +1,13 @@ +## MoErgo Glove80 + +This board definition provides ZMK support for the [MoErgo Glove80](https://www.moergo.com) +keyboard. + +MoErgo additionally offers a customized version of ZMK which adds additional functionality such as +RGB status indicators, available on GitHub at [moergo-sc/zmk](https://github.com/moergo-sc/zmk). The +MoErgo customized ZMK fork is regularly updated to include the latest changes from mainline ZMK, but +will not always be completely up-to-date. MoErgo also offers an online layout configurator and +firmware builder application using the customized fork at [my.glove80.com](https://my.glove80.com). + +While mainline ZMK is expected to work well with Glove80, MoErgo only provides support for use of +their customized fork. Likewise, the ZMK community cannot directly provide support for MoErgo's fork. diff --git a/app/boards/arm/glove80/usb_serial_number.c b/app/boards/arm/glove80/usb_serial_number.c new file mode 100644 index 000000000000..44d7ee203634 --- /dev/null +++ b/app/boards/arm/glove80/usb_serial_number.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include "usb_descriptor.h" + +#define LOG_LEVEL CONFIG_USB_DEVICE_LOG_LEVEL +#include +LOG_MODULE_DECLARE(usb_descriptor); + +int base16_encode(const uint8_t *data, int length, uint8_t *result, int bufSize); + +uint8_t *usb_update_sn_string_descriptor(void) { + /* + * nrf52840 hwinfo returns a 64-bit hardware id. Glove80 uses this as a + * serial number, encoded as base16 into the last 16 characters of the + * CONFIG_USB_DEVICE_SN template. If insufficient template space is + * available, instead return the static serial number string. + */ + const uint8_t template_len = sizeof(CONFIG_USB_DEVICE_SN); + const uint8_t sn_len = 16; + + if (template_len < sn_len + 1) { + LOG_DBG("Serial number template too short"); + return CONFIG_USB_DEVICE_SN; + } + + static uint8_t serial[sizeof(CONFIG_USB_DEVICE_SN)]; + strncpy(serial, CONFIG_USB_DEVICE_SN, template_len); + + uint8_t hwid[8]; + memset(hwid, 0, sizeof(hwid)); + uint8_t hwlen = hwinfo_get_device_id(hwid, sizeof(hwid)); + + if (hwlen > 0) { + const uint8_t offset = template_len - sn_len - 1; + LOG_HEXDUMP_DBG(&hwid, sn_len, "Serial Number"); + base16_encode(hwid, hwlen, serial + offset, sn_len + 1); + } + + return serial; +} + +int base16_encode(const uint8_t *data, int length, uint8_t *result, int bufSize) { + const char hex[] = "0123456789ABCDEF"; + + int i = 0; + while (i < bufSize && i < length * 2) { + uint8_t nibble; + if (i % 2 == 0) { + nibble = data[i / 2] >> 4; + } else { + nibble = data[i / 2] & 0xF; + } + result[i] = hex[nibble]; + ++i; + } + if (i < bufSize) { + result[i] = '\0'; + } + return i; +} diff --git a/app/boards/arm/kbdfans_tofu65/Kconfig.board b/app/boards/arm/kbdfans_tofu65/Kconfig.board new file mode 100644 index 000000000000..954166b715f4 --- /dev/null +++ b/app/boards/arm/kbdfans_tofu65/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_KBDFANS_TOFU65_V2 + bool "KBDfans Tofu65 2.0" + depends on SOC_RP2040 diff --git a/app/boards/arm/kbdfans_tofu65/Kconfig.defconfig b/app/boards/arm/kbdfans_tofu65/Kconfig.defconfig new file mode 100644 index 000000000000..0444f5101051 --- /dev/null +++ b/app/boards/arm/kbdfans_tofu65/Kconfig.defconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if BOARD_KBDFANS_TOFU65_V2 + +config ZMK_KEYBOARD_NAME + default "kbdfans tofu65" + +config RP2_FLASH_W25Q080 + default y + +endif # BOARD_KBDFANS_TOFU65_V2 diff --git a/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.dts b/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.dts new file mode 100644 index 000000000000..ae2f9521071d --- /dev/null +++ b/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.dts @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; + +#include +#include + +/ { + + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + zephyr,shell-uart = &cdc_acm_uart; + zephyr,code-partition = &code_partition; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + xtal_clk: xtal-clk { + compatible = "fixed-clock"; + clock-frequency = <12000000>; + #clock-cells = <0>; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <15>; + rows = <5>; + +// ------- Switch Matrix ---------- +// +// Column 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | +// ========================================================================================== +// Row 0 || S0 | S1 | S2 | S3 | S4 | S5 | S6 | S7 | S8 | S9 | S10 | S11 | S12 | S13 | S14 | +// Row 1 || S0 | S1 | S2 | S3 | S4 | S5 | S6 | S7 | S8 | S9 | S10 | S11 | S12 | S13 | S14 | +// Row 2 || S0 | S1 | S2 | S3 | S4 | S5 | S6 | S7 | S8 | S9 | S10 | S11 | S12 | | S13 | +// Row 3 || S0 | S1 | S2 | S3 | S4 | S5 | S6 | S7 | S8 | S9 | S10 | S11 | | S12 | S13 | +// Row 4 || S0 | S1 | S2 | | | | S3 | | S4 | S5 | S6 | | S7 | S8 | S9 | +// ----------------------------------------------------------------------------------- +// + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) RC(1,14) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,14) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,13) RC(3,14) +RC(4,0) RC(4,1) RC(4,2) RC(4,6) RC(4,8) RC(4,9) RC(4,10) RC(4,12) RC(4,13) RC(4,14) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&gpio0 29 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 28 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 27 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 26 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 22 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + col-gpios + = <&gpio0 25 GPIO_ACTIVE_HIGH> + , <&gpio0 24 GPIO_ACTIVE_HIGH> + , <&gpio0 23 GPIO_ACTIVE_HIGH> + , <&gpio0 1 GPIO_ACTIVE_HIGH> + , <&gpio0 7 GPIO_ACTIVE_HIGH> + , <&gpio0 21 GPIO_ACTIVE_HIGH> + , <&gpio0 20 GPIO_ACTIVE_HIGH> + , <&gpio0 19 GPIO_ACTIVE_HIGH> + , <&gpio0 18 GPIO_ACTIVE_HIGH> + , <&gpio0 17 GPIO_ACTIVE_HIGH> + , <&gpio0 16 GPIO_ACTIVE_HIGH> + , <&gpio0 15 GPIO_ACTIVE_HIGH> + , <&gpio0 14 GPIO_ACTIVE_HIGH> + , <&gpio0 13 GPIO_ACTIVE_HIGH> + , <&gpio0 12 GPIO_ACTIVE_HIGH> + ; + }; +}; + +&flash0 { + reg = <0x10000000 DT_SIZE_M(16)>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserved memory for the second stage bootloader */ + second_stage_bootloader: partition@0 { + reg = <0x00000000 0x100>; + read-only; + }; + + /* + * Usable flash. Starts at 0x100, after the bootloader. The partition + * size is 16MB minus the 0x100 bytes taken by the bootloader. + */ + code_partition: partition@100 { + reg = <0x100 (DT_SIZE_M(16) - 0x100)>; + read-only; + }; + }; +}; + + +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + + +&gpio0 { + status = "okay"; +}; + diff --git a/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.keymap b/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.keymap new file mode 100644 index 000000000000..7eca7919a4ab --- /dev/null +++ b/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.keymap @@ -0,0 +1,97 @@ +// Copyright (c) 2023 The ZMK Contributors +// SPDX-License-Identifier: MIT + +#include +#include + +#define BASE 0 +#define FUNC 1 + +// +// ---------- Tofu65 2.0 key switch positions ---------- +// +// ------------------------------------------------------------------------------------------------- +// | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | +// ------------------------------------------------------------------------------------------------- +// | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 24 | 26 | 27 | 28 | 29 | +// ------------------------------------------------------------------------------------------------- +// | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | +// ------------------------------------------------------------------------------------------------- +// | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | +// ------------------------------------------------------------------------------------------------- +// | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | +// ------------------------------------------------------------------------------------------------- +// + + +/ { + combos { + compatible = "zmk,combos"; + + // BACKSPACE + LCTRL + LALT = &sys_reset + combo_bootloader { + timeout-ms = <100>; + key-positions = <13 58 60>; + bindings = <&sys_reset>; + }; + + // RETURN + LCTRL + LALT = &bootloader + combo_sys_reset { + timeout-ms = <100>; + key-positions = <42 58 60>; + bindings = <&bootloader>; + }; + }; + + + keymap { + compatible = "zmk,keymap"; + + base { + +// --------- Default QWERTY Layout --------- +// Layer 0 BASE +// ------------------------------------------------------------------------------------------------- +// | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BSPC | HME | +// ------------------------------------------------------------------------------------------------- +// | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | PGU | +// ------------------------------------------------------------------------------------------------- +// | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | PGD | +// ------------------------------------------------------------------------------------------------- +// | LSHIFT | Z | X | C | V | B | N | M | , | . | / | RSHFT | ↑ | END | +// ------------------------------------------------------------------------------------------------- +// | LCTL | LGUI | LALT | SPACE | RALT | RGUI | RCTL | <- | ↓ | -> | +// ------------------------------------------------------------------------------------------------- + bindings = < +&kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp HOME +&kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp PG_UP +&kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp ENTER &kp PG_DN +&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp END +&kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT < FUNC K_APP &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT + >; + }; + + func { +// --------- Default QWERTY Layout --------- +// Layer 1 FUNC +// --------------------------------------------------------------------------------------------------- +// | ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | DEL | HME | +// --------------------------------------------------------------------------------------------------- +// | --- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | scroll lock | pause | --- | PGU | +// --------------------------------------------------------------------------------------------------- +// | CAPS | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | --- | PGD | +// --------------------------------------------------------------------------------------------------- +// | LSHIFT | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | ----- | VOL UP | MUTE | +// --------------------------------------------------------------------------------------------------- +// | ---- | ---- | ---- | ---- | -- | MO 1 | -- | PREV | VOL DN | NEXT | +// --------------------------------------------------------------------------------------------------- + bindings = < +&kp GRAVE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp DEL &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp SLCK &kp PAUSE_BREAK &trans &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp C_VOL_UP &kp C_MUTE +&trans &trans &trans &trans &trans &trans &trans &kp C_PREV &kp C_VOL_DN &kp C_NEXT + >; + }; + }; +}; diff --git a/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.yaml b/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.yaml new file mode 100644 index 000000000000..e1089766da23 --- /dev/null +++ b/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.yaml @@ -0,0 +1,15 @@ +identifier: kbdfans_tofu65_v2 +name: KBDfans Tofu65 2.0 +type: mcu +arch: arm +flash: 16384 +ram: 264 +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - gpio + - usb_device + - hwinfo + - pwm diff --git a/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.zmk.yml b/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.zmk.yml new file mode 100644 index 000000000000..382e7dd36036 --- /dev/null +++ b/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: kbdfans_tofu65_v2 +name: KBDfans Tofu65 2.0 +type: board +arch: arm +features: + - keys +outputs: + - usb +url: https://kbdfans.com/collections/tofu65-2-0/products/tofu65-2-0 diff --git a/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2_defconfig b/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2_defconfig new file mode 100644 index 000000000000..57014acf37aa --- /dev/null +++ b/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2_defconfig @@ -0,0 +1,22 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_RP2XXX=y +CONFIG_SOC_RP2040=y +CONFIG_BOARD_KBDFANS_TOFU65_V2=y + +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=125000000 + +# Enable USB CDC ACM logging for debugging +# CONFIG_ZMK_USB_LOGGING=y + +# Enable reset by default +CONFIG_RESET=y + +# Code partition needed to target the correct flash range +CONFIG_USE_DT_CODE_PARTITION=y + +# Output UF2 by default, native bootloader supports it. +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_ZMK_USB=y \ No newline at end of file diff --git a/app/boards/arm/mikoto/CMakeLists.txt b/app/boards/arm/mikoto/CMakeLists.txt new file mode 100644 index 000000000000..12cf9b1cf1a1 --- /dev/null +++ b/app/boards/arm/mikoto/CMakeLists.txt @@ -0,0 +1,6 @@ + +if(CONFIG_PINMUX) +zephyr_library() +zephyr_library_sources(pinmux.c) +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) +endif() \ No newline at end of file diff --git a/app/boards/arm/mikoto/Kconfig b/app/boards/arm/mikoto/Kconfig new file mode 100644 index 000000000000..71ec94117380 --- /dev/null +++ b/app/boards/arm/mikoto/Kconfig @@ -0,0 +1,29 @@ +config BOARD_ENABLE_DCDC + bool "Enable DCDC mode" + select SOC_DCDC_NRF52X + default y + depends on (BOARD_MIKOTO_520) + +choice BOARD_MIKOTO_CHARGER_CURRENT + prompt "Charge current to supply to attached batteries" + depends on (BOARD_MIKOTO_520) + +config BOARD_MIKOTO_CHARGER_CURRENT_40MA + bool "40mA charge current, for battery capacity 40mAh or higher" + +config BOARD_MIKOTO_CHARGER_CURRENT_100MA + bool "100mA charge current, for battery capacity 100mAh or higher" + +config BOARD_MIKOTO_CHARGER_CURRENT_150MA + bool "150mA charge current, for battery capacity 150mAh or higher" + +config BOARD_MIKOTO_CHARGER_CURRENT_250MA + bool "250mA charge current, for battery capacity 250mAh or higher" + +config BOARD_MIKOTO_CHARGER_CURRENT_350MA + bool "350mA charge current, for battery capacity 350mAh or higher" + +config BOARD_MIKOTO_CHARGER_CURRENT_NONE + bool "Disable charge current" + +endchoice \ No newline at end of file diff --git a/app/boards/arm/mikoto/Kconfig.board b/app/boards/arm/mikoto/Kconfig.board new file mode 100644 index 000000000000..a872fa1fa014 --- /dev/null +++ b/app/boards/arm/mikoto/Kconfig.board @@ -0,0 +1,8 @@ +# mikoto board configuration + +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_MIKOTO_520 + bool "mikoto_520" + depends on SOC_NRF52840_QIAA diff --git a/app/boards/arm/mikoto/Kconfig.defconfig b/app/boards/arm/mikoto/Kconfig.defconfig new file mode 100644 index 000000000000..8117cc87329b --- /dev/null +++ b/app/boards/arm/mikoto/Kconfig.defconfig @@ -0,0 +1,31 @@ +# Electronut Labs Papyr board configuration + +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if BOARD_MIKOTO_520 + +config BOARD + default "mikoto" + +if USB + +config USB_NRFX + default y + +config USB_DEVICE_STACK + default y + +endif # USB + +config BT_CTLR + default BT + +config PINMUX + default y + +choice BOARD_MIKOTO_CHARGER_CURRENT + default BOARD_MIKOTO_CHARGER_CURRENT_100MA +endchoice + +endif # BOARD_MIKOTO_520 diff --git a/app/boards/arm/mikoto/arduino_pro_micro_pins.dtsi b/app/boards/arm/mikoto/arduino_pro_micro_pins.dtsi new file mode 100644 index 000000000000..ed6097ec6b9c --- /dev/null +++ b/app/boards/arm/mikoto/arduino_pro_micro_pins.dtsi @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + +/ { + pro_micro: connector { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &gpio0 4 0> /* D0 */ + , <1 0 &gpio0 8 0> /* D1 */ + , <2 0 &gpio0 17 0> /* D2 */ + , <3 0 &gpio0 20 0> /* D3 */ + , <4 0 &gpio0 22 0> /* D4/A6 */ + , <5 0 &gpio0 24 0> /* D5 */ + , <6 0 &gpio1 0 0> /* D6/A7 */ + , <7 0 &gpio1 2 0> /* D7 */ + , <8 0 &gpio1 4 0> /* D8/A8 */ + , <9 0 &gpio1 6 0> /* D9/A9 */ + , <10 0 &gpio0 9 0> /* D10/A10 */ + , <16 0 &gpio0 10 0> /* D16 */ + , <14 0 &gpio1 13 0> /* D14 */ + , <15 0 &gpio0 2 0> /* D15 */ + , <18 0 &gpio0 29 0> /* D18/A0 */ + , <19 0 &gpio0 31 0> /* D19/A1 */ + , <20 0 &gpio0 25 0> /* D20/A2 */ + , <21 0 &gpio0 11 0> /* D21/A3 */ + ; + }; + + pro_micro_a: connector_a { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &gpio0 29 0> /* D18/A0 */ + , <1 0 &gpio0 31 0> /* D19/A1 */ + , <2 0 &gpio0 25 0> /* D20/A2 */ + , <3 0 &gpio0 11 0> /* D21/A3 */ + , <6 0 &gpio0 22 0> /* D4/A6 */ + , <7 0 &gpio1 0 0> /* D6/A7 */ + , <8 0 &gpio1 4 0> /* D8/A8 */ + , <9 0 &gpio1 6 0> /* D9/A9 */ + , <10 0 &gpio0 9 0> /* D10/A10 */ + ; + }; +}; + + +pro_micro_d: &pro_micro {}; +pro_micro_i2c: &i2c0 {}; +pro_micro_spi: &spi0 {}; +pro_micro_serial: &uart0 {}; diff --git a/app/boards/arm/mikoto/board.cmake b/app/boards/arm/mikoto/board.cmake new file mode 100644 index 000000000000..fa847d505952 --- /dev/null +++ b/app/boards/arm/mikoto/board.cmake @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: MIT + +board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") +include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) diff --git a/app/boards/arm/mikoto/mikoto_520-pinctrl.dtsi b/app/boards/arm/mikoto/mikoto_520-pinctrl.dtsi new file mode 100644 index 000000000000..df43c407eecd --- /dev/null +++ b/app/boards/arm/mikoto/mikoto_520-pinctrl.dtsi @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = ; + bias-pull-up; + }; + group2 { + psels = ; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + i2c0_default: i2c0_default { + group1 { + psels = , + ; + }; + }; + + i2c0_sleep: i2c0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; diff --git a/app/boards/arm/mikoto/mikoto_520.dts b/app/boards/arm/mikoto/mikoto_520.dts new file mode 100644 index 000000000000..05ec72dfcda4 --- /dev/null +++ b/app/boards/arm/mikoto/mikoto_520.dts @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include +#include "arduino_pro_micro_pins.dtsi" +#include "mikoto_520-pinctrl.dtsi" + +/ { + model = "mikoto"; + compatible = "zhiayang,mikoto"; + + chosen { + zephyr,code-partition = &code_partition; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + zmk,battery = &vbatt; + }; + + leds { + compatible = "gpio-leds"; + blue_led: led_0 { + gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; + }; + }; + + // Node name must match original "EXT_POWER" label to preserve user settings. + EXT_POWER { + compatible = "zmk,ext-power-generic"; + control-gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>; + init-delay-ms = <50>; + }; + + vbatt: vbatt { + compatible = "zmk,battery-voltage-divider"; + io-channels = <&adc 1>; + output-ohms = <10000000>; + full-ohms = <(10000000 + 4000000)>; + }; +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&i2c0 { + compatible = "nordic,nrf-twi"; + pinctrl-0 = <&i2c0_default>; + pinctrl-1 = <&i2c0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart0 { + compatible = "nordic,nrf-uarte"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + sd_partition: partition@0 { + reg = <0x00000000 0x00026000>; + }; + code_partition: partition@26000 { + reg = <0x00026000 0x000c6000>; + }; + + /* + * The flash starting at 0x000ec000 and ending at + * 0x000f3fff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@ec000 { + reg = <0x000ec000 0x00008000>; + }; + + boot_partition: partition@f4000 { + reg = <0x000f4000 0x0000c000>; + }; + }; +}; diff --git a/app/boards/arm/mikoto/mikoto_520.yaml b/app/boards/arm/mikoto/mikoto_520.yaml new file mode 100644 index 000000000000..8d9f49ae855b --- /dev/null +++ b/app/boards/arm/mikoto/mikoto_520.yaml @@ -0,0 +1,15 @@ +identifier: mikoto_520 +name: mikoto_520 +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog diff --git a/app/boards/arm/mikoto/mikoto_520.zmk.yml b/app/boards/arm/mikoto/mikoto_520.zmk.yml new file mode 100644 index 000000000000..91dcc9e09a6e --- /dev/null +++ b/app/boards/arm/mikoto/mikoto_520.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: mikoto_520 +name: Mikoto 5.20 +type: board +arch: arm +outputs: + - usb + - ble +url: https://github.com/zhiayang/mikoto +exposes: [pro_micro] diff --git a/app/boards/arm/mikoto/mikoto_520_defconfig b/app/boards/arm/mikoto/mikoto_520_defconfig new file mode 100644 index 000000000000..354fa56aa34a --- /dev/null +++ b/app/boards/arm/mikoto/mikoto_520_defconfig @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_MIKOTO_520=y + +# Enable MPU +CONFIG_ARM_MPU=y + +CONFIG_PINCTRL=y + +# enable GPIO +CONFIG_GPIO=y + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/mikoto/pinmux.c b/app/boards/arm/mikoto/pinmux.c new file mode 100644 index 000000000000..524aa17e5bf9 --- /dev/null +++ b/app/boards/arm/mikoto/pinmux.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include +#include + +static int pinmux_mikoto_init(const struct device *port) { + ARG_UNUSED(port); + +#if CONFIG_BOARD_MIKOTO_520 + const struct device *p0 = DEVICE_DT_GET(DT_NODELABEL(gpio0)); + const struct device *p1 = DEVICE_DT_GET(DT_NODELABEL(gpio1)); +#if CONFIG_BOARD_MIKOTO_CHARGER_CURRENT_40MA + gpio_pin_configure(p0, 26, GPIO_INPUT | GPIO_PULL_DOWN); + gpio_pin_configure(p1, 15, GPIO_INPUT); +#elif CONFIG_BOARD_MIKOTO_CHARGER_CURRENT_100MA + gpio_pin_configure(p0, 26, GPIO_OUTPUT); + gpio_pin_set(p0, 26, 0); + gpio_pin_configure(p1, 15, GPIO_INPUT); +#elif CONFIG_BOARD_MIKOTO_CHARGER_CURRENT_150MA + gpio_pin_configure(p0, 26, GPIO_OUTPUT); + gpio_pin_set(p0, 26, 0); + gpio_pin_configure(p1, 15, GPIO_INPUT | GPIO_PULL_DOWN); +#elif CONFIG_BOARD_MIKOTO_CHARGER_CURRENT_250MA + gpio_pin_configure(p0, 26, GPIO_INPUT); + gpio_pin_configure(p1, 15, GPIO_OUTPUT); + gpio_pin_set(p1, 15, 0); +#elif CONFIG_BOARD_MIKOTO_CHARGER_CURRENT_350MA + gpio_pin_configure(p0, 26, GPIO_OUTPUT); + gpio_pin_set(p0, 26, 0); + gpio_pin_configure(p1, 15, GPIO_OUTPUT); + gpio_pin_set(p1, 15, 0); +#elif CONFIG_BOARD_MIKOTO_CHARGER_CURRENT_NONE + gpio_pin_configure(p0, 26, GPIO_INPUT); + gpio_pin_configure(p1, 15, GPIO_INPUT); +#endif +#endif + return 0; +} + +SYS_INIT(pinmux_mikoto_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/app/boards/arm/nice60/Kconfig b/app/boards/arm/nice60/Kconfig new file mode 100644 index 000000000000..dfca4f1b45b9 --- /dev/null +++ b/app/boards/arm/nice60/Kconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2021 Nick Winans +# SPDX-License-Identifier: MIT + +config BOARD_ENABLE_DCDC + bool "Enable DCDC mode" + select SOC_DCDC_NRF52X + default y + depends on BOARD_NICE60 diff --git a/app/boards/arm/nice60/Kconfig.board b/app/boards/arm/nice60/Kconfig.board new file mode 100644 index 000000000000..88db9ee861b8 --- /dev/null +++ b/app/boards/arm/nice60/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2021 Nick Winans +# SPDX-License-Identifier: MIT + +config BOARD_NICE60 + bool "nice!60" + depends on SOC_NRF52840_QIAA diff --git a/app/boards/arm/nice60/Kconfig.defconfig b/app/boards/arm/nice60/Kconfig.defconfig new file mode 100644 index 000000000000..76818e87b0f6 --- /dev/null +++ b/app/boards/arm/nice60/Kconfig.defconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2021 Nick Winans +# SPDX-License-Identifier: MIT + +if BOARD_NICE60 + +config ZMK_KEYBOARD_NAME + default "nice!60" + +if USB_DEVICE_STACK + +config USB_NRFX + default y + +endif # USB_DEVICE_STACK + +config BT_CTLR + default BT + +endif # BOARD_NICE60 diff --git a/app/boards/arm/nice60/README.md b/app/boards/arm/nice60/README.md new file mode 100644 index 000000000000..dce230ae79f1 --- /dev/null +++ b/app/boards/arm/nice60/README.md @@ -0,0 +1,11 @@ +# nice!60 + +![nice!60](https://i.imgur.com/0YWv5PE.png) + +The nice!60 is a hotswap 60% made by Nice Keyboards. https://nicekeyboards.com/nice-60 + +## Building nice!60 ZMK firmware + +``` +west build -p -b nice60 +``` diff --git a/app/boards/arm/nice60/board.cmake b/app/boards/arm/nice60/board.cmake new file mode 100644 index 000000000000..2aca938a51a4 --- /dev/null +++ b/app/boards/arm/nice60/board.cmake @@ -0,0 +1,7 @@ +# Copyright (c) 2021 Nick Winans +# SPDX-License-Identifier: MIT + +set(OPENOCD_NRF5_SUBFAMILY nrf52) +board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd-nrf5.board.cmake) diff --git a/app/boards/arm/nice60/nice60-pinctrl.dtsi b/app/boards/arm/nice60/nice60-pinctrl.dtsi new file mode 100644 index 000000000000..9b0e198d3963 --- /dev/null +++ b/app/boards/arm/nice60/nice60-pinctrl.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; +}; diff --git a/app/boards/arm/nice60/nice60.dts b/app/boards/arm/nice60/nice60.dts new file mode 100644 index 000000000000..63b9685d3ca1 --- /dev/null +++ b/app/boards/arm/nice60/nice60.dts @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2021 Nick Winans + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include + +#include +#include + +#include "nice60-pinctrl.dtsi" + +/ { + model = "nice!60"; + compatible = "nice,60"; + + chosen { + zephyr,code-partition = &code_partition; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + zmk,battery = &vbatt; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + zmk,underglow = &led_strip; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <14>; + rows = <5>; + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,13) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,13) +RC(4,0) RC(4,1) RC(4,2) RC(4,5) RC(4,9) RC(4,10) RC(4,11) RC(4,13) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&gpio1 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 13 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 12 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 11 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + col-gpios + = <&gpio1 15 GPIO_ACTIVE_HIGH> + , <&gpio0 29 GPIO_ACTIVE_HIGH> + , <&gpio0 31 GPIO_ACTIVE_HIGH> + , <&gpio0 30 GPIO_ACTIVE_HIGH> + , <&gpio0 28 GPIO_ACTIVE_HIGH> + , <&gpio0 2 GPIO_ACTIVE_HIGH> + , <&gpio0 3 GPIO_ACTIVE_HIGH> + , <&gpio1 3 GPIO_ACTIVE_HIGH> + , <&gpio1 7 GPIO_ACTIVE_HIGH> + , <&gpio1 4 GPIO_ACTIVE_HIGH> + , <&gpio1 6 GPIO_ACTIVE_HIGH> + , <&gpio1 5 GPIO_ACTIVE_HIGH> + , <&gpio1 1 GPIO_ACTIVE_HIGH> + , <&gpio1 2 GPIO_ACTIVE_HIGH> + ; + }; + + leds { + compatible = "gpio-leds"; + blue_led: led_0 { + gpios = <&gpio0 26 GPIO_ACTIVE_HIGH>; + }; + }; + + // Node name must match original "EXT_POWER" label to preserve user settings. + EXT_POWER { + compatible = "zmk,ext-power-generic"; + control-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; + }; + + vbatt: vbatt { + compatible = "zmk,battery-voltage-divider"; + io-channels = <&adc 2>; + output-ohms = <2000000>; + full-ohms = <(2000000 + 806000)>; + }; +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + + pinctrl-0 = <&spi3_default>; + pinctrl-names = "default"; + status = "okay"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <12>; /* LED strip length */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + color-mapping = ; + }; +}; + +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + sd_partition: partition@0 { + reg = <0x00000000 0x00001000>; + }; + + code_partition: partition@1000 { + reg = <0x00001000 0x000d3000>; + }; + + /* + * The flash starting at 0x000d4000 and ending at + * 0x000f3fff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@d4000 { + reg = <0x000d4000 0x00020000>; + }; + + boot_partition: partition@f4000 { + reg = <0x000f4000 0x0000c000>; + }; + }; +}; diff --git a/app/boards/arm/nice60/nice60.keymap b/app/boards/arm/nice60/nice60.keymap new file mode 100644 index 000000000000..3a35716321b9 --- /dev/null +++ b/app/boards/arm/nice60/nice60.keymap @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 Nick Winans + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ------------------------------------------------------------------------------------------ +// | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | +// | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | "|" | +// | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | +// | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | +// | CTL | WIN | ALT | SPACE | ALT | WIN | MO(1) | CTL | +// ------------------------------------------------------------------------------------------ + bindings = < + &gresc &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &kp RGUI &mo 1 &kp RCTRL + >; + }; + + rgb_layer { +// ------------------------------------------------------------------------------------------------ +// | BT CLR | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | EFFECT REV | +// | BT 1 | | UP | | HUEUP | SATUP | BRIUP | SPDUP | | | | | | | +// | BT 2 | LT | DN | RT | HUEDN | SATDN | BRIDN | SPDDN | | | | | EFFECT FORW | +// | BT 3 | | | | | | | | | | | | +// | BT 4 | | | TOG RGB | PRT SCR | | | DEL | +// ------------------------------------------------------------------------------------------------ + bindings = < + &bt BT_CLR &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &rgb_ug RGB_EFR + &bt BT_SEL 0 &trans &kp UP &trans &rgb_ug RGB_HUI &rgb_ug RGB_SAI &rgb_ug RGB_BRI &rgb_ug RGB_SPI &trans &trans &trans &trans &trans &trans + &bt BT_SEL 1 &kp LEFT &kp DOWN &kp RIGHT &rgb_ug RGB_HUD &rgb_ug RGB_SAD &rgb_ug RGB_BRD &rgb_ug RGB_SPD &trans &trans &trans &trans &rgb_ug RGB_EFF + &bt BT_SEL 2 &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &bt BT_SEL 3 &trans &trans &rgb_ug RGB_TOG &kp PSCRN &trans &trans &kp DEL + >; + }; + }; +}; diff --git a/app/boards/arm/nice60/nice60.yaml b/app/boards/arm/nice60/nice60.yaml new file mode 100644 index 000000000000..d3db56f6905e --- /dev/null +++ b/app/boards/arm/nice60/nice60.yaml @@ -0,0 +1,14 @@ +identifier: nice60 +name: nice!60 +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog diff --git a/app/boards/arm/nice60/nice60.zmk.yml b/app/boards/arm/nice60/nice60.zmk.yml new file mode 100644 index 000000000000..cbcc8130cf01 --- /dev/null +++ b/app/boards/arm/nice60/nice60.zmk.yml @@ -0,0 +1,12 @@ +file_format: "1" +id: nice60 +name: nice!60 +type: board +arch: arm +features: + - keys + - underglow +outputs: + - usb + - ble +url: https://nicekeyboards.com/nice-60 diff --git a/app/boards/arm/nice60/nice60_defconfig b/app/boards/arm/nice60/nice60_defconfig new file mode 100644 index 000000000000..fabcb7eddf42 --- /dev/null +++ b/app/boards/arm/nice60/nice60_defconfig @@ -0,0 +1,34 @@ +# Copyright (c) 2021 Nick Winans +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_NICE60=y + +# Enable MPU +CONFIG_ARM_MPU=y + +CONFIG_PINCTRL=y + +# enable GPIO +CONFIG_GPIO=y + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +CONFIG_ZMK_RGB_UNDERGLOW=y +CONFIG_WS2812_STRIP=y + +CONFIG_ZMK_RGB_UNDERGLOW_HUE_START=160 +CONFIG_ZMK_RGB_UNDERGLOW_EFF_START=3 + + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/nice_nano/Kconfig b/app/boards/arm/nice_nano/Kconfig new file mode 100644 index 000000000000..ac6828a4bbe8 --- /dev/null +++ b/app/boards/arm/nice_nano/Kconfig @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT + +config BOARD_ENABLE_DCDC + bool "Enable DCDC mode" + select SOC_DCDC_NRF52X + default y + depends on (BOARD_NICE_NANO || BOARD_NICE_NANO_V2) diff --git a/app/boards/arm/nice_nano/Kconfig.board b/app/boards/arm/nice_nano/Kconfig.board new file mode 100644 index 000000000000..8dd165123585 --- /dev/null +++ b/app/boards/arm/nice_nano/Kconfig.board @@ -0,0 +1,13 @@ +# nice!nano board configuration + +# Copyright (c) 2020 Pete Johanson +# SPDX-License-Identifier: MIT + +config BOARD_NICE_NANO + bool "nice!nano" + depends on SOC_NRF52840_QIAA + +config BOARD_NICE_NANO_V2 + bool "nice!nano v2" + depends on SOC_NRF52840_QIAA + diff --git a/app/boards/arm/nice_nano/Kconfig.defconfig b/app/boards/arm/nice_nano/Kconfig.defconfig new file mode 100644 index 000000000000..63102a571f9b --- /dev/null +++ b/app/boards/arm/nice_nano/Kconfig.defconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if BOARD_NICE_NANO || BOARD_NICE_NANO_V2 + +config BOARD + default "nice_nano" + +if USB_DEVICE_STACK + +config USB_NRFX + default y + +endif # USB_DEVICE_STACK + +config BT_CTLR + default BT + +endif # BOARD_NICE_NANO || BOARD_NICE_NANO_V2 diff --git a/app/boards/arm/nice_nano/arduino_pro_micro_pins.dtsi b/app/boards/arm/nice_nano/arduino_pro_micro_pins.dtsi new file mode 100644 index 000000000000..f1b569c05db9 --- /dev/null +++ b/app/boards/arm/nice_nano/arduino_pro_micro_pins.dtsi @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ + +/ { + pro_micro: connector { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &gpio0 8 0> /* D0 */ + , <1 0 &gpio0 6 0> /* D1 */ + , <2 0 &gpio0 17 0> /* D2 */ + , <3 0 &gpio0 20 0> /* D3 */ + , <4 0 &gpio0 22 0> /* D4/A6 */ + , <5 0 &gpio0 24 0> /* D5 */ + , <6 0 &gpio1 0 0> /* D6/A7 */ + , <7 0 &gpio0 11 0> /* D7 */ + , <8 0 &gpio1 4 0> /* D8/A8 */ + , <9 0 &gpio1 6 0> /* D9/A9 */ + , <10 0 &gpio0 9 0> /* D10/A10 */ + , <16 0 &gpio0 10 0> /* D16 */ + , <14 0 &gpio1 11 0> /* D14 */ + , <15 0 &gpio1 13 0> /* D15 */ + , <18 0 &gpio1 15 0> /* D18/A0 */ + , <19 0 &gpio0 2 0> /* D19/A1 */ + , <20 0 &gpio0 29 0> /* D20/A2 */ + , <21 0 &gpio0 31 0> /* D21/A3 */ + ; + }; + + pro_micro_a: connector_a { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &gpio1 15 0> /* D18/A0 */ + , <1 0 &gpio0 2 0> /* D19/A1 */ + , <2 0 &gpio0 29 0> /* D20/A2 */ + , <3 0 &gpio0 31 0> /* D21/A3 */ + , <6 0 &gpio0 22 0> /* D4/A6 */ + , <7 0 &gpio1 0 0> /* D6/A7 */ + , <8 0 &gpio1 4 0> /* D8/A8 */ + , <9 0 &gpio1 6 0> /* D9/A9 */ + , <10 0 &gpio0 9 0> /* D10/A10 */ + ; + }; +}; + +pro_micro_d: &pro_micro {}; +pro_micro_i2c: &i2c0 {}; +pro_micro_spi: &spi0 {}; +pro_micro_serial: &uart0 {}; diff --git a/app/boards/arm/nice_nano/board.cmake b/app/boards/arm/nice_nano/board.cmake new file mode 100644 index 000000000000..fa847d505952 --- /dev/null +++ b/app/boards/arm/nice_nano/board.cmake @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: MIT + +board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") +include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) diff --git a/app/boards/arm/nice_nano/nice_nano-pinctrl.dtsi b/app/boards/arm/nice_nano/nice_nano-pinctrl.dtsi new file mode 100644 index 000000000000..15c48509202c --- /dev/null +++ b/app/boards/arm/nice_nano/nice_nano-pinctrl.dtsi @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = ; + bias-pull-up; + }; + group2 { + psels = ; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + i2c0_default: i2c0_default { + group1 { + psels = , + ; + }; + }; + + i2c0_sleep: i2c0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; diff --git a/app/boards/arm/nice_nano/nice_nano.dts b/app/boards/arm/nice_nano/nice_nano.dts new file mode 100644 index 000000000000..06be88e1c516 --- /dev/null +++ b/app/boards/arm/nice_nano/nice_nano.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include "nice_nano.dtsi" + +/ { + chosen { + zmk,battery = &vbatt; + }; + + // Node name must match original "EXT_POWER" label to preserve user settings. + EXT_POWER { + compatible = "zmk,ext-power-generic"; + control-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; + }; + + vbatt: vbatt { + compatible = "zmk,battery-voltage-divider"; + io-channels = <&adc 2>; + output-ohms = <2000000>; + full-ohms = <(2000000 + 806000)>; + }; +}; diff --git a/app/boards/arm/nice_nano/nice_nano.dtsi b/app/boards/arm/nice_nano/nice_nano.dtsi new file mode 100644 index 000000000000..81f10906b924 --- /dev/null +++ b/app/boards/arm/nice_nano/nice_nano.dtsi @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include "nice_nano-pinctrl.dtsi" +#include "arduino_pro_micro_pins.dtsi" + +/ { + model = "nice!nano"; + compatible = "nice,nano"; + + chosen { + zephyr,code-partition = &code_partition; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + }; + + leds { + compatible = "gpio-leds"; + blue_led: led_0 { + gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&i2c0 { + compatible = "nordic,nrf-twi"; + pinctrl-0 = <&i2c0_default>; + pinctrl-1 = <&i2c0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart0 { + compatible = "nordic,nrf-uarte"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + sd_partition: partition@0 { + reg = <0x00000000 0x00026000>; + }; + code_partition: partition@26000 { + reg = <0x00026000 0x000c6000>; + }; + + /* + * The flash starting at 0x000ec000 and ending at + * 0x000f3fff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@ec000 { + reg = <0x000ec000 0x00008000>; + }; + + boot_partition: partition@f4000 { + reg = <0x000f4000 0x0000c000>; + }; + }; +}; diff --git a/app/boards/arm/nice_nano/nice_nano.yaml b/app/boards/arm/nice_nano/nice_nano.yaml new file mode 100644 index 000000000000..1c367324a3c6 --- /dev/null +++ b/app/boards/arm/nice_nano/nice_nano.yaml @@ -0,0 +1,15 @@ +identifier: nice_nano +name: nice!nano +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog diff --git a/app/boards/arm/nice_nano/nice_nano.zmk.yml b/app/boards/arm/nice_nano/nice_nano.zmk.yml new file mode 100644 index 000000000000..1799c0def49a --- /dev/null +++ b/app/boards/arm/nice_nano/nice_nano.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: nice_nano +name: nice!nano v1 +type: board +arch: arm +outputs: + - usb + - ble +url: https://nicekeyboards.com/nice-nano +exposes: [pro_micro] diff --git a/app/boards/arm/nice_nano/nice_nano_defconfig b/app/boards/arm/nice_nano/nice_nano_defconfig new file mode 100644 index 000000000000..6b7fcab252d1 --- /dev/null +++ b/app/boards/arm/nice_nano/nice_nano_defconfig @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_NICE_NANO=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# enable GPIO +CONFIG_GPIO=y + +# Use pinctrl +CONFIG_PINCTRL=y + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/nice_nano/nice_nano_v2.dts b/app/boards/arm/nice_nano/nice_nano_v2.dts new file mode 100644 index 000000000000..c4f7a821c048 --- /dev/null +++ b/app/boards/arm/nice_nano/nice_nano_v2.dts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include "nice_nano.dtsi" + +/ { + chosen { + zmk,battery = &vbatt; + }; + + // Node name must match original "EXT_POWER" label to preserve user settings. + EXT_POWER { + compatible = "zmk,ext-power-generic"; + control-gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>; + init-delay-ms = <50>; + }; + + vbatt: vbatt { + compatible = "zmk,battery-nrf-vddh"; + }; +}; diff --git a/app/boards/arm/nice_nano/nice_nano_v2.yaml b/app/boards/arm/nice_nano/nice_nano_v2.yaml new file mode 100644 index 000000000000..d050ce993f95 --- /dev/null +++ b/app/boards/arm/nice_nano/nice_nano_v2.yaml @@ -0,0 +1,15 @@ +identifier: nice_nano_v2 +name: nice!nano v2 +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog diff --git a/app/boards/arm/nice_nano/nice_nano_v2.zmk.yml b/app/boards/arm/nice_nano/nice_nano_v2.zmk.yml new file mode 100644 index 000000000000..3d1149a0c259 --- /dev/null +++ b/app/boards/arm/nice_nano/nice_nano_v2.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: nice_nano_v2 +name: nice!nano v2 +type: board +arch: arm +outputs: + - usb + - ble +url: https://nicekeyboards.com/nice-nano +exposes: [pro_micro] diff --git a/app/boards/arm/nice_nano/nice_nano_v2_defconfig b/app/boards/arm/nice_nano/nice_nano_v2_defconfig new file mode 100644 index 000000000000..6b5044e5ef0b --- /dev/null +++ b/app/boards/arm/nice_nano/nice_nano_v2_defconfig @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_NICE_NANO_V2=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Use pinctrl +CONFIG_PINCTRL=y + +# enable GPIO +CONFIG_GPIO=y + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +CONFIG_ZMK_BLE=y +CONFIG_ZMK_USB=y \ No newline at end of file diff --git a/app/boards/arm/nrf52840_m2/Kconfig b/app/boards/arm/nrf52840_m2/Kconfig new file mode 100644 index 000000000000..c9cb652352ba --- /dev/null +++ b/app/boards/arm/nrf52840_m2/Kconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_ENABLE_DCDC + bool "Enable DCDC mode" + select SOC_DCDC_NRF52X + default y + depends on BOARD_NRF52840_M2 diff --git a/app/boards/arm/nrf52840_m2/Kconfig.board b/app/boards/arm/nrf52840_m2/Kconfig.board new file mode 100644 index 000000000000..b2927ff2507e --- /dev/null +++ b/app/boards/arm/nrf52840_m2/Kconfig.board @@ -0,0 +1,9 @@ +# Maker Diary nrf52840 M.2 board configuration + +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_NRF52840_M2 + bool "nrf52480_m2" + depends on SOC_NRF52840_QIAA + diff --git a/app/boards/arm/nrf52840_m2/Kconfig.defconfig b/app/boards/arm/nrf52840_m2/Kconfig.defconfig new file mode 100644 index 000000000000..a5227fc0a104 --- /dev/null +++ b/app/boards/arm/nrf52840_m2/Kconfig.defconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if BOARD_NRF52840_M2 + +config BOARD + default "nrf52480_m2" + +if USB_DEVICE_STACK + +config USB_NRFX + default y + +endif # USB_DEVICE_STACK + +config BT_CTLR + default BT + +endif # BOARD_NRF52840_M2 diff --git a/app/boards/arm/nrf52840_m2/board.cmake b/app/boards/arm/nrf52840_m2/board.cmake new file mode 100644 index 000000000000..ae1e2607870d --- /dev/null +++ b/app/boards/arm/nrf52840_m2/board.cmake @@ -0,0 +1,7 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") + +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) +include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) diff --git a/app/boards/arm/nrf52840_m2/nrf52840_m2.dts b/app/boards/arm/nrf52840_m2/nrf52840_m2.dts new file mode 100644 index 000000000000..85e9ce2107f2 --- /dev/null +++ b/app/boards/arm/nrf52840_m2/nrf52840_m2.dts @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include + +/ { + model = "Makerdiary nRF52840 M.2 module"; + compatible = "makerdiary,nrf52840_m2"; + + chosen { + zephyr,code-partition = &code_partition; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + zmk,battery = &vbatt; + }; + + leds { + compatible = "gpio-leds"; + red_led: led_0 { + gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>; + }; + green_led: led_1 { + gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>; + }; + blue_led: led_2 { + gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>; + }; + }; + + vbatt: vbatt { + compatible = "zmk,battery-voltage-divider"; + io-channels = <&adc 0>; + output-ohms = <1000000>; + full-ohms = <(1000000 + 1000000)>; + }; + +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&usbd { + compatible = "nordic,nrf-usbd"; + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + sd_partition: partition@0 { + reg = <0x00000000 0x00026000>; + }; + code_partition: partition@26000 { + reg = <0x00026000 0x000c6000>; + }; + + /* + * The flash starting at 0x000ec000 and ending at + * 0x000f3fff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@ec000 { + reg = <0x000ec000 0x00008000>; + }; + + boot_partition: partition@f4000 { + reg = <0x000f4000 0x0000c000>; + }; + }; +}; diff --git a/app/boards/arm/nrf52840_m2/nrf52840_m2.yaml b/app/boards/arm/nrf52840_m2/nrf52840_m2.yaml new file mode 100644 index 000000000000..0a999bbf6ad7 --- /dev/null +++ b/app/boards/arm/nrf52840_m2/nrf52840_m2.yaml @@ -0,0 +1,15 @@ +identifier: nrf52840_m2 +name: Makerdiary nRF52840 M.2 module +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog diff --git a/app/boards/arm/nrf52840_m2/nrf52840_m2.zmk.yml b/app/boards/arm/nrf52840_m2/nrf52840_m2.zmk.yml new file mode 100644 index 000000000000..2a4ccb0cec0b --- /dev/null +++ b/app/boards/arm/nrf52840_m2/nrf52840_m2.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: nrf52840_m2 +name: nRF52840 M.2 Module +type: board +arch: arm +outputs: + - usb + - ble +url: https://wiki.makerdiary.com/nrf52840-m2/ +exposes: [makerdiary_nrf52840_m2] diff --git a/app/boards/arm/nrf52840_m2/nrf52840_m2_defconfig b/app/boards/arm/nrf52840_m2/nrf52840_m2_defconfig new file mode 100644 index 000000000000..93eef9e6ef8d --- /dev/null +++ b/app/boards/arm/nrf52840_m2/nrf52840_m2_defconfig @@ -0,0 +1,25 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_NRF52840_M2=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# enable GPIO +CONFIG_GPIO=y + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.zmk.yml b/app/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.zmk.yml new file mode 100644 index 000000000000..2a0d99460d81 --- /dev/null +++ b/app/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: nrf52840dk_nrf52840 +name: Nordic nRF52840 DK +type: board +arch: arm +outputs: + - usb + - ble +url: https://www.nordicsemi.com/Products/Development-hardware/nrf52840-dk +exposes: [arduino_uno] diff --git a/app/boards/arm/nrf5340dk_nrf5340_cpuapp/nrf5340dk_nrf5340_cpuapp.zmk.yml b/app/boards/arm/nrf5340dk_nrf5340_cpuapp/nrf5340dk_nrf5340_cpuapp.zmk.yml new file mode 100644 index 000000000000..444de996b53a --- /dev/null +++ b/app/boards/arm/nrf5340dk_nrf5340_cpuapp/nrf5340dk_nrf5340_cpuapp.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: nrf5340dk_nrf5340_cpuapp +name: Nordic nRF5340 DK +type: board +arch: arm +outputs: + - usb + - ble +url: https://www.nordicsemi.com/Products/Development-hardware/nrf5340-dk +exposes: [arduino_uno] diff --git a/app/boards/arm/nrfmicro/CMakeLists.txt b/app/boards/arm/nrfmicro/CMakeLists.txt new file mode 100644 index 000000000000..12cf9b1cf1a1 --- /dev/null +++ b/app/boards/arm/nrfmicro/CMakeLists.txt @@ -0,0 +1,6 @@ + +if(CONFIG_PINMUX) +zephyr_library() +zephyr_library_sources(pinmux.c) +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) +endif() \ No newline at end of file diff --git a/app/boards/arm/nrfmicro/Kconfig b/app/boards/arm/nrfmicro/Kconfig new file mode 100644 index 000000000000..233ddbad4607 --- /dev/null +++ b/app/boards/arm/nrfmicro/Kconfig @@ -0,0 +1,10 @@ +config BOARD_ENABLE_DCDC + bool "Enable DCDC mode" + select SOC_DCDC_NRF52X + default y + depends on (BOARD_NRFMICRO_11 || BOARD_NRFMICRO_11_FLIPPED || BOARD_NRFMICRO_13 || BOARD_NRFMICRO_13_52833) + +config BOARD_NRFMICRO_CHARGER + bool "Enable battery charger" + default y + depends on (BOARD_NRFMICRO_13 || BOARD_NRFMICRO_13_52833) diff --git a/app/boards/arm/nrfmicro/Kconfig.board b/app/boards/arm/nrfmicro/Kconfig.board new file mode 100644 index 000000000000..441de5cff7e9 --- /dev/null +++ b/app/boards/arm/nrfmicro/Kconfig.board @@ -0,0 +1,20 @@ +# nrfmicro board configuration + +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_NRFMICRO_11 + bool "nrfmicro_11" + depends on SOC_NRF52840_QIAA + +config BOARD_NRFMICRO_11_FLIPPED + bool "nrfmicro_11_flipped" + depends on SOC_NRF52840_QIAA + +config BOARD_NRFMICRO_13 + bool "nrfmicro_13" + depends on SOC_NRF52840_QIAA + +config BOARD_NRFMICRO_13_52833 + bool "nrfmicro_13_52833" + depends on SOC_NRF52833_QIAA diff --git a/app/boards/arm/nrfmicro/Kconfig.defconfig b/app/boards/arm/nrfmicro/Kconfig.defconfig new file mode 100644 index 000000000000..659e9c5c173e --- /dev/null +++ b/app/boards/arm/nrfmicro/Kconfig.defconfig @@ -0,0 +1,31 @@ +# Electronut Labs Papyr board configuration + +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if BOARD_NRFMICRO_11 || BOARD_NRFMICRO_11_FLIPPED || BOARD_NRFMICRO_13 || BOARD_NRFMICRO_13_52833 + +config BOARD + default "nrfmicro" + +if USB_DEVICE_STACK + +config USB_NRFX + default y + +endif # USB_DEVICE_STACK + +config BT_CTLR + default BT + +config PINMUX + default y + +if BOARD_NRFMICRO_13 || BOARD_NRFMICRO_13_52833 + +config BOARD_NRFMICRO_CHARGER + default y + +endif # BOARD_NRFMICRO_13 || BOARD_NRFMICRO_13_52833 + +endif # BOARD_NRFMICRO_11 || BOARD_NRFMICRO_11_FLIPPED || BOARD_NRFMICRO_13 || BOARD_NRFMICRO_13_52833 diff --git a/app/boards/arm/nrfmicro/arduino_pro_micro_pins.dtsi b/app/boards/arm/nrfmicro/arduino_pro_micro_pins.dtsi new file mode 100644 index 000000000000..01e342c0df54 --- /dev/null +++ b/app/boards/arm/nrfmicro/arduino_pro_micro_pins.dtsi @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + +/ { + pro_micro: connector { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &gpio0 8 0> /* D0 */ + , <1 0 &gpio0 6 0> /* D1 */ + , <2 0 &gpio0 15 0> /* D2 */ + , <3 0 &gpio0 17 0> /* D3 */ + , <4 0 &gpio0 20 0> /* D4/A6 */ + , <5 0 &gpio0 13 0> /* D5 */ + , <6 0 &gpio0 24 0> /* D6/A7 */ + , <7 0 &gpio0 9 0> /* D7 */ + , <8 0 &gpio0 10 0> /* D8/A8 */ + , <9 0 &gpio1 6 0> /* D9/A9 */ + , <10 0 &gpio1 11 0> /* D10/A10 */ + , <16 0 &gpio0 28 0> /* D16 */ + , <14 0 &gpio0 3 0> /* D14 */ + , <15 0 &gpio1 13 0> /* D15 */ + , <18 0 &gpio0 2 0> /* D18/A0 */ + , <19 0 &gpio0 29 0> /* D19/A1 */ + , <20 0 &gpio0 31 0> /* D20/A2 */ + , <21 0 &gpio0 30 0> /* D21/A3 */ + ; + }; + + pro_micro_a: connector_a { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &gpio0 2 0> /* D18/A0 */ + , <1 0 &gpio0 29 0> /* D19/A1 */ + , <2 0 &gpio0 31 0> /* D20/A2 */ + , <3 0 &gpio0 30 0> /* D21/A3 */ + , <6 0 &gpio0 20 0> /* D4/A6 */ + , <7 0 &gpio0 24 0> /* D6/A7 */ + , <8 0 &gpio0 10 0> /* D8/A8 */ + , <9 0 &gpio1 6 0> /* D9/A9 */ + , <10 0 &gpio1 11 0> /* D10/A10 */ + ; + }; +}; + + +pro_micro_d: &pro_micro {}; +pro_micro_i2c: &i2c0 {}; +pro_micro_spi: &spi0 {}; +pro_micro_serial: &uart0 {}; diff --git a/app/boards/arm/nrfmicro/arduino_pro_micro_pins_52833.dtsi b/app/boards/arm/nrfmicro/arduino_pro_micro_pins_52833.dtsi new file mode 100644 index 000000000000..76ece25f786e --- /dev/null +++ b/app/boards/arm/nrfmicro/arduino_pro_micro_pins_52833.dtsi @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + +/ { + pro_micro: connector { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &gpio0 8 0> /* D0 */ + , <1 0 &gpio0 6 0> /* D1 */ + , <2 0 &gpio0 15 0> /* D2 */ + , <3 0 &gpio0 17 0> /* D3 */ + , <4 0 &gpio0 20 0> /* D4/A6 */ + , <5 0 &gpio0 13 0> /* D5 */ + , <6 0 &gpio0 24 0> /* D6/A7 */ + , <7 0 &gpio0 9 0> /* D7 */ + , <8 0 &gpio0 10 0> /* D8/A8 */ + , <9 0 &gpio1 6 0> /* D9/A9 */ + , <10 0 &gpio1 4 0> /* D10/A10 */ + , <16 0 &gpio0 28 0> /* D16 */ + , <14 0 &gpio0 3 0> /* D14 */ + , <15 0 &gpio1 5 0> /* D15 */ + , <18 0 &gpio0 2 0> /* D18/A0 */ + , <19 0 &gpio0 29 0> /* D19/A1 */ + , <20 0 &gpio0 31 0> /* D20/A2 */ + , <21 0 &gpio0 30 0> /* D21/A3 */ + ; + }; + + pro_micro_a: connector_a { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &gpio0 2 0> /* D18/A0 */ + , <1 0 &gpio0 29 0> /* D19/A1 */ + , <2 0 &gpio0 31 0> /* D20/A2 */ + , <3 0 &gpio0 30 0> /* D21/A3 */ + , <6 0 &gpio0 20 0> /* D4/A6 */ + , <7 0 &gpio0 24 0> /* D6/A7 */ + , <8 0 &gpio0 10 0> /* D8/A8 */ + , <9 0 &gpio1 6 0> /* D9/A9 */ + , <10 0 &gpio1 11 0> /* D10/A10 */ + ; + }; +}; + + +pro_micro_d: &pro_micro {}; +pro_micro_i2c: &i2c0 {}; +pro_micro_spi: &spi0 {}; +pro_micro_serial: &uart0 {}; diff --git a/app/boards/arm/nrfmicro/arduino_pro_micro_pins_flipped.dtsi b/app/boards/arm/nrfmicro/arduino_pro_micro_pins_flipped.dtsi new file mode 100644 index 000000000000..923efbbf256b --- /dev/null +++ b/app/boards/arm/nrfmicro/arduino_pro_micro_pins_flipped.dtsi @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + pro_micro: connector { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &gpio0 8 0> /* D0 */ + , <1 0 &gpio0 6 0> /* D1 */ + , <2 0 &gpio0 30 0> /* D2 */ + , <3 0 &gpio0 31 0> /* D3 */ + , <4 0 &gpio0 29 0> /* D4/A6 */ + , <5 0 &gpio0 2 0> /* D5 */ + , <6 0 &gpio1 13 0> /* D6/A7 */ + , <7 0 &gpio0 3 0> /* D7 */ + , <8 0 &gpio0 28 0> /* D8/A8 */ + , <9 0 &gpio1 11 0> /* D9/A9 */ + , <10 0 &gpio1 6 0> /* D10/A10 */ + , <16 0 &gpio0 10 0> /* D16 */ + , <14 0 &gpio0 9 0> /* D14 */ + , <15 0 &gpio0 24 0> /* D15 */ + , <18 0 &gpio0 13 0> /* D18/A0 */ + , <19 0 &gpio0 20 0> /* D19/A1 */ + , <20 0 &gpio0 17 0> /* D20/A2 */ + , <21 0 &gpio0 15 0> /* D21/A3 */ + ; + }; + + pro_micro_a: connector_a { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &gpio0 13 0> /* D18/A0 */ + , <1 0 &gpio0 20 0> /* D19/A1 */ + , <2 0 &gpio0 17 0> /* D20/A2 */ + , <3 0 &gpio0 15 0> /* D21/A3 */ + , <6 0 &gpio0 29 0> /* D4/A6 */ + , <7 0 &gpio1 13 0> /* D6/A7 */ + , <8 0 &gpio0 28 0> /* D8/A8 */ + , <9 0 &gpio1 11 0> /* D9/A9 */ + , <10 0 &gpio1 6 0> /* D10/A10 */ + ; + }; +}; + +pro_micro_d: &pro_micro {}; +pro_micro_i2c: &i2c0 {}; +pro_micro_spi: &spi0 {}; +pro_micro_serial: &uart0 {}; diff --git a/app/boards/arm/nrfmicro/board.cmake b/app/boards/arm/nrfmicro/board.cmake new file mode 100644 index 000000000000..fa847d505952 --- /dev/null +++ b/app/boards/arm/nrfmicro/board.cmake @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: MIT + +board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") +include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) diff --git a/app/boards/arm/nrfmicro/nrfmicro-flipped-pinctrl.dtsi b/app/boards/arm/nrfmicro/nrfmicro-flipped-pinctrl.dtsi new file mode 100644 index 000000000000..22bc11d40134 --- /dev/null +++ b/app/boards/arm/nrfmicro/nrfmicro-flipped-pinctrl.dtsi @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = ; + bias-pull-up; + }; + group2 { + psels = ; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + i2c0_default: i2c0_default { + group1 { + psels = , + ; + }; + }; + + i2c0_sleep: i2c0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; diff --git a/app/boards/arm/nrfmicro/nrfmicro-pinctrl.dtsi b/app/boards/arm/nrfmicro/nrfmicro-pinctrl.dtsi new file mode 100644 index 000000000000..35a46e5ae52c --- /dev/null +++ b/app/boards/arm/nrfmicro/nrfmicro-pinctrl.dtsi @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = ; + bias-pull-up; + }; + group2 { + psels = ; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + i2c0_default: i2c0_default { + group1 { + psels = , + ; + }; + }; + + i2c0_sleep: i2c0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; diff --git a/app/boards/arm/nrfmicro/nrfmicro_11.dts b/app/boards/arm/nrfmicro/nrfmicro_11.dts new file mode 100644 index 000000000000..c0c02ee9e345 --- /dev/null +++ b/app/boards/arm/nrfmicro/nrfmicro_11.dts @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include +#include "arduino_pro_micro_pins.dtsi" +#include "nrfmicro-pinctrl.dtsi" + +/ { + model = "nrfmicro"; + compatible = "joric,nrfmicro"; + + chosen { + zephyr,code-partition = &code_partition; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + }; + + leds { + compatible = "gpio-leds"; + blue_led: led_0 { + gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + }; + }; + + // Node name must match original "EXT_POWER" label to preserve user settings. + EXT_POWER { + compatible = "zmk,ext-power-generic"; + control-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; + }; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&i2c0 { + compatible = "nordic,nrf-twi"; + pinctrl-0 = <&i2c0_default>; + pinctrl-1 = <&i2c0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart0 { + compatible = "nordic,nrf-uarte"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + sd_partition: partition@0 { + reg = <0x00000000 0x00026000>; + }; + code_partition: partition@26000 { + reg = <0x00026000 0x000c6000>; + }; + + /* + * The flash starting at 0x000ec000 and ending at + * 0x000f3fff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@ec000 { + reg = <0x000ec000 0x00008000>; + }; + + boot_partition: partition@f4000 { + reg = <0x000f4000 0x0000c000>; + }; + }; +}; diff --git a/app/boards/arm/nrfmicro/nrfmicro_11.yaml b/app/boards/arm/nrfmicro/nrfmicro_11.yaml new file mode 100644 index 000000000000..4608130de8bf --- /dev/null +++ b/app/boards/arm/nrfmicro/nrfmicro_11.yaml @@ -0,0 +1,15 @@ +identifier: nrfmicro_11 +name: nrfmicro_11 +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog diff --git a/app/boards/arm/nrfmicro/nrfmicro_11.zmk.yml b/app/boards/arm/nrfmicro/nrfmicro_11.zmk.yml new file mode 100644 index 000000000000..4160ec6a77b8 --- /dev/null +++ b/app/boards/arm/nrfmicro/nrfmicro_11.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: nrfmicro_11 +name: nRFMicro 1.1/1.2 +type: board +arch: arm +outputs: + - usb + - ble +url: https://github.com/joric/nrfmicro/ +exposes: [pro_micro] diff --git a/app/boards/arm/nrfmicro/nrfmicro_11_defconfig b/app/boards/arm/nrfmicro/nrfmicro_11_defconfig new file mode 100644 index 000000000000..5ba4d6e14787 --- /dev/null +++ b/app/boards/arm/nrfmicro/nrfmicro_11_defconfig @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_NRFMICRO_11=y + +# Enable MPU +CONFIG_ARM_MPU=y + +CONFIG_PINCTRL=y + +# enable GPIO +CONFIG_GPIO=y + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y +CONFIG_CLOCK_CONTROL_NRF=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/nrfmicro/nrfmicro_11_flipped.dts b/app/boards/arm/nrfmicro/nrfmicro_11_flipped.dts new file mode 100644 index 000000000000..df3b224bc492 --- /dev/null +++ b/app/boards/arm/nrfmicro/nrfmicro_11_flipped.dts @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include +#include "arduino_pro_micro_pins_flipped.dtsi" +#include "nrfmicro-flipped-pinctrl.dtsi" + +/ { + model = "nrfmicro"; + compatible = "joric,nrfmicro"; + + chosen { + zephyr,code-partition = &code_partition; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + }; + + leds { + compatible = "gpio-leds"; + blue_led: led_0 { + gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + }; + }; + + // Node name must match original "EXT_POWER" label to preserve user settings. + EXT_POWER { + compatible = "zmk,ext-power-generic"; + control-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; + }; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&i2c0 { + compatible = "nordic,nrf-twi"; + pinctrl-0 = <&i2c0_default>; + pinctrl-1 = <&i2c0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart0 { + compatible = "nordic,nrf-uarte"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + sd_partition: partition@0 { + reg = <0x00000000 0x00026000>; + }; + code_partition: partition@26000 { + reg = <0x00026000 0x000c6000>; + }; + + /* + * The flash starting at 0x000ec000 and ending at + * 0x000f3fff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@ec000 { + reg = <0x000ec000 0x00008000>; + }; + + boot_partition: partition@f4000 { + reg = <0x000f4000 0x0000c000>; + }; + }; +}; diff --git a/app/boards/arm/nrfmicro/nrfmicro_11_flipped.yaml b/app/boards/arm/nrfmicro/nrfmicro_11_flipped.yaml new file mode 100644 index 000000000000..74461f09cebb --- /dev/null +++ b/app/boards/arm/nrfmicro/nrfmicro_11_flipped.yaml @@ -0,0 +1,15 @@ +identifier: nrfmicro_11_flipped +name: nrfmicro_11_flipped +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog diff --git a/app/boards/arm/nrfmicro/nrfmicro_11_flipped.zmk.yml b/app/boards/arm/nrfmicro/nrfmicro_11_flipped.zmk.yml new file mode 100644 index 000000000000..b63ace2d652f --- /dev/null +++ b/app/boards/arm/nrfmicro/nrfmicro_11_flipped.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: nrfmicro_11_flipped +name: nRFMicro 1.1 (flipped) +type: board +arch: arm +outputs: + - usb + - ble +url: https://github.com/joric/nrfmicro/ +exposes: [pro_micro] diff --git a/app/boards/arm/nrfmicro/nrfmicro_11_flipped_defconfig b/app/boards/arm/nrfmicro/nrfmicro_11_flipped_defconfig new file mode 100644 index 000000000000..31cbfc9ae750 --- /dev/null +++ b/app/boards/arm/nrfmicro/nrfmicro_11_flipped_defconfig @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_NRFMICRO_11_FLIPPED=y + +# Enable MPU +CONFIG_ARM_MPU=y + +CONFIG_PINCTRL=y + +# enable GPIO +CONFIG_GPIO=y + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y +CONFIG_CLOCK_CONTROL_NRF=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/nrfmicro/nrfmicro_13.dts b/app/boards/arm/nrfmicro/nrfmicro_13.dts new file mode 100644 index 000000000000..f5ae81c95453 --- /dev/null +++ b/app/boards/arm/nrfmicro/nrfmicro_13.dts @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include +#include "arduino_pro_micro_pins.dtsi" +#include "nrfmicro-pinctrl.dtsi" + +/ { + model = "nrfmicro"; + compatible = "joric,nrfmicro"; + + chosen { + zephyr,code-partition = &code_partition; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + zmk,battery = &vbatt; + }; + + leds { + compatible = "gpio-leds"; + blue_led: led_0 { + gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + }; + }; + + // Node name must match original "EXT_POWER" label to preserve user settings. + EXT_POWER { + compatible = "zmk,ext-power-generic"; + control-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; + }; + + vbatt: vbatt { + compatible = "zmk,battery-voltage-divider"; + io-channels = <&adc 2>; + output-ohms = <2000000>; + full-ohms = <(2000000 + 820000)>; + }; +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&i2c0 { + compatible = "nordic,nrf-twi"; + pinctrl-0 = <&i2c0_default>; + pinctrl-1 = <&i2c0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart0 { + compatible = "nordic,nrf-uarte"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + sd_partition: partition@0 { + reg = <0x00000000 0x00026000>; + }; + code_partition: partition@26000 { + reg = <0x00026000 0x000c6000>; + }; + + /* + * The flash starting at 0x000ec000 and ending at + * 0x000f3fff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@ec000 { + reg = <0x000ec000 0x00008000>; + }; + + boot_partition: partition@f4000 { + reg = <0x000f4000 0x0000c000>; + }; + }; +}; diff --git a/app/boards/arm/nrfmicro/nrfmicro_13.yaml b/app/boards/arm/nrfmicro/nrfmicro_13.yaml new file mode 100644 index 000000000000..a7415e4429e7 --- /dev/null +++ b/app/boards/arm/nrfmicro/nrfmicro_13.yaml @@ -0,0 +1,15 @@ +identifier: nrfmicro_13 +name: nrfmicro_13 +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog diff --git a/app/boards/arm/nrfmicro/nrfmicro_13.zmk.yml b/app/boards/arm/nrfmicro/nrfmicro_13.zmk.yml new file mode 100644 index 000000000000..8fd28d377941 --- /dev/null +++ b/app/boards/arm/nrfmicro/nrfmicro_13.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: nrfmicro_13 +name: nRFMicro 1.3/1.4 +type: board +arch: arm +outputs: + - usb + - ble +url: https://github.com/joric/nrfmicro/ +exposes: [pro_micro] diff --git a/app/boards/arm/nrfmicro/nrfmicro_13_52833.dts b/app/boards/arm/nrfmicro/nrfmicro_13_52833.dts new file mode 100644 index 000000000000..d6c88692d950 --- /dev/null +++ b/app/boards/arm/nrfmicro/nrfmicro_13_52833.dts @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include +#include "arduino_pro_micro_pins_52833.dtsi" +#include "nrfmicro-pinctrl.dtsi" + +/ { + model = "nrfmicro"; + compatible = "joric,nrfmicro"; + + chosen { + zephyr,code-partition = &code_partition; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + zmk,battery = &vbatt; + }; + + leds { + compatible = "gpio-leds"; + blue_led: led_0 { + gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>; + }; + }; + + // Node name must match original "EXT_POWER" label to preserve user settings. + EXT_POWER { + compatible = "zmk,ext-power-generic"; + control-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; + }; + + vbatt: vbatt { + compatible = "zmk,battery-voltage-divider"; + io-channels = <&adc 2>; + output-ohms = <2000000>; + full-ohms = <(2000000 + 820000)>; + }; +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&i2c0 { + compatible = "nordic,nrf-twi"; + pinctrl-0 = <&i2c0_default>; + pinctrl-1 = <&i2c0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart0 { + compatible = "nordic,nrf-uarte"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + sd_partition: partition@0 { + reg = <0x00000000 0x00026000>; + }; + code_partition: partition@26000 { + reg = <0x00026000 0x00046000>; + }; + + /* + * The flash starting at 0x0006c000 and ending at + * 0x00073fff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@6c000 { + reg = <0x0006c000 0x00008000>; + }; + + boot_partition: partition@74000 { + reg = <0x00074000 0x0000c000>; + }; + }; +}; diff --git a/app/boards/arm/nrfmicro/nrfmicro_13_52833.yaml b/app/boards/arm/nrfmicro/nrfmicro_13_52833.yaml new file mode 100644 index 000000000000..768a59c9c400 --- /dev/null +++ b/app/boards/arm/nrfmicro/nrfmicro_13_52833.yaml @@ -0,0 +1,15 @@ +identifier: nrfmicro_13_52833 +name: nrfmicro_13_52833 +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog diff --git a/app/boards/arm/nrfmicro/nrfmicro_13_52833.zmk.yml b/app/boards/arm/nrfmicro/nrfmicro_13_52833.zmk.yml new file mode 100644 index 000000000000..757ff860a1c0 --- /dev/null +++ b/app/boards/arm/nrfmicro/nrfmicro_13_52833.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: nrfmicro_13_52833 +name: nRFMicro 1.3/1.4 (nRF52833) +type: board +arch: arm +outputs: + - usb + - ble +url: https://github.com/joric/nrfmicro/ +exposes: [pro_micro] diff --git a/app/boards/arm/nrfmicro/nrfmicro_13_52833_defconfig b/app/boards/arm/nrfmicro/nrfmicro_13_52833_defconfig new file mode 100644 index 000000000000..f459f35636a5 --- /dev/null +++ b/app/boards/arm/nrfmicro/nrfmicro_13_52833_defconfig @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52833_QIAA=y +CONFIG_BOARD_NRFMICRO_13_52833=y + +# Enable MPU +CONFIG_ARM_MPU=y + +CONFIG_PINCTRL=y + +# enable GPIO +CONFIG_GPIO=y + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y +CONFIG_CLOCK_CONTROL_NRF=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/nrfmicro/nrfmicro_13_defconfig b/app/boards/arm/nrfmicro/nrfmicro_13_defconfig new file mode 100644 index 000000000000..9ffb2766a663 --- /dev/null +++ b/app/boards/arm/nrfmicro/nrfmicro_13_defconfig @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_NRFMICRO_13=y + +# Enable MPU +CONFIG_ARM_MPU=y + +CONFIG_PINCTRL=y + +# enable GPIO +CONFIG_GPIO=y + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y +CONFIG_CLOCK_CONTROL_NRF=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/nrfmicro/pinmux.c b/app/boards/arm/nrfmicro/pinmux.c new file mode 100644 index 000000000000..6362b39250c0 --- /dev/null +++ b/app/boards/arm/nrfmicro/pinmux.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include +#include + +static int pinmux_nrfmicro_init(const struct device *port) { + ARG_UNUSED(port); + +#if (CONFIG_BOARD_NRFMICRO_13 || CONFIG_BOARD_NRFMICRO_13_52833) + const struct device *p0 = DEVICE_DT_GET(DT_NODELABEL(gpio0)); +#if CONFIG_BOARD_NRFMICRO_CHARGER + gpio_pin_configure(p0, 5, GPIO_OUTPUT); + gpio_pin_set(p0, 5, 0); +#else + gpio_pin_configure(p0, 5, GPIO_INPUT); +#endif +#endif + return 0; +} + +SYS_INIT(pinmux_nrfmicro_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/app/boards/arm/pillbug/Kconfig b/app/boards/arm/pillbug/Kconfig new file mode 100644 index 000000000000..3d53e3244fde --- /dev/null +++ b/app/boards/arm/pillbug/Kconfig @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT + +config BOARD_ENABLE_DCDC + bool "Enable DCDC mode" + select SOC_DCDC_NRF52X + default y + depends on (BOARD_PILLBUG) diff --git a/app/boards/arm/pillbug/Kconfig.board b/app/boards/arm/pillbug/Kconfig.board new file mode 100644 index 000000000000..70232e18a72a --- /dev/null +++ b/app/boards/arm/pillbug/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_PILLBUG + bool "PillBug" + depends on SOC_NRF52840_QIAA diff --git a/app/boards/arm/pillbug/Kconfig.defconfig b/app/boards/arm/pillbug/Kconfig.defconfig new file mode 100644 index 000000000000..48427ed3ec2c --- /dev/null +++ b/app/boards/arm/pillbug/Kconfig.defconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if BOARD_PILLBUG + +config BOARD + default "PillBug" + +if USB_DEVICE_STACK + +config USB_NRFX + default y + +endif # USB_DEVICE_STACK + +config BT_CTLR + default BT + +endif # BOARD_PILLBUG diff --git a/app/boards/arm/pillbug/blackpill_pins.dtsi b/app/boards/arm/pillbug/blackpill_pins.dtsi new file mode 100644 index 000000000000..e7e351403c75 --- /dev/null +++ b/app/boards/arm/pillbug/blackpill_pins.dtsi @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022 Kyle McCreery + * + * SPDX-License-Identifier: MIT + */ + +/ { + blackpill: connector { + compatible = "blackpill"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <2 0 &gpio0 9 0> /* PC13 */ + , <3 0 &gpio0 10 0> /* PC14 */ + , <4 0 &gpio1 6 0> /* PC15 */ + , <10 0 &gpio0 25 0> /* PA0 */ + , <11 0 &gpio0 5 0> /* PA1 */ + , <12 0 &gpio1 15 0> /* PA2 */ + , <13 0 &gpio0 2 0> /* PA3 */ + , <14 0 &gpio1 11 0> /* PA4 */ + , <15 0 &gpio1 8 0> /* PA5 */ + , <16 0 &gpio0 26 0> /* PA6 */ + , <17 0 &gpio0 11 0> /* PA7 */ + , <18 0 &gpio1 9 0> /* PB0 */ + , <19 0 &gpio1 14 0> /* PB1 */ + , <20 0 &gpio0 3 0> /* PB2 */ + , <21 0 &gpio0 31 0> /* PB10 */ + , <25 0 &gpio0 12 0> /* PB12 */ + , <26 0 &gpio0 19 0> /* PB13 */ + , <27 0 &gpio1 1 0> /* PB14 */ + , <28 0 &gpio0 29 0> /* PB15 */ + , <29 0 &gpio1 13 0> /* PA8 */ + , <30 0 &gpio0 6 0> /* PA9 */ + , <31 0 &gpio0 8 0> /* PA10 */ + , <38 0 &gpio1 0 0> /* PA15 */ + , <39 0 &gpio1 10 0> /* PB3 */ + , <40 0 &gpio1 2 0> /* PB4 */ + , <41 0 &gpio1 4 0> /* PB5 */ + , <42 0 &gpio0 13 0> /* PB6 */ + , <43 0 &gpio0 15 0> /* PB7 */ + , <45 0 &gpio0 17 0> /* PB8 */ + , <46 0 &gpio0 24 0> /* PB9 */ + ; + }; +}; + +blackpill_i2c: &i2c0 {}; +blackpill_spi: &spi1 {}; +blackpill_serial: &uart0 {}; diff --git a/app/boards/arm/pillbug/board.cmake b/app/boards/arm/pillbug/board.cmake new file mode 100644 index 000000000000..992f395d95f5 --- /dev/null +++ b/app/boards/arm/pillbug/board.cmake @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MIT + +set(OPENOCD_NRF5_SUBFAMILY nrf52) +board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd-nrf5.board.cmake) diff --git a/app/boards/arm/pillbug/pillbug-pinctrl.dtsi b/app/boards/arm/pillbug/pillbug-pinctrl.dtsi new file mode 100644 index 000000000000..8a9e9fc21abd --- /dev/null +++ b/app/boards/arm/pillbug/pillbug-pinctrl.dtsi @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = ; + bias-pull-up; + }; + group2 { + psels = ; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + i2c0_default: i2c0_default { + group1 { + psels = , + ; + }; + }; + + i2c0_sleep: i2c0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + spi1_default: spi1_default { + group1 { + psels = , + , + ; + }; + }; + + spi1_sleep: spi1_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; diff --git a/app/boards/arm/pillbug/pillbug.dts b/app/boards/arm/pillbug/pillbug.dts new file mode 100644 index 000000000000..c30d306e2751 --- /dev/null +++ b/app/boards/arm/pillbug/pillbug.dts @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; + +#include +#include "pillbug-pinctrl.dtsi" +#include "blackpill_pins.dtsi" + +/ { + model = "PillBug"; + compatible = "pillbug"; + + chosen { + zephyr,code-partition = &code_partition; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + zmk,battery = &vbatt; + }; + + leds { + compatible = "gpio-leds"; + blue_led: led_0 { + gpios = <&gpio0 20 GPIO_ACTIVE_LOW>; + }; + }; + + // Node name must match original "EXT_POWER" label to preserve user settings. + EXT_POWER { + compatible = "zmk,ext-power-generic"; + control-gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; + init-delay-ms = <50>; + }; + + vbatt: vbatt { + compatible = "zmk,battery-voltage-divider"; + io-channels = <&adc 2>; + output-ohms = <2000000>; + full-ohms = <(2000000 + 820000)>; + }; +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&i2c0 { + compatible = "nordic,nrf-twi"; + pinctrl-0 = <&i2c0_default>; + pinctrl-1 = <&i2c0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&spi1 { + status = "disabled"; + compatible = "nordic,nrf-spim"; + pinctrl-0 = <&spi1_default>; + pinctrl-1 = <&spi1_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart0 { + compatible = "nordic,nrf-uarte"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + sd_partition: partition@0 { + reg = <0x00000000 0x00001000>; + }; + + code_partition: partition@1000 { + reg = <0x00001000 0x000d3000>; + }; + + /* + * The flash starting at 0x000d4000 and ending at + * 0x000f3fff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@d4000 { + reg = <0x000d4000 0x00020000>; + }; + + boot_partition: partition@f4000 { + reg = <0x000f4000 0x0000c000>; + }; + }; +}; diff --git a/app/boards/arm/pillbug/pillbug.yaml b/app/boards/arm/pillbug/pillbug.yaml new file mode 100644 index 000000000000..50aa4486c871 --- /dev/null +++ b/app/boards/arm/pillbug/pillbug.yaml @@ -0,0 +1,15 @@ +identifier: pillbug +name: PillBug +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog diff --git a/app/boards/arm/pillbug/pillbug.zmk.yml b/app/boards/arm/pillbug/pillbug.zmk.yml new file mode 100644 index 000000000000..5df11b9e04dc --- /dev/null +++ b/app/boards/arm/pillbug/pillbug.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: pillbug +name: PillBug +type: board +arch: arm +outputs: + - usb + - ble +url: https://mechwild.com/product/pillbug +exposes: [blackpill] diff --git a/app/boards/arm/pillbug/pillbug_defconfig b/app/boards/arm/pillbug/pillbug_defconfig new file mode 100644 index 000000000000..9ec72c417ef3 --- /dev/null +++ b/app/boards/arm/pillbug/pillbug_defconfig @@ -0,0 +1,28 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_PILLBUG=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Use pinctrl +CONFIG_PINCTRL=y + +# enable GPIO +CONFIG_GPIO=y + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/planck/CMakeLists.txt b/app/boards/arm/planck/CMakeLists.txt new file mode 100644 index 000000000000..91bd098807e4 --- /dev/null +++ b/app/boards/arm/planck/CMakeLists.txt @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: MIT + +list(APPEND EXTRA_DTC_FLAGS "-qq") + diff --git a/app/boards/arm/planck/Kconfig.board b/app/boards/arm/planck/Kconfig.board new file mode 100644 index 000000000000..28b7381fb034 --- /dev/null +++ b/app/boards/arm/planck/Kconfig.board @@ -0,0 +1,8 @@ +# Planck V6 board configuration + +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_PLANCK_REV6 + bool "Planck V6 Keyboard" + depends on SOC_STM32F303XC diff --git a/app/boards/arm/planck/Kconfig.defconfig b/app/boards/arm/planck/Kconfig.defconfig new file mode 100644 index 000000000000..69dea84ce54b --- /dev/null +++ b/app/boards/arm/planck/Kconfig.defconfig @@ -0,0 +1,14 @@ +# Planck keyboard configuration + +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if BOARD_PLANCK_REV6 + +config ZMK_KEYBOARD_NAME + default "Planck V6" + +config ZMK_KSCAN_MATRIX_POLLING + default y + +endif # BOARD_PLANCK_REV6 diff --git a/app/boards/arm/planck/board.cmake b/app/boards/arm/planck/board.cmake new file mode 100644 index 000000000000..772796da6f0a --- /dev/null +++ b/app/boards/arm/planck/board.cmake @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT + +board_runner_args(dfu-util "--pid=0483:df11" "--alt=0" "--dfuse") +board_runner_args(jlink "--device=STM32F303VC" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/dfu-util.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/app/boards/arm/planck/planck_rev6.dts b/app/boards/arm/planck/planck_rev6.dts new file mode 100644 index 000000000000..0951d6182723 --- /dev/null +++ b/app/boards/arm/planck/planck_rev6.dts @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include +#include +#include + +/ { + model = "Plack PCD, rev6"; + compatible = "planck,rev6", "st,stm32f303"; + + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + zmk,kscan = &kscan0; + zmk,matrix_transform = &layout_grid_transform; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + row-gpios + = <&gpioa 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpioa 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpioa 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpiob 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpioc 13 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpioc 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpioc 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpioa 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + col-gpios + = <&gpiob 11 GPIO_ACTIVE_HIGH> + , <&gpiob 10 GPIO_ACTIVE_HIGH> + , <&gpiob 2 GPIO_ACTIVE_HIGH> + , <&gpiob 1 GPIO_ACTIVE_HIGH> + , <&gpioa 7 GPIO_ACTIVE_HIGH> + , <&gpiob 0 GPIO_ACTIVE_HIGH> + ; + }; + +layout_grid_transform: + keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <6>; + rows = <8>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(5,0) RC(5,1) RC(5,2) RC(5,3) RC(5,4) RC(5,5) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(6,0) RC(6,1) RC(6,2) RC(6,3) RC(6,4) RC(6,5) + RC(3,0) RC(3,1) RC(3,2) RC(7,3) RC(7,4) RC(7,5) RC(7,0) RC(7,1) RC(7,2) RC(3,3) RC(3,4) RC(3,5) + >; + }; +layout_mit_transform: + keymap_transform_1 { + compatible = "zmk,matrix-transform"; + columns = <6>; + rows = <8>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(5,0) RC(5,1) RC(5,2) RC(5,3) RC(5,4) RC(5,5) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(6,0) RC(6,1) RC(6,2) RC(6,3) RC(6,4) RC(6,5) + RC(3,0) RC(3,1) RC(3,2) RC(7,3) RC(7,4) RC(7,0) RC(7,1) RC(7,2) RC(3,3) RC(3,4) RC(3,5) + >; + }; +layout_2x2u_transform: + keymap_transform_2 { + compatible = "zmk,matrix-transform"; + columns = <6>; + rows = <8>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(5,0) RC(5,1) RC(5,2) RC(5,3) RC(5,4) RC(5,5) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(6,0) RC(6,1) RC(6,2) RC(6,3) RC(6,4) RC(6,5) + RC(3,0) RC(3,1) RC(3,2) RC(7,3) RC(7,5) RC(7,1) RC(7,2) RC(3,3) RC(3,4) RC(3,5) + >; + }; +}; + +&usb { + pinctrl-0 = <&usb_dm_pa11 &usb_dp_pa12>; + pinctrl-names = "default"; + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + +&clk_hse { + status = "okay"; + clock-frequency = ; +}; + +&pll { + prediv = <1>; + mul = <9>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <2>; + apb2-prescaler = <1>; +}; + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/guides/dts/index.html#flash-partitions + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Set 6Kb of storage at the end of the 256Kb of flash */ + storage_partition: partition@3e800 { + reg = <0x0003e800 0x00001800>; + }; + }; +}; diff --git a/app/boards/arm/planck/planck_rev6.keymap b/app/boards/arm/planck/planck_rev6.keymap new file mode 100644 index 000000000000..651380572830 --- /dev/null +++ b/app/boards/arm/planck/planck_rev6.keymap @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + // ----------------------------------------------------------------------------------------- + // | TAB | Q | W | E | R | T | Y | U | I | O | P | BSPC | + // | ESC | A | S | D | F | G | H | J | K | L | ; | ' | + // | SHIFT | Z | X | C | V | B | N | M | , | . | / | RET | + // | | LCTL | LALT | LGUI | LOWR | SPACE | RAIS | LARW | DARW | UARW | RARW | + bindings = < + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSPC + &kp ESC &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp SLASH &kp RET + &trans &kp LCTL &kp LALT &kp LGUI &mo 1 &trans &kp SPACE &mo 2 &kp LEFT &kp DOWN &kp UP &kp RIGHT + >; + }; + + lower { + bindings = < + &kp LS(GRAVE) &kp LS(N1) &kp LS(N2) &kp LS(N3) &kp LS(N4) &kp LS(N5) &kp LS(N6) &kp LS(N7) &kp LS(N8) &kp LS(N9) &kp LS(N0) &kp DEL + &kp DEL &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp UNDER &kp PLUS &kp LBRC &kp RBRC &kp PIPE + &trans &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp LS(HASH) &kp LS(BSLH) &kp HOME &kp END &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp C_NEXT &kp C_VOL_DN &kp C_VOL_UP &kp C_PP + >; + }; + + raise { + bindings = < + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp BSPC + &kp DEL &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH + &trans &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp HASH &kp BSLH &kp PG_UP &kp PG_DN &trans + &sys_reset &bootloader &trans &trans &trans &trans &trans &trans &kp C_NEXT &kp C_VOL_DN &kp C_VOL_UP &kp C_PP + >; + }; + }; +}; diff --git a/app/boards/arm/planck/planck_rev6.yaml b/app/boards/arm/planck/planck_rev6.yaml new file mode 100644 index 000000000000..9c5af3fae96a --- /dev/null +++ b/app/boards/arm/planck/planck_rev6.yaml @@ -0,0 +1,19 @@ +identifier: planck_rev6 +name: PLANKREV6 +type: keyboard +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 40 +supported: + - gpio + - i2c + - counter + - spi + - usb_device + - lsm303dlhc + - nvs + - can + - kscan diff --git a/app/boards/arm/planck/planck_rev6.zmk.yml b/app/boards/arm/planck/planck_rev6.zmk.yml new file mode 100644 index 000000000000..56c0000671f8 --- /dev/null +++ b/app/boards/arm/planck/planck_rev6.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: planck_rev6 +name: Planck Rev6 +type: board +arch: arm +features: + - keys +outputs: + - usb +url: https://olkb.com/collections/planck diff --git a/app/boards/arm/planck/planck_rev6_defconfig b/app/boards/arm/planck/planck_rev6_defconfig new file mode 100644 index 000000000000..74050f3d9c10 --- /dev/null +++ b/app/boards/arm/planck/planck_rev6_defconfig @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_STM32F3X=y +CONFIG_SOC_STM32F303XC=y +# 72MHz system clock +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=72000000 + + +# enable pinmux +CONFIG_PINMUX=y +CONFIG_PINCTRL=y + +# enable GPIO +CONFIG_GPIO=y + +# clock configuration +CONFIG_CLOCK_CONTROL=y + +CONFIG_ZMK_USB=y diff --git a/app/boards/arm/preonic/CMakeLists.txt b/app/boards/arm/preonic/CMakeLists.txt new file mode 100644 index 000000000000..91bd098807e4 --- /dev/null +++ b/app/boards/arm/preonic/CMakeLists.txt @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: MIT + +list(APPEND EXTRA_DTC_FLAGS "-qq") + diff --git a/app/boards/arm/preonic/Kconfig.board b/app/boards/arm/preonic/Kconfig.board new file mode 100644 index 000000000000..39f35db6b504 --- /dev/null +++ b/app/boards/arm/preonic/Kconfig.board @@ -0,0 +1,8 @@ +# Preonic V3 board configuration + +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_PREONIC_REV3 + bool "Preonic V3 Keyboard" + depends on SOC_STM32F303XC diff --git a/app/boards/arm/preonic/Kconfig.defconfig b/app/boards/arm/preonic/Kconfig.defconfig new file mode 100644 index 000000000000..86b2e3d0ef44 --- /dev/null +++ b/app/boards/arm/preonic/Kconfig.defconfig @@ -0,0 +1,14 @@ +# Preonic keyboard configuration + +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if BOARD_PREONIC_REV3 + +config ZMK_KEYBOARD_NAME + default "Preonic V3" + +config ZMK_KSCAN_MATRIX_POLLING + default y + +endif # BOARD_PREONIC_REV3 diff --git a/app/boards/arm/preonic/board.cmake b/app/boards/arm/preonic/board.cmake new file mode 100644 index 000000000000..772796da6f0a --- /dev/null +++ b/app/boards/arm/preonic/board.cmake @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT + +board_runner_args(dfu-util "--pid=0483:df11" "--alt=0" "--dfuse") +board_runner_args(jlink "--device=STM32F303VC" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/dfu-util.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/app/boards/arm/preonic/preonic_rev3.dts b/app/boards/arm/preonic/preonic_rev3.dts new file mode 100644 index 000000000000..249c8f3c6ed4 --- /dev/null +++ b/app/boards/arm/preonic/preonic_rev3.dts @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include +#include +#include + + +/ { + model = "Preonic PCD, rev3"; + compatible = "preonic,rev3", "st,stm32f303"; + + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zmk,kscan = &kscan0; + zmk,matrix_transform = &layout_grid_transform; + }; + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + row-gpios + = <&gpioa 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpioa 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpioa 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpiob 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpioc 13 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpioc 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpioc 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpioa 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpioa 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpioa 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + col-gpios + = <&gpiob 11 GPIO_ACTIVE_HIGH> + , <&gpiob 10 GPIO_ACTIVE_HIGH> + , <&gpiob 2 GPIO_ACTIVE_HIGH> + , <&gpiob 1 GPIO_ACTIVE_HIGH> + , <&gpioa 7 GPIO_ACTIVE_HIGH> + , <&gpiob 0 GPIO_ACTIVE_HIGH> + ; + }; + + layout_grid_transform: + keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <6>; + rows = <10>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(5,0) RC(5,1) RC(5,2) RC(5,3) RC(5,4) RC(5,5) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(6,0) RC(6,1) RC(6,2) RC(6,3) RC(6,4) RC(6,5) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(7,0) RC(7,1) RC(7,2) RC(7,3) RC(7,4) RC(7,5) + RC(8,0) RC(8,1) RC(8,2) RC(9,3) RC(9,4) RC(9,5) RC(9,0) RC(9,1) RC(9,2) RC(8,3) RC(8,4) RC(8,5) + >; + }; + + layout_mit_transform: + keymap_transform_1 { + compatible = "zmk,matrix-transform"; + columns = <6>; + rows = <10>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(5,0) RC(5,1) RC(5,2) RC(5,3) RC(5,4) RC(5,5) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(6,0) RC(6,1) RC(6,2) RC(6,3) RC(6,4) RC(6,5) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(7,0) RC(7,1) RC(7,2) RC(7,3) RC(7,4) RC(7,5) + RC(8,0) RC(8,1) RC(8,2) RC(9,3) RC(9,4) RC(9,0) RC(9,1) RC(9,2) RC(8,3) RC(8,4) RC(8,5) + >; + }; + + layout_2x2u_transform: + keymap_transform_2 { + compatible = "zmk,matrix-transform"; + columns = <6>; + rows = <10>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(5,0) RC(5,1) RC(5,2) RC(5,3) RC(5,4) RC(5,5) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(6,0) RC(6,1) RC(6,2) RC(6,3) RC(6,4) RC(6,5) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(7,0) RC(7,1) RC(7,2) RC(7,3) RC(7,4) RC(7,5) + RC(8,0) RC(8,1) RC(8,2) RC(9,3) RC(9,5) RC(9,1) RC(9,2) RC(8,3) RC(8,4) RC(8,5) + >; + }; +}; + +&usb { + pinctrl-0 = <&usb_dm_pa11 &usb_dp_pa12>; + pinctrl-names = "default"; + status = "okay"; +cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + +&clk_hse { + status = "okay"; + clock-frequency = ; +}; + +&pll { + prediv = <1>; + mul = <9>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <2>; + apb2-prescaler = <1>; +}; + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/guides/dts/index.html#flash-partitions + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Set 6Kb of storage at the end of the 256Kb of flash */ + storage_partition: partition@3e800 { + reg = <0x0003e800 0x00001800>; + }; + }; +}; diff --git a/app/boards/arm/preonic/preonic_rev3.keymap b/app/boards/arm/preonic/preonic_rev3.keymap new file mode 100644 index 000000000000..350fe6de917e --- /dev/null +++ b/app/boards/arm/preonic/preonic_rev3.keymap @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +#define DEFAULT 0 +#define LOWER 1 +#define RAISE 2 + +/ { + chosen { zmk,matrix_transform = &layout_grid_transform; }; + keymap { + compatible = "zmk,keymap"; + default_layer { + // ------------------------------------------------------------------------------------------------- + // | GRAV | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | BSPC | + // | TAB | Q | W | E | R | T | Y | U | I | O | P | DEL | + // | ESC | A | S | D | F | G | H | J | K | L | ; | ' | + // | SHIFT | Z | X | C | V | B | N | M | , | . | / | RET | + // | | LGUI | LALT | LCTL | LOWER | SPACE | SPACE | RAISE | LEFT | DOWN | UP | RIGHT | + bindings = < + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp DEL + &kp ESC &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LSHIFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp SLASH &kp RET + &none &kp LCTRL &kp LALT &kp LGUI &mo LOWER &kp SPACE &kp SPACE &mo RAISE &kp LEFT &kp DOWN &kp UP &kp RIGHT + >; + }; + lower { + // ------------------------------------------------------------------------------------------ + // | ~ | ! | @ | # | $ | % | ^ | & | * | ( | ) | BSPC | + // | ~ | ! | @ | # | $ | % | ^ | & | * | ( | ) | DEL | + // | DEL | F1 | F2 | F3 | F4 | F5 | F6 | - | + | [ | ] | | | + // | | F7 | F8 | F9 | F10 | F11 | F12 | | LCTL | HOME | END | | + // | LALT | | | | | | | | NEXT | VOL- | VOL+ | PLAY | + bindings = < + &kp LS(GRAVE) &kp LS(N1) &kp LS(N2) &kp LS(N3) &kp LS(N4) &kp LS(N5) &kp LS(N6) &kp LS(N7) &kp LS(N8) &kp LS(N9) &kp LS(N0) &kp BSPC + &kp LS(GRAVE) &kp LS(N1) &kp LS(N2) &kp LS(N3) &kp LS(N4) &kp LS(N5) &kp LS(N6) &kp LS(N7) &kp LS(N8) &kp LS(N9) &kp LS(N0) &kp DEL + &kp DEL &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp MINUS &kp PLUS &kp LEFT_BRACKET &kp RIGHT_BRACKET &kp PIPE + &none &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &none &kp LCTRL &kp HOME &kp END &none + &kp LALT &none &none &none &trans &none &none &none &kp C_NEXT &kp C_VOL_UP &kp C_VOL_UP &kp C_PLAY + >; + }; + raise { + // ------------------------------------------------------------------------------------------- + // | ` | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | BSPC | + // | ` | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | DEL | + // | DEL | F1 | F2 | F3 | F4 | F5 | F6 | - | = | [ | ] | \ | + // | | F7 | F8 | F9 | F10 | F11 | F12 | # | \ | PGUP | PGDN | | + // | | | | | | SHIFT | | | NEXT | VOL- | VOL+ | PLAY | + bindings = < + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp BSPC + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp DEL + &kp DEL &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp MINUS &kp KP_EQUAL &kp LEFT_BRACKET &kp RIGHT_BRACKET &kp BSLH + &none &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp HASH &kp BSLH &kp PG_UP &kp PG_DN &none + &none &none &none &none &none &kp LSHIFT &none &trans &kp C_NEXT &kp C_VOL_DN &kp C_VOL_UP &kp C_PLAY + >; + }; + }; +}; diff --git a/app/boards/arm/preonic/preonic_rev3.yaml b/app/boards/arm/preonic/preonic_rev3.yaml new file mode 100644 index 000000000000..861f1d2da9d7 --- /dev/null +++ b/app/boards/arm/preonic/preonic_rev3.yaml @@ -0,0 +1,19 @@ +identifier: preonic_rev3 +name: PREONICREV3 +type: keyboard +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 40 +supported: + - gpio + - i2c + - counter + - spi + - usb_device + - lsm303dlhc + - nvs + - can + - kscan diff --git a/app/boards/arm/preonic/preonic_rev3.zmk.yml b/app/boards/arm/preonic/preonic_rev3.zmk.yml new file mode 100644 index 000000000000..bd9d95794da5 --- /dev/null +++ b/app/boards/arm/preonic/preonic_rev3.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: preonic_rev3 +name: Preonic Rev3 +type: board +arch: arm +features: + - keys +outputs: + - usb +url: https://olkb.com/collections/preonic diff --git a/app/boards/arm/preonic/preonic_rev3_defconfig b/app/boards/arm/preonic/preonic_rev3_defconfig new file mode 100644 index 000000000000..e063827a4e2d --- /dev/null +++ b/app/boards/arm/preonic/preonic_rev3_defconfig @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_STM32F3X=y +CONFIG_SOC_STM32F303XC=y +# 72MHz system clock +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=72000000 + +# enable pinctrl +CONFIG_PINCTRL=y + +# enable GPIO +CONFIG_GPIO=y + +# clock configuration +CONFIG_CLOCK_CONTROL=y + +CONFIG_ZMK_USB=y \ No newline at end of file diff --git a/app/boards/arm/proton_c/Kconfig.board b/app/boards/arm/proton_c/Kconfig.board new file mode 100644 index 000000000000..1596077fc1dd --- /dev/null +++ b/app/boards/arm/proton_c/Kconfig.board @@ -0,0 +1,8 @@ +# QMK Proton-C board configuration + +# Copyright (c) 2020 Pete Johanson +# SPDX-License-Identifier: MIT + +config BOARD_QMK_PROTON_C + bool "QMK Proton-C" + depends on SOC_STM32F303XC diff --git a/app/boards/arm/proton_c/Kconfig.defconfig b/app/boards/arm/proton_c/Kconfig.defconfig new file mode 100644 index 000000000000..eed4b830442d --- /dev/null +++ b/app/boards/arm/proton_c/Kconfig.defconfig @@ -0,0 +1,11 @@ +# QMK Proton-C board configuration + +# Copyright (c) 2020 Pete Johanson +# SPDX-License-Identifier: MIT + +if BOARD_QMK_PROTON_C + +config BOARD + default "proton_c" + +endif # BOARD_QMK_PROTON_C diff --git a/app/boards/arm/proton_c/arduino_pro_micro_pins.dtsi b/app/boards/arm/proton_c/arduino_pro_micro_pins.dtsi new file mode 100644 index 000000000000..1831194289c7 --- /dev/null +++ b/app/boards/arm/proton_c/arduino_pro_micro_pins.dtsi @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ + +/ { + pro_micro: connector { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &gpioa 10 0> /* D0 */ + , <1 0 &gpioa 9 0> /* D1 */ + , <2 0 &gpiob 7 0> /* D2 */ + , <3 0 &gpiob 6 0> /* D3 */ + , <4 0 &gpiob 5 0> /* D4/A6 */ + , <5 0 &gpiob 4 0> /* D5 */ + , <6 0 &gpiob 3 0> /* D6/A7 */ + , <7 0 &gpiob 2 0> /* D7 */ + , <8 0 &gpiob 1 0> /* D8/A8 */ + , <9 0 &gpiob 0 0> /* D9/A9 */ + , <10 0 &gpiob 9 0> /* D10/A10 */ + , <16 0 &gpiob 15 0> /* D16 */ + , <14 0 &gpiob 14 0> /* D14 */ + , <15 0 &gpiob 13 0> /* D15 */ + , <18 0 &gpiob 8 0> /* D18/A0 */ + , <19 0 &gpioa 0 0> /* D19/A1 */ + , <20 0 &gpioa 1 0> /* D20/A2 */ + , <21 0 &gpioa 2 0> /* D21/A3 */ + ; + }; + + pro_micro_a: connector_a { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &gpiob 8 0> /* D18/A0 */ + , <1 0 &gpioa 0 0> /* D19/A1 */ + , <2 0 &gpioa 1 0> /* D20/A2 */ + , <3 0 &gpioa 2 0> /* D21/A3 */ + , <6 0 &gpiob 5 0> /* D4/A6 */ + , <7 0 &gpiob 3 0> /* D6/A7 */ + , <8 0 &gpiob 1 0> /* D8/A8 */ + , <9 0 &gpiob 0 0> /* D9/A9 */ + , <10 0 &gpiob 9 0> /* D10/A10 */ + ; + }; +}; + +pro_micro_d: &pro_micro {}; +pro_micro_i2c: &i2c1 {}; +pro_micro_spi: &spi2 {}; +pro_micro_serial: &usart1 {}; diff --git a/app/boards/arm/proton_c/board.cmake b/app/boards/arm/proton_c/board.cmake new file mode 100644 index 000000000000..9da8ea911229 --- /dev/null +++ b/app/boards/arm/proton_c/board.cmake @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT + +board_runner_args(dfu-util "--pid=0483:df11" "--alt=0" "--dfuse") +board_runner_args(jlink "--device=STM32F303CC" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/dfu-util.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/app/boards/arm/proton_c/proton_c.dts b/app/boards/arm/proton_c/proton_c.dts new file mode 100644 index 000000000000..3aad62c8f30b --- /dev/null +++ b/app/boards/arm/proton_c/proton_c.dts @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include +#include +#include "arduino_pro_micro_pins.dtsi" + +/ { + model = "QMK Proton C"; + compatible = "qmk,proton_c", "st,stm32f303"; + + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart0; + }; + + aliases { + led0 = &led; + }; + + leds { + compatible = "gpio-leds"; + led: led_0 { + gpios = <&gpioc 13 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&usart1 { + pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>; + pinctrl-names = "default"; +}; + +&spi2 { + pinctrl-0 = <&spi2_sck_pb13 &spi2_miso_pb14 &spi2_mosi_pb15>; + pinctrl-names = "default"; +}; + +&i2c1 { + pinctrl-0 = <&i2c1_scl_pb6 &i2c1_sda_pb7>; + pinctrl-names = "default"; +}; + +&clk_hse { + status = "okay"; + clock-frequency = ; +}; + +&pll { + prediv = <1>; + mul = <9>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <2>; + apb2-prescaler = <1>; +}; + +&usb { + pinctrl-0 = <&usb_dm_pa11 &usb_dp_pa12>; + pinctrl-names = "default"; + status = "okay"; + cdc_acm_uart0: cdc_acm_uart0 { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + +&rtc { + status = "okay"; +}; + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/guides/dts/index.html#flash-partitions + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Set 6Kb of storage at the end of the 256Kb of flash */ + storage_partition: partition@3e800 { + reg = <0x0003e800 0x00001800>; + }; + }; +}; diff --git a/app/boards/arm/proton_c/proton_c.yaml b/app/boards/arm/proton_c/proton_c.yaml new file mode 100644 index 000000000000..86b14b9aeb57 --- /dev/null +++ b/app/boards/arm/proton_c/proton_c.yaml @@ -0,0 +1,18 @@ +identifier: proton_c +name: QMK Proton-C +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 40 +supported: + - gpio + - i2c + - counter + - spi + - usb_device + - lsm303dlhc + - nvs + - can diff --git a/app/boards/arm/proton_c/proton_c.zmk.yml b/app/boards/arm/proton_c/proton_c.zmk.yml new file mode 100644 index 000000000000..682783ce606a --- /dev/null +++ b/app/boards/arm/proton_c/proton_c.zmk.yml @@ -0,0 +1,9 @@ +file_format: "1" +id: proton_c +name: QMK Proton-C +type: board +arch: arm +outputs: + - usb +url: https://qmk.fm/proton-c/ +exposes: [pro_micro] diff --git a/app/boards/arm/proton_c/proton_c_defconfig b/app/boards/arm/proton_c/proton_c_defconfig new file mode 100644 index 000000000000..c552bf15df9f --- /dev/null +++ b/app/boards/arm/proton_c/proton_c_defconfig @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_STM32F3X=y +CONFIG_SOC_STM32F303XC=y +# 72MHz system clock +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=72000000 + +# Floating Point Options +CONFIG_FPU=y + +# enable pinctrl +CONFIG_PINCTRL=y + +# enable GPIO +CONFIG_GPIO=y + +# clock configuration +CONFIG_CLOCK_CONTROL=y + +CONFIG_ZMK_USB=y \ No newline at end of file diff --git a/app/boards/arm/puchi_ble/CMakeLists.txt b/app/boards/arm/puchi_ble/CMakeLists.txt new file mode 100644 index 000000000000..12cf9b1cf1a1 --- /dev/null +++ b/app/boards/arm/puchi_ble/CMakeLists.txt @@ -0,0 +1,6 @@ + +if(CONFIG_PINMUX) +zephyr_library() +zephyr_library_sources(pinmux.c) +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) +endif() \ No newline at end of file diff --git a/app/boards/arm/puchi_ble/Kconfig b/app/boards/arm/puchi_ble/Kconfig new file mode 100644 index 000000000000..719c3845721c --- /dev/null +++ b/app/boards/arm/puchi_ble/Kconfig @@ -0,0 +1,3 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + diff --git a/app/boards/arm/puchi_ble/Kconfig.board b/app/boards/arm/puchi_ble/Kconfig.board new file mode 100644 index 000000000000..0f5b7f96d848 --- /dev/null +++ b/app/boards/arm/puchi_ble/Kconfig.board @@ -0,0 +1,8 @@ +# Puchi-BLE board configuration + +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_PUCHI_BLE_v1 + bool "puchi_ble_v1" + depends on SOC_NRF52840_QIAA diff --git a/app/boards/arm/puchi_ble/Kconfig.defconfig b/app/boards/arm/puchi_ble/Kconfig.defconfig new file mode 100644 index 000000000000..3533104b2a52 --- /dev/null +++ b/app/boards/arm/puchi_ble/Kconfig.defconfig @@ -0,0 +1,22 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if BOARD_PUCHI_BLE_v1 + +config BOARD + default "puchi_ble" + +if USB_DEVICE_STACK + +config USB_NRFX + default y + +endif # USB_DEVICE_STACK + +config BT_CTLR + default BT + +config PINMUX + default y + +endif # BOARD_PUCHI_BLE_v1 diff --git a/app/boards/arm/puchi_ble/arduino_pro_micro_pins.dtsi b/app/boards/arm/puchi_ble/arduino_pro_micro_pins.dtsi new file mode 100644 index 000000000000..3037ea3e14b1 --- /dev/null +++ b/app/boards/arm/puchi_ble/arduino_pro_micro_pins.dtsi @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + +/ { + pro_micro: connector { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &gpio0 8 0> /* D0 */ + , <1 0 &gpio0 6 0> /* D1 */ + , <2 0 &gpio0 15 0> /* D2 */ + , <3 0 &gpio0 17 0> /* D3 */ + , <4 0 &gpio0 20 0> /* D4/A6 */ + , <5 0 &gpio0 13 0> /* D5 */ + , <6 0 &gpio0 24 0> /* D6/A7 */ + , <7 0 &gpio0 9 0> /* D7 */ + , <8 0 &gpio0 10 0> /* D8/A8 */ + , <9 0 &gpio1 6 0> /* D9/A9 */ + , <10 0 &gpio1 11 0> /* D10/A10 */ + , <16 0 &gpio0 28 0> /* D16 */ + , <14 0 &gpio0 3 0> /* D14 */ + , <15 0 &gpio1 13 0> /* D15 */ + , <18 0 &gpio0 2 0> /* D18/A0 */ + , <19 0 &gpio0 29 0> /* D19/A1 */ + , <20 0 &gpio0 31 0> /* D20/A2 */ + , <21 0 &gpio0 30 0> /* D21/A3 */ + ; + }; + + pro_micro_a: connector_a { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &gpio0 2 0> /* D18/A0 */ + , <1 0 &gpio0 29 0> /* D19/A1 */ + , <2 0 &gpio0 31 0> /* D20/A2 */ + , <3 0 &gpio0 30 0> /* D21/A3 */ + , <6 0 &gpio0 20 0> /* D4/A6 */ + , <7 0 &gpio0 24 0> /* D6/A7 */ + , <8 0 &gpio0 10 0> /* D8/A8 */ + , <9 0 &gpio1 6 0> /* D9/A9 */ + , <10 0 &gpio1 11 0> /* D10/A10 */ + ; + }; +}; + + +pro_micro_d: &pro_micro {}; +pro_micro_i2c: &i2c0 {}; +pro_micro_spi: &spi0 {}; +pro_micro_serial: &uart0 {}; diff --git a/app/boards/arm/puchi_ble/board.cmake b/app/boards/arm/puchi_ble/board.cmake new file mode 100644 index 000000000000..3b5c4aeafa15 --- /dev/null +++ b/app/boards/arm/puchi_ble/board.cmake @@ -0,0 +1,6 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") +include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) diff --git a/app/boards/arm/puchi_ble/pinmux.c b/app/boards/arm/puchi_ble/pinmux.c new file mode 100644 index 000000000000..2817827493b6 --- /dev/null +++ b/app/boards/arm/puchi_ble/pinmux.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include +#include + +static int pinmux_puchi_ble_init(const struct device *port) { + ARG_UNUSED(port); + +#if CONFIG_BOARD_PUCHI_BLE_v1 + const struct device *p0 = DEVICE_DT_GET(DT_NODELABEL(gpio0)); +#if CONFIG_BOARD_PUCHI_BLE_CHARGER + gpio_pin_configure(p0, 5, GPIO_OUTPUT); + gpio_pin_set(p0, 5, 0); +#else + gpio_pin_configure(p0, 5, GPIO_INPUT); +#endif +#endif + return 0; +} + +SYS_INIT(pinmux_puchi_ble_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/app/boards/arm/puchi_ble/puchi_ble_v1-pinctrl.dtsi b/app/boards/arm/puchi_ble/puchi_ble_v1-pinctrl.dtsi new file mode 100644 index 000000000000..35a46e5ae52c --- /dev/null +++ b/app/boards/arm/puchi_ble/puchi_ble_v1-pinctrl.dtsi @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + uart0_default: uart0_default { + group1 { + psels = ; + bias-pull-up; + }; + group2 { + psels = ; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + i2c0_default: i2c0_default { + group1 { + psels = , + ; + }; + }; + + i2c0_sleep: i2c0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; diff --git a/app/boards/arm/puchi_ble/puchi_ble_v1.dts b/app/boards/arm/puchi_ble/puchi_ble_v1.dts new file mode 100644 index 000000000000..05aba8d37804 --- /dev/null +++ b/app/boards/arm/puchi_ble/puchi_ble_v1.dts @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include +#include "arduino_pro_micro_pins.dtsi" +#include "puchi_ble_v1-pinctrl.dtsi" + +/ { + model = "puchi_ble"; + compatible = "puchi_ble"; + + chosen { + zephyr,code-partition = &code_partition; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + zmk,battery = &vbatt; + }; + + leds { + compatible = "gpio-leds"; + blue_led: led_0 { + gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + }; + }; + + // Node name must match original "EXT_POWER" label to preserve user settings. + EXT_POWER { + compatible = "zmk,ext-power-generic"; + control-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; + }; + + vbatt: vbatt { + compatible = "zmk,battery-voltage-divider"; + io-channels = <&adc 2>; + output-ohms = <2000000>; + full-ohms = <(2000000 + 820000)>; + }; +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&i2c0 { + compatible = "nordic,nrf-twi"; + pinctrl-0 = <&i2c0_default>; + pinctrl-1 = <&i2c0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart0 { + compatible = "nordic,nrf-uarte"; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + sd_partition: partition@0 { + reg = <0x00000000 0x00026000>; + }; + code_partition: partition@26000 { + reg = <0x00026000 0x000c6000>; + }; + + /* + * The flash starting at 0x000ec000 and ending at + * 0x000f3fff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@ec000 { + reg = <0x000ec000 0x00008000>; + }; + + boot_partition: partition@f4000 { + reg = <0x000f4000 0x0000c000>; + }; + }; +}; diff --git a/app/boards/arm/puchi_ble/puchi_ble_v1.yaml b/app/boards/arm/puchi_ble/puchi_ble_v1.yaml new file mode 100644 index 000000000000..18770722242a --- /dev/null +++ b/app/boards/arm/puchi_ble/puchi_ble_v1.yaml @@ -0,0 +1,15 @@ +identifier: puchi_ble_v1 +name: puchi_ble_v1 +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog diff --git a/app/boards/arm/puchi_ble/puchi_ble_v1.zmk.yml b/app/boards/arm/puchi_ble/puchi_ble_v1.zmk.yml new file mode 100644 index 000000000000..f31140080433 --- /dev/null +++ b/app/boards/arm/puchi_ble/puchi_ble_v1.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: puchi_ble_v1 +name: Puchi-BLE V1 +type: board +arch: arm +outputs: + - usb + - ble +url: https://keycapsss.com/keyboard-parts/mcu-controller/202/puchi-ble-wireless-microcontroller +exposes: [pro_micro] diff --git a/app/boards/arm/puchi_ble/puchi_ble_v1_defconfig b/app/boards/arm/puchi_ble/puchi_ble_v1_defconfig new file mode 100644 index 000000000000..ab197df0a808 --- /dev/null +++ b/app/boards/arm/puchi_ble/puchi_ble_v1_defconfig @@ -0,0 +1,30 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_PUCHI_BLE_v1=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# enable GPIO +CONFIG_GPIO=y + +# Use pinctrl +CONFIG_PINCTRL=y + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y +CONFIG_CLOCK_CONTROL_NRF=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/s40nc/Kconfig.board b/app/boards/arm/s40nc/Kconfig.board new file mode 100644 index 000000000000..e703d7269af4 --- /dev/null +++ b/app/boards/arm/s40nc/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_S40NC + bool "S40NC" + depends on SOC_NRF52840_QIAA diff --git a/app/boards/arm/s40nc/Kconfig.defconfig b/app/boards/arm/s40nc/Kconfig.defconfig new file mode 100644 index 000000000000..f892f392d5c6 --- /dev/null +++ b/app/boards/arm/s40nc/Kconfig.defconfig @@ -0,0 +1,22 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if BOARD_S40NC + +config ZMK_KEYBOARD_NAME + default "S40NC" + +if USB + +config USB_NRFX + default y + +config USB_DEVICE_STACK + default y + +endif # USB + +config BT_CTLR + default BT + +endif # BOARD_S40NC diff --git a/app/boards/arm/s40nc/README.md b/app/boards/arm/s40nc/README.md new file mode 100644 index 000000000000..96bebb336973 --- /dev/null +++ b/app/boards/arm/s40nc/README.md @@ -0,0 +1,11 @@ +# S40NC + +![S40NC](https://i.imgur.com/fk8587n.jpg) + +Shorty40NoCordy (S40NC) is a limited run 40% bluetooth keyboard originally made and sold by MechWild. + +## Building S40NC ZMK firmware + +``` +west build -p -b s40nc +``` diff --git a/app/boards/arm/s40nc/board.cmake b/app/boards/arm/s40nc/board.cmake new file mode 100644 index 000000000000..c50b2d9d8add --- /dev/null +++ b/app/boards/arm/s40nc/board.cmake @@ -0,0 +1,7 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +set(OPENOCD_NRF5_SUBFAMILY nrf52) +board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd-nrf5.board.cmake) diff --git a/app/boards/arm/s40nc/s40nc.dts b/app/boards/arm/s40nc/s40nc.dts new file mode 100644 index 000000000000..aff094608532 --- /dev/null +++ b/app/boards/arm/s40nc/s40nc.dts @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include +#include + +/ { + model = "S40NC"; + compatible = "s40nc"; + + chosen { + zephyr,code-partition = &code_partition; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + zmk,battery = &vbatt; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <12>; + rows = <4>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,11) + RC(2,0) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) + RC(3,0) RC(3,1) RC(3,2) RC(3,4) RC(3,6) RC(3,8) RC(3,9) RC(3,10) RC(3,11) + >; + }; + + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&gpio1 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + col-gpios + = <&gpio1 2 GPIO_ACTIVE_HIGH> + , <&gpio1 1 GPIO_ACTIVE_HIGH> + , <&gpio1 3 GPIO_ACTIVE_HIGH> + , <&gpio1 0 GPIO_ACTIVE_HIGH> + , <&gpio0 22 GPIO_ACTIVE_HIGH> + , <&gpio1 15 GPIO_ACTIVE_HIGH> + , <&gpio0 3 GPIO_ACTIVE_HIGH> + , <&gpio0 2 GPIO_ACTIVE_HIGH> + , <&gpio0 28 GPIO_ACTIVE_HIGH> + , <&gpio0 29 GPIO_ACTIVE_HIGH> + , <&gpio0 30 GPIO_ACTIVE_HIGH> + , <&gpio0 31 GPIO_ACTIVE_HIGH> + ; + }; + + leds { + compatible = "gpio-leds"; + blue_led: led_0 { + gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>; + }; + }; + + vbatt: vbatt { + compatible = "zmk,battery-voltage-divider"; + io-channels = <&adc 2>; + output-ohms = <2000000>; + full-ohms = <(2000000 + 820000)>; + }; +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + sd_partition: partition@0 { + reg = <0x00000000 0x00001000>; + }; + + code_partition: partition@1000 { + reg = <0x00001000 0x000d3000>; + }; + + /* + * The flash starting at 0x000d4000 and ending at + * 0x000f3fff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@d4000 { + reg = <0x000d4000 0x00020000>; + }; + + boot_partition: partition@f4000 { + reg = <0x000f4000 0x0000c000>; + }; + }; +}; diff --git a/app/boards/arm/s40nc/s40nc.keymap b/app/boards/arm/s40nc/s40nc.keymap new file mode 100644 index 000000000000..dfc352d79d36 --- /dev/null +++ b/app/boards/arm/s40nc/s40nc.keymap @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +#define DEFAULT 0 +#define LOWER 1 +#define RAISE 2 +#define CONTROL 3 + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSPC + &mo LOWER &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp ENTER + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp FSLH &kp UP &kp RSHFT + &kp LCTRL &kp LGUI &kp LALT < LOWER SPACE < CONTROL SPACE < RAISE SPACE &kp LEFT &kp DOWN &kp RIGHT + >; + }; + + lower_layer { + bindings = < + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp DEL + &kp PSCRN &kp MINUS &kp EQUAL &trans &trans &trans &trans &kp LBKT &kp RBKT &kp SEMI &kp APOS + &trans &trans &trans &trans &trans &trans &trans &kp COMMA &kp DOT &kp PG_UP &kp BSLH + &trans &trans &trans &kp TAB &kp TAB &kp TAB &kp HOME &kp PG_DN &kp END + >; + }; + + raise_layer { + bindings = < + &kp TILDE &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp STAR &kp LPAR &kp RPAR &trans + &kp PSCRN &kp UNDER &kp PLUS &trans &trans &trans &trans &kp LBRC &kp RBRC &kp COLON &kp DQT + &trans &trans &trans &trans &trans &trans &trans &kp LT &kp GT &kp PG_UP &kp PIPE + &trans &trans &trans &kp TAB &kp TAB &kp TAB &kp HOME &kp PG_DN &kp END + >; + }; + + control_layer { + bindings = < + &bt BT_CLR &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp C_PP + &bt BT_SEL 0 &kp F11 &kp F12 &trans &trans &trans &trans &trans &trans &trans &kp K_LOCK + &bt BT_SEL 1 &out OUT_USB &kp CAPS &kp KP_NUM &kp SLCK &trans &trans &kp COMMA &kp DOT &kp K_VOL_UP &kp K_MUTE + &bt BT_SEL 2 &out OUT_BLE &kp PAUSE_BREAK &sys_reset &trans &bootloader &kp C_BRI_DN &kp K_VOL_DN &kp C_BRI_UP + >; + }; + }; +}; + diff --git a/app/boards/arm/s40nc/s40nc.yaml b/app/boards/arm/s40nc/s40nc.yaml new file mode 100644 index 000000000000..1fb23ee33f73 --- /dev/null +++ b/app/boards/arm/s40nc/s40nc.yaml @@ -0,0 +1,14 @@ +identifier: s40nc +name: S40NC +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog diff --git a/app/boards/arm/s40nc/s40nc.zmk.yml b/app/boards/arm/s40nc/s40nc.zmk.yml new file mode 100644 index 000000000000..57b30ecae69d --- /dev/null +++ b/app/boards/arm/s40nc/s40nc.zmk.yml @@ -0,0 +1,11 @@ +file_format: "1" +id: s40nc +name: S40NC +type: board +arch: arm +features: + - keys +outputs: + - usb + - ble +url: https://mechwild.com diff --git a/app/boards/arm/s40nc/s40nc_defconfig b/app/boards/arm/s40nc/s40nc_defconfig new file mode 100644 index 000000000000..b523ceb80b7a --- /dev/null +++ b/app/boards/arm/s40nc/s40nc_defconfig @@ -0,0 +1,25 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_S40NC=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# enable GPIO +CONFIG_GPIO=y + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/seeeduino_xiao/seeeduino_xiao.zmk.yml b/app/boards/arm/seeeduino_xiao/seeeduino_xiao.zmk.yml new file mode 100644 index 000000000000..1225fb317bc2 --- /dev/null +++ b/app/boards/arm/seeeduino_xiao/seeeduino_xiao.zmk.yml @@ -0,0 +1,9 @@ +file_format: "1" +id: seeeduino_xiao +name: Seeeduino XIAO +type: board +arch: arm +outputs: + - usb +url: https://wiki.seeedstudio.com/Seeeduino-XIAO/ +exposes: [seeed_xiao] diff --git a/app/boards/arm/seeeduino_xiao_ble/seeeduino_xiao_ble.zmk.yml b/app/boards/arm/seeeduino_xiao_ble/seeeduino_xiao_ble.zmk.yml new file mode 100644 index 000000000000..360bd04b3140 --- /dev/null +++ b/app/boards/arm/seeeduino_xiao_ble/seeeduino_xiao_ble.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: seeeduino_xiao_ble +name: Seeeduino XIAO BLE +type: board +arch: arm +outputs: + - usb + - ble +url: https://wiki.seeedstudio.com/XIAO_BLE/ +exposes: [seeed_xiao] diff --git a/app/boards/arm/seeeduino_xiao_rp2040/seeeduino_xiao_rp2040.zmk.yml b/app/boards/arm/seeeduino_xiao_rp2040/seeeduino_xiao_rp2040.zmk.yml new file mode 100644 index 000000000000..77d8d664dad1 --- /dev/null +++ b/app/boards/arm/seeeduino_xiao_rp2040/seeeduino_xiao_rp2040.zmk.yml @@ -0,0 +1,9 @@ +file_format: "1" +id: seeeduino_xiao_rp2040 +name: Seeeduino XIAO RP2040 +type: board +arch: arm +outputs: + - usb +url: https://wiki.seeedstudio.com/XIAO-RP2040/ +exposes: [seeed_xiao] diff --git a/app/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.zmk.yml b/app/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.zmk.yml new file mode 100644 index 000000000000..26a2ca640255 --- /dev/null +++ b/app/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.zmk.yml @@ -0,0 +1,9 @@ +file_format: "1" +id: sparkfun_pro_micro_rp2040 +name: SparkFun Pro Micro RP2040 +type: board +arch: arm +outputs: + - usb +url: https://www.sparkfun.com/products/18288 +exposes: [pro_micro] diff --git a/app/boards/blackpill_f401ce.conf b/app/boards/blackpill_f401ce.conf new file mode 100644 index 000000000000..07e304cfa5c3 --- /dev/null +++ b/app/boards/blackpill_f401ce.conf @@ -0,0 +1,7 @@ +CONFIG_CONSOLE=n +CONFIG_SERIAL=n +CONFIG_UART_CONSOLE=n +CONFIG_UART_INTERRUPT_DRIVEN=n +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=n +CONFIG_ZMK_KSCAN_MATRIX_POLLING=y diff --git a/app/boards/blackpill_f401ce.overlay b/app/boards/blackpill_f401ce.overlay new file mode 100644 index 000000000000..54e360a393ed --- /dev/null +++ b/app/boards/blackpill_f401ce.overlay @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + +/ { + blackpill: connector { + compatible = "blackpill"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <2 0 &gpioc 13 0> /* PC13 */ + , <3 0 &gpioc 14 0> /* PC14 */ + , <4 0 &gpioc 15 0> /* PC15 */ + , <10 0 &gpioa 0 0> /* PA0 */ + , <11 0 &gpioa 1 0> /* PA1 */ + , <12 0 &gpioa 2 0> /* PA2 */ + , <13 0 &gpioa 3 0> /* PA3 */ + , <14 0 &gpioa 4 0> /* PA4 */ + , <15 0 &gpioa 5 0> /* PA5 */ + , <16 0 &gpioa 6 0> /* PA6 */ + , <17 0 &gpioa 7 0> /* PA7 */ + , <18 0 &gpiob 0 0> /* PB0 */ + , <19 0 &gpiob 1 0> /* PB1 */ + , <20 0 &gpiob 2 0> /* PB2 */ + , <21 0 &gpiob 10 0> /* PB10 */ + , <25 0 &gpiob 12 0> /* PB12 */ + , <26 0 &gpiob 13 0> /* PB13 */ + , <27 0 &gpiob 14 0> /* PB14 */ + , <28 0 &gpiob 15 0> /* PB15 */ + , <29 0 &gpioa 8 0> /* PA8 */ + , <30 0 &gpioa 9 0> /* PA9 */ + , <31 0 &gpioa 10 0> /* PA10 */ + , <38 0 &gpioa 15 0> /* PA15 */ + , <39 0 &gpiob 3 0> /* PB3 */ + , <40 0 &gpiob 4 0> /* PB4 */ + , <41 0 &gpiob 5 0> /* PB5 */ + , <42 0 &gpiob 6 0> /* PB6 */ + , <43 0 &gpiob 7 0> /* PB7 */ + , <45 0 &gpiob 8 0> /* PB8 */ + , <46 0 &gpiob 9 0> /* PB9 */ + ; + }; +}; + +blackpill_i2c: &i2c1 {}; +blackpill_spi: &spi1 {}; +blackpill_serial: &usart1 {}; diff --git a/app/boards/blackpill_f411ce.conf b/app/boards/blackpill_f411ce.conf new file mode 100644 index 000000000000..07e304cfa5c3 --- /dev/null +++ b/app/boards/blackpill_f411ce.conf @@ -0,0 +1,7 @@ +CONFIG_CONSOLE=n +CONFIG_SERIAL=n +CONFIG_UART_CONSOLE=n +CONFIG_UART_INTERRUPT_DRIVEN=n +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=n +CONFIG_ZMK_KSCAN_MATRIX_POLLING=y diff --git a/app/boards/blackpill_f411ce.overlay b/app/boards/blackpill_f411ce.overlay new file mode 100644 index 000000000000..54e360a393ed --- /dev/null +++ b/app/boards/blackpill_f411ce.overlay @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + +/ { + blackpill: connector { + compatible = "blackpill"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <2 0 &gpioc 13 0> /* PC13 */ + , <3 0 &gpioc 14 0> /* PC14 */ + , <4 0 &gpioc 15 0> /* PC15 */ + , <10 0 &gpioa 0 0> /* PA0 */ + , <11 0 &gpioa 1 0> /* PA1 */ + , <12 0 &gpioa 2 0> /* PA2 */ + , <13 0 &gpioa 3 0> /* PA3 */ + , <14 0 &gpioa 4 0> /* PA4 */ + , <15 0 &gpioa 5 0> /* PA5 */ + , <16 0 &gpioa 6 0> /* PA6 */ + , <17 0 &gpioa 7 0> /* PA7 */ + , <18 0 &gpiob 0 0> /* PB0 */ + , <19 0 &gpiob 1 0> /* PB1 */ + , <20 0 &gpiob 2 0> /* PB2 */ + , <21 0 &gpiob 10 0> /* PB10 */ + , <25 0 &gpiob 12 0> /* PB12 */ + , <26 0 &gpiob 13 0> /* PB13 */ + , <27 0 &gpiob 14 0> /* PB14 */ + , <28 0 &gpiob 15 0> /* PB15 */ + , <29 0 &gpioa 8 0> /* PA8 */ + , <30 0 &gpioa 9 0> /* PA9 */ + , <31 0 &gpioa 10 0> /* PA10 */ + , <38 0 &gpioa 15 0> /* PA15 */ + , <39 0 &gpiob 3 0> /* PB3 */ + , <40 0 &gpiob 4 0> /* PB4 */ + , <41 0 &gpiob 5 0> /* PB5 */ + , <42 0 &gpiob 6 0> /* PB6 */ + , <43 0 &gpiob 7 0> /* PB7 */ + , <45 0 &gpiob 8 0> /* PB8 */ + , <46 0 &gpiob 9 0> /* PB9 */ + ; + }; +}; + +blackpill_i2c: &i2c1 {}; +blackpill_spi: &spi1 {}; +blackpill_serial: &usart1 {}; diff --git a/app/boards/boardsource_blok.conf b/app/boards/boardsource_blok.conf new file mode 100644 index 000000000000..21c1893d91f4 --- /dev/null +++ b/app/boards/boardsource_blok.conf @@ -0,0 +1,4 @@ +CONFIG_CONSOLE=n +CONFIG_SERIAL=n +CONFIG_UART_CONSOLE=n +CONFIG_ZMK_USB=y diff --git a/app/boards/boardsource_blok.overlay b/app/boards/boardsource_blok.overlay new file mode 100644 index 000000000000..b14e0d04d478 --- /dev/null +++ b/app/boards/boardsource_blok.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "usb_console.dtsi" + +&pro_micro_serial { status = "disabled"; }; diff --git a/app/boards/interconnects/arduino_uno/arduino_uno.zmk.yml b/app/boards/interconnects/arduino_uno/arduino_uno.zmk.yml new file mode 100644 index 000000000000..d6eb89a3df29 --- /dev/null +++ b/app/boards/interconnects/arduino_uno/arduino_uno.zmk.yml @@ -0,0 +1,25 @@ +file_format: "1" +id: arduino_uno +name: Arduino Uno Rev3 +type: interconnect +url: https://store-usa.arduino.cc/products/arduino-uno-rev3?selectedStore=us +manufacturer: Arduino +description: | + The Arduino Uno Rev3 is a board who's popularity lead to countless shields being developed for it. By + natural extension, once there were many shields designed for it, many other *boards* began to be developed + that were compatible to leverage the extensive available shields. Today, many dev kits come with Uno + headers to make it easy to work with them. + + Note: ZMK doesn't support boards with AVR 8-bit processors, such as the ATmega32U4, because Zephyr™ only + supports 32-bit and 64-bit platforms. As a result, boards like the original Arduino Uno Rev3 itself are + *not* supported by ZMK. +node_labels: + gpio: arduino_header + i2c: arduino_i2c + spi: arduino_spi + uart: arduino_serial + adc: arduino_adc +design_guideline: | + The GPIO pin references for the Uno format are a bit odd. The `&arduino_header` label is used, but the numbering + starts at the `A0` pin and increments as you go counter clockwise around the board. That means the `D6` pin + can be referenced by `&arduino_header 12` in your overlay files. diff --git a/app/boards/interconnects/blackpill/blackpill.zmk.yml b/app/boards/interconnects/blackpill/blackpill.zmk.yml new file mode 100644 index 000000000000..0d91e96c7305 --- /dev/null +++ b/app/boards/interconnects/blackpill/blackpill.zmk.yml @@ -0,0 +1,15 @@ +file_format: "1" +id: blackpill +name: BlackPill +type: interconnect +url: https://github.com/WeActStudio/WeActStudio.MiniSTM32F4x1 +manufacturer: WeAct Studio +description: | + The WeAct Studio BlackPill has grown in popularity due to its low price, availability, and utilization of the powerful STM32F4x1CEU6 microcontroller. The BlackPill features more GPIO than most other boards, but also has a comparatively larger footprint as a result. Many clones and variations of the original BlackPill are available on the market as an affordable and more powerful alternative to many popular boards. The official WeAct variations of the WeAct Studio BlackPill are powered by the STM32F411CEU6 and STM32F401CEU6 microcontrollers. +node_labels: + gpio: blackpill + i2c: blackpill_i2c + spi: blackpill_spi + uart: blackpill_serial +design_guideline: | + ZMK uses the blue color coded pin names to generate devicetree node references. For example, to refer to the pin labeled `17` in the diagram, use `&blackpill 17` in the devicetree files. diff --git a/app/boards/interconnects/makerdiary_nrf52840_m2/makerdiary_nrf52840_m2.zmk.yml b/app/boards/interconnects/makerdiary_nrf52840_m2/makerdiary_nrf52840_m2.zmk.yml new file mode 100644 index 000000000000..890c5dedf4be --- /dev/null +++ b/app/boards/interconnects/makerdiary_nrf52840_m2/makerdiary_nrf52840_m2.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: makerdiary_nrf52840_m2 +name: MakerDiary nRF52840 M.2 +type: interconnect +url: https://wiki.makerdiary.com/nrf52840-m2/ +manufacturer: MakerDiary +description: | + The MakerDiary nRF52840 M.2 module is a module using the M.2/NGFF form factor to expose a + large number of GPIO pins, allowing use of a variety of peripherals such using I2C, SPI, + etc. diff --git a/app/boards/interconnects/pro_micro/pro_micro.zmk.yml b/app/boards/interconnects/pro_micro/pro_micro.zmk.yml new file mode 100644 index 000000000000..83aa31c75d48 --- /dev/null +++ b/app/boards/interconnects/pro_micro/pro_micro.zmk.yml @@ -0,0 +1,21 @@ +file_format: "1" +id: pro_micro +name: Pro Micro +type: interconnect +url: https://www.sparkfun.com/products/12640 +manufacturer: SparkFun +description: | + The SparkFun Pro Micro grew popular as a low cost ATmega32U4 board with sufficient GPIO and peripherals + to work for many keyboard needs. Since the original Pro Micro, many pin compatible boards have appeared, + with various changes or improvements, such as the Elite-C w/ USB-C, nice!nano with nRF52840 wireless. + + Note: ZMK doesn't support boards with AVR 8-bit processors, such as the ATmega32U4, because Zephyr™ only + supports 32-bit and 64-bit platforms. As a result, controllers like the SparkFun Pro Micro and the Elite-C + are *not* supported by ZMK. +node_labels: + gpio: pro_micro + i2c: pro_micro_i2c + spi: pro_micro_spi + uart: pro_micro_serial +design_guideline: | + ZMK uses the blue color coded "Arduino" pin names to generate devicetree node references. For example, to refer to the pin labeled `0` in the diagram, use `&pro_micro 0` in the devicetree files. diff --git a/app/boards/interconnects/seeed_xiao/seeed_xiao.zmk.yml b/app/boards/interconnects/seeed_xiao/seeed_xiao.zmk.yml new file mode 100644 index 000000000000..48080c7f2f95 --- /dev/null +++ b/app/boards/interconnects/seeed_xiao/seeed_xiao.zmk.yml @@ -0,0 +1,17 @@ +file_format: "1" +id: seeed_xiao +name: Seeed XIAO +type: interconnect +url: https://wiki.seeedstudio.com/Seeeduino-XIAO/ +manufacturer: Seeed +description: | + The Seeed(uino) XIAO is a popular smaller format micro-controller, that has gained popularity as an alterative + to the SparkFun Pro Micro. Since its creation, several pin compatible controllers, such + as the Seeeduino XIAO BLE, Adafruit QT Py and Adafruit QT Py RP2040, have become available. +node_labels: + gpio: xiao_d + i2c: xiao_i2c + spi: xiao_spi + uart: xiao_serial +design_guideline: | + ZMK uses the "D"-prefixed, green color coded pin names, e.g. `D2`, to generate devicetree node references. For example, to refer to the pin labeled `D0` in the diagram, use `&xiao_d 0` in the devicetree files. diff --git a/app/boards/native_posix.conf b/app/boards/native_posix.conf new file mode 100644 index 000000000000..c3d0260e866f --- /dev/null +++ b/app/boards/native_posix.conf @@ -0,0 +1,7 @@ +CONFIG_GPIO=n +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_DEBUG=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 diff --git a/app/boards/native_posix.overlay b/app/boards/native_posix.overlay new file mode 100644 index 000000000000..d5ebcf18454d --- /dev/null +++ b/app/boards/native_posix.overlay @@ -0,0 +1,17 @@ +#include +#include +#include + +/ { + chosen { + zmk,kscan = &kscan; + }; + + kscan: kscan { + compatible = "zmk,kscan-mock"; + + rows = <2>; + columns = <2>; + exit-after; + }; +}; diff --git a/app/boards/native_posix_64.conf b/app/boards/native_posix_64.conf new file mode 100644 index 000000000000..0d8e0d81f0fb --- /dev/null +++ b/app/boards/native_posix_64.conf @@ -0,0 +1,8 @@ +CONFIG_GPIO=n +# Enable to have the native posix build expose USBIP device(s) +# CONFIG_ZMK_USB=y +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_DEBUG=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 diff --git a/app/boards/native_posix_64.overlay b/app/boards/native_posix_64.overlay new file mode 100644 index 000000000000..d0526ca38eb2 --- /dev/null +++ b/app/boards/native_posix_64.overlay @@ -0,0 +1,27 @@ +#include +#include +#include + +/ { + chosen { + zephyr,console = &uart0; + zmk,kscan = &kscan; + }; + + kscan: kscan { + compatible = "zmk,kscan-mock"; + + rows = <2>; + columns = <2>; + exit-after; + }; + + uart0: uart { + status = "okay"; + compatible = "zephyr,native-posix-uart"; + /* Dummy current-speed entry to comply with serial + * DTS binding + */ + current-speed = <0>; + }; +}; diff --git a/app/boards/nrf52840dk_nrf52840.conf b/app/boards/nrf52840dk_nrf52840.conf new file mode 100644 index 000000000000..6c9bcdf134e1 --- /dev/null +++ b/app/boards/nrf52840dk_nrf52840.conf @@ -0,0 +1,12 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y diff --git a/app/boards/nrf52_bsim.conf b/app/boards/nrf52_bsim.conf new file mode 100644 index 000000000000..526f3bc7d7e2 --- /dev/null +++ b/app/boards/nrf52_bsim.conf @@ -0,0 +1,4 @@ +CONFIG_ZMK_BLE=y +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y diff --git a/app/boards/nrf52_bsim.overlay b/app/boards/nrf52_bsim.overlay new file mode 100644 index 000000000000..ec7c49ae92ac --- /dev/null +++ b/app/boards/nrf52_bsim.overlay @@ -0,0 +1,16 @@ +#include +#include +#include + +/ { + chosen { + zmk,kscan = &kscan; + }; + + kscan: kscan { + compatible = "zmk,kscan-mock"; + + rows = <2>; + columns = <2>; + }; +}; diff --git a/app/boards/nrf5340dk_nrf5340_cpuapp.conf b/app/boards/nrf5340dk_nrf5340_cpuapp.conf new file mode 100644 index 000000000000..ccb0ddbaf40b --- /dev/null +++ b/app/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -0,0 +1,16 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +# Default main and BLE stack sizes are too small for HCI RPMsg +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_ZMK_BLE_THREAD_STACK_SIZE=1024 diff --git a/app/boards/nrf5340dk_nrf5340_cpuapp.overlay b/app/boards/nrf5340dk_nrf5340_cpuapp.overlay new file mode 100644 index 000000000000..9427d9ca1504 --- /dev/null +++ b/app/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +&arduino_i2c { + // Default buffer size is too small for use with displays. + zephyr,concat-buf-size = <1024>; +}; diff --git a/app/boards/rpi_pico.conf b/app/boards/rpi_pico.conf new file mode 100644 index 000000000000..f0db8ed14dc5 --- /dev/null +++ b/app/boards/rpi_pico.conf @@ -0,0 +1,5 @@ +CONFIG_CONSOLE=n +CONFIG_SERIAL=n +CONFIG_UART_CONSOLE=n +CONFIG_UART_INTERRUPT_DRIVEN=n +CONFIG_ZMK_USB=y diff --git a/app/boards/rpi_pico.overlay b/app/boards/rpi_pico.overlay new file mode 100644 index 000000000000..efc8e080f15d --- /dev/null +++ b/app/boards/rpi_pico.overlay @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "usb_console.dtsi" + diff --git a/app/boards/seeeduino_xiao.conf b/app/boards/seeeduino_xiao.conf new file mode 100644 index 000000000000..f0db8ed14dc5 --- /dev/null +++ b/app/boards/seeeduino_xiao.conf @@ -0,0 +1,5 @@ +CONFIG_CONSOLE=n +CONFIG_SERIAL=n +CONFIG_UART_CONSOLE=n +CONFIG_UART_INTERRUPT_DRIVEN=n +CONFIG_ZMK_USB=y diff --git a/app/boards/seeeduino_xiao.overlay b/app/boards/seeeduino_xiao.overlay new file mode 100644 index 000000000000..285ee4de332c --- /dev/null +++ b/app/boards/seeeduino_xiao.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + chosen { + zephyr,console = &cdc_acm_uart; + }; +}; + +&usb0 { + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + diff --git a/app/boards/seeeduino_xiao_ble.conf b/app/boards/seeeduino_xiao_ble.conf new file mode 100644 index 000000000000..205f67e91272 --- /dev/null +++ b/app/boards/seeeduino_xiao_ble.conf @@ -0,0 +1,15 @@ + +CONFIG_CONSOLE=n +CONFIG_SERIAL=n +CONFIG_UART_CONSOLE=n +CONFIG_UART_INTERRUPT_DRIVEN=n +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y + + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y \ No newline at end of file diff --git a/app/boards/seeeduino_xiao_ble.overlay b/app/boards/seeeduino_xiao_ble.overlay new file mode 100644 index 000000000000..d2ffbe461cbc --- /dev/null +++ b/app/boards/seeeduino_xiao_ble.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + +/ { + chosen { + zephyr,console = &cdc_acm_uart; + zmk,battery = &vbatt; + }; + + vbatt: vbatt { + compatible = "zmk,battery-voltage-divider"; + io-channels = <&adc 7>; + power-gpios = <&gpio0 14 (GPIO_OPEN_DRAIN | GPIO_ACTIVE_LOW)>; + output-ohms = <510000>; + full-ohms = <(1000000 + 510000)>; + }; +}; + +&adc { + status = "okay"; +}; + +&usbd { + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + +&qspi { + status = "disabled"; +}; diff --git a/app/boards/seeeduino_xiao_rp2040.conf b/app/boards/seeeduino_xiao_rp2040.conf new file mode 100644 index 000000000000..21c1893d91f4 --- /dev/null +++ b/app/boards/seeeduino_xiao_rp2040.conf @@ -0,0 +1,4 @@ +CONFIG_CONSOLE=n +CONFIG_SERIAL=n +CONFIG_UART_CONSOLE=n +CONFIG_ZMK_USB=y diff --git a/app/boards/seeeduino_xiao_rp2040.overlay b/app/boards/seeeduino_xiao_rp2040.overlay new file mode 100644 index 000000000000..d89e53f4a8e5 --- /dev/null +++ b/app/boards/seeeduino_xiao_rp2040.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "usb_console.dtsi" + +&xiao_serial { status = "disabled"; }; diff --git a/app/boards/shields/Kconfig.defconfig b/app/boards/shields/Kconfig.defconfig new file mode 100644 index 000000000000..58dd45d6e9bf --- /dev/null +++ b/app/boards/shields/Kconfig.defconfig @@ -0,0 +1,14 @@ + + + +config ZMK_KEYBOARD_NAME + default "cradios" + +# Unable to use interrupts as the same pin number is used +# across A & B controllers, and STM32F303CCT6 can't enable +# interrutps for multiple controllers for the same "line" +# for the external interrupts. +config ZMK_KSCAN_GPIO_POLLING + default y + + diff --git a/app/boards/shields/Kconfig.shield b/app/boards/shields/Kconfig.shield new file mode 100644 index 000000000000..cab78898de82 --- /dev/null +++ b/app/boards/shields/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2020 Pete Johanson +# SPDX-License-Identifier: MIT + +config SHIELD_CRADIOS + def_bool $(shields_list_contains,cradios) diff --git a/app/boards/shields/a_dux/Kconfig.defconfig b/app/boards/shields/a_dux/Kconfig.defconfig new file mode 100644 index 000000000000..2dc40dbe33ab --- /dev/null +++ b/app/boards/shields/a_dux/Kconfig.defconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_A_DUX_LEFT + +config ZMK_KEYBOARD_NAME + default "A. Dux" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_A_DUX_LEFT || SHIELD_A_DUX_RIGHT + +config ZMK_SPLIT + default y + +endif diff --git a/app/boards/shields/a_dux/Kconfig.shield b/app/boards/shields/a_dux/Kconfig.shield new file mode 100644 index 000000000000..928f432c410d --- /dev/null +++ b/app/boards/shields/a_dux/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_A_DUX_LEFT + def_bool $(shields_list_contains,a_dux_left) + +config SHIELD_A_DUX_RIGHT + def_bool $(shields_list_contains,a_dux_right) diff --git a/app/boards/shields/a_dux/README.md b/app/boards/shields/a_dux/README.md new file mode 100644 index 000000000000..2f84e31a34eb --- /dev/null +++ b/app/boards/shields/a_dux/README.md @@ -0,0 +1,15 @@ +# A. Dux + +Shield configuration for [Architeuthis Dux by Tapi][1] (aka A. Dux, A.D., "Giant Squid"). + +![Wireless Architeuthis Dux with nice!nano controllers][2] + +This shield is an adaptation of the direct pin [Cradio shield by @davidphilipbarr][3]. + +## Cephalopoda + +Check out the rest of Tapi's Cephalopoda collection of low profile split ergonomic mechanical keyboards at . + +[1]: https://github.com/tapioki/cephalopoda/tree/main/Architeuthis%20dux +[2]: https://media.discordapp.net/attachments/855822038287908864/866315666802081792/image0.jpg +[3]: https://github.com/zmkfirmware/zmk/tree/main/app/boards/shields/cradio diff --git a/app/boards/shields/a_dux/a_dux.conf b/app/boards/shields/a_dux/a_dux.conf new file mode 100644 index 000000000000..fa9715791ee4 --- /dev/null +++ b/app/boards/shields/a_dux/a_dux.conf @@ -0,0 +1,2 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT diff --git a/app/boards/shields/a_dux/a_dux.dtsi b/app/boards/shields/a_dux/a_dux.dtsi new file mode 100644 index 000000000000..c13f3dd133a0 --- /dev/null +++ b/app/boards/shields/a_dux/a_dux.dtsi @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <34>; + rows = <1>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,21) RC(0,20) RC(0,19) RC(0,18) RC(0,17) + RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,26) RC(0,25) RC(0,24) RC(0,23) RC(0,22) + RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,31) RC(0,30) RC(0,29) RC(0,28) RC(0,27) + RC(0,15) RC(0,16) RC(0,33) RC(0,32) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-direct"; + input-gpios = + <&pro_micro 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + <&pro_micro 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + <&pro_micro 18 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + <&pro_micro 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + <&pro_micro 21 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + <&pro_micro 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + <&pro_micro 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + <&pro_micro 19 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + <&pro_micro 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + <&pro_micro 20 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + <&pro_micro 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + <&pro_micro 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + <&pro_micro 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + <&pro_micro 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + <&pro_micro 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + <&pro_micro 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + <&pro_micro 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; + }; + +}; diff --git a/app/boards/shields/a_dux/a_dux.keymap b/app/boards/shields/a_dux/a_dux.keymap new file mode 100644 index 000000000000..0f162a33ce59 --- /dev/null +++ b/app/boards/shields/a_dux/a_dux.keymap @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +/ { + + keymap { + compatible = "zmk,keymap"; + + // This is a sample keymap intended to be replaced with your own + base_layer { + bindings = < + &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P + &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI + &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp SLASH + &kp TAB &kp BSPC &kp SPACE &kp ENTER + >; + }; + + }; +}; diff --git a/app/boards/shields/a_dux/a_dux.zmk.yml b/app/boards/shields/a_dux/a_dux.zmk.yml new file mode 100644 index 000000000000..b19a24219bdb --- /dev/null +++ b/app/boards/shields/a_dux/a_dux.zmk.yml @@ -0,0 +1,11 @@ +file_format: "1" +id: a_dux +name: A. Dux +type: shield +url: https://github.com/tapioki/cephalopoda/tree/main/Architeuthis%20dux +requires: [pro_micro] +features: + - keys +siblings: + - a_dux_left + - a_dux_right diff --git a/app/boards/shields/a_dux/a_dux_left.overlay b/app/boards/shields/a_dux/a_dux_left.overlay new file mode 100644 index 000000000000..c69106077b48 --- /dev/null +++ b/app/boards/shields/a_dux/a_dux_left.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "a_dux.dtsi" diff --git a/app/boards/shields/a_dux/a_dux_right.overlay b/app/boards/shields/a_dux/a_dux_right.overlay new file mode 100644 index 000000000000..d4aed65c2f8d --- /dev/null +++ b/app/boards/shields/a_dux/a_dux_right.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "a_dux.dtsi" + +&default_transform { + col-offset = <17>; +}; diff --git a/app/boards/shields/bat43/Kconfig.defconfig b/app/boards/shields/bat43/Kconfig.defconfig new file mode 100644 index 000000000000..43de1fa8f88e --- /dev/null +++ b/app/boards/shields/bat43/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_BAT43 + +config ZMK_KEYBOARD_NAME + default "Bat43" + +endif diff --git a/app/boards/shields/bat43/Kconfig.shield b/app/boards/shields/bat43/Kconfig.shield new file mode 100644 index 000000000000..10ee88cee980 --- /dev/null +++ b/app/boards/shields/bat43/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_BAT43 + def_bool $(shields_list_contains,bat43) diff --git a/app/boards/shields/bat43/bat43.keymap b/app/boards/shields/bat43/bat43.keymap new file mode 100644 index 000000000000..0f7e2d551ec2 --- /dev/null +++ b/app/boards/shields/bat43/bat43.keymap @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +#define LOWER 1 +#define RAISE 2 + +#define L_SPC < LOWER SPACE +#define R_RET < RAISE RET + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < +&kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp MINUS +&kp TAB &kp A &kp S &kp D &kp F &kp G &kp BSPC &kp H &kp J &kp K &kp L &kp SEMI &kp RSHFT +&kp LCTRL &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RCTRL + &kp LGUI &kp LANG2 L_SPC R_RET &kp LANG1 &kp RALT + &bt BT_CLR &out OUT_TOG &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 + >; + }; + lower_layer { + bindings = < +&trans &none &none &none &none &none &none &kp EQUAL &kp PLUS &kp STAR &kp PRCNT &trans +&trans &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &trans &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &trans +&trans &none &none &none &none &none &none &none &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans + >; + }; + raise_layer { + bindings = < +&trans &kp BSLH &kp EXCL &kp AMPS &kp PIPE &none &none &kp EQUAL &kp PLUS &kp STAR &kp PRCNT &trans +&trans &kp HASH &kp GRAVE &kp DQT &kp SQT &kp TILDE &trans &kp LEFT &kp DOWN &kp UP &kp RIGHT &kp DLLR &trans +&trans &none &none &kp LBRC &kp LBKT &kp LPAR &kp RPAR &kp RBKT &kp RBRC &kp AT &kp CARET &trans + &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans + >; + }; + }; +}; diff --git a/app/boards/shields/bat43/bat43.overlay b/app/boards/shields/bat43/bat43.overlay new file mode 100644 index 000000000000..7ebe653a010f --- /dev/null +++ b/app/boards/shields/bat43/bat43.overlay @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <6>; + rows = <7>; + + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(3,0) RC(5,0) RC(5,1) RC(5,2) RC(5,3) RC(5,4) RC(5,5) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(6,0) RC(6,1) RC(6,2) RC(6,3) RC(6,4) RC(6,5) + RC(3,3) RC(3,4) RC(3,5) RC(7,0) RC(7,1) RC(7,2) + RC(7,5) RC(7,4) RC(7,3) RC(3,1) RC(3,2) + >; + }; + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + col-gpios + = <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; diff --git a/app/boards/shields/bat43/bat43.zmk.yml b/app/boards/shields/bat43/bat43.zmk.yml new file mode 100644 index 000000000000..a84bf86297d8 --- /dev/null +++ b/app/boards/shields/bat43/bat43.zmk.yml @@ -0,0 +1,8 @@ +file_format: "1" +id: bat43 +name: BAT43 +type: shield +url: https://kbd.dailycraft.jp/bat43/ +requires: [pro_micro] +features: + - keys diff --git a/app/boards/shields/bfo9000/Kconfig.defconfig b/app/boards/shields/bfo9000/Kconfig.defconfig new file mode 100644 index 000000000000..7e41b04a4895 --- /dev/null +++ b/app/boards/shields/bfo9000/Kconfig.defconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_BFO9000_LEFT + +config ZMK_KEYBOARD_NAME + default "BFO-9000" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_BFO9000_LEFT || SHIELD_BFO9000_RIGHT + +config ZMK_SPLIT + default y + +endif \ No newline at end of file diff --git a/app/boards/shields/bfo9000/Kconfig.shield b/app/boards/shields/bfo9000/Kconfig.shield new file mode 100644 index 000000000000..5746abbe42ca --- /dev/null +++ b/app/boards/shields/bfo9000/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_BFO9000_LEFT + def_bool $(shields_list_contains,bfo9000_left) + +config SHIELD_BFO9000_RIGHT + def_bool $(shields_list_contains,bfo9000_right) diff --git a/app/boards/shields/bfo9000/README.md b/app/boards/shields/bfo9000/README.md new file mode 100644 index 000000000000..54893aedfe11 --- /dev/null +++ b/app/boards/shields/bfo9000/README.md @@ -0,0 +1,13 @@ +# [BFO-9000](https://keeb.io/products/bfo-9000-keyboard-customizable-full-size-split-ortholinear) + +Customizable full-size split ortholinear. + +## Features + +- Compatible with MX-compatible, Alps-compatible, and Kailh Low-Profile Choc switches. +- Breakoff pieces to allow for 4 to 6 rows and 7 to 9 columns. +- RGB LED connections + +## Hardware Notes + +[Included default keymap](http://www.keyboard-layout-editor.com/#/gists/51293c31afcd5f1765e8f413a46bfcf8) diff --git a/app/boards/shields/bfo9000/bfo9000.conf b/app/boards/shields/bfo9000/bfo9000.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/bfo9000/bfo9000.dtsi b/app/boards/shields/bfo9000/bfo9000.dtsi new file mode 100644 index 000000000000..d9d09a8320c4 --- /dev/null +++ b/app/boards/shields/bfo9000/bfo9000.dtsi @@ -0,0 +1,43 @@ + /* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <18>; + rows = <6>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,15) RC(0,16) RC(0,17) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) RC(1,14) RC(1,15) RC(1,16) RC(1,17) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) RC(2,14) RC(2,15) RC(2,16) RC(2,17) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) RC(3,13) RC(3,14) RC(3,15) RC(3,16) RC(3,17) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,13) RC(4,14) RC(4,15) RC(4,16) RC(4,17) + RC(5,0) RC(5,1) RC(5,2) RC(5,3) RC(5,4) RC(5,5) RC(5,6) RC(5,7) RC(5,8) RC(5,9) RC(5,10) RC(5,11) RC(5,12) RC(5,13) RC(5,14) RC(5,15) RC(5,16) RC(5,17) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + }; +}; \ No newline at end of file diff --git a/app/boards/shields/bfo9000/bfo9000.keymap b/app/boards/shields/bfo9000/bfo9000.keymap new file mode 100644 index 000000000000..18a2085c3b72 --- /dev/null +++ b/app/boards/shields/bfo9000/bfo9000.keymap @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include +#include + +#define DEFAULT 0 +#define LOWER 1 + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + // | Esc | Vol Up | Esc | F1 | F2 | F3 | F4 | F5 | F6 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | Del | + // | Home | Vol Dn | ` | 1 | 2 | 3 | 4 | 5 | 6 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | Bk Spc | + // | End | Tab | Tab | Q | W | E | R | T | Y | T | Y | U | I | O | P | [ | ] | \ | + // | Pg Up | Caps | Ctrl | A | S | D | F | G | H | G | H | J | K | L | ; | ' | Enter | Enter | + // | Pg Dn | Up | Shift | Z | X | C | V | B | N | B | N | M | , | . | / | Shift | Up | | + // | Left | Dn | Right | Ctrl | Alt | Win | Spc | Spc | Enter | Bk Spc | Spc | Spc | Win | Alt | Ctrl | Left | Dn | Right | + bindings = < + &kp ESC &kp C_VOL_UP &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp DEL + &kp HOME &kp C_VOL_DN &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC + &kp END &kp TAB &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH + &kp PG_UP &kp CAPS &kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp APOS &kp ENTER &kp ENTER + &kp PG_DN &kp UP &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp B &kp N &kp M &kp COMMA &kp DOT &kp SLASH &kp RSHFT &kp UP &mo LOWER + &kp LEFT &kp DOWN &kp RIGHT &kp LCTRL &kp LALT &kp LMETA &kp SPACE &kp SPACE &kp ENTER &kp BSPC &kp SPACE &kp SPACE &kp RMETA &kp RALT &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT + >; + }; + + lower_layer { + // | | | | | | | | | | | | | | | | | | | + // | | | | | | | | | | | | | | | | | | | + // | | | | | | | | | | | | | | | | | | | + // | | | | | | | | | | | | | | | | | | | + // | | | | | | | | | | | | | | | | | | | + // | | | | | | | | | | | | | | | | | | | + bindings = < + &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &bt BT_SEL 5 &bt BT_SEL 6 &bt BT_SEL 7 &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &bt BT_SEL 5 &bt BT_SEL 6 &bt BT_SEL 7 + &out OUT_USB &out OUT_BLE &trans &trans &trans &trans &trans &trans &trans &out OUT_USB &out OUT_BLE &trans &trans &trans &trans &trans &trans &trans + &ext_power EP_ON &ext_power EP_OFF &trans &trans &trans &trans &trans &trans &trans &ext_power EP_ON &ext_power EP_OFF &trans &trans &trans &trans &trans &trans &trans + &sys_reset &bootloader &trans &trans &trans &trans &trans &trans &trans &sys_reset &bootloader &trans &trans &trans &trans &trans &trans &trans + &rgb_ug RGB_TOG &rgb_ug RGB_HUI &rgb_ug RGB_SAI &rgb_ug RGB_BRI &rgb_ug RGB_SPI &rgb_ug RGB_EFF &trans &trans &trans &rgb_ug RGB_TOG &rgb_ug RGB_HUI &rgb_ug RGB_SAI &rgb_ug RGB_BRI &rgb_ug RGB_SPI &rgb_ug RGB_EFF &trans &trans &trans + &trans &rgb_ug RGB_HUD &rgb_ug RGB_SAD &rgb_ug RGB_BRD &rgb_ug RGB_SPD &rgb_ug RGB_EFR &trans &trans &trans &trans &rgb_ug RGB_HUD &rgb_ug RGB_SAD &rgb_ug RGB_BRD &rgb_ug RGB_SPD &rgb_ug RGB_EFR &trans &trans &trans + >; + }; + }; +}; diff --git a/app/boards/shields/bfo9000/bfo9000.zmk.yml b/app/boards/shields/bfo9000/bfo9000.zmk.yml new file mode 100644 index 000000000000..c63e7e317818 --- /dev/null +++ b/app/boards/shields/bfo9000/bfo9000.zmk.yml @@ -0,0 +1,11 @@ +file_format: "1" +id: bfo9000 +name: BFO-9000 +type: shield +url: https://keeb.io/products/bfo-9000-keyboard-customizable-full-size-split-ortholinear +requires: [pro_micro] +features: + - keys +siblings: + - bfo9000_left + - bfo9000_right diff --git a/app/boards/shields/bfo9000/bfo9000_left.conf b/app/boards/shields/bfo9000/bfo9000_left.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/bfo9000/bfo9000_left.overlay b/app/boards/shields/bfo9000/bfo9000_left.overlay new file mode 100644 index 000000000000..9e9210536400 --- /dev/null +++ b/app/boards/shields/bfo9000/bfo9000_left.overlay @@ -0,0 +1,21 @@ + /* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "bfo9000.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 21 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/bfo9000/bfo9000_right.conf b/app/boards/shields/bfo9000/bfo9000_right.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/bfo9000/bfo9000_right.overlay b/app/boards/shields/bfo9000/bfo9000_right.overlay new file mode 100644 index 000000000000..897c6b0bfdd1 --- /dev/null +++ b/app/boards/shields/bfo9000/bfo9000_right.overlay @@ -0,0 +1,25 @@ + /* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "bfo9000.dtsi" + +&default_transform { + col-offset = <9>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 21 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/boardsource3x4/Kconfig.defconfig b/app/boards/shields/boardsource3x4/Kconfig.defconfig new file mode 100644 index 000000000000..4c55aab085bc --- /dev/null +++ b/app/boards/shields/boardsource3x4/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_BOARDSOURCE3X4 + +config ZMK_KEYBOARD_NAME + default "Boardsource 3x4" + +endif \ No newline at end of file diff --git a/app/boards/shields/boardsource3x4/Kconfig.shield b/app/boards/shields/boardsource3x4/Kconfig.shield new file mode 100644 index 000000000000..7f574cea67a6 --- /dev/null +++ b/app/boards/shields/boardsource3x4/Kconfig.shield @@ -0,0 +1,6 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_BOARDSOURCE3X4 + def_bool $(shields_list_contains,boardsource3x4) + diff --git a/app/boards/shields/boardsource3x4/boardsource3x4.conf b/app/boards/shields/boardsource3x4/boardsource3x4.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/boardsource3x4/boardsource3x4.keymap b/app/boards/shields/boardsource3x4/boardsource3x4.keymap new file mode 100644 index 000000000000..c47126abcaaf --- /dev/null +++ b/app/boards/shields/boardsource3x4/boardsource3x4.keymap @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + + bindings = < + &tog 1 &kp C_PREV &kp C_PP &kp C_NEXT + &mo 2 &kp C_VOL_DN &kp UP &kp C_VOL_UP + &mo 3 &kp LEFT &kp DOWN &kp RIGHT + >; + + }; + + num_layer { + bindings = < + &trans &kp N7 &kp N8 &kp N9 + &trans &kp N4 &kp N5 &kp N6 + < 3 N0 &kp N1 &kp N2 &kp N3 + >; + }; + + lower_layer { + bindings = < + &bt BT_CLR &none &sys_reset &bootloader + &trans &bt BT_SEL 3 &bt BT_SEL 4 &none + &none &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 + >; + }; + + raise_layer { + bindings = < + &kp 0x68 &kp 0x69 &kp 0x6A &kp 0x6B + &kp 0x6C &kp 0x6D &kp 0x6E &kp 0x6F + &trans &kp 0x70 &kp 0x71 &kp 0x72 + >; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/boardsource3x4/boardsource3x4.overlay b/app/boards/shields/boardsource3x4/boardsource3x4.overlay new file mode 100644 index 000000000000..389f5b7ab7c9 --- /dev/null +++ b/app/boards/shields/boardsource3x4/boardsource3x4.overlay @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + col-gpios + = <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + ; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/boardsource3x4/boardsource3x4.zmk.yml b/app/boards/shields/boardsource3x4/boardsource3x4.zmk.yml new file mode 100644 index 000000000000..fee279659a27 --- /dev/null +++ b/app/boards/shields/boardsource3x4/boardsource3x4.zmk.yml @@ -0,0 +1,8 @@ +file_format: "1" +id: boardsource3x4 +name: Boardsource 3x4 Macropad +type: shield +url: https://boardsource.xyz/store/5ecc2008eee64242946c98c1 +requires: [pro_micro] +features: + - keys diff --git a/app/boards/shields/boardsource5x12/Kconfig.defconfig b/app/boards/shields/boardsource5x12/Kconfig.defconfig new file mode 100644 index 000000000000..ca7979d4981c --- /dev/null +++ b/app/boards/shields/boardsource5x12/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_BOARDSOURCE5X12 + +config ZMK_KEYBOARD_NAME + default "boardsource5x12" + +endif \ No newline at end of file diff --git a/app/boards/shields/boardsource5x12/Kconfig.shield b/app/boards/shields/boardsource5x12/Kconfig.shield new file mode 100644 index 000000000000..b2d7b63fba90 --- /dev/null +++ b/app/boards/shields/boardsource5x12/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_BOARDSOURCE5X12 + def_bool $(shields_list_contains,boardsource5x12) \ No newline at end of file diff --git a/app/boards/shields/boardsource5x12/boardsource5x12.conf b/app/boards/shields/boardsource5x12/boardsource5x12.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/boardsource5x12/boardsource5x12.keymap b/app/boards/shields/boardsource5x12/boardsource5x12.keymap new file mode 100644 index 000000000000..cb851c35cac1 --- /dev/null +++ b/app/boards/shields/boardsource5x12/boardsource5x12.keymap @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + // ------------------------------------------------------------------------------------------ + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | BSPC | + // | TAB | Q | W | E | R | T | Y | U | I | O | P | \ | + // | SHIFT | A | S | D | F | G | H | J | K | L | ; | ' | + // | CTRL | Z | X | C | V | B | N | M | , | . | / | ENTER | + // |ADJUST | LCTL | LALT | LGUI | LOWR | SPACE| SPACE | RAIS | LARW | DARW | UARW | RARW | + + + bindings = < + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSLH + &kp LSHFT &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LCTRL &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RET + &mo 3 &kp LCTRL &kp LALT &kp LGUI &mo 1 &kp SPACE &kp SPACE &mo 2 &kp LEFT &kp DOWN &kp UP &kp RIGHT + >; + }; + + lower_layer { + // ------------------------------------------------------------------------------------------- + // | ESC | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | + // | ~ | ! | @ | # | $ | % | ^ | & | * | ( | ) | DEL | + // | | F1 | F2 | F3 | F4 | F5 | F6 | _ | + | { | } | | | + // | | F7 | F8 | F9 | F10 | F11 | F12 | LS(#) |LS(|) | | | | + // | | | | | | | | | NEXT | Vol- | Vol+ | PLAY | + bindings = < + &kp ESC &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 + &kp TILDE &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp ASTRK &kp LPAR &kp RPAR &kp DEL + &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp UNDER &kp PLUS &kp LBRC &kp RBRC &kp PIPE + &trans &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp LS(NON_US_HASH) &kp LS(NON_US_BSLH) &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &mo 3 &kp C_NEXT &kp C_VOL_DN &kp C_VOL_UP &kp C_PLAY_PAUSE + >; + }; + + raise_layer { + // ------------------------------------------------------------------------------------------ + // | ESC | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | + // | ~ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | DEL | + // | DEL | F1 | F2 | F3 | F4 | F5 | F6 | - | = | [ | ] | \ | + // | | F7 | F8 | F9 | F10 | F11 | F12 | # | | | | | | + // | | | | | | | | | | | | | + bindings = < + &kp ESC &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 + &kp TILDE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp DEL + &kp DEL &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH + &trans &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp NON_US_HASH &kp NON_US_BSLH &trans &trans &trans + &trans &trans &trans &trans &mo 3 &trans &trans &trans &trans &trans &trans &trans + >; + }; + + adjust_layer { + // ------------------------------------------------------------------------------------------ + // |tog(4)| F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | + // | | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA |LALT(PRTSN)| + // | | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | PRTSN | + // | | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA |LCTRL(DEL) | + // | | | | | |BOOTLD|BOOTLD| | | | | | + bindings = < + &tog 4 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 + &trans &none &none &none &none &none &none &none &none &none &none &kp LA(PSCRN) + &trans &none &none &none &none &none &none &none &none &none &none &kp PSCRN + &trans &none &none &none &none &none &none &none &none &none &none &kp LC(DEL) + &trans &trans &trans &trans &trans &bootloader &bootloader &trans &trans &trans &trans &trans + >; + }; + + flock_layer { + // ---------------------------------------------------------------------------------------------- + // |tog(4) | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | | + // |out tog|BT_SEL 0|BT_SEL 1|BT_SEL 2|BT_SEL 3|BT_SEL 4|BT_PRV|BT_NXT|BT_CLR| | | | + // | | | | | | | | | | | | | + // | | | | | | | | | | | | | + // | | | | | | | | | | | | | + bindings = < + &tog 4 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &trans + &out OUT_TOG &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &bt BT_PRV &bt BT_NXT &bt BT_CLR &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/boardsource5x12/boardsource5x12.overlay b/app/boards/shields/boardsource5x12/boardsource5x12.overlay new file mode 100644 index 000000000000..9a721d0c4aa0 --- /dev/null +++ b/app/boards/shields/boardsource5x12/boardsource5x12.overlay @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + col-gpios + = <&pro_micro 21 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + ; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/boardsource5x12/boardsource5x12.zmk.yml b/app/boards/shields/boardsource5x12/boardsource5x12.zmk.yml new file mode 100644 index 000000000000..6987e27a0abe --- /dev/null +++ b/app/boards/shields/boardsource5x12/boardsource5x12.zmk.yml @@ -0,0 +1,8 @@ +file_format: "1" +id: boardsource5x12 +name: Boardsource 5x12 +type: shield +url: https://boardsource.xyz/store/5ecb802c86879c9a0c22db61 +requires: [pro_micro] +features: + - keys diff --git a/app/boards/shields/chalice/Kconfig.defconfig b/app/boards/shields/chalice/Kconfig.defconfig new file mode 100644 index 000000000000..9987a79a21b4 --- /dev/null +++ b/app/boards/shields/chalice/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_CHALICE + +config ZMK_KEYBOARD_NAME + default "Chalice" + +endif diff --git a/app/boards/shields/chalice/Kconfig.shield b/app/boards/shields/chalice/Kconfig.shield new file mode 100644 index 000000000000..bd03bf7609b9 --- /dev/null +++ b/app/boards/shields/chalice/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_CHALICE + def_bool $(shields_list_contains,chalice) diff --git a/app/boards/shields/chalice/boards/nice_nano.overlay b/app/boards/shields/chalice/boards/nice_nano.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/chalice/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/chalice/boards/nice_nano_v2.overlay b/app/boards/shields/chalice/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/chalice/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/chalice/chalice.conf b/app/boards/shields/chalice/chalice.conf new file mode 100644 index 000000000000..da6422568279 --- /dev/null +++ b/app/boards/shields/chalice/chalice.conf @@ -0,0 +1,3 @@ +# Uncomment the following lines to enable RGB underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y \ No newline at end of file diff --git a/app/boards/shields/chalice/chalice.keymap b/app/boards/shields/chalice/chalice.keymap new file mode 100644 index 000000000000..c72e3ee1b81f --- /dev/null +++ b/app/boards/shields/chalice/chalice.keymap @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + + bindings = < + &kp ESC &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC + &kp INSERT &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH + &kp DELETE &kp CAPS &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp ENTER + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp B &kp N &kp M &kp COMMA &kp DOT &kp SLASH &kp RSHFT &kp UP + &kp LCTRL &kp LALT &kp SPACE &mo 1 &kp SPACE &kp RALT &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT + >; + }; + + function_layer { + + bindings = < + &bootloader &out OUT_TOG &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &trans + &trans &bt BT_CLR &rgb_ug RGB_TOG &rgb_ug RGB_HUD &rgb_ug RGB_HUI &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &bt BT_SEL 0 &rgb_ug RGB_EFF &rgb_ug RGB_SAD &rgb_ug RGB_SAI &trans &trans &trans &trans &trans &trans &trans &trans &trans + &bt BT_SEL 1 &rgb_ug RGB_EFR &rgb_ug RGB_BRD &rgb_ug RGB_BRI &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp PG_UP + &bt BT_SEL 2 &trans &trans &trans &trans &trans &trans &kp HOME &kp PG_DN &kp END + >; + }; + }; +}; diff --git a/app/boards/shields/chalice/chalice.overlay b/app/boards/shields/chalice/chalice.overlay new file mode 100644 index 000000000000..85c9b1ed6575 --- /dev/null +++ b/app/boards/shields/chalice/chalice.overlay @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <7>; + rows = <10>; + + map = < + RC(0,0) RC(1,0) RC(0,1) RC(1,1) RC(0,2) RC(1,2) RC(0,3) RC(1,3) RC(0,4) RC(1,4) RC(0,5) RC(1,5) RC(0,6) RC(1,6) RC(4,6) + RC(2,0) RC(3,0) RC(2,1) RC(3,1) RC(2,2) RC(3,2) RC(2,3) RC(3,3) RC(2,4) RC(3,4) RC(2,5) RC(3,5) RC(2,6) RC(3,6) RC(5,6) + RC(4,0) RC(5,0) RC(4,1) RC(5,1) RC(4,2) RC(5,2) RC(4,3) RC(5,3) RC(4,4) RC(5,4) RC(4,5) RC(5,5) RC(6,6) RC(7,6) + RC(6,0) RC(7,0) RC(6,1) RC(7,1) RC(6,2) RC(7,2) RC(6,3) RC(7,3) RC(6,4) RC(7,4) RC(6,5) RC(7,5) RC(8,6) RC(9,6) + RC(8,0) RC(9,1) RC(8,2) RC(9,2) RC(8,3) RC(9,3) RC(8,4) RC(9,4) RC(8,5) RC(9,5) + >; + }; + + splitbs_transform: keymap_transform_1 { + compatible = "zmk,matrix-transform"; + columns = <7>; + rows = <10>; + + map = < + RC(0,0) RC(1,0) RC(0,1) RC(1,1) RC(0,2) RC(1,2) RC(0,3) RC(1,3) RC(0,4) RC(1,4) RC(0,5) RC(1,5) RC(0,6) RC(1,6) RC(4,6) RC(8,1) + RC(2,0) RC(3,0) RC(2,1) RC(3,1) RC(2,2) RC(3,2) RC(2,3) RC(3,3) RC(2,4) RC(3,4) RC(2,5) RC(3,5) RC(2,6) RC(3,6) RC(5,6) + RC(4,0) RC(5,0) RC(4,1) RC(5,1) RC(4,2) RC(5,2) RC(4,3) RC(5,3) RC(4,4) RC(5,4) RC(4,5) RC(5,5) RC(6,6) RC(7,6) + RC(6,0) RC(7,0) RC(6,1) RC(7,1) RC(6,2) RC(7,2) RC(6,3) RC(7,3) RC(6,4) RC(7,4) RC(6,5) RC(7,5) RC(8,6) RC(9,6) + RC(8,0) RC(9,1) RC(8,2) RC(9,2) RC(8,3) RC(9,3) RC(8,4) RC(9,4) RC(8,5) RC(9,5) + >; + }; + + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + col-gpios + = <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 0 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; diff --git a/app/boards/shields/chalice/chalice.zmk.yml b/app/boards/shields/chalice/chalice.zmk.yml new file mode 100644 index 000000000000..a284dbe57853 --- /dev/null +++ b/app/boards/shields/chalice/chalice.zmk.yml @@ -0,0 +1,9 @@ +file_format: "1" +id: chalice +name: Chalice +type: shield +url: https://customkbd.com/products/chalice-pre-order +requires: [pro_micro] +features: + - keys + - underglow diff --git a/app/boards/shields/clog/Kconfig.defconfig b/app/boards/shields/clog/Kconfig.defconfig new file mode 100644 index 000000000000..53ded4d779c0 --- /dev/null +++ b/app/boards/shields/clog/Kconfig.defconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_CLOG_LEFT + +config ZMK_KEYBOARD_NAME + default "Clog" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_CLOG_LEFT || SHIELD_CLOG_RIGHT + +config ZMK_SPLIT + default y + +endif diff --git a/app/boards/shields/clog/Kconfig.shield b/app/boards/shields/clog/Kconfig.shield new file mode 100644 index 000000000000..69ecef8da446 --- /dev/null +++ b/app/boards/shields/clog/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_CLOG_LEFT + def_bool $(shields_list_contains,clog_left) + +config SHIELD_CLOG_RIGHT + def_bool $(shields_list_contains,clog_right) diff --git a/app/boards/shields/clog/README.md b/app/boards/shields/clog/README.md new file mode 100644 index 000000000000..6b63889a8524 --- /dev/null +++ b/app/boards/shields/clog/README.md @@ -0,0 +1,8 @@ +# The Clog + +The Clog is a 34-key choc v1 split board by S'mores. This firmware works for both the [Clog][clog], +as well as the [Sephirette][sephirette], the MX version. You can purchase kits for both boards +at smoresboards.com. + +[clog]: https://github.com/smores56/clog +[sephirette]: https://github.com/smores56/sephirette diff --git a/app/boards/shields/clog/clog.conf b/app/boards/shields/clog/clog.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/clog/clog.dtsi b/app/boards/shields/clog/clog.dtsi new file mode 100644 index 000000000000..bcc08c71beaa --- /dev/null +++ b/app/boards/shields/clog/clog.dtsi @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <34>; + rows = <1>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,20) RC(0,19) RC(0,18) RC(0,17) + RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,26) RC(0,25) RC(0,24) RC(0,23) RC(0,22) RC(0,21) + RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,31) RC(0,30) RC(0,29) RC(0,28) RC(0,27) + RC(0,15) RC(0,16) RC(0,33) RC(0,32) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-direct"; + + input-gpios + = <&pro_micro 18 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 19 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 20 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 21 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; + }; +}; diff --git a/app/boards/shields/clog/clog.keymap b/app/boards/shields/clog/clog.keymap new file mode 100644 index 000000000000..885404f73258 --- /dev/null +++ b/app/boards/shields/clog/clog.keymap @@ -0,0 +1,113 @@ +/* +* Copyright (c) 2022 The ZMK Contributors +* +* SPDX-License-Identifier: MIT +*/ + +#include +#include +#include + +#define MAIN 0 +#define SYM 1 +#define NAV 2 +#define BT 3 + +&mt { + flavor = "tap-preferred"; + tapping_term_ms = <140>; +}; + +/ { + combos { + compatible = "zmk,combos"; + + combo_esc { + timeout-ms = <100>; + key-positions = <21 22>; + bindings = <&kp ESC>; + }; + + combo_tab { + timeout-ms = <100>; + key-positions = <22 23>; + bindings = <&kp TAB>; + }; + + combo_minus { + timeout-ms = <100>; + key-positions = <26 27>; + bindings = <&kp MINUS>; + }; + + combo_underscore { + timeout-ms = <100>; + key-positions = <26 28>; + bindings = <&kp UNDERSCORE>; + }; + + combo_colon { + timeout-ms = <100>; + key-positions = <7 8>; + bindings = <&kp COLON>; + }; + + combo_semicolon { + timeout-ms = <100>; + key-positions = <6 8>; + bindings = <&kp SEMICOLON>; + }; + + combo_backslash { + timeout-ms = <100>; + key-positions = <27 28>; + bindings = <&kp BSLH>; + }; + + combo_grave { + timeout-ms = <100>; + key-positions = <8 9>; + bindings = <&kp GRAVE>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + MAIN_layer { + bindings = < + &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O + &kp Q &kp A &kp S &kp D < SYM F &kp G &kp H < SYM J &kp K &kp L &kp SQT &kp P + &mt LSHFT Z &mt LALT X &mt LCTRL C &mt LGUI V &kp B &kp N &mt RGUI M &mt RCTRL COMMA &mt RALT DOT &mt RSHFT FSLH + < BT ENTER < NAV SPACE &sk RSHFT &kp BSPC + >; + }; + + SYM_layer { + bindings = < + &kp N7 &kp N8 &kp N9 &kp STAR &kp DLLR &kp LBRC &kp RBRC &kp HASH + &kp AMPS &kp EXCL &kp N1 &kp N2 &kp N3 &kp EQUAL &kp LT &kp LPAR &kp RPAR &kp GT &kp PIPE &none + &kp CARET &kp N4 &kp N5 &kp N6 &kp PLUS &kp TILDE &kp LBKT &kp RBKT &kp AT &kp PRCNT + &kp DOT &kp N0 &trans &none + >; + }; + + NAV_layer { + bindings = < + &kp C_VOL_DN &kp C_VOL_UP &kp C_NEXT &kp C_PP &none &kp F7 &kp F8 &kp F9 + &kp C_PREV &kp LEFT &kp DOWN &kp UP &kp RIGHT &kp LC(TAB) &kp PSCRN &kp F1 &kp F2 &kp F3 &kp F10 &kp F12 + &kp HOME &kp PG_DN &kp PG_UP &kp END &kp LS(LC(TAB)) &kp CAPS &kp F4 &kp F5 &kp F6 &kp F11 + &none &none &trans &kp DEL + >; + }; + + BT_layer { + bindings = < + &none &none &none &none &none &none &none &none + &none &none &none &none &none &none &none &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &none + &none &none &none &none &none &none &bt BT_CLR &none &none &none + &none &none &none &none + >; + }; + }; +}; diff --git a/app/boards/shields/clog/clog.zmk.yml b/app/boards/shields/clog/clog.zmk.yml new file mode 100644 index 000000000000..f71df0df4e0e --- /dev/null +++ b/app/boards/shields/clog/clog.zmk.yml @@ -0,0 +1,11 @@ +file_format: "1" +id: clog +name: Clog +type: shield +url: https://github.com/smores56/clog +requires: [pro_micro] +features: + - keys +siblings: + - clog_left + - clog_right diff --git a/app/boards/shields/clog/clog_left.overlay b/app/boards/shields/clog/clog_left.overlay new file mode 100644 index 000000000000..582460252a64 --- /dev/null +++ b/app/boards/shields/clog/clog_left.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "clog.dtsi" diff --git a/app/boards/shields/clog/clog_right.overlay b/app/boards/shields/clog/clog_right.overlay new file mode 100644 index 000000000000..8b0efb3d2602 --- /dev/null +++ b/app/boards/shields/clog/clog_right.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "clog.dtsi" + +&default_transform { + col-offset = <17>; +}; diff --git a/app/boards/shields/clueboard_california/Kconfig.defconfig b/app/boards/shields/clueboard_california/Kconfig.defconfig new file mode 100644 index 000000000000..278aaa4472c2 --- /dev/null +++ b/app/boards/shields/clueboard_california/Kconfig.defconfig @@ -0,0 +1,14 @@ + +if SHIELD_CLUEBOARD_CALIFORNIA + +config ZMK_KEYBOARD_NAME + default "Clueboard California Macropad" + +# Unable to use interrupts as the same pin number is used +# across A & B controllers, and STM32F303CCT6 can't enable +# interrutps for multiple controllers for the same "line" +# for the external interrupts. +config ZMK_KSCAN_DIRECT_POLLING + default y + +endif diff --git a/app/boards/shields/clueboard_california/Kconfig.shield b/app/boards/shields/clueboard_california/Kconfig.shield new file mode 100644 index 000000000000..e987d29a65fb --- /dev/null +++ b/app/boards/shields/clueboard_california/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2020 Pete Johanson +# SPDX-License-Identifier: MIT + +config SHIELD_CLUEBOARD_CALIFORNIA + def_bool $(shields_list_contains,clueboard_california) diff --git a/app/boards/shields/clueboard_california/README.md b/app/boards/shields/clueboard_california/README.md new file mode 100644 index 000000000000..0255eff755e5 --- /dev/null +++ b/app/boards/shields/clueboard_california/README.md @@ -0,0 +1,24 @@ +# [Clueboard California Macropad](https://clueboard.co/parts/clueboard-california-macropad-kit) + +A small 10-key macropad in the shape of the US state of California. + +## Features + +- Per key LED. +- Proton-C only, including space for the piezo speaker. +- Direct GPIO wiring, no GPIO matrix at all. + +## Hardware Notes + +| Switch | Switch Pin | LED Pin | +| ------------ | ---------- | ------- | +| shasta1 | a10 | a2 | +| modoc1 | a9 | b5 | +| mendocino1 | a0 | a1 | +| lassen1 | b8 | b4 | +| eldorado1 | b11 | b12 | +| big_sur1 | b9 | b10 | +| sierra1 | a8 | a15 | +| los_padres1 | a7 | a6 | +| mojave1 | b1 | b0 | +| joshua_tree1 | b2 | b3 | diff --git a/app/boards/shields/clueboard_california/clueboard_california.conf b/app/boards/shields/clueboard_california/clueboard_california.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/clueboard_california/clueboard_california.keymap b/app/boards/shields/clueboard_california/clueboard_california.keymap new file mode 100644 index 000000000000..9af22fa1f278 --- /dev/null +++ b/app/boards/shields/clueboard_california/clueboard_california.keymap @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +/ { + keymap0: keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp N9 &kp N8 + &kp N7 &kp N6 + &kp N5 + &kp N4 &kp N3 + &kp N2 &kp N1 + &kp N0 + >; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/clueboard_california/clueboard_california.overlay b/app/boards/shields/clueboard_california/clueboard_california.overlay new file mode 100644 index 000000000000..8cea791e2c06 --- /dev/null +++ b/app/boards/shields/clueboard_california/clueboard_california.overlay @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ + +/ { + chosen { + zmk,kscan = &kscan0; + }; + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-direct"; + + input-gpios + = <&gpioa 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpioa 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpioa 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpiob 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpiob 11 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpiob 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpioa 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpioa 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpiob 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&gpiob 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; + + }; + + // TODO: Per-key LED node(s) +}; + diff --git a/app/boards/shields/contra/Kconfig.defconfig b/app/boards/shields/contra/Kconfig.defconfig new file mode 100644 index 000000000000..8fde0970d1a8 --- /dev/null +++ b/app/boards/shields/contra/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_CONTRA + +config ZMK_KEYBOARD_NAME + default "Contra Keyboard" + +endif \ No newline at end of file diff --git a/app/boards/shields/contra/Kconfig.shield b/app/boards/shields/contra/Kconfig.shield new file mode 100644 index 000000000000..e9f8e80464fb --- /dev/null +++ b/app/boards/shields/contra/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_CONTRA + def_bool $(shields_list_contains,contra) \ No newline at end of file diff --git a/app/boards/shields/contra/contra.conf b/app/boards/shields/contra/contra.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/contra/contra.keymap b/app/boards/shields/contra/contra.keymap new file mode 100644 index 000000000000..77b431b65b4c --- /dev/null +++ b/app/boards/shields/contra/contra.keymap @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +#define DEFAULT 0 +#define NUM_MODS 1 +#define BT_CTRL 2 + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSPC + &kp TAB &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp ENTER + &kp LCTRL &kp LGUI &kp LALT &kp BSLH &to DEFAULT &kp SPACE &trans &to NUM_MODS &kp LEFT &kp RIGHT &kp UP &kp DOWN + >; + }; + + num_mods { + bindings = < + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp DEL + &kp TAB &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp MINUS &kp PG_UP &kp LBKT &kp RBKT &kp BSLH + &kp LSHFT &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp EQUAL &kp PG_DN &kp HOME &kp END &kp ENTER + &kp LCTRL &kp LGUI &kp LALT &sys_reset &to DEFAULT &kp SPACE &trans &mo BT_CTRL &kp LEFT &kp RIGHT &kp UP &kp DOWN + >; + }; + + bt_control { + bindings = < + &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &bt BT_PRV &bt BT_NXT &trans &trans + >; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/contra/contra.overlay b/app/boards/shields/contra/contra.overlay new file mode 100644 index 000000000000..0ac042d63571 --- /dev/null +++ b/app/boards/shields/contra/contra.overlay @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + chosen { + zmk,kscan = &kscan0; + }; + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + col-gpios + = <&pro_micro 21 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 3 GPIO_ACTIVE_HIGH> + , <&pro_micro 2 GPIO_ACTIVE_HIGH> + , <&pro_micro 0 GPIO_ACTIVE_HIGH> + , <&pro_micro 1 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/contra/contra.zmk.yml b/app/boards/shields/contra/contra.zmk.yml new file mode 100644 index 000000000000..da3a94474439 --- /dev/null +++ b/app/boards/shields/contra/contra.zmk.yml @@ -0,0 +1,8 @@ +file_format: "1" +id: contra +name: Contra +type: shield +url: https://github.com/ai03-2725/Contra +requires: [pro_micro] +features: + - keys diff --git a/app/boards/shields/corne/Kconfig.defconfig b/app/boards/shields/corne/Kconfig.defconfig new file mode 100644 index 000000000000..07dd07e9c0f9 --- /dev/null +++ b/app/boards/shields/corne/Kconfig.defconfig @@ -0,0 +1,46 @@ +if SHIELD_CORNE_LEFT + +config ZMK_KEYBOARD_NAME + default "Corne" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_CORNE_LEFT || SHIELD_CORNE_RIGHT + +config ZMK_SPLIT + default y + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif diff --git a/app/boards/shields/corne/Kconfig.shield b/app/boards/shields/corne/Kconfig.shield new file mode 100644 index 000000000000..099680b9dbce --- /dev/null +++ b/app/boards/shields/corne/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2020 Pete Johanson +# SPDX-License-Identifier: MIT + +config SHIELD_CORNE_LEFT + def_bool $(shields_list_contains,corne_left) + +config SHIELD_CORNE_RIGHT + def_bool $(shields_list_contains,corne_right) diff --git a/app/boards/shields/corne/boards/nice_nano.overlay b/app/boards/shields/corne/boards/nice_nano.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/corne/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/corne/boards/nice_nano_v2.overlay b/app/boards/shields/corne/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/corne/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/corne/corne.conf b/app/boards/shields/corne/corne.conf new file mode 100644 index 000000000000..974243c8aea3 --- /dev/null +++ b/app/boards/shields/corne/corne.conf @@ -0,0 +1,6 @@ +# Uncomment the following lines to enable the Corne RGB Underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y + +# Uncomment the following line to enable the Corne OLED Display +# CONFIG_ZMK_DISPLAY=y diff --git a/app/boards/shields/corne/corne.dtsi b/app/boards/shields/corne/corne.dtsi new file mode 100644 index 000000000000..5058f67a617b --- /dev/null +++ b/app/boards/shields/corne/corne.dtsi @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zephyr,display = &oled; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <12>; + rows = <4>; +// | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | +// | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | +// | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | +// | SW19 | SW20 | SW21 | | SW21 | SW20 | SW19 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) + RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) + >; + }; + + five_column_transform: keymap_transform_1 { + compatible = "zmk,matrix-transform"; + columns = <10>; + rows = <4>; +// | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | +// | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | +// | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | +// | SW19 | SW20 | SW21 | | SW21 | SW20 | SW19 | + map = < +RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) +RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) +RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) + RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + }; + + // TODO: per-key RGB node(s)? +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/corne/corne.keymap b/app/boards/shields/corne/corne.keymap new file mode 100644 index 000000000000..0555cf41757c --- /dev/null +++ b/app/boards/shields/corne/corne.keymap @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ----------------------------------------------------------------------------------------- +// | TAB | Q | W | E | R | T | | Y | U | I | O | P | BKSP | +// | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | +// | SHFT | Z | X | C | V | B | | N | M | , | . | / | ESC | +// | GUI | LWR | SPC | | ENT | RSE | ALT | + bindings = < + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSPC + &kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp ESC + &kp LGUI &mo 1 &kp SPACE &kp RET &mo 2 &kp RALT + >; + }; + lower_layer { +// ----------------------------------------------------------------------------------------- +// | TAB | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | BKSP | +// | BTCLR| BT1 | BT2 | BT3 | BT4 | BT5 | | LFT | DWN | UP | RGT | | | +// | SHFT | | | | | | | | | | | | | +// | GUI | | SPC | | ENT | | ALT | + bindings = < + &kp TAB &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp BSPC + &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &kp LEFT &kp DOWN &kp UP &kp RIGHT &trans &trans + &kp LSHFT &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &kp LGUI &trans &kp SPACE &kp RET &trans &kp RALT + >; + }; + + raise_layer { +// ----------------------------------------------------------------------------------------- +// | TAB | ! | @ | # | $ | % | | ^ | & | * | ( | ) | BKSP | +// | CTRL | | | | | | | - | = | [ | ] | \ | ` | +// | SHFT | | | | | | | _ | + | { | } | "|" | ~ | +// | GUI | | SPC | | ENT | | ALT | + bindings = < + &kp TAB &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp KP_MULTIPLY &kp LPAR &kp RPAR &kp BSPC + &kp LCTRL &trans &trans &trans &trans &trans &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH &kp GRAVE + &kp LSHFT &trans &trans &trans &trans &trans &kp UNDER &kp PLUS &kp LBRC &kp RBRC &kp PIPE &kp TILDE + &kp LGUI &trans &kp SPACE &kp RET &trans &kp RALT + >; + }; + }; +}; diff --git a/app/boards/shields/corne/corne.zmk.yml b/app/boards/shields/corne/corne.zmk.yml new file mode 100644 index 000000000000..1e8a5fbb79b8 --- /dev/null +++ b/app/boards/shields/corne/corne.zmk.yml @@ -0,0 +1,14 @@ +file_format: "1" +id: corne +name: Corne +type: shield +url: https://github.com/foostan/crkbd/ +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - underglow +siblings: + - corne_left + - corne_right diff --git a/app/boards/shields/corne/corne_left.conf b/app/boards/shields/corne/corne_left.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/corne/corne_left.overlay b/app/boards/shields/corne/corne_left.overlay new file mode 100644 index 000000000000..117cb19efd9b --- /dev/null +++ b/app/boards/shields/corne/corne_left.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ + +#include "corne.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 21 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/corne/corne_right.conf b/app/boards/shields/corne/corne_right.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/corne/corne_right.overlay b/app/boards/shields/corne/corne_right.overlay new file mode 100644 index 000000000000..a8a0cfe7bf2e --- /dev/null +++ b/app/boards/shields/corne/corne_right.overlay @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ + +#include "corne.dtsi" + +&default_transform { + col-offset = <6>; +}; + +&five_column_transform { + col-offset = <6>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 21 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/cradio/Kconfig.defconfig b/app/boards/shields/cradio/Kconfig.defconfig new file mode 100644 index 000000000000..c5d03f4ee7af --- /dev/null +++ b/app/boards/shields/cradio/Kconfig.defconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_CRADIO_LEFT + +config ZMK_KEYBOARD_NAME + default "Cradio" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_CRADIO_LEFT || SHIELD_CRADIO_RIGHT + +config ZMK_SPLIT + default y + +endif diff --git a/app/boards/shields/cradio/Kconfig.shield b/app/boards/shields/cradio/Kconfig.shield new file mode 100644 index 000000000000..affb1c53c920 --- /dev/null +++ b/app/boards/shields/cradio/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_CRADIO_LEFT + def_bool $(shields_list_contains,cradio_left) + +config SHIELD_CRADIO_RIGHT + def_bool $(shields_list_contains,cradio_right) diff --git a/app/boards/shields/cradio/README.md b/app/boards/shields/cradio/README.md new file mode 100644 index 000000000000..2c4e2e6019d5 --- /dev/null +++ b/app/boards/shields/cradio/README.md @@ -0,0 +1,35 @@ +# Cradio + +Cradio is a firmware for a few 34 key keyboards, including Cradio, Hypergolic and Sweep. + +## Pin arrangement + +Some revisions of the aforementioned PCBs have slightly different pin arrangements compared to what's defined in [`cradio.dtsi`](./cradio.dtsi). If you need to swap a few keys for your particular PCB, you can easily reorder the `input-gpio` definition in your own keymap file (i.e. in `zmk-config/config/cradio.keymap`): + +```dts +/* Adjusted Cradio pin arrangement */ +/* The position of Q and B keys have been swapped */ +&kscan0 { + input-gpios + = <&pro_micro 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 18 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 19 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 20 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 21 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; +}; +``` + +This `&kscan0` block must be placed outside of any blocks surrounded by curly braces (`{...}`). diff --git a/app/boards/shields/cradio/cradio.conf b/app/boards/shields/cradio/cradio.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/cradio/cradio.dtsi b/app/boards/shields/cradio/cradio.dtsi new file mode 100644 index 000000000000..3f7ed01cc2c5 --- /dev/null +++ b/app/boards/shields/cradio/cradio.dtsi @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <34>; + rows = <1>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,21) RC(0,20) RC(0,19) RC(0,18) RC(0,17) + RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,26) RC(0,25) RC(0,24) RC(0,23) RC(0,22) + RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,31) RC(0,30) RC(0,29) RC(0,28) RC(0,27) + RC(0,15) RC(0,16) RC(0,33) RC(0,32) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-direct"; + input-gpios + = <&pro_micro 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 18 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 19 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 20 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 21 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; + }; + +}; diff --git a/app/boards/shields/cradio/cradio.keymap b/app/boards/shields/cradio/cradio.keymap new file mode 100644 index 000000000000..ab4591babb6d --- /dev/null +++ b/app/boards/shields/cradio/cradio.keymap @@ -0,0 +1,103 @@ +// Copyright (c) 2022 The ZMK Contributors +// SPDX-License-Identifier: MIT + +#include +#include +#include + +// Home row mods macro +#define HRML(k1,k2,k3,k4) &ht LSHFT k1 &ht LALT k2 &ht LCTRL k3 &ht LGUI k4 +#define HRMR(k1,k2,k3,k4) &ht RGUI k1 &ht RCTRL k2 &ht RALT k3 &ht RSHFT k4 + +/ { + behaviors { + ht: hold_tap { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <220>; + quick-tap-ms = <150>; + require-prior-idle-ms = <100>; + bindings = <&kp>, <&kp>; + }; + }; + + conditional_layers { + compatible = "zmk,conditional-layers"; + tri_layer { + if-layers = <1 2>; + then-layer = <3>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + default_layer { + bindings = < + //╭──────────┬──────────┬──────────┬──────────┬──────────╮ ╭──────────┬──────────┬──────────┬──────────┬──────────╮ + //│ Q │ W │ E │ R │ T │ │ Y │ U │ I │ O │ P │ + &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P + //├──────────┼──────────┼──────────┼──────────┼──────────┤ ├──────────┼──────────┼──────────┼──────────┼──────────┤ + //│ A │ S │ D │ F │ G │ │ H │ J │ K │ L │ ' " │ + HRML(A, S, D, F) &kp G &kp H HRMR(J, K, L, SQT) + //├──────────┼──────────┼──────────┼──────────┼──────────┤ ├──────────┼──────────┼──────────┼──────────┼──────────┤ + //│ Z │ X │ C │ V │ B │ │ N │ M │ , < │ . > │ / ? │ + &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH + //╰──────────┴──────────┴──────────┼──────────┼──────────┤ ├──────────┼──────────┼──────────┴──────────┴──────────╯ + < 2 TAB &kp ENTER &kp SPACE < 1 BSPC + // ╰──────────┴──────────╯ ╰──────────┴──────────╯ + >; + }; + + right_layer { + bindings = < + //╭──────────┬──────────┬──────────┬──────────┬──────────╮ ╭──────────┬──────────┬──────────┬──────────┬──────────╮ + //│ INSERT │ 1 │ 2 │ 3 │ │ │ HOME │ PAGE DN │ PAGE UP │ END │ : │ + &kp INS &kp N1 &kp N2 &kp N3 &trans &kp HOME &kp PG_DN &kp PG_UP &kp END &kp COLON + //├──────────┼──────────┼──────────┼──────────┼──────────┤ ├──────────┼──────────┼──────────┼──────────┼──────────┤ + //│ DELETE │ 4 │ 5 │ 6 │ │ │ LEFT │ DOWN │ UP │ RIGHT │ ; │ + &kp DEL &kp N4 &kp N5 &kp N6 &trans &kp LARW &kp DARW &kp UARW &kp RARW &kp SEMI + //├──────────┼──────────┼──────────┼──────────┼──────────┤ ├──────────┼──────────┼──────────┼──────────┼──────────┤ + //│ CAPS │ 7 │ 8 │ 9 │ 0 │ │ │ │ │ │ │ + &caps_word &kp N7 &kp N8 &kp N9 &kp N0 &trans &trans &trans &trans &trans + //╰──────────┴──────────┴──────────┼──────────┼──────────┤ ├──────────┼──────────┼──────────┴──────────┴──────────╯ + &trans &kp ESC &trans &trans + // ╰──────────┴──────────╯ ╰──────────┴──────────╯ + >; + }; + + left_layer { + bindings = < + //╭──────────┬──────────┬──────────┬──────────┬──────────╮ ╭──────────┬──────────┬──────────┬──────────┬──────────╮ + //│ │ [ │ { │ } │ │ │ ^ │ ( │ ) │ ] │ ~ │ + &trans &kp LBKT &kp LBRC &kp RBRC &trans &kp CARET &kp LPAR &kp RPAR &kp RBKT &kp TILDE + //├──────────┼──────────┼──────────┼──────────┼──────────┤ ├──────────┼──────────┼──────────┼──────────┼──────────┤ + //│ ! │ @ │ # │ $ │ % │ │ * │ - │ = │ \ │ ` │ + &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp ASTRK &kp MINUS &kp EQUAL &kp BSLH &kp GRAVE + //├──────────┼──────────┼──────────┼──────────┼──────────┤ ├──────────┼──────────┼──────────┼──────────┼──────────┤ + //│ │ │ │ │ │ │ & │ _ │ + │ │ │ │ + &trans &trans &trans &trans &trans &kp AMPS &kp UNDER &kp PLUS &kp PIPE &trans + //╰──────────┴──────────┴──────────┼──────────┼──────────┤ ├──────────┼──────────┼──────────┴──────────┴──────────╯ + &trans &trans &trans &trans + // ╰──────────┴──────────╯ ╰──────────┴──────────╯ + >; + }; + + tri_layer { + bindings = < + //╭──────────┬──────────┬──────────┬──────────┬──────────╮ ╭──────────┬──────────┬──────────┬──────────┬──────────╮ + //│ RESET │ │ │ │PROFILE 0 │ │ │ │ │ │ RESET │ + &sys_reset &trans &trans &trans &bt BT_SEL 0 &trans &trans &trans &trans &sys_reset + //├──────────┼──────────┼──────────┼──────────┼──────────┤ ├──────────┼──────────┼──────────┼──────────┼──────────┤ + //│BOOTLOADER│ │ │ │PROFILE 1 │ │ │ │ │ │BOOTLOADER│ + &bootloader &trans &trans &trans &bt BT_SEL 1 &trans &trans &trans &trans &bootloader + //├──────────┼──────────┼──────────┼──────────┼──────────┤ ├──────────┼──────────┼──────────┼──────────┼──────────┤ + //│ │ │ │ CLEAR BT │PROFILE 2 │ │ │ │ │ │ │ + &trans &trans &trans &bt BT_CLR &bt BT_SEL 2 &trans &trans &trans &trans &trans + //╰──────────┴──────────┴──────────┼──────────┼──────────┤ ├──────────┼──────────┼──────────┴──────────┴──────────╯ + &trans &trans &trans &trans + // ╰──────────┴──────────╯ ╰──────────┴──────────╯ + >; + }; + }; +}; diff --git a/app/boards/shields/cradio/cradio.zmk.yml b/app/boards/shields/cradio/cradio.zmk.yml new file mode 100644 index 000000000000..76cf1ab283d6 --- /dev/null +++ b/app/boards/shields/cradio/cradio.zmk.yml @@ -0,0 +1,12 @@ +file_format: "1" +id: cradio +name: Cradio/Sweep +type: shield +url: https://github.com/davidphilipbarr/Sweep +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys +siblings: + - cradio_left + - cradio_right diff --git a/app/boards/shields/cradio/cradio_left.conf b/app/boards/shields/cradio/cradio_left.conf new file mode 100644 index 000000000000..c9f7988a7df5 --- /dev/null +++ b/app/boards/shields/cradio/cradio_left.conf @@ -0,0 +1,2 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT diff --git a/app/boards/shields/cradio/cradio_left.overlay b/app/boards/shields/cradio/cradio_left.overlay new file mode 100644 index 000000000000..96867c415c26 --- /dev/null +++ b/app/boards/shields/cradio/cradio_left.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "cradio.dtsi" diff --git a/app/boards/shields/cradio/cradio_right.conf b/app/boards/shields/cradio/cradio_right.conf new file mode 100644 index 000000000000..c9f7988a7df5 --- /dev/null +++ b/app/boards/shields/cradio/cradio_right.conf @@ -0,0 +1,2 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT diff --git a/app/boards/shields/cradio/cradio_right.overlay b/app/boards/shields/cradio/cradio_right.overlay new file mode 100644 index 000000000000..fea9ae1ccd78 --- /dev/null +++ b/app/boards/shields/cradio/cradio_right.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "cradio.dtsi" + +&default_transform { + col-offset = <17>; +}; diff --git a/app/boards/shields/crbn/Kconfig.defconfig b/app/boards/shields/crbn/Kconfig.defconfig new file mode 100644 index 000000000000..c00e97a41ee7 --- /dev/null +++ b/app/boards/shields/crbn/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_CRBN + +config ZMK_KEYBOARD_NAME + default "CRBN" + +endif diff --git a/app/boards/shields/crbn/Kconfig.shield b/app/boards/shields/crbn/Kconfig.shield new file mode 100644 index 000000000000..bf92dbf1ea54 --- /dev/null +++ b/app/boards/shields/crbn/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_CRBN + def_bool $(shields_list_contains,crbn) diff --git a/app/boards/shields/crbn/crbn.conf b/app/boards/shields/crbn/crbn.conf new file mode 100644 index 000000000000..15f65fb1248e --- /dev/null +++ b/app/boards/shields/crbn/crbn.conf @@ -0,0 +1,3 @@ +# Uncomment lines below to enable encoder +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y \ No newline at end of file diff --git a/app/boards/shields/crbn/crbn.keymap b/app/boards/shields/crbn/crbn.keymap new file mode 100644 index 000000000000..f963ba844349 --- /dev/null +++ b/app/boards/shields/crbn/crbn.keymap @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + // ----------------------------------------------------------------------------------------- + // | TAB | Q | W | E | R | T | Y | U | I | O | P | BSPC | + // | ESC | A | S | D | F | G | H | J | K | L | ; | ' | + // | SHIFT | Z | X | C | V | B | N | M | , | . | / | RET | + // | | LCTL | LALT | LGUI | LOWR | SPACE | RAIS | LARW | DARW | UARW | RARW | + bindings = < + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSPC + &kp ESC &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp SLASH &kp RET + &trans &kp LCTL &kp LALT &kp LGUI &mo 1 &kp SPACE &trans &mo 2 &kp LEFT &kp DOWN &kp UP &kp RIGHT + >; + + sensor-bindings = <&inc_dec_kp PG_UP PG_DN>; + }; + + lower { + bindings = < + &kp LS(GRAVE) &kp LS(N1) &kp LS(N2) &kp LS(N3) &kp LS(N4) &kp LS(N5) &kp LS(N6) &kp LS(N7) &kp LS(N8) &kp LS(N9) &kp LS(N0) &kp DEL + &kp DEL &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp UNDER &kp PLUS &kp LBRC &kp RBRC &kp PIPE + &trans &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp LS(HASH) &kp LS(BSLH) &kp HOME &kp END &trans + &trans &trans &trans &trans &trans &trans &trans &mo 3 &kp C_NEXT &kp C_VOL_DN &kp C_VOL_UP &kp C_PP + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + raise { + bindings = < + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp BSPC + &kp DEL &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH + &trans &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp HASH &kp BSLH &kp PG_UP &kp PG_DN &trans + &trans &trans &trans &trans &mo 3 &trans &trans &trans &kp C_NEXT &kp C_VOL_DN &kp C_VOL_UP &kp C_PP + >; + + sensor-bindings = <&inc_dec_kp PG_UP PG_DN>; + }; + + control { + bindings = < + &sys_reset &bootloader &bt BT_CLR &bt BT_PRV &bt BT_NXT &trans &trans &trans &trans &trans &trans &trans + &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + }; + }; +}; diff --git a/app/boards/shields/crbn/crbn.overlay b/app/boards/shields/crbn/crbn.overlay new file mode 100644 index 000000000000..5cc9ec6c1d59 --- /dev/null +++ b/app/boards/shields/crbn/crbn.overlay @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + }; + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + col-gpios + = <&pro_micro 1 GPIO_ACTIVE_HIGH> + , <&pro_micro 0 GPIO_ACTIVE_HIGH> + , <&pro_micro 2 GPIO_ACTIVE_HIGH> + , <&pro_micro 3 GPIO_ACTIVE_HIGH> + , <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; + + encoder: encoder { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + resolution = <2>; + status = "okay"; + }; + + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&encoder>; + }; +}; diff --git a/app/boards/shields/crbn/crbn.zmk.yml b/app/boards/shields/crbn/crbn.zmk.yml new file mode 100644 index 000000000000..baa73ea066d1 --- /dev/null +++ b/app/boards/shields/crbn/crbn.zmk.yml @@ -0,0 +1,9 @@ +file_format: "1" +id: crbn +name: CRBN Featherlight +type: shield +url: https://github.com/PolarityWorks/CRBN-Featherlight +requires: [pro_micro] +features: + - keys + - encoder diff --git a/app/boards/shields/eek/Kconfig.defconfig b/app/boards/shields/eek/Kconfig.defconfig new file mode 100644 index 000000000000..b84dd2886104 --- /dev/null +++ b/app/boards/shields/eek/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_EEK + +config ZMK_KEYBOARD_NAME + default "eek! ~ Keyboard" + +endif \ No newline at end of file diff --git a/app/boards/shields/eek/Kconfig.shield b/app/boards/shields/eek/Kconfig.shield new file mode 100644 index 000000000000..220b63eaf749 --- /dev/null +++ b/app/boards/shields/eek/Kconfig.shield @@ -0,0 +1,8 @@ + # + # Copyright (c) 2020 The ZMK Contributors + # + # SPDX-License-Identifier: MIT + # + +config SHIELD_EEK + def_bool $(shields_list_contains,eek) \ No newline at end of file diff --git a/app/boards/shields/eek/README.md b/app/boards/shields/eek/README.md new file mode 100644 index 000000000000..2a1b46b4916e --- /dev/null +++ b/app/boards/shields/eek/README.md @@ -0,0 +1 @@ +A fixed split 36key-board with a typing angle of 90 degrees distributed by cbkbd diff --git a/app/boards/shields/eek/eek.conf b/app/boards/shields/eek/eek.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/eek/eek.keymap b/app/boards/shields/eek/eek.keymap new file mode 100644 index 000000000000..74ecc4071e94 --- /dev/null +++ b/app/boards/shields/eek/eek.keymap @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default { +// -------------------------------------------------------------------------------------------------------------------------------------------------------------------- +// Q | W | E | R | T | | Y | U | I | O | P | +// A | S | D | F | G | | H | J | K | L | ; | +// Lsft/Z| X | C | V | B | | N | M | , | . |Rsft//| +// | LCTL | Bspc/LMOD | SPC | | Del/Num | Ent | Sym | + bindings = < + &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P + &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI + &mt LSHFT Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &mt RSHFT FSLH + &kp LCTRL &mt LGUI BSPC &kp SPACE < 1 DEL &kp RET &mo 2 + >; + }; + numbers { +// -------------------------------------------------------------------------------------------------------------------------------------------------------------------- +// 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | +// TAB | BT_PRV | BT_NXT | VOL-| VOL+| | < | v | ∧ | > | ' | +// Lsft| BT_SEL0| BT_CLR | MUTE| | | HOME| END | PGUP| PGDN| Rsft| +// | LCTL | LMOD| LALT | | Num | | BL-reset | + bindings = < + &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 + &kp TAB &bt BT_PRV &bt BT_NXT &kp C_VOL_DN &kp C_VOL_UP &kp LEFT &kp DOWN &kp UP &kp RIGHT &kp SQT + &kp LSHFT &bt BT_SEL 0 &bt BT_CLR &kp C_MUTE &none &kp HOME &kp END &kp PG_UP &kp PG_DN &kp RSHFT + &kp LCTRL &kp LGUI &kp LALT &trans &none &bootloader + >; + }; + symbols { +// -------------------------------------------------------------------------------------------------------------------------------------------------------------------- +// ESC | F1 | F2 | F3 | F4 | | OUT_USB | OUT_BLE | | = | - | +// CAPS| F5 | F6 | F7 | F8 | | [ | ] | | ` | \ | +// LSFT| F9 | F10 | F11 | F12 | | | | | | RSFT | +// | LCTL | LMOD| LALT | | RESET | | SYM | + bindings = < + &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &out OUT_USB &out OUT_BLE &none &kp EQUAL &kp MINUS + &kp CAPS &kp F5 &kp F6 &kp F7 &kp F8 &kp LBKT &kp RBKT &none &kp GRAVE &kp BSLH + &kp LSHFT &kp F9 &kp F10 &kp F11 &kp F12 &none &none &none &none &kp RSHFT + &kp LCTRL &kp LGUI &kp LALT &sys_reset &none &trans + >; + }; + }; +}; diff --git a/app/boards/shields/eek/eek.overlay b/app/boards/shields/eek/eek.overlay new file mode 100644 index 000000000000..8ec6714e033a --- /dev/null +++ b/app/boards/shields/eek/eek.overlay @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <10>; + rows = <4>; + map = < + RC(0,9) RC(0,8) RC(0,7) RC(0,6) RC(0,5) RC(0,4) RC(0,3) RC(0,2) RC(0,1) RC(0,0) + RC(1,9) RC(1,8) RC(1,7) RC(1,6) RC(1,5) RC(1,4) RC(1,3) RC(1,2) RC(1,1) RC(1,0) + RC(2,9) RC(2,8) RC(2,7) RC(2,6) RC(2,5) RC(2,4) RC(2,3) RC(2,2) RC(2,1) RC(2,0) + RC(3,7) RC(3,6) RC(3,5) RC(3,4) RC(3,3) RC(3,2) + >; + }; + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + col-gpios + = <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 21 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/eek/eek.zmk.yml b/app/boards/shields/eek/eek.zmk.yml new file mode 100644 index 000000000000..bac88f636d62 --- /dev/null +++ b/app/boards/shields/eek/eek.zmk.yml @@ -0,0 +1,8 @@ +file_format: "1" +id: eek +name: eek! +type: shield +url: https://github.com/Klackygears/eek_doc +requires: [pro_micro] +features: + - keys diff --git a/app/boards/shields/elephant42/Kconfig.defconfig b/app/boards/shields/elephant42/Kconfig.defconfig new file mode 100644 index 000000000000..70a312c10d55 --- /dev/null +++ b/app/boards/shields/elephant42/Kconfig.defconfig @@ -0,0 +1,49 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_ELEPHANT42_LEFT + +config ZMK_KEYBOARD_NAME + default "Elephant42" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_ELEPHANT42_LEFT || SHIELD_ELEPHANT42_RIGHT + +config ZMK_SPLIT + default y + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif \ No newline at end of file diff --git a/app/boards/shields/elephant42/Kconfig.shield b/app/boards/shields/elephant42/Kconfig.shield new file mode 100644 index 000000000000..258418684d64 --- /dev/null +++ b/app/boards/shields/elephant42/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_ELEPHANT42_LEFT + def_bool $(shields_list_contains,elephant42_left) + +config SHIELD_ELEPHANT42_RIGHT + def_bool $(shields_list_contains,elephant42_right) \ No newline at end of file diff --git a/app/boards/shields/elephant42/boards/nice_nano.overlay b/app/boards/shields/elephant42/boards/nice_nano.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/elephant42/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/elephant42/boards/nice_nano_v2.overlay b/app/boards/shields/elephant42/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/elephant42/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/elephant42/elephant42.conf b/app/boards/shields/elephant42/elephant42.conf new file mode 100644 index 000000000000..1b41763fa600 --- /dev/null +++ b/app/boards/shields/elephant42/elephant42.conf @@ -0,0 +1,6 @@ +# Uncomment the following lines to enable the Elephant42 RGB Underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y + +# Uncomment the following line to enable the Elephant42 OLED Display +# CONFIG_ZMK_DISPLAY=y \ No newline at end of file diff --git a/app/boards/shields/elephant42/elephant42.dtsi b/app/boards/shields/elephant42/elephant42.dtsi new file mode 100644 index 000000000000..d364bef9a09e --- /dev/null +++ b/app/boards/shields/elephant42/elephant42.dtsi @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <12>; + rows = <4>; + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) + RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) + RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + }; +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/elephant42/elephant42.keymap b/app/boards/shields/elephant42/elephant42.keymap new file mode 100644 index 000000000000..62484728ff81 --- /dev/null +++ b/app/boards/shields/elephant42/elephant42.keymap @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +#define LOWR 1 +#define RAIS 2 +#define ADJT 3 + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + < ADJT ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp DEL + &mt LCTRL TAB &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH + &kp LSHFT &mo LOWR &kp LGUI &kp BSPC &kp SPACE &kp ENTER &mo RAIS &kp LALT + >; + }; + + lower { + bindings = < + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp C_PLAY_PAUSE + &trans &trans &trans &trans &trans &trans &kp LEFT &kp DOWN &kp UP &kp RIGHT &trans &trans + &trans &trans &trans &trans &kp LBKT &kp RBKT &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans + >; + }; + raise { + bindings = < + &kp TILDE &trans &trans &trans &trans &trans &trans &trans &trans &kp MINUS &kp EQUAL &kp C_PLAY_PAUSE + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp BSLH + &trans &trans &trans &trans &kp LBKT &kp RBKT &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans + >; + }; + + adjust { + bindings = < + &trans &bt BT_NXT &bt BT_PRV &trans &trans &bt BT_CLR &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &out OUT_TOG &trans &trans &trans &trans &trans &trans &trans + >; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/elephant42/elephant42.zmk.yml b/app/boards/shields/elephant42/elephant42.zmk.yml new file mode 100644 index 000000000000..60eb377793b2 --- /dev/null +++ b/app/boards/shields/elephant42/elephant42.zmk.yml @@ -0,0 +1,14 @@ +file_format: "1" +id: elephant42 +name: Elephant42 +type: shield +url: https://github.com/illness072/elephant42 +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - underglow +siblings: + - elephant42_left + - elephant42_right diff --git a/app/boards/shields/elephant42/elephant42_left.overlay b/app/boards/shields/elephant42/elephant42_left.overlay new file mode 100644 index 000000000000..104734389bbf --- /dev/null +++ b/app/boards/shields/elephant42/elephant42_left.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "elephant42.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 21 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + ; +}; \ No newline at end of file diff --git a/app/boards/shields/elephant42/elephant42_right.overlay b/app/boards/shields/elephant42/elephant42_right.overlay new file mode 100644 index 000000000000..c8f69a04a539 --- /dev/null +++ b/app/boards/shields/elephant42/elephant42_right.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "elephant42.dtsi" + +&default_transform { + col-offset = <6>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 21 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/ergodash/Kconfig.defconfig b/app/boards/shields/ergodash/Kconfig.defconfig new file mode 100644 index 000000000000..34a87e8e311e --- /dev/null +++ b/app/boards/shields/ergodash/Kconfig.defconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_ERGODASH_LEFT + +config ZMK_KEYBOARD_NAME + default "Ergodash" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_ERGODASH_LEFT || SHIELD_ERGODASH_RIGHT + +config ZMK_SPLIT + default y + +endif diff --git a/app/boards/shields/ergodash/Kconfig.shield b/app/boards/shields/ergodash/Kconfig.shield new file mode 100644 index 000000000000..5814e21ef556 --- /dev/null +++ b/app/boards/shields/ergodash/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_ERGODASH_LEFT + def_bool $(shields_list_contains,ergodash_left) + +config SHIELD_ERGODASH_RIGHT + def_bool $(shields_list_contains,ergodash_right) diff --git a/app/boards/shields/ergodash/ergodash.conf b/app/boards/shields/ergodash/ergodash.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/ergodash/ergodash.dtsi b/app/boards/shields/ergodash/ergodash.dtsi new file mode 100644 index 000000000000..7b9ac0125c21 --- /dev/null +++ b/app/boards/shields/ergodash/ergodash.dtsi @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <14>; + rows = <5>; +// Numbering based on rev 1.2 schema +// * keys that can be in different positions are denoted as MW +// * MW40 can be broken off +// | SW1 | SW5 | SW9 | SW13 | SW17 | SW21 | SW25 | | | | SW25 | SW21 | SW17 | SW13 | SW9 | SW5 | SW1 | +// | SW2 | SW6 | SW10 | SW14 | SW18 | SW22 | SW26 | | | | SW26 | SW22 | SW18 | SW14 | SW10 | SW6 | SW2 | +// | SW3 | SW7 | SW11 | SW15 | SW19 | SW23 | SW27 | | | | SW27 | SW23 | SW19 | SW15 | SW11 | SW7 | SW3 | +// | SW4 | SW8 | SW12 | SW16 | SW20 | SW24 | | MW28 | | MW28 | | SW24 | SW20 | SW16 | SW12 | SW8 | SW4 | +// | SW30 | SW31 | SW32 | MW33 | SW34 | | MW35 | MW40 | | MW40 | MW35 | | SW34 | MW33 | SW32 | SW31 | SW30 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,13) RC(0,12) RC(0,11) RC(0,10) RC(0,9) RC(0,8) RC(0,7) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,13) RC(1,12) RC(1,11) RC(1,10) RC(1,9) RC(1,8) RC(1,7) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,13) RC(2,12) RC(2,11) RC(2,10) RC(2,9) RC(2,8) RC(2,7) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,13) RC(3,12) RC(3,11) RC(3,10) RC(3,9) RC(3,8) RC(3,7) +RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,13) RC(4,12) RC(4,11) RC(4,10) RC(4,9) RC(4,8) RC(4,7) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + col-gpios + = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; + diff --git a/app/boards/shields/ergodash/ergodash.keymap b/app/boards/shields/ergodash/ergodash.keymap new file mode 100644 index 000000000000..e384e504fbea --- /dev/null +++ b/app/boards/shields/ergodash/ergodash.keymap @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +#define DEFAULT 0 +#define LOWER 1 +#define RAISE 2 + + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +/* QWERTY + * .----------------------------------------------------------------------------------------------------------------------. + * | ` | 1 | 2 | 3 | 4 | 5 | [ | | ] | 6 | 7 | 8 | 9 | 0 | PScr | + * |------+------+------+------+------+------+------+--------------------+------+------+------+------+------+------+------| + * | ESC | Q | W | E | R | T | - | | = | Y | U | I | O | P | \ | + * |------+------+------+------+------+------+------+--------------------+------+------+------+------+------+------+------| + * | Tab | A | S | D | F | G | Del | | Bksp | H | J | K | L | ; | ' | + * |------+------+------+------+------+------+---------------------------+------+------+------+------+------+------+------| + * | Shift| Z | X | C | V | B | End | | Home | N | M | , | . | / | Shift| + * |-------------+------+------+------+------+------+------+------+------+------+------+------+------+------+-------------| + * | Ctrl | | PGDN | Win |||||||| Alt | Space| Lower|||||||| Raise| Enter| RAlt |||||||| | PGUP | Ins | RCtrl| + * .----------------------------------------------------------------------------------------------------------------------. + */ + bindings = < +&kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp LBKT &kp RBKT &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp PSCRN +&kp ESC &kp Q &kp W &kp E &kp R &kp T &kp MINUS &kp EQUAL &kp Y &kp U &kp I &kp O &kp P &kp BSLH +&kp TAB &kp A &kp S &kp D &kp F &kp G &kp DEL &kp BSPC &kp H &kp J &kp K &kp L &kp SEMI &kp SQT +&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp END &kp HOME &kp N &kp M &kp COMMA &kp DOT &kp SLASH &kp RSHFT +&kp LCTRL &none &kp PG_DN &kp LMETA &kp LALT &kp SPACE &mo LOWER &mo RAISE &kp RET &kp RALT &none &kp PG_UP &kp INS &kp RCTRL + >; + }; + lower_layer { +/* .----------------------------------------------------------------------------------------------------------------------. + * | F11 | F1 | F2 | F3 | F4 | F5 | | | | F6 | F7 | F8 | F9 | F10 | F12 | + * |------+------+------+------+------+------+------+--------------------+------+------+------+------+------+------+------| + * | | | | | | | | | | | | | | | | + * |------+------+------+------+------+------+------+--------------------+------+------+------+------+------+------+------| + * | | | | | | | | | | | | | | | | + * |------+------+------+------+------+------+---------------------------+------+------+------+------+------+------+------| + * | Shift| Boot | Reset| | | | | | | | | | | | Shift| + * |-------------+------+------+------+------+------+------+------+------+------+------+------+------+------+-------------| + * | Ctlr | | | Win |||||||| Alt | | Lower|||||||| Raise| | RAlt |||||||| | | | RCtrl| + * .----------------------------------------------------------------------------------------------------------------------. + */ /* FIXME boot and reset are not yet locale aware */ + bindings = < +&kp F11 &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &none &none &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F12 +&none &none &none &none &none &none &none &none &none &none &none &none &none &none +&none &none &none &none &none &none &none &none &none &none &none &none &none &none +&trans &bootloader &sys_reset &none &none &none &none &none &none &none &none &none &none &trans +&trans &none &none &trans &trans &none &trans &trans &none &trans &none &none &none &trans + >; + }; + raise_layer { +/* .----------------------------------------------------------------------------------------------------------------------. + * | | BT 0 | BT 1 | BT 2 | BT 3 | | BTCL | | | | | | | | | + * |------+------+------+------+------+------+------+--------------------+------+------+------+------+------+------+------| + * | | | | | | | | | | | | | | | | + * |------+------+------+------+------+------+------+--------------------+------+------+------+------+------+------+------| + * | | | | | | | | | | | | | | | | + * |------+------+------+------+------+------+---------------------------+------+------+------+------+------+------+------| + * | Shift| | | | | | | | | | | | Boot | Reset| Shift| + * |-------------+------+------+------+------+------+------+------+------+------+------+------+------+------+-------------| + * | Ctlr | | | Win |||||||| Alt | | Lower|||||||| Raise| | RAlt |||||||| | | | RCtrl| + * .----------------------------------------------------------------------------------------------------------------------. + */ /* FIXME boot and reset are not yet locale aware */ + bindings = < +&none &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &none &bt BT_CLR &none &none &none &none &none &none &none +&none &none &none &none &none &none &none &none &none &none &none &none &none &none +&none &none &none &none &none &none &none &none &none &none &none &none &none &none +&trans &none &none &none &none &none &none &none &none &none &none &bootloader &sys_reset &trans +&trans &none &none &trans &trans &none &trans &trans &none &trans &none &none &none &trans + >; + }; + }; +}; + diff --git a/app/boards/shields/ergodash/ergodash.zmk.yml b/app/boards/shields/ergodash/ergodash.zmk.yml new file mode 100644 index 000000000000..376831a67863 --- /dev/null +++ b/app/boards/shields/ergodash/ergodash.zmk.yml @@ -0,0 +1,11 @@ +file_format: "1" +id: ergodash +name: Ergodash +type: shield +url: https://github.com/omkbd/ErgoDash +requires: [pro_micro] +features: + - keys +siblings: + - ergodash_left + - ergodash_right diff --git a/app/boards/shields/ergodash/ergodash_left.overlay b/app/boards/shields/ergodash/ergodash_left.overlay new file mode 100644 index 000000000000..40263aa4b5d0 --- /dev/null +++ b/app/boards/shields/ergodash/ergodash_left.overlay @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "ergodash.dtsi" + diff --git a/app/boards/shields/ergodash/ergodash_right.overlay b/app/boards/shields/ergodash/ergodash_right.overlay new file mode 100644 index 000000000000..07fbbb70bf96 --- /dev/null +++ b/app/boards/shields/ergodash/ergodash_right.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "ergodash.dtsi" + +&default_transform { + col-offset = <7>; +}; diff --git a/app/boards/shields/eternal_keypad/Kconfig.defconfig b/app/boards/shields/eternal_keypad/Kconfig.defconfig new file mode 100644 index 000000000000..725141921ca1 --- /dev/null +++ b/app/boards/shields/eternal_keypad/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_ETERNAL_KEYPAD || SHIELD_ETERNAL_KEYPAD_LEFTY + +config ZMK_KEYBOARD_NAME + default "Eternal Keypad" + +endif diff --git a/app/boards/shields/eternal_keypad/Kconfig.shield b/app/boards/shields/eternal_keypad/Kconfig.shield new file mode 100644 index 000000000000..2301515396f9 --- /dev/null +++ b/app/boards/shields/eternal_keypad/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_ETERNAL_KEYPAD + def_bool $(shields_list_contains,eternal_keypad) + +config SHIELD_ETERNAL_KEYPAD_LEFTY + def_bool $(shields_list_contains,eternal_keypad_lefty) diff --git a/app/boards/shields/eternal_keypad/README.md b/app/boards/shields/eternal_keypad/README.md new file mode 100644 index 000000000000..4b217c5fdc53 --- /dev/null +++ b/app/boards/shields/eternal_keypad/README.md @@ -0,0 +1,10 @@ +# Eternal Keypad + +Eternal Keypad is an open-source input device for gaming that can be assembled for both right and left hand mouse users. + +Firmware is described in the [Eternal Keypad](https://github.com/duckyb/eternal-keypad) repository [README](https://github.com/duckyb/eternal-keypad#firmware). + +Two keymaps are included: + +- eternal_keypad (default) +- eternal_keypad_lefty (for left handed users) diff --git a/app/boards/shields/eternal_keypad/boards/nice_nano.overlay b/app/boards/shields/eternal_keypad/boards/nice_nano.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/eternal_keypad/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/eternal_keypad/boards/nice_nano_v2.overlay b/app/boards/shields/eternal_keypad/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/eternal_keypad/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/eternal_keypad/eternal_keypad.conf b/app/boards/shields/eternal_keypad/eternal_keypad.conf new file mode 100644 index 000000000000..65fa295516d7 --- /dev/null +++ b/app/boards/shields/eternal_keypad/eternal_keypad.conf @@ -0,0 +1,9 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Uncomment to turn on logging, and set ZMK logging to debug output +# CONFIG_ZMK_USB_LOGGING=y + +# Uncomment the following lines to enable RGB underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y diff --git a/app/boards/shields/eternal_keypad/eternal_keypad.dtsi b/app/boards/shields/eternal_keypad/eternal_keypad.dtsi new file mode 100644 index 000000000000..14e877e54f5f --- /dev/null +++ b/app/boards/shields/eternal_keypad/eternal_keypad.dtsi @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + col-gpios + = <&pro_micro 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <8>; + rows = <5>; + map = < + RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) + RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,5) RC(4,7) + >; + }; +}; diff --git a/app/boards/shields/eternal_keypad/eternal_keypad.keymap b/app/boards/shields/eternal_keypad/eternal_keypad.keymap new file mode 100644 index 000000000000..da06d2744c4e --- /dev/null +++ b/app/boards/shields/eternal_keypad/eternal_keypad.keymap @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +#define BASE 0 +#define ARROW 1 +#define FUNC 2 + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp N7 + &kp F13 &kp ENTER &kp A &kp S &kp D &kp F &kp G &kp N8 + &kp F14 &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N9 + &kp F15 &kp LCTRL &sl FUNC &kp LALT &kp SPACE < ARROW N0 + >; + }; + + arrow_layer { + bindings = < + &bt BT_SEL 0 &bt BT_SEL 1 &trans &trans &trans &out OUT_USB &out OUT_BLE + &trans &trans &kp UP &trans &rgb_ug RGB_TOG &rgb_ug RGB_HUI &rgb_ug RGB_HUD + &bt BT_CLR &trans &kp LEFT &kp DOWN &kp RIGHT &trans &rgb_ug RGB_BRI &rgb_ug RGB_BRD + &sys_reset &trans &trans &trans &trans &trans &rgb_ug RGB_EFF &rgb_ug RGB_EFR + &bootloader &trans &trans &trans &trans &trans + >; + }; + + function_layer { + bindings = < + &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 + &trans &kp P &kp O &kp I &kp U &kp Y &kp F7 + &bt BT_CLR &kp BSPC &kp SEMI &kp L &kp K &kp J &kp H &kp F8 + &sys_reset &trans &kp LGUI &kp M &kp N &kp F12 &kp F11 &kp F9 + &bootloader &trans &trans &trans &trans &kp F10 + >; + }; + }; +}; diff --git a/app/boards/shields/eternal_keypad/eternal_keypad.overlay b/app/boards/shields/eternal_keypad/eternal_keypad.overlay new file mode 100644 index 000000000000..4828baf73812 --- /dev/null +++ b/app/boards/shields/eternal_keypad/eternal_keypad.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "eternal_keypad.dtsi" diff --git a/app/boards/shields/eternal_keypad/eternal_keypad.zmk.yml b/app/boards/shields/eternal_keypad/eternal_keypad.zmk.yml new file mode 100644 index 000000000000..c5c86bc7c2e4 --- /dev/null +++ b/app/boards/shields/eternal_keypad/eternal_keypad.zmk.yml @@ -0,0 +1,9 @@ +file_format: "1" +id: eternal_keypad +name: Eternal Keypad +type: shield +url: https://github.com/duckyb/eternal-keypad +requires: [pro_micro] +features: + - keys + - underglow diff --git a/app/boards/shields/eternal_keypad/eternal_keypad_lefty.keymap b/app/boards/shields/eternal_keypad/eternal_keypad_lefty.keymap new file mode 100644 index 000000000000..817100321529 --- /dev/null +++ b/app/boards/shields/eternal_keypad/eternal_keypad_lefty.keymap @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +#define BASE 0 +#define ARROW 1 +#define FUNC 2 + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp N7 + &kp F13 &kp ENTER &kp D &kp S &kp A &kp F &kp G &kp N8 + &kp F14 &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N9 + &kp F15 &kp LCTRL &sl FUNC &kp LALT &kp SPACE < ARROW N0 + >; + }; + + arrow_layer { + bindings = < + &bt BT_SEL 0 &bt BT_SEL 1 &trans &trans &trans &out OUT_USB &out OUT_BLE + &trans &trans &kp UP &trans &rgb_ug RGB_TOG &rgb_ug RGB_HUI &rgb_ug RGB_HUD + &bt BT_CLR &trans &kp RIGHT &kp DOWN &kp RIGHT &trans &rgb_ug RGB_BRI &rgb_ug RGB_BRD + &sys_reset &trans &trans &trans &trans &trans &rgb_ug RGB_EFF &rgb_ug RGB_EFR + &bootloader &trans &trans &trans &trans &trans + >; + }; + + function_layer { + bindings = < + &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 + &trans &kp P &kp O &kp I &kp U &kp Y &kp F7 + &bt BT_CLR &kp BSPC &kp SEMI &kp L &kp K &kp J &kp H &kp F8 + &sys_reset &trans &kp LGUI &kp M &kp N &kp F12 &kp F11 &kp F9 + &bootloader &trans &trans &trans &trans &kp F10 + >; + }; + }; +}; diff --git a/app/boards/shields/eternal_keypad/eternal_keypad_lefty.overlay b/app/boards/shields/eternal_keypad/eternal_keypad_lefty.overlay new file mode 100644 index 000000000000..0c5599a16b8d --- /dev/null +++ b/app/boards/shields/eternal_keypad/eternal_keypad_lefty.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 202 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "eternal_keypad.dtsi" diff --git a/app/boards/shields/eternal_keypad/eternal_keypad_lefty.zmk.yml b/app/boards/shields/eternal_keypad/eternal_keypad_lefty.zmk.yml new file mode 100644 index 000000000000..9f5fb57858e8 --- /dev/null +++ b/app/boards/shields/eternal_keypad/eternal_keypad_lefty.zmk.yml @@ -0,0 +1,9 @@ +file_format: "1" +id: eternal_keypad_lefty +name: Eternal Keypad Lefty +type: shield +url: https://github.com/duckyb/eternal-keypad +requires: [pro_micro] +features: + - keys + - underglow diff --git a/app/boards/shields/fourier/Kconfig.defconfig b/app/boards/shields/fourier/Kconfig.defconfig new file mode 100644 index 000000000000..a07ca714961b --- /dev/null +++ b/app/boards/shields/fourier/Kconfig.defconfig @@ -0,0 +1,20 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + + +if SHIELD_FOURIER_LEFT + +config ZMK_KEYBOARD_NAME + default "Fourier" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_FOURIER_LEFT || SHIELD_FOURIER_RIGHT + +config ZMK_SPLIT + default y + +endif diff --git a/app/boards/shields/fourier/Kconfig.shield b/app/boards/shields/fourier/Kconfig.shield new file mode 100644 index 000000000000..ee28c7ace827 --- /dev/null +++ b/app/boards/shields/fourier/Kconfig.shield @@ -0,0 +1,9 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + + +config SHIELD_FOURIER_LEFT + def_bool $(shields_list_contains,fourier_left) + +config SHIELD_FOURIER_RIGHT + def_bool $(shields_list_contains,fourier_right) diff --git a/app/boards/shields/fourier/fourier.dtsi b/app/boards/shields/fourier/fourier.dtsi new file mode 100644 index 000000000000..fdd54901d82d --- /dev/null +++ b/app/boards/shields/fourier/fourier.dtsi @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + /* + * This transform correspondsto the 60% left without macro keypad and 65% right, even this + * combination of PCBs can have keys in different locations based on configuration. + */ + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <13>; + rows = <4>; + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) /**/ RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0, 11) RC(0,12) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) /**/ RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,12) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) /**/ RC(2,6) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) /**/ RC(3,6) RC(3,9) RC(3,10) RC(3,11) RC(3,12) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // Row A + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // Row B + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // Row C + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // Row D + ; + }; +}; diff --git a/app/boards/shields/fourier/fourier.keymap b/app/boards/shields/fourier/fourier.keymap new file mode 100644 index 000000000000..f0912bf1f73a --- /dev/null +++ b/app/boards/shields/fourier/fourier.keymap @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + +// ---------------------------------------------- ---------------------------------------------- +// | ESC | Q | W | E | R | T | | Y | U | I | O | P | | BKSP | +// | TAB | A | S | D | F | G | | H | J | K | L | ' | ENTER | +// | SHIFT | Z | X | C | V | B | | N | M | , | . | / | RSHFT | +// | LCTRL | LALT| LGUI | SPACE | | SPACE/L1 | L2 | RGUI | RALT |RCTRL| +// ------------------------------------------- ----------------------------------------------- + + default_layer { + bindings = < + &kp ESC &kp Q &kp W &kp E &kp R &kp T /**/ &kp Y &kp U &kp I &kp O &kp P &none &kp BACKSPACE + &kp TAB &kp A &kp S &kp D &kp F &kp G /**/ &kp H &kp J &kp K &kp L &kp SQT &kp ENTER + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B /**/ &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LCTRL &kp LALT &kp LGUI &none &kp SPACE /**/ < 1 SPACE &mo 2 &kp RGUI &kp RALT &kp RCTRL + >; + }; + +// ---------------------------------------------- ---------------------------------------------- +// | 1 | 2 | 3 | 4 | 5 | 6 | | 7 | 8 | 9 | O | PSCR | | DEL | +// | ` | | <- | ^ | -> | Vo+ | | [ | ] | - | = | ; | \ | +// | trans | | | | V | Vo- | | | | | | | trans | +// | trans | trans| trans | trans | | trans | trans | trans | trans|trans| +// ------------------------------------------- ----------------------------------------------- + + symbols_layer { + bindings = < + &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 /**/ &kp N7 &kp N8 &kp N9 &kp N0 &kp PSCRN &none &kp DEL + &kp GRAVE &none &kp LEFT &kp UP &kp RIGHT &kp C_VOL_UP /**/ &kp LBKT &kp RBKT &kp MINUS &kp EQUAL &kp SEMI &kp BACKSLASH + &trans &none &none &none &kp DOWN &kp C_VOL_DN /**/ &none &none &none &none &none &trans + &trans &trans &trans &none &trans /**/ &trans &trans &trans &trans &trans + >; + }; + +// ---------------------------------------------- ---------------------------------------------- +// | F1 | F2 | F3 | F4 | F5 | F6 | | F7 | F8 | F9 | F1O | F11 | | F12 | +// | CAP | | home| PgUp | End | | | | | | | | | +// | trans | RGB T | RGB M | PgDn | | | BT_NXT | BT_CLR | | | | |trans| +// | trans | trans| trans | trans | | trans | trans | trans | trans | trans | +// ------------------------------------------- ----------------------------------------------- + + fn_layer { + bindings = < + &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 /**/ &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &none &kp F12 + &kp CAPS &none &kp HOME &kp PG_UP &kp END &none /**/ &none &none &none &none &none &none + &trans &rgb_ug RGB_TOG &rgb_ug RGB_EFF &none &kp PG_DN &none /**/ &bt BT_NXT &bt BT_CLR &none &none &none &trans + &trans &trans &trans &none &trans /**/ &trans &trans &trans &trans &trans + >; + }; + }; +}; diff --git a/app/boards/shields/fourier/fourier.zmk.yml b/app/boards/shields/fourier/fourier.zmk.yml new file mode 100644 index 000000000000..d4e3b3ca958b --- /dev/null +++ b/app/boards/shields/fourier/fourier.zmk.yml @@ -0,0 +1,12 @@ +file_format: "1" +id: fourier +name: Fourier Rev. 1 +type: shield +url: https://github.com/keebio/fourier +requires: + - pro_micro +features: + - keys +siblings: + - fourier_left + - fourier_right diff --git a/app/boards/shields/fourier/fourier_left.overlay b/app/boards/shields/fourier/fourier_left.overlay new file mode 100644 index 000000000000..1d0f2c816272 --- /dev/null +++ b/app/boards/shields/fourier/fourier_left.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "fourier.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 20 GPIO_ACTIVE_HIGH> // Col1 + , <&pro_micro 19 GPIO_ACTIVE_HIGH> // Col2 + , <&pro_micro 18 GPIO_ACTIVE_HIGH> // Col3 + , <&pro_micro 15 GPIO_ACTIVE_HIGH> // Col4 + , <&pro_micro 14 GPIO_ACTIVE_HIGH> // Col5 + , <&pro_micro 16 GPIO_ACTIVE_HIGH> // Col6 + ; +}; diff --git a/app/boards/shields/fourier/fourier_right.overlay b/app/boards/shields/fourier/fourier_right.overlay new file mode 100644 index 000000000000..77c00d60ac0b --- /dev/null +++ b/app/boards/shields/fourier/fourier_right.overlay @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "fourier.dtsi" + +&default_transform { + col-offset = <6>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 20 GPIO_ACTIVE_HIGH> // Col1 + , <&pro_micro 19 GPIO_ACTIVE_HIGH> // Col2 + , <&pro_micro 18 GPIO_ACTIVE_HIGH> // Col3 + , <&pro_micro 15 GPIO_ACTIVE_HIGH> // Col4 + , <&pro_micro 14 GPIO_ACTIVE_HIGH> // Col5 + , <&pro_micro 16 GPIO_ACTIVE_HIGH> // Col6 + , <&pro_micro 10 GPIO_ACTIVE_HIGH> // Col7 + ; +}; diff --git a/app/boards/shields/helix/Kconfig.defconfig b/app/boards/shields/helix/Kconfig.defconfig new file mode 100644 index 000000000000..62d73c44c0dc --- /dev/null +++ b/app/boards/shields/helix/Kconfig.defconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_HELIX_LEFT + +config ZMK_KEYBOARD_NAME + default "Helix" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_HELIX_LEFT || SHIELD_HELIX_RIGHT + +config ZMK_SPLIT + default y + +endif \ No newline at end of file diff --git a/app/boards/shields/helix/Kconfig.shield b/app/boards/shields/helix/Kconfig.shield new file mode 100644 index 000000000000..7e5bb9aea3ac --- /dev/null +++ b/app/boards/shields/helix/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_HELIX_LEFT + def_bool $(shields_list_contains,helix_left) + +config SHIELD_HELIX_RIGHT + def_bool $(shields_list_contains,helix_right) \ No newline at end of file diff --git a/app/boards/shields/helix/README.md b/app/boards/shields/helix/README.md new file mode 100644 index 000000000000..f8b0e13f75a6 --- /dev/null +++ b/app/boards/shields/helix/README.md @@ -0,0 +1,12 @@ +#### Note to user: + +- If desired, RGB underglow must be manually enabled before building and flashing. Check 'helix.conf' to do so. +- Peripheral RGB function is impaired until full support is implemented in the master branch. +- OLED displays are not currently included in this shield. This will be updated after OLED support is live. +- 'KANA' and 'EISUU' input is currently utilized under the 'LANG1' and 'LANG2' keycodes respectively. + +--- + +Thanks to Nicell, KemoNine, petejohanson, TJ "Chormbo The Great", joelspadin/Rinh, Wofiel, Okke, innovaker, +and the rest of the ZMK contributors for their support in constructing this shield. I appreciate your assistance greatly. +This has been a valuable learning experience for me. May this contribution serve the community well. diff --git a/app/boards/shields/helix/boards/nice_nano.overlay b/app/boards/shields/helix/boards/nice_nano.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/helix/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/helix/boards/nice_nano_v2.overlay b/app/boards/shields/helix/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/helix/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/helix/helix.conf b/app/boards/shields/helix/helix.conf new file mode 100644 index 000000000000..a8e57338de1f --- /dev/null +++ b/app/boards/shields/helix/helix.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Enables RGB functionality (Uncomment lines below to enable.) +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y \ No newline at end of file diff --git a/app/boards/shields/helix/helix.dtsi b/app/boards/shields/helix/helix.dtsi new file mode 100644 index 000000000000..2ee68e0fab7d --- /dev/null +++ b/app/boards/shields/helix/helix.dtsi @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <14>; + rows = <5>; +// | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | +// | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | +// | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | +// | SW19 | SW20 | SW21 | SW22 | SW23 | SW24 | SW25 | | SW25 | SW24 | SW23 | SW22 | SW21 | SW20 | SW19 | +// | SW26 | SW27 | SW28 | SW29 | SW30 | SW31 | SW32 | | SW32 | SW31 | SW30 | SW29 | SW28 | SW27 | SW26 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) RC(3,13) +RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,13) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + }; +}; \ No newline at end of file diff --git a/app/boards/shields/helix/helix.keymap b/app/boards/shields/helix/helix.keymap new file mode 100644 index 000000000000..80678fe60925 --- /dev/null +++ b/app/boards/shields/helix/helix.keymap @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + #include + #include + #include + #include + #include + #include + + #define DEFAULT 0 + #define LOWER 1 + #define RAISE 2 + #define ADJUST 3 + +/* NOTE: At the time of the creation of this keymap, there are no specified codes for 'eisuu' and 'kana' input in ZMK. +However, 'LANG1' and 'LANG2' are fully-functioning candidates for 'kana' and 'eisuu' input respectively. +As such, those are in use within the default layer at this time.*/ + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + // --------------------------------------------------------------------------------------------------------------------------------- + // | GRAVE | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | DEL | + // | TAB | Q | W | E | R | T | | Y | U | I | O | P | BSPC | + // | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | + // | SHIFT | Z | X | C | V | B | LBKT | | RBKT | N | M | , | . | / | RET | + // | ADJUST | ESC | ALT | LGUI | EISUU | LOWER | SPACE | | SPACE | RAISE | KANA | LEFT | DOWN | UP | RIGHT | + bindings = < + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp DEL + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSPC + &kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LBKT &kp RBKT &kp N &kp M &kp COMMA &kp PERIOD &kp SLASH &kp RET + &mo ADJUST &kp ESC &kp LALT &kp LGUI &kp LANG2 &mo LOWER &kp SPACE &kp SPACE &mo RAISE &kp LANG1 &kp LEFT &kp DOWN &kp UP &kp RIGHT + >; + }; + lower_layer { + // --------------------------------------------------------------------------------------------------------------------------------- + // | | | | | | | | | | | | | | + // | ~ | ! | @ | # | $ | % | | ^ | & | * | ( | ) | | + // | | | | | | | | | _ | + | { | } | PIPE | + // | | | | | | | ( | | ) | | | | HOME | END | | + // | | | | | | | | | | | | | | | | + bindings = < + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &kp TILDE &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp ASTRK &kp LPAR &kp RPAR &trans + &trans &trans &trans &trans &trans &trans &trans &kp UNDER &kp PLUS &kp LBRC &kp RBRC &kp PIPE + &trans &trans &trans &trans &trans &trans &kp LPAR &kp RPAR &trans &trans &trans &kp HOME &kp END &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + }; + raise_layer { + // --------------------------------------------------------------------------------------------------------------------------------- + // | | | | | | | | | | | | | | + // | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | DEL | + // | | F1 | F2 | F3 | F4 | F5 | | F6 | - | = | [ | ] | \ | + // | | F7 | F8 | F9 | F10 | F11 | | | | F12 | | PSCRN | PG_DN | PG_UP | | + // | | | | | | | | | | | | NEXT | VOL- | VOL+ | PLAY | + bindings = < + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp DEL + &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH + &trans &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &trans &trans &kp F12 &trans &kp PSCRN &kp PG_DN &kp PG_UP &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp C_NEXT &kp C_VOL_DN &kp C_VOL_UP &kp C_PP + >; + }; + adjust_layer { + // --------------------------------------------------------------------------------------------------------------------------------- + // | ` | ! | @ | # | $ | % | | ^ | & | * | ( | ) | EP TOG | + // | BT CLR | BT SEL0 | BT SEL1 | BT SEL2 | BGT SEL3 | BT SEL4 | | RGB EFF+ | RGB HUE+ | RGB SAT+ | RGB SPD+ | RGB BRI+ | RGB TOG | + // | BT NXT | OUT TOG | OUT USB | OUT BLE | | | | RGB EFF- | RGB HUE- | RGB SAT- | RGB SPD- | RGB BRI- | | + // | BT PRV | | | | | | { | | } | | | | | | | + // | | | | | | | | | | | | | | | | + bindings = < + &kp GRAVE &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp ASTRK &kp LPAR &kp RPAR &ext_power EP_TOG + &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &rgb_ug RGB_EFF &rgb_ug RGB_HUI &rgb_ug RGB_SAI &rgb_ug RGB_SPI &rgb_ug RGB_BRI &rgb_ug RGB_TOG + &bt BT_NXT &out OUT_TOG &out OUT_USB &out OUT_BLE &trans &trans &rgb_ug RGB_EFR &rgb_ug RGB_HUD &rgb_ug RGB_SAD &rgb_ug RGB_SPD &rgb_ug RGB_BRD &trans + &bt BT_PRV &trans &trans &trans &trans &trans &kp LBRC &kp RBRC &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/helix/helix.zmk.yml b/app/boards/shields/helix/helix.zmk.yml new file mode 100644 index 000000000000..f24b9e09cd00 --- /dev/null +++ b/app/boards/shields/helix/helix.zmk.yml @@ -0,0 +1,13 @@ +file_format: "1" +id: helix +name: Helix +type: shield +url: https://github.com/MakotoKurauchi/helix +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display +siblings: + - helix_left + - helix_right diff --git a/app/boards/shields/helix/helix_left.overlay b/app/boards/shields/helix/helix_left.overlay new file mode 100644 index 000000000000..2a7ac8057a32 --- /dev/null +++ b/app/boards/shields/helix/helix_left.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "helix.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 21 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/helix/helix_right.overlay b/app/boards/shields/helix/helix_right.overlay new file mode 100644 index 000000000000..0d3cc63d14ae --- /dev/null +++ b/app/boards/shields/helix/helix_right.overlay @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "helix.dtsi" + +&default_transform { + col-offset = <7>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 21 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/hummingbird/Kconfig.defconfig b/app/boards/shields/hummingbird/Kconfig.defconfig new file mode 100644 index 000000000000..343eb6ad37dd --- /dev/null +++ b/app/boards/shields/hummingbird/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_HUMMINGBIRD + +config ZMK_KEYBOARD_NAME + default "Hummingbird" + +endif diff --git a/app/boards/shields/hummingbird/Kconfig.shield b/app/boards/shields/hummingbird/Kconfig.shield new file mode 100644 index 000000000000..b81153593822 --- /dev/null +++ b/app/boards/shields/hummingbird/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_HUMMINGBIRD + def_bool $(shields_list_contains,hummingbird) diff --git a/app/boards/shields/hummingbird/hummingbird.conf b/app/boards/shields/hummingbird/hummingbird.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/hummingbird/hummingbird.keymap b/app/boards/shields/hummingbird/hummingbird.keymap new file mode 100644 index 000000000000..9f1a24c2d03f --- /dev/null +++ b/app/boards/shields/hummingbird/hummingbird.keymap @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#define DEF_L 0 +#define NAV_L 1 +#define NUM_L 2 +#define SYM_L 3 + +// Using layer taps on thumbs, having quick tap as well helps w/ repeating space/backspace +< { quick_tap_ms = <200>; }; + +/ { + behaviors { + hm: homerow_mods { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + tapping_term_ms = <225>; + flavor = "tap-preferred"; + bindings = <&kp>, <&kp>; + }; + }; + + combos { + compatible = "zmk,combos"; + combo_z { + timeout-ms = <50>; + key-positions = <20 21>; + bindings = <&kp Z>; + }; + combo_b { + timeout-ms = <50>; + key-positions = <21 22>; + bindings = <&kp B>; + }; + + combo_y { + timeout-ms = <50>; + key-positions = <23 24>; + bindings = <&kp Y>; + }; + + combo_slash { + timeout-ms = <50>; + key-positions = <24 25>; + bindings = <&kp SLASH>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp Q &kp W &kp E &kp R &kp T &kp H &kp U &kp I &kp O &kp P + &hm LGUI A &hm LALT S &hm LCTRL D &hm LSHFT F &kp G &kp N &hm RSHFT J &hm RCTRL K &hm LALT L &hm RGUI QUOT + &kp X &kp C &kp V &kp M &kp COMMA &kp DOT + < NAV_L TAB &kp RET < NUM_L SPACE < SYM_L BKSP + >; + }; + + nav_layer { + display-name = "Nav"; + bindings = < + &trans &trans &trans &trans &trans &trans &kp HOME &kp UARW &kp PG_UP &trans + &trans &trans &trans &trans &trans &trans &kp LARW &kp DARW &kp RARW &trans + &trans &trans &trans &kp END &trans &kp PG_DN + &trans &trans &kp ESC &kp DEL + >; + }; + + num_layer { + display-name = "Num"; + bindings = < + &kp LBKT &kp N7 &kp N8 &kp N9 &kp RBKT &trans &trans &trans &trans &trans + &kp SEMI &kp N4 &kp N5 &kp N6 &kp EQUAL &trans &trans &trans &trans &trans + &kp N1 &kp N2 &kp N3 &trans &trans &trans + &kp N0 &kp MINUS &trans &trans + >; + }; + + sym_layer { + display-name = "Sym"; + bindings = < + &kp LBRC &kp LS(N7) &kp LS(N8) &kp LS(N9) &kp RBRC &trans &trans &trans &trans &trans + &kp COLON &kp LS(N4) &kp LS(N5) &kp LS(N6) &kp PLUS &trans &trans &trans &trans &trans + &kp LS(N1) &kp LS(N2) &kp LS(N3) &trans &trans &trans + &kp LS(N0) &kp UNDER &trans &trans + >; + }; + }; +}; diff --git a/app/boards/shields/hummingbird/hummingbird.overlay b/app/boards/shields/hummingbird/hummingbird.overlay new file mode 100644 index 000000000000..661e94898362 --- /dev/null +++ b/app/boards/shields/hummingbird/hummingbird.overlay @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + /delete-property/ zephyr,console; + /delete-property/ zephyr,shell-uart; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <7>; + rows = <6>; + map = < + RC(0,0) RC(1,0) RC(0,1) RC(1,1) RC(0,2) RC(1,2) RC(0,3) RC(1,3) RC(0,4) RC(1,4) + RC(2,0) RC(3,0) RC(2,1) RC(3,1) RC(2,2) RC(3,2) RC(2,3) RC(3,3) RC(2,4) RC(3,4) + RC(4,0) RC(5,0) RC(4,1) RC(5,2) RC(4,3) RC(5,3) + RC(5,1) RC(4,2) RC(5,4) RC(4,4) + >; + }; + + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "row2col"; + + col-gpios + = <&xiao_d 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&xiao_d 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&xiao_d 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&xiao_d 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&xiao_d 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + row-gpios + = <&xiao_d 0 GPIO_ACTIVE_HIGH> + , <&xiao_d 1 GPIO_ACTIVE_HIGH> + , <&xiao_d 2 GPIO_ACTIVE_HIGH> + , <&xiao_d 3 GPIO_ACTIVE_HIGH> + , <&xiao_d 4 GPIO_ACTIVE_HIGH> + , <&xiao_d 5 GPIO_ACTIVE_HIGH> + ; + }; + +}; + +&xiao_spi { status = "disabled"; }; +&xiao_serial { status = "disabled"; }; diff --git a/app/boards/shields/hummingbird/hummingbird.zmk.yml b/app/boards/shields/hummingbird/hummingbird.zmk.yml new file mode 100644 index 000000000000..ee3a8bc804a6 --- /dev/null +++ b/app/boards/shields/hummingbird/hummingbird.zmk.yml @@ -0,0 +1,8 @@ +file_format: "1" +id: hummingbird +name: Hummingbird +type: shield +url: https://github.com/PJE66/hummingbird +requires: [seeed_xiao] +features: + - keys diff --git a/app/boards/shields/iris/Kconfig.defconfig b/app/boards/shields/iris/Kconfig.defconfig new file mode 100644 index 000000000000..b68bc99967c1 --- /dev/null +++ b/app/boards/shields/iris/Kconfig.defconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2020 Pete Johanson, Kurtis Lew +# SPDX-License-Identifier: MIT + +if SHIELD_IRIS_LEFT + +config ZMK_KEYBOARD_NAME + default "Iris" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_IRIS_LEFT || SHIELD_IRIS_RIGHT + +config ZMK_SPLIT + default y + +endif \ No newline at end of file diff --git a/app/boards/shields/iris/Kconfig.shield b/app/boards/shields/iris/Kconfig.shield new file mode 100644 index 000000000000..764d8101155f --- /dev/null +++ b/app/boards/shields/iris/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2020 Pete Johanson, Kurtis Lew +# SPDX-License-Identifier: MIT + +config SHIELD_IRIS_LEFT + def_bool $(shields_list_contains,iris_left) + +config SHIELD_IRIS_RIGHT + def_bool $(shields_list_contains,iris_right) diff --git a/app/boards/shields/iris/iris.conf b/app/boards/shields/iris/iris.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/iris/iris.dtsi b/app/boards/shields/iris/iris.dtsi new file mode 100644 index 000000000000..8c5bb447d812 --- /dev/null +++ b/app/boards/shields/iris/iris.dtsi @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Pete Johanson, Kurtis Lew + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <16>; + rows = <4>; +// | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | +// | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | +// | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | +// | SW24 | SW23 | SW22 | SW21 | SW20 | SW19 | SW25 | | SW25 | SW19 | SW20 | SW21 | SW22 | SW23 | SW24 | +// | SW29 | SW28 | SW27 | SW26 | | SW26 | SW27 | SW28 | SW29 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,2) RC(4,9) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) + RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + }; +}; \ No newline at end of file diff --git a/app/boards/shields/iris/iris.keymap b/app/boards/shields/iris/iris.keymap new file mode 100644 index 000000000000..209c2277071b --- /dev/null +++ b/app/boards/shields/iris/iris.keymap @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ------------------------------------------------------------------------------------------------------------ +// | ESC | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | ` | +// | TAB | Q | W | E | R | T | | Y | U | I | O | P | - | +// | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | +// | SHIFT | Z | X | C | V | B | "[" | | "]" | N | M | , | . | / | SHIFT | +// | GUI | LOWER| SPACE | | ENTER | RAISE| ALT | + bindings = < +&kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp GRAVE +&kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp MINUS +&kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT +&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LBKT &kp RBKT &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LGUI &mo 1 &kp SPACE &kp RET &mo 2 &kp RALT + >; + }; + + lower_layer { +// ------------------------------------------------------------------------------------------------------------ +// | BTCLR | BT1 | BT2 | BT3 | BT4 | BT5 | | | | | | | | +// | F1 | F2 | F3 | F4 | F5 | F6 | | F7 | F8 | F9 | F10 | F11 | F12 | +// | ` | ! | @ | # | $ | % | | ^ | & | * | ( | ) | ~ | +// | | | | | | | | | | | _ | + | { | } | "|" | +// | | | | | | | | + bindings = < +&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans +&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 +&kp GRAVE &kp EXCL &kp AT &kp HASH &kp DOLLAR &kp PRCNT &kp CARET &kp AMPS &kp KP_MULTIPLY &kp LPAR &kp RPAR &kp TILDE +&trans &trans &trans &trans &trans &trans &trans &trans &trans &kp MINUS &kp KP_PLUS &kp LBRC &kp RBRC &kp PIPE + &trans &trans &trans &trans &trans &trans + >; + }; + + raise_layer { +// ------------------------------------------------------------------------------------------------------------ +// | | | | | | | | | | | | | | +// | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | | +// | F1 | F2 | F3 | F4 | F5 | F6 | | | <- | ^ | v | -> | | +// | F7 | F8 | F9 | F10 | F11 | F12 | | | | + | - | = | [ | ] | \ | +// | | | | | | | | + bindings = < +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &trans +&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &trans &kp LEFT &kp DOWN &kp UP &kp RIGHT &trans +&kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &trans &trans &kp KP_PLUS &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH + &trans &trans &trans &trans &trans &trans + >; + }; + }; +}; diff --git a/app/boards/shields/iris/iris.zmk.yml b/app/boards/shields/iris/iris.zmk.yml new file mode 100644 index 000000000000..2b25ec3e5c9b --- /dev/null +++ b/app/boards/shields/iris/iris.zmk.yml @@ -0,0 +1,14 @@ +file_format: "1" +id: iris +name: Iris +type: shield +url: https://keeb.io/products/iris-keyboard-split-ergonomic-keyboard +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder +siblings: + - iris_left + - iris_right diff --git a/app/boards/shields/iris/iris_left.conf b/app/boards/shields/iris/iris_left.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/iris/iris_left.overlay b/app/boards/shields/iris/iris_left.overlay new file mode 100644 index 000000000000..eb330d31ab25 --- /dev/null +++ b/app/boards/shields/iris/iris_left.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2020 Pete Johanson, Kurtis Lew + * + * SPDX-License-Identifier: MIT + */ + +#include "iris.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/iris/iris_right.conf b/app/boards/shields/iris/iris_right.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/iris/iris_right.overlay b/app/boards/shields/iris/iris_right.overlay new file mode 100644 index 000000000000..d2375b18ed3e --- /dev/null +++ b/app/boards/shields/iris/iris_right.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2020 Pete Johanson, Kurtis Lew + * + * SPDX-License-Identifier: MIT + */ + +#include "iris.dtsi" + +&default_transform { + col-offset = <6>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/jian/Kconfig.defconfig b/app/boards/shields/jian/Kconfig.defconfig new file mode 100644 index 000000000000..2f3d0a17c442 --- /dev/null +++ b/app/boards/shields/jian/Kconfig.defconfig @@ -0,0 +1,17 @@ + +if SHIELD_JIAN_LEFT + +config ZMK_KEYBOARD_NAME + default "Jian" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_JIAN_LEFT || SHIELD_JIAN_RIGHT + +config ZMK_SPLIT + default y + +endif diff --git a/app/boards/shields/jian/Kconfig.shield b/app/boards/shields/jian/Kconfig.shield new file mode 100644 index 000000000000..efcfa21458be --- /dev/null +++ b/app/boards/shields/jian/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_JIAN_LEFT + def_bool $(shields_list_contains,jian_left) + +config SHIELD_JIAN_RIGHT + def_bool $(shields_list_contains,jian_right) diff --git a/app/boards/shields/jian/jian.conf b/app/boards/shields/jian/jian.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/jian/jian.dtsi b/app/boards/shields/jian/jian.dtsi new file mode 100644 index 000000000000..1962ae1536a7 --- /dev/null +++ b/app/boards/shields/jian/jian.dtsi @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <12>; + rows = <4>; +// | SW0 | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | SW0 | +// | | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | +// | | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | +// | SW19 | SW20 | SW21 | | SW21 | SW20 | SW19 | + map = < + RC(2,0) RC(0,0) RC(0,1) RC(1,2) RC(0,2) RC(0,3) RC(0,4) RC(0,7) RC(0,8) RC(0,9) RC(1,9) RC(0,10) RC(0,11) RC(2,11) + RC(1,0) RC(1,1) RC(2,2) RC(1,3) RC(1,4) RC(0,5) RC(0,6) RC(1,7) RC(1,8) RC(2,9) RC(1,10) RC(1,11) + RC(2,1) RC(3,2) RC(3,3) RC(2,3) RC(2,4) RC(1,5) RC(1,6) RC(2,7) RC(2,8) RC(3,8) RC(3,9) RC(2,10) + RC(3,4) RC(2,5) RC(3,5) RC(3,6) RC(2,6) RC(3,7) + >; + }; + + crkbd_transform: keymap_transform_1 { + compatible = "zmk,matrix-transform"; + columns = <12>; + rows = <4>; +// | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | +// | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | +// | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | +// | SW19 | SW20 | SW21 | | SW21 | SW20 | SW19 | + map = < + RC(0,0) RC(0,1) RC(1,2) RC(0,2) RC(0,3) RC(0,4) RC(0,7) RC(0,8) RC(0,9) RC(1,9) RC(0,10) RC(0,11) + RC(1,0) RC(1,1) RC(2,2) RC(1,3) RC(1,4) RC(0,5) RC(0,6) RC(1,7) RC(1,8) RC(2,9) RC(1,10) RC(1,11) + RC(2,1) RC(3,2) RC(3,3) RC(2,3) RC(2,4) RC(1,5) RC(1,6) RC(2,7) RC(2,8) RC(3,8) RC(3,9) RC(2,10) + RC(3,4) RC(2,5) RC(3,5) RC(3,6) RC(2,6) RC(3,7) + >; + }; + + five_column_transform: keymap_transform_2 { + compatible = "zmk,matrix-transform"; + columns = <10>; + rows = <4>; +// | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | +// | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | +// | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | +// | SW19 | SW20 | SW21 | | SW21 | SW20 | SW19 | + map = < + RC(0,1) RC(1,2) RC(0,2) RC(0,3) RC(0,4) RC(0,7) RC(0,8) RC(0,9) RC(1,9) RC(0,10) + RC(1,1) RC(2,2) RC(1,3) RC(1,4) RC(0,5) RC(0,6) RC(1,7) RC(1,8) RC(2,9) RC(1,10) + RC(3,2) RC(3,3) RC(2,3) RC(2,4) RC(1,5) RC(1,6) RC(2,7) RC(2,8) RC(3,8) RC(3,9) + RC(3,4) RC(2,5) RC(3,5) RC(3,6) RC(2,6) RC(3,7) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + }; +}; diff --git a/app/boards/shields/jian/jian.keymap b/app/boards/shields/jian/jian.keymap new file mode 100644 index 000000000000..e8f7dcc87a11 --- /dev/null +++ b/app/boards/shields/jian/jian.keymap @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +#define DEF 0 +#define LWR 1 +#define RSE 2 +#define ADJ 3 + +< { quick_tap_ms = <200>; }; +&mt { quick_tap_ms = <200>; }; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ----------------------------------------------------------------------------------------- +// | GUI | ~ | Q | W | E | R | T | | Y | U | I | O | P | [ | GUI/] | +// | CTRL | A | S | D | F | G | | H | J | K | L | ; |CTRL/'| +// | LALT | Z | X | C | V | B | | N | M | , | . | / | RALT | +// | RSE | SPC | LWR | | LWR | BKSP | RSE | + bindings = < + &kp LWIN &kp GRAVE &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &mt RWIN RBKT + &kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &mt RCTRL SQT + &kp LALT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &mt RALT BSLH + < RSE TAB &mt LSHFT SPACE < LWR RET < LWR ESC &mt RSHFT BSPC < RSE DEL + >; + }; + lower_layer { +// ----------------------------------------------------------------------------------------- +// | | _ | F1 | F2 | F3 | F4 | F5 | | F6 | F7 | F8 | F9 | F10 | F11 | F12 | +// | + | ! | @ | # | $ | % | | ^ | & | * | ( | ) | - | +// | = | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | | +// | GUI | | SPC | | ENT | | ALT | + bindings = < + &trans &kp UNDER &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &mt RGUI F12 + &mt LCTRL PLUS &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp STAR &kp LPAR &kp RPAR &mt RCTRL MINUS + &mt LALT EQUAL &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &trans + < ADJ TAB &trans &trans &trans &trans < ADJ DEL + >; + }; + + raise_layer { +// ----------------------------------------------------------------------------------------- +// | | NMLK | / | 7 | 8 | 9 | - | | VOLU| HOME| PRSC| PGUP| SCLK| CLCK| | +// | CTRL | * | 4 | 5 | 6 | + | | MUT | LEFT| UP | RGHT| INS | APP | +// | | 0 | 1 | 2 | 3 | . | | VOLD| END | DOWN| PGDN| PAUS| | +// | | | ADJ | | ADJ | | | + bindings = < + &trans &kp KP_NUM &kp KP_SLASH &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_MINUS &kp C_VOL_UP &kp HOME &kp PSCRN &kp PG_UP &kp SLCK &kp CAPS &trans + &mt LCTRL EQUAL &kp KP_MULTIPLY &kp KP_N4 &kp KP_N5 &kp KP_N6 &kp KP_PLUS &kp C_MUTE &kp LEFT &kp UP &kp RIGHT &kp INS &mt RCTRL K_APP + &trans &kp KP_N0 &kp KP_N1 &kp KP_N2 &kp KP_N3 &kp KP_DOT &kp C_VOL_DN &kp END &kp DOWN &kp PG_DN &kp PAUSE_BREAK &trans + &trans &trans < ADJ RET < ADJ ESC &trans &trans + >; + }; + adjust_layer { +// ----------------------------------------------------------------------------------------- +// | RST | BLDR | | | | | | | | | | | | BLDR | RST | +// | BTCLR| BT0 | BT1 | BT2 | BT3 | BT4 | | BT4 | BT3 | BT2 | BT1 | BT0 | BTCLR| +// | | | | | | | | | | | | | | +// | | | | | | | | + bindings = < + &sys_reset &bootloader &none &none &none &none &none &none &none &none &none &none &bootloader &sys_reset + &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &bt BT_SEL 4 &bt BT_SEL 3 &bt BT_SEL 2 &bt BT_SEL 1 &bt BT_SEL 0 &bt BT_CLR + &none &none &none &none &none &none &none &none &none &none &none &none + &trans &none &trans &trans &none &trans + >; + }; + }; +}; diff --git a/app/boards/shields/jian/jian.zmk.yml b/app/boards/shields/jian/jian.zmk.yml new file mode 100644 index 000000000000..84ed69d748ca --- /dev/null +++ b/app/boards/shields/jian/jian.zmk.yml @@ -0,0 +1,11 @@ +file_format: "1" +id: jian +name: Jian +type: shield +url: https://github.com/KGOH/Jian-Info +requires: [pro_micro] +features: + - keys +siblings: + - jian_left + - jian_right diff --git a/app/boards/shields/jian/jian_left.conf b/app/boards/shields/jian/jian_left.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/jian/jian_left.overlay b/app/boards/shields/jian/jian_left.overlay new file mode 100644 index 000000000000..e402f03b1c53 --- /dev/null +++ b/app/boards/shields/jian/jian_left.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "jian.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 1 GPIO_ACTIVE_HIGH> + , <&pro_micro 0 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/jian/jian_right.conf b/app/boards/shields/jian/jian_right.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/jian/jian_right.overlay b/app/boards/shields/jian/jian_right.overlay new file mode 100644 index 000000000000..f646741bf7d4 --- /dev/null +++ b/app/boards/shields/jian/jian_right.overlay @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "jian.dtsi" + +&default_transform { + col-offset = <6>; +}; + +&crkbd_transform { + col-offset = <6>; +}; + +&five_column_transform { + col-offset = <6>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 0 GPIO_ACTIVE_HIGH> + , <&pro_micro 1 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/jiran/Kconfig.defconfig b/app/boards/shields/jiran/Kconfig.defconfig new file mode 100644 index 000000000000..0c6683f4f76f --- /dev/null +++ b/app/boards/shields/jiran/Kconfig.defconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_JIRAN_LEFT + +config ZMK_KEYBOARD_NAME + default "Jiran" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_JIRAN_LEFT || SHIELD_JIRAN_RIGHT + +config ZMK_SPLIT + default y + +endif diff --git a/app/boards/shields/jiran/Kconfig.shield b/app/boards/shields/jiran/Kconfig.shield new file mode 100644 index 000000000000..8f4807232889 --- /dev/null +++ b/app/boards/shields/jiran/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_JIRAN_LEFT + def_bool $(shields_list_contains,jiran_left) + +config SHIELD_JIRAN_RIGHT + def_bool $(shields_list_contains,jiran_right) diff --git a/app/boards/shields/jiran/jiran.conf b/app/boards/shields/jiran/jiran.conf new file mode 100644 index 000000000000..406f9a44b1d8 --- /dev/null +++ b/app/boards/shields/jiran/jiran.conf @@ -0,0 +1 @@ +# CONFIG_ZMK_SLEEP=y \ No newline at end of file diff --git a/app/boards/shields/jiran/jiran.dtsi b/app/boards/shields/jiran/jiran.dtsi new file mode 100644 index 000000000000..55ba2cb07760 --- /dev/null +++ b/app/boards/shields/jiran/jiran.dtsi @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <12>; + rows = <5>; + +// | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | +// | SW0 | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | SW0 | +// | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | +// | SW19 | SW20 | SW21 | SW22 | SW23 | SW24 | | SW24 | SW23 | SW22 | SW21 | SW20 | SW19 | +// | SW25 | SW26 | SW27 | | SW27 | SW26 | SW25 | + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) + RC(4,0) RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(4,11) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) + RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) + >; + }; + + jian_transform: keymap_transform_1 { + compatible = "zmk,matrix-transform"; + columns = <12>; + rows = <5>; + +// | SW0 | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | SW0 | +// | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | +// | SW19 | SW20 | SW21 | SW22 | SW23 | SW24 | | SW24 | SW23 | SW22 | SW21 | SW20 | SW19 | +// | SW25 | SW26 | SW27 | | SW27 | SW26 | SW25 | + map = < + RC(4,0) RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(4,11) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) + RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) + >; + }; + + crkbd_transform: keymap_transform_2 { + compatible = "zmk,matrix-transform"; + columns = <12>; + rows = <5>; + +// | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | +// | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | +// | SW19 | SW20 | SW21 | SW22 | SW23 | SW24 | | SW24 | SW23 | SW22 | SW21 | SW20 | SW19 | +// | SW25 | SW26 | SW27 | | SW27 | SW26 | SW25 | + map = < + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) + RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + }; +}; diff --git a/app/boards/shields/jiran/jiran.keymap b/app/boards/shields/jiran/jiran.keymap new file mode 100644 index 000000000000..6dcd733cdbe7 --- /dev/null +++ b/app/boards/shields/jiran/jiran.keymap @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS + &kp LGUI &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &mt RGUI RBKT + &kp LSHIFT &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &mt RSHIFT SQT + &kp LCTRL &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &mt RCTRL BSLH + &mo 1 &kp SPACE &kp LALT &mt RALT RET &kp BSPC &mo 1 + >; + }; + + lower_layer { + bindings = < + &kp GRAVE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp EQUAL + &kp F11 &kp TAB &bt BT_CLR &kp HOME &sys_reset &kp PG_UP &kp C_VOL_UP &kp C_VOL_UP &kp PG_UP &sys_reset &kp HOME &kp INS &kp DEL &kp F12 + &kp LSHIFT &bt BT_NXT &kp LEFT &kp UP &kp RIGHT &kp C_MUTE &kp C_MUTE &kp LEFT &kp UP &kp RIGHT &kp PSCRN &mt RSHIFT SLCK + &kp LCTRL &bt BT_PRV &kp END &kp DOWN &kp PG_DN &kp C_VOL_DN &kp C_VOL_DN &kp PG_DN &kp DOWN &kp END &kp PAUSE_BREAK &mt RCTRL KP_NUM + &trans &kp SPACE &kp LALT &mt RALT RET &kp BSPC &trans + >; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/jiran/jiran.zmk.yml b/app/boards/shields/jiran/jiran.zmk.yml new file mode 100644 index 000000000000..1e21df7c41bf --- /dev/null +++ b/app/boards/shields/jiran/jiran.zmk.yml @@ -0,0 +1,11 @@ +file_format: "1" +id: jiran +name: Jiran +type: shield +url: https://github.com/Ladniy/jiran +requires: [pro_micro] +features: + - keys +siblings: + - jiran_left + - jiran_right diff --git a/app/boards/shields/jiran/jiran_left.overlay b/app/boards/shields/jiran/jiran_left.overlay new file mode 100644 index 000000000000..3b7f5e555513 --- /dev/null +++ b/app/boards/shields/jiran/jiran_left.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "jiran.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 1 GPIO_ACTIVE_HIGH> + , <&pro_micro 0 GPIO_ACTIVE_HIGH> + , <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/jiran/jiran_right.overlay b/app/boards/shields/jiran/jiran_right.overlay new file mode 100644 index 000000000000..668c55139ce3 --- /dev/null +++ b/app/boards/shields/jiran/jiran_right.overlay @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "jiran.dtsi" + +&default_transform { + col-offset = <6>; +}; + +&jian_transform { + col-offset = <6>; +}; + +&crkbd_transform { + col-offset = <6>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 0 GPIO_ACTIVE_HIGH> + , <&pro_micro 1 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/jorne/Kconfig.defconfig b/app/boards/shields/jorne/Kconfig.defconfig new file mode 100644 index 000000000000..04beb792c4df --- /dev/null +++ b/app/boards/shields/jorne/Kconfig.defconfig @@ -0,0 +1,47 @@ + +if SHIELD_JORNE_LEFT + +config ZMK_KEYBOARD_NAME + default "Jorne" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_JORNE_LEFT || SHIELD_JORNE_RIGHT + +config ZMK_SPLIT + default y + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif diff --git a/app/boards/shields/jorne/Kconfig.shield b/app/boards/shields/jorne/Kconfig.shield new file mode 100644 index 000000000000..37a3cab59cdd --- /dev/null +++ b/app/boards/shields/jorne/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_JORNE_LEFT + def_bool $(shields_list_contains,jorne_left) + +config SHIELD_JORNE_RIGHT + def_bool $(shields_list_contains,jorne_right) diff --git a/app/boards/shields/jorne/boards/nice_nano.overlay b/app/boards/shields/jorne/boards/nice_nano.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/jorne/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/jorne/boards/nice_nano_v2.overlay b/app/boards/shields/jorne/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/jorne/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/jorne/jorne.conf b/app/boards/shields/jorne/jorne.conf new file mode 100644 index 000000000000..c4e62fc0c3a3 --- /dev/null +++ b/app/boards/shields/jorne/jorne.conf @@ -0,0 +1,6 @@ +# Uncomment the following lines to enable the Jorne RGB Underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y + +# Uncomment the following line to enable the Jorne OLED Display +# CONFIG_ZMK_DISPLAY=y diff --git a/app/boards/shields/jorne/jorne.dtsi b/app/boards/shields/jorne/jorne.dtsi new file mode 100644 index 000000000000..e5300c862639 --- /dev/null +++ b/app/boards/shields/jorne/jorne.dtsi @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zephyr,display = &oled; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <12>; + rows = <4>; +// | SW0 | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | SW0 | +// | | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | +// | | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | +// | SW19 | SW20 | SW21 | | SW21 | SW20 | SW19 | + map = < + RC(3,0) RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(3,11) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) + RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) + >; + }; + + crkbd_transform: keymap_transform_1 { + compatible = "zmk,matrix-transform"; + columns = <12>; + rows = <4>; +// | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | +// | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | +// | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | +// | SW19 | SW20 | SW21 | | SW21 | SW20 | SW19 | + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) + RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) + >; + }; + + five_column_transform: keymap_transform_2 { + compatible = "zmk,matrix-transform"; + columns = <10>; + rows = <4>; +// | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | +// | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | +// | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | +// | SW19 | SW20 | SW21 | | SW21 | SW20 | SW19 | + map = < +RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) +RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) +RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) + RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + }; + + // TODO: per-key RGB node(s)? +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/jorne/jorne.keymap b/app/boards/shields/jorne/jorne.keymap new file mode 100644 index 000000000000..2a109fe8ef18 --- /dev/null +++ b/app/boards/shields/jorne/jorne.keymap @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +#define DEF 0 +#define LWR 1 +#define RSE 2 +#define ADJ 3 + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ----------------------------------------------------------------------------------------- +// | GUI | ~ | Q | W | E | R | T | | Y | U | I | O | P | [ | GUI/] | +// | CTRL | A | S | D | F | G | | H | J | K | L | ; |CTRL/'| +// | LALT | Z | X | C | V | B | | N | M | , | . | / | RALT | +// | RSE | SPC | LWR | | LWR | BKSP | RSE | + bindings = < + &kp LWIN &kp GRAVE &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &mt RWIN RBKT + &kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &mt RCTRL SQT + &kp LALT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp BSLH + < RSE TAB &mt LSHFT SPACE < LWR RET < LWR ESC &mt RSHFT BSPC < RSE DEL + >; + }; + lower_layer { +// ----------------------------------------------------------------------------------------- +// | | _ | F1 | F2 | F3 | F4 | F5 | | F6 | F7 | F8 | F9 | F10 | F11 | F12 | +// | + | ! | @ | # | $ | % | | ^ | & | * | ( | ) | - | +// | = | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | | +// | GUI | | SPC | | ENT | | ALT | + bindings = < + &trans &kp UNDER &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &mt RGUI F12 + &mt LCTRL PLUS &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp STAR &kp LPAR &kp RPAR &mt RCTRL MINUS + &mt LALT EQUAL &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &trans + < ADJ TAB &trans &trans &trans &trans < ADJ DEL + >; + }; + + raise_layer { +// ----------------------------------------------------------------------------------------- +// | | NMLK | / | 7 | 8 | 9 | - | | VOLU| HOME| PRSC| PGUP| SCLK| CLCK| | +// | CTRL | * | 4 | 5 | 6 | + | | MUT | LEFT| UP | RGHT| INS | APP | +// | | 0 | 1 | 2 | 3 | . | | VOLD| END | DOWN| PGDN| PAUS| | +// | | | ADJ | | ADJ | | | + bindings = < + &trans &kp KP_NUM &kp KP_SLASH &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_MINUS &kp C_VOL_UP &kp HOME &kp PSCRN &kp PG_UP &kp SLCK &kp CAPS &trans + &mt LCTRL EQUAL &kp KP_MULTIPLY &kp KP_N4 &kp KP_N5 &kp KP_N6 &kp KP_PLUS &kp C_MUTE &kp LEFT &kp UP &kp RIGHT &kp INS &mt RCTRL K_APP + &trans &kp KP_N0 &kp KP_N1 &kp KP_N2 &kp KP_N3 &kp KP_DOT &kp C_VOL_DN &kp END &kp DOWN &kp PG_DN &kp PAUSE_BREAK &trans + &trans &trans < ADJ RET < ADJ ESC &trans &trans + >; + }; + adjust_layer { +// ----------------------------------------------------------------------------------------- +// | RST | BLDR | | | | | | | | | | | | BLDR | RST | +// | BTCLR| BT0 | BT1 | BT2 | BT3 | BT4 | | BT4 | BT3 | BT2 | BT1 | BT0 | BTCLR| +// | | | | | | | | | | | | | | +// | | | | | | | | + bindings = < + &sys_reset &bootloader &none &none &none &none &none &none &none &none &none &none &bootloader &sys_reset + &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &bt BT_SEL 4 &bt BT_SEL 3 &bt BT_SEL 2 &bt BT_SEL 1 &bt BT_SEL 0 &bt BT_CLR + &none &none &none &none &none &none &none &none &none &none &none &none + &trans &none &trans &trans &none &trans + >; + }; + }; +}; diff --git a/app/boards/shields/jorne/jorne.zmk.yml b/app/boards/shields/jorne/jorne.zmk.yml new file mode 100644 index 000000000000..16efe2ae8af8 --- /dev/null +++ b/app/boards/shields/jorne/jorne.zmk.yml @@ -0,0 +1,14 @@ +file_format: "1" +id: jorne +name: Jorne +type: shield +url: https://github.com/joric/jorne +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - underglow +siblings: + - jorne_left + - jorne_right diff --git a/app/boards/shields/jorne/jorne_left.conf b/app/boards/shields/jorne/jorne_left.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/jorne/jorne_left.overlay b/app/boards/shields/jorne/jorne_left.overlay new file mode 100644 index 000000000000..f0476b41f2e0 --- /dev/null +++ b/app/boards/shields/jorne/jorne_left.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "jorne.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 21 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/jorne/jorne_right.conf b/app/boards/shields/jorne/jorne_right.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/jorne/jorne_right.overlay b/app/boards/shields/jorne/jorne_right.overlay new file mode 100644 index 000000000000..604f48162058 --- /dev/null +++ b/app/boards/shields/jorne/jorne_right.overlay @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "jorne.dtsi" + +&default_transform { + col-offset = <6>; +}; + +&crkbd_transform { + col-offset = <6>; +}; + +&five_column_transform { + col-offset = <6>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 21 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/knob_goblin/Kconfig.defconfig b/app/boards/shields/knob_goblin/Kconfig.defconfig new file mode 100644 index 000000000000..d8d468edb948 --- /dev/null +++ b/app/boards/shields/knob_goblin/Kconfig.defconfig @@ -0,0 +1,39 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_KNOB_GOBLIN + +config ZMK_KEYBOARD_NAME + default "Knob Goblin" + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif # SHIELD_KNOB_GOBLIN diff --git a/app/boards/shields/knob_goblin/Kconfig.shield b/app/boards/shields/knob_goblin/Kconfig.shield new file mode 100644 index 000000000000..5a140cb90f04 --- /dev/null +++ b/app/boards/shields/knob_goblin/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_KNOB_GOBLIN + def_bool $(shields_list_contains,knob_goblin) diff --git a/app/boards/shields/knob_goblin/knob_goblin.conf b/app/boards/shields/knob_goblin/knob_goblin.conf new file mode 100644 index 000000000000..2eefae4d9e6c --- /dev/null +++ b/app/boards/shields/knob_goblin/knob_goblin.conf @@ -0,0 +1,9 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Uncomment to enable Encoders +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# Uncomment the following line to enable the Knob Goblin OLED Display +CONFIG_ZMK_DISPLAY=y diff --git a/app/boards/shields/knob_goblin/knob_goblin.keymap b/app/boards/shields/knob_goblin/knob_goblin.keymap new file mode 100644 index 000000000000..8e4a7e6622a1 --- /dev/null +++ b/app/boards/shields/knob_goblin/knob_goblin.keymap @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + + bindings = < + &trans &kp EQUAL &kp KP_SLASH &kp KP_MULTIPLY &kp KP_MINUS + &trans &kp KP_NUMBER_7 &kp KP_NUMBER_8 &kp KP_NUMBER_9 &kp KP_PLUS + &trans &kp KP_NUMBER_4 &kp KP_NUMBER_5 &kp KP_NUMBER_6 &kp KP_PLUS + &kp C_PLAY_PAUSE &kp KP_NUMBER_1 &kp KP_NUMBER_2 &kp KP_NUMBER_3 &kp KP_ENTER + &kp C_MUTE &mo 1 &kp KP_NUMBER_0 &kp KP_DOT &kp KP_ENTER + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + + num_layer { + bindings = < + &trans &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 + &trans &kp HOME &trans &kp PAGE_UP &trans + &trans &kp END &kp UP_ARROW &kp PAGE_DOWN &trans + &trans &kp LEFT_ARROW &kp DOWN_ARROW &kp RIGHT_ARROW &kp SPACE + &trans &trans &kp BACKSPACE &kp DELETE &trans + >; + + }; + }; +}; + diff --git a/app/boards/shields/knob_goblin/knob_goblin.overlay b/app/boards/shields/knob_goblin/knob_goblin.overlay new file mode 100644 index 000000000000..533727387738 --- /dev/null +++ b/app/boards/shields/knob_goblin/knob_goblin.overlay @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zephyr,display = &oled; + zmk,kscan = &kscan0; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + col-gpios + = <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + ; + }; + + top_encoder: encoder_top { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 19 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 18 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + steps = <80>; + status = "okay"; + }; + + bottom_encoder: encoder_bottom { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 20 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 21 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + steps = <80>; + status = "okay"; + }; + + sensors: sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&top_encoder &bottom_encoder>; + triggers-per-rotation = <20>; + }; + +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/knob_goblin/knob_goblin.zmk.yml b/app/boards/shields/knob_goblin/knob_goblin.zmk.yml new file mode 100644 index 000000000000..5383d1c2ee30 --- /dev/null +++ b/app/boards/shields/knob_goblin/knob_goblin.zmk.yml @@ -0,0 +1,11 @@ +file_format: "1" +id: knob_goblin +name: Knob Goblin +type: shield +url: https://knob-goblin.com/ +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder diff --git a/app/boards/shields/kyria/Kconfig.defconfig b/app/boards/shields/kyria/Kconfig.defconfig new file mode 100644 index 000000000000..2d162736b49f --- /dev/null +++ b/app/boards/shields/kyria/Kconfig.defconfig @@ -0,0 +1,47 @@ + +if SHIELD_KYRIA_LEFT || SHIELD_KYRIA_REV2_LEFT || SHIELD_KYRIA_REV3_LEFT + +config ZMK_KEYBOARD_NAME + default "Kyria" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_KYRIA + +config ZMK_SPLIT + default y + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif diff --git a/app/boards/shields/kyria/Kconfig.shield b/app/boards/shields/kyria/Kconfig.shield new file mode 100644 index 000000000000..a9d5ac4fa930 --- /dev/null +++ b/app/boards/shields/kyria/Kconfig.shield @@ -0,0 +1,29 @@ +# Copyright (c) 2020 Pete Johanson +# SPDX-License-Identifier: MIT + +config SHIELD_KYRIA + bool + +config SHIELD_KYRIA_LEFT + def_bool $(shields_list_contains,kyria_left) + select SHIELD_KYRIA + +config SHIELD_KYRIA_RIGHT + def_bool $(shields_list_contains,kyria_right) + select SHIELD_KYRIA + +config SHIELD_KYRIA_REV2_LEFT + def_bool $(shields_list_contains,kyria_rev2_left) + select SHIELD_KYRIA + +config SHIELD_KYRIA_REV2_RIGHT + def_bool $(shields_list_contains,kyria_rev2_right) + select SHIELD_KYRIA + +config SHIELD_KYRIA_REV3_LEFT + def_bool $(shields_list_contains,kyria_rev3_left) + select SHIELD_KYRIA + +config SHIELD_KYRIA_REV3_RIGHT + def_bool $(shields_list_contains,kyria_rev3_right) + select SHIELD_KYRIA diff --git a/app/boards/shields/kyria/boards/nice_nano.overlay b/app/boards/shields/kyria/boards/nice_nano.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/kyria/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/kyria/boards/nice_nano_v2.overlay b/app/boards/shields/kyria/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/kyria/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/kyria/boards/nrfmicro_11.overlay b/app/boards/shields/kyria/boards/nrfmicro_11.overlay new file mode 100644 index 000000000000..dba8377ec2ac --- /dev/null +++ b/app/boards/shields/kyria/boards/nrfmicro_11.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi1_default: spi1_default { + group1 { + psels = ; + }; + }; + + spi1_sleep: spi1_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi1 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi1_default>; + pinctrl-1 = <&spi1_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/kyria/boards/nrfmicro_11_flipped.overlay b/app/boards/shields/kyria/boards/nrfmicro_11_flipped.overlay new file mode 100644 index 000000000000..dba8377ec2ac --- /dev/null +++ b/app/boards/shields/kyria/boards/nrfmicro_11_flipped.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi1_default: spi1_default { + group1 { + psels = ; + }; + }; + + spi1_sleep: spi1_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi1 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi1_default>; + pinctrl-1 = <&spi1_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/kyria/boards/nrfmicro_13.overlay b/app/boards/shields/kyria/boards/nrfmicro_13.overlay new file mode 100644 index 000000000000..dba8377ec2ac --- /dev/null +++ b/app/boards/shields/kyria/boards/nrfmicro_13.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi1_default: spi1_default { + group1 { + psels = ; + }; + }; + + spi1_sleep: spi1_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi1 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi1_default>; + pinctrl-1 = <&spi1_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/kyria/kyria.conf b/app/boards/shields/kyria/kyria.conf new file mode 100644 index 000000000000..7a0b5b6c54fd --- /dev/null +++ b/app/boards/shields/kyria/kyria.conf @@ -0,0 +1,10 @@ +# Uncomment these two line to add support for encoders to your firmware +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# Uncomment the following line to enable the Kyria OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment the following lines to enable RGB underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y diff --git a/app/boards/shields/kyria/kyria.dtsi b/app/boards/shields/kyria/kyria.dtsi new file mode 100644 index 000000000000..b98240e495c5 --- /dev/null +++ b/app/boards/shields/kyria/kyria.dtsi @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "kyria_common.dtsi" + +/ { + chosen { + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <16>; + rows = <4>; +// | MX6 | MX5 | MX4 | MX3 | MX2 | MX1 | | MX1 | MX2 | MX3 | MX4 | MX5 | MX6 | +// | MX12 | MX11 | MX10 | MX9 | MX8 | MX7 | | MX7 | MX8 | MX9 | MX10 | MX11 | MX12 | +// | MX20 | MX19 | MX18 | MX17 | MX16 | MX15 | MX14 | MX13 | | MX13 | MX14 | MX15 | MX16 | MX17 | MX18 | MX19 | MX20 | +// | MX25 | MX24 | MX23 | MX22 | MX21 | | MX21 | MX22 | MX23 | MX24 | MX25 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,15) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,10) RC(1,11) RC(1,12) RC(1,13) RC(1,14) RC(1,15) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) RC(2,14) RC(2,15) + RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) + >; + }; + +// | MX5 | MX4 | MX3 | MX2 | MX1 | | MX1 | MX2 | MX3 | MX4 | MX5 | +// | MX11 | MX10 | MX9 | MX8 | MX7 | | MX7 | MX8 | MX9 | MX10 | MX11 | +// | MX19 | MX18 | MX17 | MX16 | MX15 | MX14 | MX13 | | MX13 | MX14 | MX15 | MX16 | MX17 | MX18 | MX19 | +// | MX25 | MX24 | MX23 | MX22 | MX21 | | MX21 | MX22 | MX23 | MX24 | MX25 | + five_column_transform: keymap_transform_1 { + compatible = "zmk,matrix-transform"; + columns = <14>; + rows = <4>; + map = < +RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) +RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,10) RC(1,11) RC(1,12) RC(1,13) RC(1,14) +RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) RC(2,14) + RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) + >; + }; +}; + +&kscan0 { + row-gpios + = <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; +}; + +&left_encoder { + a-gpios = <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; +}; + +&right_encoder { + a-gpios = <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; +}; diff --git a/app/boards/shields/kyria/kyria.keymap b/app/boards/shields/kyria/kyria.keymap new file mode 100644 index 000000000000..a11c13259e18 --- /dev/null +++ b/app/boards/shields/kyria/kyria.keymap @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// --------------------------------------------------------------------------------------------------------------------------------- +// | ESC | Q | W | E | R | T | | Y | U | I | O | P | \ | +// | TAB | A | S | D | F | G | | H | J | K | L | ; | ' | +// | SHIFT | Z | X | C | V | B | L SHIFT | L SHIFT | | LAYER 1 | L SHIFT | N | M | , | . | / | CTRL | +// | GUI | DEL | RET | SPACE | ESC | | RET | SPACE | TAB | BSPC | R-ALT | + bindings = < + &kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSLH + &kp TAB &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LSHFT &kp LSHFT &mo 1 &kp LSHFT &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RCTRL + &kp LGUI &kp DEL &kp RET &kp SPACE &kp ESC &kp RET &kp SPACE &kp TAB &kp BSPC &kp RALT + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + function_layer { +// --------------------------------------------------------------------------------------------------------------------------------- +// | | |BT_CLR|BTSEL0|BTSEL1|BTSEL2| | | | | | | | +// | | | |BTSEL3|BTSEL4| | | | | | | | | +// | | | | | | | | | | | | | | | | | | | +// | | | | | | | | | | | | | + bindings = < + &trans &trans &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &trans &trans &trans &trans &trans &trans + &trans &trans &trans &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + }; +}; diff --git a/app/boards/shields/kyria/kyria.zmk.yml b/app/boards/shields/kyria/kyria.zmk.yml new file mode 100644 index 000000000000..95e6c3b7ebe3 --- /dev/null +++ b/app/boards/shields/kyria/kyria.zmk.yml @@ -0,0 +1,15 @@ +file_format: "1" +id: kyria +name: Kyria +type: shield +url: https://splitkb.com/products/kyria-pcb-kit +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder + - underglow +siblings: + - kyria_left + - kyria_right diff --git a/app/boards/shields/kyria/kyria_common.dtsi b/app/boards/shields/kyria/kyria_common.dtsi new file mode 100644 index 000000000000..f68b743e7420 --- /dev/null +++ b/app/boards/shields/kyria/kyria_common.dtsi @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zephyr,display = &oled; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + }; + + left_encoder: encoder_left { + compatible = "alps,ec11"; + steps = <80>; + status = "disabled"; + }; + + right_encoder: encoder_right { + compatible = "alps,ec11"; + steps = <80>; + status = "disabled"; + }; + + sensors: sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + triggers-per-rotation = <20>; + }; + + // TODO: RGB node(s) +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <64>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <63>; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/kyria/kyria_left.conf b/app/boards/shields/kyria/kyria_left.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/kyria/kyria_left.overlay b/app/boards/shields/kyria/kyria_left.overlay new file mode 100644 index 000000000000..d89a077525bc --- /dev/null +++ b/app/boards/shields/kyria/kyria_left.overlay @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ + +#include "kyria.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 21 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + ; +}; + +&left_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/kyria/kyria_rev2.conf b/app/boards/shields/kyria/kyria_rev2.conf new file mode 100644 index 000000000000..7a0b5b6c54fd --- /dev/null +++ b/app/boards/shields/kyria/kyria_rev2.conf @@ -0,0 +1,10 @@ +# Uncomment these two line to add support for encoders to your firmware +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# Uncomment the following line to enable the Kyria OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment the following lines to enable RGB underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y diff --git a/app/boards/shields/kyria/kyria_rev2.dtsi b/app/boards/shields/kyria/kyria_rev2.dtsi new file mode 100644 index 000000000000..e61131bfd53e --- /dev/null +++ b/app/boards/shields/kyria/kyria_rev2.dtsi @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "kyria_common.dtsi" + +/ { + chosen { + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <16>; + rows = <4>; +// | MX6 | MX5 | MX4 | MX3 | MX2 | MX1 | | MX1 | MX2 | MX3 | MX4 | MX5 | MX6 | +// | MX12 | MX11 | MX10 | MX9 | MX8 | MX7 | | MX7 | MX8 | MX9 | MX10 | MX11 | MX12 | +// | MX20 | MX19 | MX18 | MX17 | MX16 | MX15 | MX14 | MX13 | | MX13 | MX14 | MX15 | MX16 | MX17 | MX18 | MX19 | MX20 | +// | MX25 | MX24 | MX23 | MX22 | MX21 | | MX21 | MX22 | MX23 | MX24 | MX25 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,15) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,10) RC(1,11) RC(1,12) RC(1,13) RC(1,14) RC(1,15) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) RC(2,14) RC(2,15) + RC(3,2) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,13) + >; + }; + +// | MX5 | MX4 | MX3 | MX2 | MX1 | | MX1 | MX2 | MX3 | MX4 | MX5 | +// | MX11 | MX10 | MX9 | MX8 | MX7 | | MX7 | MX8 | MX9 | MX10 | MX11 | +// | MX19 | MX18 | MX17 | MX16 | MX15 | MX14 | MX13 | | MX13 | MX14 | MX15 | MX16 | MX17 | MX18 | MX19 | +// | MX25 | MX24 | MX23 | MX22 | MX21 | | MX21 | MX22 | MX23 | MX24 | MX25 | + five_column_transform: keymap_transform_1 { + compatible = "zmk,matrix-transform"; + columns = <14>; + rows = <4>; + map = < +RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) +RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,10) RC(1,11) RC(1,12) RC(1,13) RC(1,14) +RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) RC(2,14) + RC(3,2) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,13) + >; + }; +}; + +&left_encoder { + a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; +}; + +&right_encoder { + a-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; +}; diff --git a/app/boards/shields/kyria/kyria_rev2.keymap b/app/boards/shields/kyria/kyria_rev2.keymap new file mode 100644 index 000000000000..a11c13259e18 --- /dev/null +++ b/app/boards/shields/kyria/kyria_rev2.keymap @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// --------------------------------------------------------------------------------------------------------------------------------- +// | ESC | Q | W | E | R | T | | Y | U | I | O | P | \ | +// | TAB | A | S | D | F | G | | H | J | K | L | ; | ' | +// | SHIFT | Z | X | C | V | B | L SHIFT | L SHIFT | | LAYER 1 | L SHIFT | N | M | , | . | / | CTRL | +// | GUI | DEL | RET | SPACE | ESC | | RET | SPACE | TAB | BSPC | R-ALT | + bindings = < + &kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSLH + &kp TAB &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LSHFT &kp LSHFT &mo 1 &kp LSHFT &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RCTRL + &kp LGUI &kp DEL &kp RET &kp SPACE &kp ESC &kp RET &kp SPACE &kp TAB &kp BSPC &kp RALT + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + function_layer { +// --------------------------------------------------------------------------------------------------------------------------------- +// | | |BT_CLR|BTSEL0|BTSEL1|BTSEL2| | | | | | | | +// | | | |BTSEL3|BTSEL4| | | | | | | | | +// | | | | | | | | | | | | | | | | | | | +// | | | | | | | | | | | | | + bindings = < + &trans &trans &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &trans &trans &trans &trans &trans &trans + &trans &trans &trans &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + }; +}; diff --git a/app/boards/shields/kyria/kyria_rev2.zmk.yml b/app/boards/shields/kyria/kyria_rev2.zmk.yml new file mode 100644 index 000000000000..6488f69055ec --- /dev/null +++ b/app/boards/shields/kyria/kyria_rev2.zmk.yml @@ -0,0 +1,15 @@ +file_format: "1" +id: kyria_rev2 +name: Kyria Rev2 +type: shield +url: https://splitkb.com/products/kyria-pcb-kit +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder + - underglow +siblings: + - kyria_rev2_left + - kyria_rev2_right diff --git a/app/boards/shields/kyria/kyria_rev2_left.overlay b/app/boards/shields/kyria/kyria_rev2_left.overlay new file mode 100644 index 000000000000..67eaeac226f8 --- /dev/null +++ b/app/boards/shields/kyria/kyria_rev2_left.overlay @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "kyria_rev2.dtsi" + +&kscan0 { + row-gpios + = <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + col-gpios + = <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + ; +}; + +&left_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/kyria/kyria_rev2_right.overlay b/app/boards/shields/kyria/kyria_rev2_right.overlay new file mode 100644 index 000000000000..acc806cf0903 --- /dev/null +++ b/app/boards/shields/kyria/kyria_rev2_right.overlay @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "kyria_rev2.dtsi" + +&default_transform { + col-offset = <8>; +}; + +&five_column_transform { + col-offset = <8>; +}; + +&kscan0 { + row-gpios + = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + col-gpios + = <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + ; +}; + +&right_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/kyria/kyria_rev3.conf b/app/boards/shields/kyria/kyria_rev3.conf new file mode 100644 index 000000000000..7a0b5b6c54fd --- /dev/null +++ b/app/boards/shields/kyria/kyria_rev3.conf @@ -0,0 +1,10 @@ +# Uncomment these two line to add support for encoders to your firmware +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# Uncomment the following line to enable the Kyria OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment the following lines to enable RGB underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y diff --git a/app/boards/shields/kyria/kyria_rev3.dtsi b/app/boards/shields/kyria/kyria_rev3.dtsi new file mode 100644 index 000000000000..0cf91c60a076 --- /dev/null +++ b/app/boards/shields/kyria/kyria_rev3.dtsi @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "kyria_common.dtsi" + +/ { + chosen { + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <14>; + rows = <4>; + // | MX6 | MX5 | MX4 | MX3 | MX2 | MX1 | | MX1 | MX2 | MX3 | MX4 | MX5 | MX6 | + // | MX12 | MX11 | MX10 | MX9 | MX8 | MX7 | | MX7 | MX8 | MX9 | MX10 | MX11 | MX12 | + // | MX20 | MX19 | MX18 | MX17 | MX16 | MX15 | MX14 | MX13 | | MX13 | MX14 | MX15 | MX16 | MX17 | MX18 | MX19 | MX20 | + // | MX25 | MX24 | MX23 | MX22 | MX21 | | MX21 | MX22 | MX23 | MX24 | MX25 | + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(3,3) RC(2,6) RC(2,7) RC(3,10) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) + RC(3,2) RC(3,4) RC(3,5) RC(3,1) RC(3,6) RC(3,7) RC(3,12) RC(3,8) RC(3,9) RC(3,11) + >; + }; +}; + +&left_encoder { + resolution = <2>; + a-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; +}; + +&right_encoder { + resolution = <2>; + a-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; +}; diff --git a/app/boards/shields/kyria/kyria_rev3.keymap b/app/boards/shields/kyria/kyria_rev3.keymap new file mode 100644 index 000000000000..ac2fc044e734 --- /dev/null +++ b/app/boards/shields/kyria/kyria_rev3.keymap @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/* Uncomment this block if using RGB +&led_strip { + chain-length = <6>; + // chain-length = <31>; // Uncomment if using both per-key and underglow LEDs + // chain-length = <25>; // Uncomment if using only per-key LEDs. +}; + */ + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + // --------------------------------------------------------------------------------------------------------------------------------- + // | ESC | Q | W | E | R | T | | Y | U | I | O | P | \ | + // | TAB | A | S | D | F | G | | H | J | K | L | ; | ' | + // | SHIFT | Z | X | C | V | B | L SHIFT | L SHIFT | | LAYER 1 | L SHIFT | N | M | , | . | / | CTRL | + // | GUI | DEL | RET | SPACE | ESC | | RET | SPACE | TAB | BSPC | R-ALT | + bindings = < + &kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSLH + &kp TAB &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LSHFT &kp LSHFT &mo 1 &kp LSHFT &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RCTRL + &kp LGUI &kp DEL &kp RET &kp SPACE &kp ESC &kp RET &kp SPACE &kp TAB &kp BSPC &kp RALT + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + function_layer { + // --------------------------------------------------------------------------------------------------------------------------------- + // | | |BT_CLR|BTSEL0|BTSEL1|BTSEL2| | | | | | | | + // | | | |BTSEL3|BTSEL4| | | | | | | | | + // | | | | | | | | | | | | | | | | | | | + // | | | | | | | | | | | | | + bindings = < + &trans &trans &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &trans &trans &trans &trans &trans &trans + &trans &trans &trans &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + }; +}; diff --git a/app/boards/shields/kyria/kyria_rev3.zmk.yml b/app/boards/shields/kyria/kyria_rev3.zmk.yml new file mode 100644 index 000000000000..bf84c82cbe14 --- /dev/null +++ b/app/boards/shields/kyria/kyria_rev3.zmk.yml @@ -0,0 +1,15 @@ +file_format: "1" +id: kyria_rev3 +name: Kyria Rev3 +type: shield +url: https://splitkb.com/products/kyria-pcb-kit +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder + - underglow +siblings: + - kyria_rev3_left + - kyria_rev3_right diff --git a/app/boards/shields/kyria/kyria_rev3_left.overlay b/app/boards/shields/kyria/kyria_rev3_left.overlay new file mode 100644 index 000000000000..577b89dc1342 --- /dev/null +++ b/app/boards/shields/kyria/kyria_rev3_left.overlay @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "kyria_rev3.dtsi" + +&kscan0 { + row-gpios + = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + col-gpios + = <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + ; +}; + +&left_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/kyria/kyria_rev3_right.overlay b/app/boards/shields/kyria/kyria_rev3_right.overlay new file mode 100644 index 000000000000..88ed658962f9 --- /dev/null +++ b/app/boards/shields/kyria/kyria_rev3_right.overlay @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "kyria_rev3.dtsi" + +&default_transform { + col-offset = <7>; +}; + +&kscan0 { + row-gpios + = <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + col-gpios + = <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + ; +}; + +&right_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/kyria/kyria_right.conf b/app/boards/shields/kyria/kyria_right.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/kyria/kyria_right.overlay b/app/boards/shields/kyria/kyria_right.overlay new file mode 100644 index 000000000000..72d970279923 --- /dev/null +++ b/app/boards/shields/kyria/kyria_right.overlay @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ + +#include "kyria.dtsi" + +&default_transform { + col-offset = <8>; +}; + +&five_column_transform { + col-offset = <8>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 21 GPIO_ACTIVE_HIGH> + ; +}; + + +&right_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/leeloo/Kconfig.defconfig b/app/boards/shields/leeloo/Kconfig.defconfig new file mode 100644 index 000000000000..046bd49a3dd2 --- /dev/null +++ b/app/boards/shields/leeloo/Kconfig.defconfig @@ -0,0 +1,59 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_LEELOO_REV2_LEFT + +config ZMK_KEYBOARD_NAME + default "Leeloo v2" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_LEELOO_LEFT + +config ZMK_KEYBOARD_NAME + default "Leeloo" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_LEELOO + +config ZMK_SPLIT + default y + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif diff --git a/app/boards/shields/leeloo/Kconfig.shield b/app/boards/shields/leeloo/Kconfig.shield new file mode 100644 index 000000000000..1d7843957e5e --- /dev/null +++ b/app/boards/shields/leeloo/Kconfig.shield @@ -0,0 +1,21 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_LEELOO + bool + +config SHIELD_LEELOO_LEFT + def_bool $(shields_list_contains,leeloo_left) + select SHIELD_LEELOO + +config SHIELD_LEELOO_RIGHT + def_bool $(shields_list_contains,leeloo_right) + select SHIELD_LEELOO + +config SHIELD_LEELOO_REV2_LEFT + def_bool $(shields_list_contains,leeloo_rev2_left) + select SHIELD_LEELOO + +config SHIELD_LEELOO_REV2_RIGHT + def_bool $(shields_list_contains,leeloo_rev2_right) + select SHIELD_LEELOO \ No newline at end of file diff --git a/app/boards/shields/leeloo/README.md b/app/boards/shields/leeloo/README.md new file mode 100644 index 000000000000..27d5e872b5a2 --- /dev/null +++ b/app/boards/shields/leeloo/README.md @@ -0,0 +1,127 @@ +# Clickety Split | Leeloo v2 + +![Leeloo v2](https://github.com/ClicketySplit/build-guides/blob/main/leeloo/images/gallery/Leeloo-v2-ZMK.jpg) + +Keyboard Designer: [clicketysplit.ca](https://clicketysplit.ca) +GitHub: [ClicketySplit](https://github.com/ClicketySplit) +Hardware Supported: Pro Micro, Elite-C, and nice!nano v2 + +Leeloo v2 has been designed from scratch—again. Everything from the wiring schematic to its case. Leeloo v2 still keeps the column stagger that it's known for, along with its low profile design. + +## Features/Differences from Leeloo v1 + +- Support for Kailh Low Profile Choc switches with 18mm x 18mm spacing. + - A version for Kailh Box/MX switches with 19.05mm x 19.05mm spacing will be available in the future. +- All switch locations are socketed. +- Rotary encoder locations are socketed. + - One of two locations on each side can be used for a rotary encoder. +- OLED Displays and nice!view Displays are natively supported, socketed, and no extra wiring is required. +- Support for per-switch RGB underglow. +- Better location for 110mAh or 700mAh batteries. + - Different location for soldering battery leads. +- Support for Alps Alpine Micro On/off switches. + +# Leeloo v1 + +![Leeloo](https://github.com/ClicketySplit/build-guides/blob/main/leeloo/images/gallery/Leeloo-v1.jpg) + +## Features + +- 4x6x5m Split Keyboard +- Support for both Low Profile Choc switches, and Box/MX switches; 19.05mm x 19.05mm spacing. +- 90% of the switches are socketed; with the exception to the rotary encoder positions. +- Support for Alps Alpine EC11 Rotary Encoders—one on each side, in one of three locations. +- Support for OLED Displays or nice!view Displays. + - nice!view displays require a wire to be soldered from the CS Pin on nice!view display to P0.22 or D4 on the nice!nano. +- Support for both 110mAh or 700mAh batteries. +- Solder pads for battery leads. +- Support for Alps Alpine Micro On/off switches. + +# Building Leeloo's ZMK Firmware + +ZMK Firmware: [Introduction to ZMK](https://zmk.dev/docs/) +Installation: [Installing ZMK](https://zmk.dev/docs/user-setup) +Customization: [Customizing ZMK](https://zmk.dev/docs/customization) +Development Environment: [Basic Setup](https://zmk.dev/docs/development/setup) + +Build commands for the default keymap of Leeloo v1: + +``` +west build -d build/left -p -b nice_nano_v2 -- -DSHIELD=leeloo_left +west build -d build/right -p -b nice_nano_v2 -- -DSHIELD=leeloo_right +``` + +Build commands for the default keymap of Leeloo v2: + +``` +west build -d build/left_v2 -p -b nice_nano_v2 -- -DSHIELD=leeloo_rev2_left +west build -d build/right_v2 -p -b nice_nano_v2 -- -DSHIELD=leeloo_rev2_right +``` + +Build commands for your custom keymap of Leeloo v1: + +``` +west build -d build/right -p -b nice_nano_v2 -- -DSHIELD=leeloo_right -DZMK_CONFIG="C:/dev/zmk/[yourName]/leeloo/config" +west build -d build/left -p -b nice_nano_v2 -- -DSHIELD=leeloo_left -DZMK_CONFIG="C:/dev/zmk/[yourName]/leeloo/config" +``` + +Build commands for your custom keymap of Leeloo v2: + +``` +west build -d build/right_v2 -p -b nice_nano_v2 -- -DSHIELD=leeloo_rev2_right -DZMK_CONFIG="C:/dev/zmk/[yourName]/leeloo_v2/config" +west build -d build/left_v2 -p -b nice_nano_v2 -- -DSHIELD=leeloo_rev2_left -DZMK_CONFIG="C:/dev/zmk/[yourName]/leeloo_v2/config" +``` + +## Building Leeloo's ZMK Firmware with nice!view Displays + +There are a couple of files that need to be adjusted before the build commands can be run. + +### Edit the leeloo[_rev2].keymap File + +Near the top 3rd of the leeloo[_rev2].keymap file, locate the following code block: + +``` +//nice_view_spi: &spi0 { +// cs-gpios = <&pro_micro 4 GPIO_ACTIVE_HIGH>; +//}; +``` + +Remove the forward slashes to resemble the following: + +``` +nice_view_spi: &spi0 { + cs-gpios = <&pro_micro 4 GPIO_ACTIVE_HIGH>; +}; +``` + +Save your changes and close the file. + +### Sample Build Commands for nice!view Displays + +Build commands for the default keymap of Leeloo v1: + +``` +west build -d build/left -p -b nice_nano_v2 -- -DSHIELD="leeloo_left nice_view_adapter nice_view" +west build -d build/right -p -b nice_nano_v2 -- -DSHIELD="leeloo_right nice_view_adapter nice_view" +``` + +Build commands for the default keymap of Leeloo v2: + +``` +west build -d build/left_v2 -p -b nice_nano_v2 -- -DSHIELD="leeloo_rev2_left nice_view_adapter nice_view" +west build -d build/right_v2 -p -b nice_nano_v2 -- -DSHIELD="leeloo_rev2_right nice_view_adapter nice_view" +``` + +Build commands for your custom keymap of Leeloo v2: + +``` +west build -d build/left -p -b nice_nano_v2 -- -DSHIELD="leeloo_rev2_left nice_view_adapter nice_view" -DZMK_CONFIG="/workspaces/zmk-config/[yourName]/leeloo_v2/config" +west build -d build/right -p -b nice_nano_v2 -- -DSHIELD="leeloo_rev2_right nice_view_adapter nice_view" -DZMK_CONFIG="/workspaces/zmk-config/[yourName]/leeloo_v2/config" +``` + +# Support + +If you have any questions with regards to Leeloo, please [Contact Us](https://clicketysplit.ca/pages/contact-us). + +Clickety Split +For the love of split keyboards. diff --git a/app/boards/shields/leeloo/boards/nice_nano_v2.overlay b/app/boards/shields/leeloo/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..e95fac9dcdbf --- /dev/null +++ b/app/boards/shields/leeloo/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <37>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo/leeloo.conf b/app/boards/shields/leeloo/leeloo.conf new file mode 100644 index 000000000000..466279a33e33 --- /dev/null +++ b/app/boards/shields/leeloo/leeloo.conf @@ -0,0 +1,16 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Uncomment the following line to enable the OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment to turn off WPM Status. +# CONFIG_ZMK_WIDGET_WPM_STATUS=n + +# Uncomment to invert colour when using nice!view Displays +# CONFIG_ZMK_DISPLAY_INVERT=y + + +# Uncomment these two lines to add support for encoders +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y \ No newline at end of file diff --git a/app/boards/shields/leeloo/leeloo.dtsi b/app/boards/shields/leeloo/leeloo.dtsi new file mode 100644 index 000000000000..dad05c55c6e0 --- /dev/null +++ b/app/boards/shields/leeloo/leeloo.dtsi @@ -0,0 +1,6 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include "leeloo_common.dtsi" \ No newline at end of file diff --git a/app/boards/shields/leeloo/leeloo.keymap b/app/boards/shields/leeloo/leeloo.keymap new file mode 100644 index 000000000000..91e4f333448b --- /dev/null +++ b/app/boards/shields/leeloo/leeloo.keymap @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +/* + * Assign the cs-gpios pin to 4. + * Uncomment these next few lines if implementing nice!view Displays + * A wire from the nice!view CS display needs to be connected to the + * High Frequency P0.22, also known as D4 if you choose to refer to + * the pins with Arduino Labels. + */ +//nice_view_spi: &spi0 { +// cs-gpios = <&pro_micro 4 GPIO_ACTIVE_HIGH>; +//}; + +/ { + + keymap { + compatible = "zmk,keymap"; + + default_layer { + display-name = " QWERTY"; + bindings = < +&kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp BSLH +&kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp GRAV +&kp CAPS &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT +&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LGUI &kp LGUI &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LALT &kp LCTRL < 1 RET < 2 MINUS < 2 EQUAL < 1 SPACE &kp BSPC &kp DEL + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + lower_layer { + display-name = " Lower"; + bindings = < +&trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 +&trans &trans &trans &trans &trans &trans &kp PG_UP &kp HOME &kp UP &kp END &trans &kp F12 +&trans &trans &trans &trans &trans &trans &kp PG_DN &kp LEFT &kp DOWN &kp RIGHT &trans &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + raise_layer { + display-name = " Raise"; + bindings = < +&trans &trans &trans &trans &trans &trans &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &sys_reset &bootloader +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &bt BT_CLR &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + }; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo/leeloo.zmk.yml b/app/boards/shields/leeloo/leeloo.zmk.yml new file mode 100644 index 000000000000..c7e0e6e85b5b --- /dev/null +++ b/app/boards/shields/leeloo/leeloo.zmk.yml @@ -0,0 +1,14 @@ +file_format: "1" +id: leeloo +name: Leeloo +type: shield +url: https://clicketysplit.ca/pages/leeloo +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder +siblings: + - leeloo_left + - leeloo_right diff --git a/app/boards/shields/leeloo/leeloo_common.dtsi b/app/boards/shields/leeloo/leeloo_common.dtsi new file mode 100644 index 000000000000..7c4ab22d8c12 --- /dev/null +++ b/app/boards/shields/leeloo/leeloo_common.dtsi @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zephyr,display = &oled; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <12>; + rows = <5>; +// | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | +// | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | +// | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | +// | SW19 | SW20 | SW21 | SW22 | SW23 | SW24 | SW29 | | SW29 | SW24 | SW23 | SW22 | SW21 | SW20 | SW19 | +// | SW25 | SW26 | SW27 | SW28 | | SW28 | SW27 | SW26 | SW25 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) + RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,7) RC(4,8) RC(4,9) RC(4,10) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; + + left_encoder: left_encoder { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <120>; + status = "disabled"; + }; + + right_encoder: right_encoder { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <120>; + status = "disabled"; + }; + + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + triggers-per-rotation = <30>; + }; + +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/leeloo/leeloo_left.overlay b/app/boards/shields/leeloo/leeloo_left.overlay new file mode 100644 index 000000000000..4421e1124ef3 --- /dev/null +++ b/app/boards/shields/leeloo/leeloo_left.overlay @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include "leeloo.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + ; +}; + +&left_encoder { + status = "okay"; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo/leeloo_rev2.conf b/app/boards/shields/leeloo/leeloo_rev2.conf new file mode 100644 index 000000000000..8c1cf3eed7b3 --- /dev/null +++ b/app/boards/shields/leeloo/leeloo_rev2.conf @@ -0,0 +1,43 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Uncomment the following line to enable the OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment to turn off WPM Status. +# CONFIG_ZMK_WIDGET_WPM_STATUS=n + +# Uncomment to invert colour when using nice!view Displays +# CONFIG_ZMK_DISPLAY_INVERT=y + + +# Uncomment the following line to enable per-key lighting +# CONFIG_ZMK_RGB_UNDERGLOW=y + +# Use the STRIP config specific to the LEDs you're using +# CONFIG_WS2812_STRIP=y + +# Keep OLED or nice!view Displays on even when toggling off LEDs +# Change to y if you wish to toggle Displays on and off with LEDs +# CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER=n + +# Turn off LEDs when idle. +# Change to n if you wish to keep LEDs on even when idle. +# CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE=y + +# When USB is disconnected, turn off LEDs +# Change to n if you wish to keep LEDs on even when USB is unpluged. +# CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_USB=y + +# Start LEDs off at 75% +# CONFIG_ZMK_RGB_UNDERGLOW_BRT_START=75 + + +# Uncomment these two lines to add support for encoders +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + + +# Uncomment if you are experiencing connectivity issues; this +# configuration item boosts the BLE transmit power. +# CONFIG_BT_CTLR_TX_PWR_PLUS_8=y \ No newline at end of file diff --git a/app/boards/shields/leeloo/leeloo_rev2.dtsi b/app/boards/shields/leeloo/leeloo_rev2.dtsi new file mode 100644 index 000000000000..dad05c55c6e0 --- /dev/null +++ b/app/boards/shields/leeloo/leeloo_rev2.dtsi @@ -0,0 +1,6 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include "leeloo_common.dtsi" \ No newline at end of file diff --git a/app/boards/shields/leeloo/leeloo_rev2.keymap b/app/boards/shields/leeloo/leeloo_rev2.keymap new file mode 100644 index 000000000000..a2eda050f2b7 --- /dev/null +++ b/app/boards/shields/leeloo/leeloo_rev2.keymap @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +// Short versions +#define RGBON &rgb_ug RGB_ON +#define RGBOFF &rgb_ug RGB_OFF +#define RGBTOG &rgb_ug RGB_TOG +#define RGBHUI &rgb_ug RGB_HUI +#define RGBHUD &rgb_ug RGB_HUD +#define RGBSAI &rgb_ug RGB_SAI +#define RGBSAD &rgb_ug RGB_SAD +#define RGBBRI &rgb_ug RGB_BRI +#define RGBBRD &rgb_ug RGB_BRD +#define RGBEFF &rgb_ug RGB_EFF + + +/* + * Assign the cs-gpios pin to 4. + * Uncomment these next few lines if implementing nice!view Displays + */ +//nice_view_spi: &spi0 { +// cs-gpios = <&pro_micro 4 GPIO_ACTIVE_HIGH>; +//}; + + +/ { + + keymap { + compatible = "zmk,keymap"; + + default_layer { + display-name = " QWERTY"; + bindings = < +&kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp BSLH +&kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp GRAV +&kp CAPS &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT +&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LGUI &kp RGUI &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LALT &kp LCTRL < 1 RET < 2 MINUS < 2 EQUAL < 1 SPACE &kp BSPC &kp DEL + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + lower_layer { + display-name = " Lower"; + bindings = < +&trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 +&trans &trans &trans &trans &trans &trans &kp PG_UP &kp HOME &kp UP &kp END &trans &kp F12 +&trans &trans &trans &trans &trans &trans &kp PG_DN &kp LEFT &kp DOWN &kp RIGHT &trans &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + raise_layer { + display-name = " Raise"; + bindings = < +&trans &trans &trans &trans &trans &trans &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &sys_reset &bootloader +RGBON RGBTOG RGBHUI RGBSAI RGBBRI &trans &trans &trans &trans &trans &trans &trans +RGBOFF RGBEFF RGBHUD RGBSAD RGBBRD &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &bt BT_CLR &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + }; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo/leeloo_rev2.zmk.yml b/app/boards/shields/leeloo/leeloo_rev2.zmk.yml new file mode 100644 index 000000000000..5e0a4db3dc51 --- /dev/null +++ b/app/boards/shields/leeloo/leeloo_rev2.zmk.yml @@ -0,0 +1,15 @@ +file_format: "1" +id: leeloo_rev2 +name: Leeloo v2 +type: shield +url: https://clicketysplit.ca/pages/leeloo +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder + - underglow +siblings: + - leeloo_rev2_left + - leeloo_rev2_right diff --git a/app/boards/shields/leeloo/leeloo_rev2_left.overlay b/app/boards/shields/leeloo/leeloo_rev2_left.overlay new file mode 100644 index 000000000000..14ddc0eceb17 --- /dev/null +++ b/app/boards/shields/leeloo/leeloo_rev2_left.overlay @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include "leeloo_rev2.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + ; +}; + +&left_encoder { + status = "okay"; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo/leeloo_rev2_right.overlay b/app/boards/shields/leeloo/leeloo_rev2_right.overlay new file mode 100644 index 000000000000..afca41b474b7 --- /dev/null +++ b/app/boards/shields/leeloo/leeloo_rev2_right.overlay @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include "leeloo_rev2.dtsi" + +&default_transform { + col-offset = <6>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + ; +}; + +&right_encoder { + status = "okay"; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo/leeloo_right.overlay b/app/boards/shields/leeloo/leeloo_right.overlay new file mode 100644 index 000000000000..b860c2ca6510 --- /dev/null +++ b/app/boards/shields/leeloo/leeloo_right.overlay @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include "leeloo.dtsi" + +&default_transform { + col-offset = <6>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + ; +}; + +&right_encoder { + status = "okay"; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo_micro/Kconfig.defconfig b/app/boards/shields/leeloo_micro/Kconfig.defconfig new file mode 100644 index 000000000000..26256120a76a --- /dev/null +++ b/app/boards/shields/leeloo_micro/Kconfig.defconfig @@ -0,0 +1,49 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_LEELOO_MICRO_LEFT + +config ZMK_KEYBOARD_NAME + default "Leeloo-Micro" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_LEELOO_MICRO + +config ZMK_SPLIT + default y + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif diff --git a/app/boards/shields/leeloo_micro/Kconfig.shield b/app/boards/shields/leeloo_micro/Kconfig.shield new file mode 100644 index 000000000000..c622f16dfcdf --- /dev/null +++ b/app/boards/shields/leeloo_micro/Kconfig.shield @@ -0,0 +1,13 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_LEELOO_MICRO + bool + +config SHIELD_LEELOO_MICRO_LEFT + def_bool $(shields_list_contains,leeloo_micro_left) + select SHIELD_LEELOO_MICRO + +config SHIELD_LEELOO_MICRO_RIGHT + def_bool $(shields_list_contains,leeloo_micro_right) + select SHIELD_LEELOO_MICRO \ No newline at end of file diff --git a/app/boards/shields/leeloo_micro/README.md b/app/boards/shields/leeloo_micro/README.md new file mode 100644 index 000000000000..c1827f82b72a --- /dev/null +++ b/app/boards/shields/leeloo_micro/README.md @@ -0,0 +1,89 @@ +# Clickety Split | Leeloo-Micro + +![Leeloo-Micro v1 Wireless](https://github.com/ClicketySplit/build-guides/blob/main/leeloo/images/gallery/Leeloo-Micro-v1-ZMK.jpg) + +Keyboard Designer: [clicketysplit.ca](https://clicketysplit.ca) +GitHub: [ClicketySplit](https://github.com/ClicketySplit) +Hardware Supported: nice!nano v2, nice!view v1 + +Leeloo-Micro is a 3x5x5m derivative of Leeloo v2; inheriting the column stagger and modifiers row, yet, reducing the number of switches by removing the top row and outside columns. With Leeloo-Micro's inaugural release being wireless, it leverages nice!nanos and nice!views for its microcontrollers and displays. + +## Features + +- 3x5x5m Split Keyboard +- Support for Kailh Low Profile Choc switches with 18mm x 18mm spacing. +- All switch locations are socketed. +- Support for Alps Alpine EC11 Rotary Encoders—one on each side, in one of two locations. + - Rotary encoder locations are socketed. +- nice!view Displays are inherently supported, socketed, and no extra wiring is required. +- Support for per-switch RGB underglow. +- Support for both 110mAh or 700mAh batteries. +- Support for Alps Alpine Micro On/off switches. + +# Building Leeloo-Micro ZMK Firmware + +ZMK Firmware: [Introduction to ZMK](https://zmk.dev/docs/) +Installation: [Installing ZMK](https://zmk.dev/docs/user-setup) +Customization: [Customizing ZMK](https://zmk.dev/docs/customization) +Development Environment: [Basic Setup](https://zmk.dev/docs/development/setup) + +Build commands for the default keymap of Leeloo-Micro: + +``` +west build -d build/left -p -b nice_nano_v2 -- -DSHIELD=leeloo_micro_left +west build -d build/right -p -b nice_nano_v2 -- -DSHIELD=leeloo_micro_right +``` + +Build commands for your custom keymap of Leeloo-Micro: + +``` +west build -d build/right -p -b nice_nano_v2 -- -DSHIELD=leeloo_micro_right -DZMK_CONFIG="C:/dev/zmk/[yourName]/leeloo_micro/config" +west build -d build/left -p -b nice_nano_v2 -- -DSHIELD=leeloo_micro_left -DZMK_CONFIG="C:/dev/zmk/[yourName]/leeloo_micro/config" +``` + +## Building Leeloo-Micro's ZMK Firmware with nice!view Displays + +There are a couple of files that need to be adjusted before the build commands can be run. + +### Edit the leeloo_micro.keymap File + +Near the top 3rd of the leeloo_micro.keymap file, locate the following code block: + +``` +//nice_view_spi: &spi0 { +// cs-gpios = <&pro_micro 4 GPIO_ACTIVE_HIGH>; +//}; +``` + +Remove the forward slashes to resemble the following: + +``` +nice_view_spi: &spi0 { + cs-gpios = <&pro_micro 4 GPIO_ACTIVE_HIGH>; +}; +``` + +Save your changes and close the file. + +### Sample Build Commands for nice!view Displays + +Build commands for the default keymap of Leeloo-Micro: + +``` +west build -d build/left -p -b nice_nano_v2 -- -DSHIELD="leeloo_micro_left nice_view_adapter nice_view" +west build -d build/right -p -b nice_nano_v2 -- -DSHIELD="leeloo_micro_right nice_view_adapter nice_view" +``` + +Build commands for your custom keymap of Leeloo-Micro: + +``` +west build -d build/left -p -b nice_nano_v2 -- -DSHIELD="leeloo_micro_left nice_view_adapter nice_view" -DZMK_CONFIG="/workspaces/zmk-config/[yourName]/leeloo_micro/config" +west build -d build/right -p -b nice_nano_v2 -- -DSHIELD="leeloo_micro_right nice_view_adapter nice_view" -DZMK_CONFIG="/workspaces/zmk-config/[yourName]/leeloo_micro/config" +``` + +# Support + +If you have any questions with regards to Leeloo-Micro, please [Contact Us](https://clicketysplit.ca/pages/contact-us). + +Clickety Split +For the love of split keyboards. diff --git a/app/boards/shields/leeloo_micro/boards/nice_nano_v2.overlay b/app/boards/shields/leeloo_micro/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..ba29cb2c06b0 --- /dev/null +++ b/app/boards/shields/leeloo_micro/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <20>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo_micro/leeloo_micro.conf b/app/boards/shields/leeloo_micro/leeloo_micro.conf new file mode 100644 index 000000000000..02c1d60587b6 --- /dev/null +++ b/app/boards/shields/leeloo_micro/leeloo_micro.conf @@ -0,0 +1,38 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Uncomment the following line to enable the OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment to turn off WPM Status. +# CONFIG_ZMK_WIDGET_WPM_STATUS=n + +# Uncomment to invert colour, if using nice!view Displays +# CONFIG_ZMK_DISPLAY_INVERT=y + + +# Uncomment the following line to enable per-key lighting +# CONFIG_ZMK_RGB_UNDERGLOW=y + +# Use the STRIP config specific to the LEDs you're using +# CONFIG_WS2812_STRIP=y + +# Keep OLED or nice!view Displays on even when toggling off LEDs +# Change to y if you wish to toggle Displays on and off with LEDs +# CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER=n + +# Turn off LEDs when idle. +# Change to n if you wish to keep LEDs on even when idle. +# CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE=y + +# When USB is disconnected, turn off LEDs +# Change to n if you wish to keep LEDs on even when USB is unpluged. +# CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_USB=y + +# Start LEDs off at 75% +# CONFIG_ZMK_RGB_UNDERGLOW_BRT_START=75 + + +# Uncomment these two lines to add support for encoders +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y \ No newline at end of file diff --git a/app/boards/shields/leeloo_micro/leeloo_micro.dtsi b/app/boards/shields/leeloo_micro/leeloo_micro.dtsi new file mode 100644 index 000000000000..c07c5093cd23 --- /dev/null +++ b/app/boards/shields/leeloo_micro/leeloo_micro.dtsi @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zephyr,display = &oled; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <10>; + rows = <4>; +// +// | SW1 | SW2 | SW3 | SW4 | SW5 | | SW15 | SW4 | SW3 | SW2 | SW1 | +// | SW6 | SW7 | SW8 | SW9 | SW10 | | SW10 | SW9 | SW8 | SW7 | SW6 | +// | SW11 | SW12 | SW13 | SW14 | SW15 | SW20 | | SW20 | SW15 | SW14 | SW13 | SW12 | SW11 | +// | SW16 | SW17 | SW18 | SW19 | | SW19 | SW18 | SW17 | SW16 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(3,4) RC(3,5) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,6) RC(3,7) RC(3,8) RC(3,9) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; + + left_encoder: left_encoder { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + status = "disabled"; + steps = <60>; + }; + + right_encoder: right_encoder { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + status = "disabled"; + steps = <60>; + }; + + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + triggers-per-rotation = <30>; + }; + +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo_micro/leeloo_micro.keymap b/app/boards/shields/leeloo_micro/leeloo_micro.keymap new file mode 100644 index 000000000000..2317015c1066 --- /dev/null +++ b/app/boards/shields/leeloo_micro/leeloo_micro.keymap @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +// Layers +#define QW_M 0 // Main +#define QW_L 1 // Lower +#define QW_R 2 // Raise +#define QW_A 3 // Adjust + +#define QC_N 4 // Number Pad +#define QC_B 5 // Firmware + + +// Short versions +#define BT0 BT_SEL 0 +#define BT1 BT_SEL 1 +#define BT2 BT_SEL 2 +#define BT3 BT_SEL 3 +#define BT4 BT_SEL 4 + +#define BOOTLDR &bootloader + +#define RGBON &rgb_ug RGB_ON +#define RGBOFF &rgb_ug RGB_OFF +#define RGBTOG &rgb_ug RGB_TOG +#define RGBHUI &rgb_ug RGB_HUI +#define RGBHUD &rgb_ug RGB_HUD +#define RGBSAI &rgb_ug RGB_SAI +#define RGBSAD &rgb_ug RGB_SAD +#define RGBBRI &rgb_ug RGB_BRI +#define RGBBRD &rgb_ug RGB_BRD +#define RGBEFF &rgb_ug RGB_EFF + + +/* + * Assign the cs-gpios pin to 4. + * Uncomment these next few lines if implementing nice!view Displays. + */ +//nice_view_spi: &spi0 { +// cs-gpios = <&pro_micro 4 GPIO_ACTIVE_HIGH>; +//}; + + +/ { + conditional_layers { + compatible = "zmk,conditional-layers"; + adjust_layer { + if-layers = ; + then-layer = ; + }; + }; + + combos { + compatible = "zmk,combos"; + + combo_esc { + timeout-ms = <50>; + key-positions = <0 1>; + layers = ; + bindings = <&kp ESC>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + display-name = " QWERTY"; + bindings = < +&kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P +&kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI +&mt LSFT Z &kp X &kp C &kp V &kp B &mo QC_N &kp RGUI &kp N &kp M &kp COMMA &kp DOT &mt RSFT FSLH + &kp LALT &kp LCTRL < 1 RET < 2 MINUS < 2 EQUAL < 1 SPACE &kp BSPC &mo QC_B + >; + + sensor-bindings = <&inc_dec_kp C_VOL_DN C_VOL_UP>; + }; + + lower_layer { + display-name = " Lower"; + bindings = < +&kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 +&trans &trans &trans &trans &trans &trans &trans &trans &trans &kp QUOT +&kp LSHFT &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp RSHFT + &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_DN C_VOL_UP>; + }; + + raise_layer { + display-name = " Raise"; + bindings = < +&kp TAB &trans &trans &trans &trans &kp PG_UP &kp HOME &kp UP &kp END &kp BSLH +&kp CAPS &trans &trans &trans &trans &kp PG_DN &kp LEFT &kp DOWN &kp RIGHT &kp GRAVE +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &mt RSFT TILDE + &trans &trans &trans &trans &trans &trans &kp DEL &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_DN C_VOL_UP>; + }; + + adjust_layer { + display-name = " Adjust"; + bindings = < + +&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &trans &trans &trans &trans &trans +&kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &trans &trans &trans &trans &trans +&kp F11 &kp F12 &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_DN C_VOL_UP>; + }; + + numpad_layer { + display-name = " NumPad"; + bindings = < + +&trans &none &none &none &none &kp SLASH &kp N7 &kp N8 &kp N9 &kp MINUS +RGBON RGBTOG RGBHUI RGBSAI RGBBRI &kp ASTRK &kp N4 &kp N5 &kp N6 &kp PLUS +RGBOFF RGBEFF RGBHUD RGBSAD RGBBRD &trans &trans &none &kp N1 &kp N2 &kp N3 &kp EQUAL + &trans &trans &trans &trans &trans &kp N0 &kp DOT &none + >; + + sensor-bindings = <&inc_dec_kp C_VOL_DN C_VOL_UP>; + }; + + ble_layer { + display-name = " BLE"; + bindings = < + +&bt BT0 &bt BT1 &bt BT2 &bt BT3 &bt BT4 &bt BT0 &bt BT1 &bt BT2 &bt BT3 &bt BT4 +BOOTLDR &sys_reset &trans &trans &trans &trans &trans &trans &sys_reset BOOTLDR +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &bt BT_CLR &trans &trans &trans &trans &bt BT_CLR &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_DN C_VOL_UP>; + }; + + }; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo_micro/leeloo_micro.zmk.yml b/app/boards/shields/leeloo_micro/leeloo_micro.zmk.yml new file mode 100644 index 000000000000..e78ce0a35306 --- /dev/null +++ b/app/boards/shields/leeloo_micro/leeloo_micro.zmk.yml @@ -0,0 +1,15 @@ +file_format: "1" +id: leeloo_micro +name: Leeloo-Micro +type: shield +url: https://clicketysplit.ca/pages/leeloo-micro +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder + - underglow +siblings: + - leeloo_micro_left + - leeloo_micro_right diff --git a/app/boards/shields/leeloo_micro/leeloo_micro_left.overlay b/app/boards/shields/leeloo_micro/leeloo_micro_left.overlay new file mode 100644 index 000000000000..d31fcf2c0fda --- /dev/null +++ b/app/boards/shields/leeloo_micro/leeloo_micro_left.overlay @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include "leeloo_micro.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + ; +}; + +&left_encoder { + status = "okay"; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo_micro/leeloo_micro_right.overlay b/app/boards/shields/leeloo_micro/leeloo_micro_right.overlay new file mode 100644 index 000000000000..a3f347fb9c3c --- /dev/null +++ b/app/boards/shields/leeloo_micro/leeloo_micro_right.overlay @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include "leeloo_micro.dtsi" + +&default_transform { + col-offset = <5>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + ; +}; + +&right_encoder { + status = "okay"; +}; \ No newline at end of file diff --git a/app/boards/shields/lily58/Kconfig.defconfig b/app/boards/shields/lily58/Kconfig.defconfig new file mode 100644 index 000000000000..e77a9c2208df --- /dev/null +++ b/app/boards/shields/lily58/Kconfig.defconfig @@ -0,0 +1,48 @@ + +if SHIELD_LILY58_LEFT + +config ZMK_KEYBOARD_NAME + default "Lily58" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_LILY58_LEFT || SHIELD_LILY58_RIGHT + +config ZMK_SPLIT + default y + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif + diff --git a/app/boards/shields/lily58/Kconfig.shield b/app/boards/shields/lily58/Kconfig.shield new file mode 100644 index 000000000000..1b3bb6ba819f --- /dev/null +++ b/app/boards/shields/lily58/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2020 Pete Johanson +# SPDX-License-Identifier: MIT + +config SHIELD_LILY58_LEFT + def_bool $(shields_list_contains,lily58_left) + +config SHIELD_LILY58_RIGHT + def_bool $(shields_list_contains,lily58_right) diff --git a/app/boards/shields/lily58/boards/nice_nano.overlay b/app/boards/shields/lily58/boards/nice_nano.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/lily58/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/lily58/boards/nice_nano_v2.overlay b/app/boards/shields/lily58/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/lily58/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/lily58/lily58.conf b/app/boards/shields/lily58/lily58.conf new file mode 100644 index 000000000000..31eb7c6806e2 --- /dev/null +++ b/app/boards/shields/lily58/lily58.conf @@ -0,0 +1,6 @@ +# Uncomment to enable encoder +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# Uncomment the following line to enable the Lily58 OLED Display +# CONFIG_ZMK_DISPLAY=y diff --git a/app/boards/shields/lily58/lily58.dtsi b/app/boards/shields/lily58/lily58.dtsi new file mode 100644 index 000000000000..bd6d04e6d67d --- /dev/null +++ b/app/boards/shields/lily58/lily58.dtsi @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zephyr,display = &oled; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <16>; + rows = <5>; +// | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | +// | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | +// | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | +// | SW24 | SW23 | SW22 | SW21 | SW20 | SW19 | SW25 | | SW25 | SW19 | SW20 | SW21 | SW22 | SW23 | SW24 | +// | SW29 | SW28 | SW27 | SW26 | | SW26 | SW27 | SW28 | SW29 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) + RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,7) RC(4,8) RC(4,9) RC(4,10) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + }; + + left_encoder: encoder_left { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + }; + + sensors: sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder>; + triggers-per-rotation = <20>; + }; +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/lily58/lily58.keymap b/app/boards/shields/lily58/lily58.keymap new file mode 100644 index 000000000000..7df3277f780e --- /dev/null +++ b/app/boards/shields/lily58/lily58.keymap @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ------------------------------------------------------------------------------------------------------------ +// | ESC | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | ` | +// | TAB | Q | W | E | R | T | | Y | U | I | O | P | - | +// | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | +// | SHIFT | Z | X | C | V | B | "[" | | "]" | N | M | , | . | / | SHIFT | +// | ALT | GUI | LOWER| SPACE | | ENTER | RAISE| BSPC | GUI | + bindings = < +&kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp GRAVE +&kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp MINUS +&kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT +&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LBKT &kp RBKT &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LALT &kp LGUI &mo 1 &kp SPACE &kp RET &mo 2 &kp BSPC &kp RGUI + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + lower_layer { +// ------------------------------------------------------------------------------------------------------------ +// | BTCLR | BT1 | BT2 | BT3 | BT4 | BT5 | | | | | | | | +// | F1 | F2 | F3 | F4 | F5 | F6 | | F7 | F8 | F9 | F10 | F11 | F12 | +// | ` | ! | @ | # | $ | % | | ^ | & | * | ( | ) | ~ | +// | | | | | | | | | | | _ | + | { | } | "|" | +// | | | | | | | | | | + bindings = < +&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans +&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 +&kp GRAVE &kp EXCL &kp AT &kp HASH &kp DOLLAR &kp PRCNT &kp CARET &kp AMPS &kp KP_MULTIPLY &kp LPAR &kp RPAR &kp TILDE +&trans &ext_power EP_ON &ext_power EP_OFF &ext_power EP_TOG &trans &trans &trans &trans &trans &kp MINUS &kp KP_PLUS &kp LBRC &kp RBRC &kp PIPE + &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + raise_layer { +// ------------------------------------------------------------------------------------------------------------ +// | | | | | | | | | | | | | | +// | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | | +// | F1 | F2 | F3 | F4 | F5 | F6 | | | <- | v | ^ | -> | | +// | F7 | F8 | F9 | F10 | F11 | F12 | | | | + | - | = | [ | ] | \ | +// | | | | | | | | | | + bindings = < +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &trans +&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &trans &kp LEFT &kp DOWN &kp UP &kp RIGHT &trans +&kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &trans &trans &kp KP_PLUS &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH + &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + }; +}; diff --git a/app/boards/shields/lily58/lily58.zmk.yml b/app/boards/shields/lily58/lily58.zmk.yml new file mode 100644 index 000000000000..65069a13e9f5 --- /dev/null +++ b/app/boards/shields/lily58/lily58.zmk.yml @@ -0,0 +1,13 @@ +file_format: "1" +id: lily58 +name: Lily58 +type: shield +url: https://github.com/kata0510/Lily58 +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display +siblings: + - lily58_left + - lily58_right diff --git a/app/boards/shields/lily58/lily58_left.conf b/app/boards/shields/lily58/lily58_left.conf new file mode 100644 index 000000000000..24f8d77923d1 --- /dev/null +++ b/app/boards/shields/lily58/lily58_left.conf @@ -0,0 +1,3 @@ +# Uncomment to enable encoder +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y diff --git a/app/boards/shields/lily58/lily58_left.overlay b/app/boards/shields/lily58/lily58_left.overlay new file mode 100644 index 000000000000..b95332d9845d --- /dev/null +++ b/app/boards/shields/lily58/lily58_left.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ + +#include "lily58.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + ; +}; + +&left_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/lily58/lily58_right.conf b/app/boards/shields/lily58/lily58_right.conf new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/app/boards/shields/lily58/lily58_right.conf @@ -0,0 +1 @@ + diff --git a/app/boards/shields/lily58/lily58_right.overlay b/app/boards/shields/lily58/lily58_right.overlay new file mode 100644 index 000000000000..15820ad2966e --- /dev/null +++ b/app/boards/shields/lily58/lily58_right.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ + +#include "lily58.dtsi" + +&default_transform { + col-offset = <6>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/lotus58/Kconfig.defconfig b/app/boards/shields/lotus58/Kconfig.defconfig new file mode 100644 index 000000000000..62695c2020a5 --- /dev/null +++ b/app/boards/shields/lotus58/Kconfig.defconfig @@ -0,0 +1,49 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_LOTUS58_LEFT + +config ZMK_KEYBOARD_NAME + default "Lotus58" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_LOTUS58_LEFT || SHIELD_LOTUS58_RIGHT + +config ZMK_SPLIT + default y + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif diff --git a/app/boards/shields/lotus58/Kconfig.shield b/app/boards/shields/lotus58/Kconfig.shield new file mode 100644 index 000000000000..2d91c58cb471 --- /dev/null +++ b/app/boards/shields/lotus58/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_LOTUS58_LEFT + def_bool $(shields_list_contains,lotus58_left) + +config SHIELD_LOTUS58_RIGHT + def_bool $(shields_list_contains,lotus58_right) diff --git a/app/boards/shields/lotus58/lotus58.conf b/app/boards/shields/lotus58/lotus58.conf new file mode 100644 index 000000000000..193f1ab477d9 --- /dev/null +++ b/app/boards/shields/lotus58/lotus58.conf @@ -0,0 +1,9 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Uncomment the following line to enable the Lotus58 OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment these two lines to add support for encoders +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y diff --git a/app/boards/shields/lotus58/lotus58.dtsi b/app/boards/shields/lotus58/lotus58.dtsi new file mode 100644 index 000000000000..c58e9404265e --- /dev/null +++ b/app/boards/shields/lotus58/lotus58.dtsi @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zephyr,display = &oled; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <16>; + rows = <4>; +// | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | +// | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | +// | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | SW30 | | SW30 | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | +// | SW24 | SW23 | SW22 | SW21 | SW20 | SW19 | SW25 | | SW25 | SW19 | SW20 | SW21 | SW22 | SW23 | SW24 | +// | SW29 | SW28 | SW27 | SW26 | | SW26 | SW27 | SW28 | SW29 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(4,0) RC(4,11) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) + RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,7) RC(4,8) RC(4,9) RC(4,10) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; + + left_encoder: encoder_left { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + right_encoder: encoder_right { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + sensors: sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + triggers-per-rotation = <20>; + }; +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/lotus58/lotus58.keymap b/app/boards/shields/lotus58/lotus58.keymap new file mode 100644 index 000000000000..e9846e817981 --- /dev/null +++ b/app/boards/shields/lotus58/lotus58.keymap @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +/ { + combos { + compatible = "zmk,combos"; + combo_dsklg { + timeout-ms = <100>; + key-positions = <24 52>; + layers = <0>; + bindings = <&kp LGUI>; + }; + }; + + behaviors { + fofunc: four_ffour { + compatible = "zmk,behavior-mod-morph"; + #binding-cells = <0>; + bindings = <&kp N4>, <&kp F4>; + mods = <(MOD_LALT|MOD_RALT)>; + }; + sleft: s_left { + compatible = "zmk,behavior-mod-morph"; + #binding-cells = <0>; + bindings = <&kp S>, <&kp LEFT>; + mods = <(MOD_LGUI|MOD_RGUI)>; + }; + fright: f_right { + compatible = "zmk,behavior-mod-morph"; + #binding-cells = <0>; + bindings = <&kp F>, <&kp RIGHT>; + mods = <(MOD_LGUI|MOD_RGUI)>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ------------------------------------------------------------------------------------------------------------ +// 0| ESC | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | = | 11 +// 12| TAB | Q | W | E | R | T | | Y | U | I | O | P | [ | 23 +// 24| SFT | A | S | D | F | G | RESET | | RESET | H | J | K | L | ; | ' SFT | 37 +// 38| CTRL | Z | X | C | V | B | MUTE | | PLAY | N | M | , | . | / | \ CTRL| 51 +// 52 |ENT RS| ALT | SPACE|DELETE LW| |ENTER RS| BSPC | ] LW | RGUI | 59 + bindings = < +&kp ESC &kp N1 &kp N2 &kp N3 &fofunc &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp EQUAL +&kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT +&kp LSHFT &kp A &sleft &kp D &fright &kp G &sys_reset &sys_reset &kp H &kp J &kp K &kp L &kp SEMI &mt RSHFT SQT +&kp LCTRL &kp Z &kp X &kp C &kp V &kp B &kp C_MUTE &kp C_PP &kp N &kp M &kp COMMA &kp DOT &kp FSLH &mt RCTRL BSLH + < 2 RET &kp LALT &kp SPACE < 1 DEL < 2 RET &kp BSPC < 1 RBKT &kp LGUI + >; + + sensor-bindings = <&inc_dec_kp C_VOL_DN C_VOL_UP &inc_dec_kp PG_UP PG_DN>; + }; + + lower_layer { +// ------------------------------------------------------------------------------------------------------------ +// | ` | F1 | F2 | F3 | F4 | F5 | | F6 | F7 | F8 | F9 | F10 | F11 | +// | | ! | HOME| ^ | END | % | | VOL^ | PGUP | INS | ^ | PSCR | - | +// | | # | <- | v | -> | $ | | | | VOLv | <- | ^ | -> | ~ | _ | +// | | @ | - | ( | ) | & | | | | MUTE | PGDN | v | : | * | | | +// | F11 | | | | | | | | F12 | + bindings = < +&kp GRAVE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp PLUS +&trans &kp EXCL &kp HOME &kp UP &kp END &kp PRCNT &kp C_VOL_UP &kp PG_UP &kp INS &kp CARET &kp PSCRN &kp MINUS +&trans &kp HASH &kp LEFT &kp DOWN &kp RIGHT &kp DLLR &trans &trans &kp C_VOL_DN &kp LEFT &kp UP &kp RIGHT &kp TILDE &kp UNDER +&trans &kp AT &kp MINUS &kp LBRC &kp RBRC &kp AMPS &trans &trans &kp C_MUTE &kp PG_DN &kp DOWN &kp COLON &kp STAR &kp PIPE + &kp F11 &trans &trans &trans &trans &trans &trans &kp F12 + >; + + sensor-bindings = <&inc_dec_kp C_VOL_DN C_VOL_UP &inc_dec_kp C_NEXT C_PREV>; + }; + + raise_layer { +// ------------------------------------------------------------------------------------------------------------ +// |BTCLR| BT1 | BT2 | BT3 | BT4 | BT5 | |OUTTOG|OUTUSB| OUTBT | | RESET | FLASH | +// | | INS | PSCR | GUI | RESET | | | PGUP | | ^ | | | | +// | | ALT | CTRL | SHIFT | FLASH | CAPS | | | | PGDN | <- | v | -> | DEL | BSPC | +// | | UNDO | CUT | COPY | PASTE | | | | | | |> | <|<| | |>|> | | | +// | | | | | | | | | | + bindings = < +&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &out OUT_TOG &out OUT_USB &out OUT_BLE &trans &sys_reset &bootloader +&trans &kp INS &kp PSCRN &kp K_CMENU &sys_reset &trans &kp PG_UP &trans &kp UP &trans &trans &trans +&trans &kp LALT &kp LCTRL &kp LSHFT &bootloader &kp CLCK &trans &trans &kp PG_DN &kp LEFT &kp DOWN &kp RIGHT &kp DEL &kp BSPC +&trans &kp K_UNDO &kp K_CUT &kp K_COPY &kp K_PASTE &trans &trans &trans &trans &kp C_PP &kp C_PREV &kp C_NEXT &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_DN C_VOL_UP &inc_dec_kp PG_UP PG_DN>; + }; + }; +}; diff --git a/app/boards/shields/lotus58/lotus58.zmk.yml b/app/boards/shields/lotus58/lotus58.zmk.yml new file mode 100644 index 000000000000..5cabbd0ee4e4 --- /dev/null +++ b/app/boards/shields/lotus58/lotus58.zmk.yml @@ -0,0 +1,14 @@ +file_format: "1" +id: lotus58 +name: Lotus58 +type: shield +url: https://github.com/TweetyDaBird/Lotus58 +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder +siblings: + - lotus58_left + - lotus58_right diff --git a/app/boards/shields/lotus58/lotus58_left.overlay b/app/boards/shields/lotus58/lotus58_left.overlay new file mode 100644 index 000000000000..a1fc1e28e4f3 --- /dev/null +++ b/app/boards/shields/lotus58/lotus58_left.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "lotus58.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + ; +}; + +&left_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/lotus58/lotus58_right.overlay b/app/boards/shields/lotus58/lotus58_right.overlay new file mode 100644 index 000000000000..5bdfe710a277 --- /dev/null +++ b/app/boards/shields/lotus58/lotus58_right.overlay @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "lotus58.dtsi" + +&default_transform { + col-offset = <6>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + ; +}; + +&right_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/m60/Kconfig.defconfig b/app/boards/shields/m60/Kconfig.defconfig new file mode 100644 index 000000000000..a46969540c3a --- /dev/null +++ b/app/boards/shields/m60/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_M60 + +config ZMK_KEYBOARD_NAME + default "m60" + +endif diff --git a/app/boards/shields/m60/Kconfig.shield b/app/boards/shields/m60/Kconfig.shield new file mode 100644 index 000000000000..b1414b96dcd2 --- /dev/null +++ b/app/boards/shields/m60/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_M60 + def_bool $(shields_list_contains,m60) diff --git a/app/boards/shields/m60/README.md b/app/boards/shields/m60/README.md new file mode 100644 index 000000000000..e801c788dcfe --- /dev/null +++ b/app/boards/shields/m60/README.md @@ -0,0 +1,14 @@ +# [Makerdiary M60](https://wiki.makerdiary.com/m60) + +A 60% ANSI keyboard designed and manufactured by Makerdiary. +http://makerdiary.com + +## Features + +- Per key RGB LED. +- Uses makerdiary M.2 nRF52840 module +- Matrix wiring + +## Hardware Notes + +https://wiki.makerdiary.com/m60/developer_guide/hardware/ diff --git a/app/boards/shields/m60/m60.conf b/app/boards/shields/m60/m60.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/m60/m60.keymap b/app/boards/shields/m60/m60.keymap new file mode 100644 index 000000000000..8daa6b7cd7af --- /dev/null +++ b/app/boards/shields/m60/m60.keymap @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + keymap0: keymap { + compatible = "zmk,keymap"; + + default_layer { +// ------------------------------------------------------------------------------------------ +// | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | +// | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | +// | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | +// | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | +// | CTL | WIN | ALT | SPACE | ALT | MO(1) | WIN | CTRL | +// ------------------------------------------------------------------------------------------ + bindings = < + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &mo 1 &kp RGUI &kp RCTRL + >; + }; + + fn_layer { + bindings = < +&kp GRAVE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &bootloader +&trans &bt BT_CLR &none &none &none &none &none &none &none &none &none &none &none &sys_reset +&trans &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &kp LEFT &kp DOWN &kp UP &kp RIGHT &none &none &trans +&trans &none &none &none &none &none &none &none &none &none &none &trans +&trans &trans &trans &trans &trans &trans &trans &trans + >; + }; + }; +}; diff --git a/app/boards/shields/m60/m60.overlay b/app/boards/shields/m60/m60.overlay new file mode 100644 index 000000000000..7757abefe62c --- /dev/null +++ b/app/boards/shields/m60/m60.overlay @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&gpio0 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 12 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 11 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + col-gpios + = <&gpio0 19 GPIO_ACTIVE_HIGH> + , <&gpio0 20 GPIO_ACTIVE_HIGH> + , <&gpio0 21 GPIO_ACTIVE_HIGH> + , <&gpio0 22 GPIO_ACTIVE_HIGH> + , <&gpio0 23 GPIO_ACTIVE_HIGH> + , <&gpio0 24 GPIO_ACTIVE_HIGH> + , <&gpio0 25 GPIO_ACTIVE_HIGH> + , <&gpio0 26 GPIO_ACTIVE_HIGH> + ; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <8>; + rows = <8>; +// | MX1 | MX2 | MX3 | MX4 | MX5 | MX6 | MX7 | MX8 | MX9 | MX10 | MX11 | MX12 | MX13 | MX14 | +// | MX15 | MX16 | MX17 | MX18 | MX19 | MX20 | MX21 | MX22 | MX23 | MX24 | MX25 | MX26 | MX27 | MX28 | +// | MX29 | MX30 | MX31 | MX32 | MX33 | MX34 | MX35 | MX36 | MX37 | MX38 | MX39 | MX40 | MX41 | +// | MX42 | MX43 | MX44 | MX45 | MX46 | MX47 | MX48 | MX49 | MX50 | MX51 | MX52 | MX53 | +// | MX54 | MX55 | MX56 | MX57 | MX58 | MX59 | MX60 | MX61 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) +RC(3,3) RC(3,2) RC(3,1) RC(3,0) RC(2,7) RC(2,6) RC(2,5) RC(2,4) RC(2,3) RC(2,2) RC(2,1) RC(2,0) RC(1,7) RC(1,6) +RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(5,0) +RC(6,4) RC(6,3) RC(6,2) RC(6,1) RC(6,0) RC(5,7) RC(5,6) RC(5,5) RC(5,4) RC(5,3) RC(5,2) RC(5,1) +RC(6,5) RC(6,6) RC(6,7) RC(7,0) RC(7,1) RC(7,2) RC(7,3) RC(7,4) + >; + }; +}; + diff --git a/app/boards/shields/m60/m60.zmk.yml b/app/boards/shields/m60/m60.zmk.yml new file mode 100644 index 000000000000..8050df456291 --- /dev/null +++ b/app/boards/shields/m60/m60.zmk.yml @@ -0,0 +1,8 @@ +file_format: "1" +id: m60 +name: MakerDiary m60 +type: shield +url: https://makerdiary.com/pages/m60-mechanical-keyboard +requires: [makerdiary_nrf52840_m2] +features: + - keys diff --git a/app/boards/shields/microdox/Kconfig.defconfig b/app/boards/shields/microdox/Kconfig.defconfig new file mode 100644 index 000000000000..e355c6411ee3 --- /dev/null +++ b/app/boards/shields/microdox/Kconfig.defconfig @@ -0,0 +1,49 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_MICRODOX_LEFT || SHIELD_MICRODOX_V2_LEFT + +config ZMK_KEYBOARD_NAME + default "Microdox" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_MICRODOX_LEFT || SHIELD_MICRODOX_RIGHT || SHIELD_MICRODOX_V2_LEFT || SHIELD_MICRODOX_V2_RIGHT + +config ZMK_SPLIT + default y + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif diff --git a/app/boards/shields/microdox/Kconfig.shield b/app/boards/shields/microdox/Kconfig.shield new file mode 100644 index 000000000000..e0f461ff56fb --- /dev/null +++ b/app/boards/shields/microdox/Kconfig.shield @@ -0,0 +1,14 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_MICRODOX_LEFT + def_bool $(shields_list_contains,microdox_left) + +config SHIELD_MICRODOX_RIGHT + def_bool $(shields_list_contains,microdox_right) + +config SHIELD_MICRODOX_V2_LEFT + def_bool $(shields_list_contains,microdox_v2_left) + +config SHIELD_MICRODOX_V2_RIGHT + def_bool $(shields_list_contains,microdox_v2_right) diff --git a/app/boards/shields/microdox/README.md b/app/boards/shields/microdox/README.md new file mode 100644 index 000000000000..f92807bb7eba --- /dev/null +++ b/app/boards/shields/microdox/README.md @@ -0,0 +1,8 @@ +# Microdox + +Microdox is a 36 key split keyboard by Boardsource. + +Two variants are defined for this shield – V1 and V2. The layout is exactly the same between the +two. Per [help documentation](https://www.boardsource.xyz/help/6129be4a9c85c6050be190d2), if you +purchased your PCB before April 2022, use `microdox_left`/`microdox_right`. Otherwise, use +`microdox_v2_left`/`microdox_v2_right`. diff --git a/app/boards/shields/microdox/boards/nice_nano.overlay b/app/boards/shields/microdox/boards/nice_nano.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/microdox/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/microdox/boards/nice_nano_v2.overlay b/app/boards/shields/microdox/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/microdox/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/microdox/microdox.conf b/app/boards/shields/microdox/microdox.conf new file mode 100644 index 000000000000..0d38398c0293 --- /dev/null +++ b/app/boards/shields/microdox/microdox.conf @@ -0,0 +1,6 @@ +# Uncomment the following lines to enable the Microdox RGB Underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y + +# Uncomment the following line to enable the Microdox OLED Display +# CONFIG_ZMK_DISPLAY=y diff --git a/app/boards/shields/microdox/microdox.dtsi b/app/boards/shields/microdox/microdox.dtsi new file mode 100644 index 000000000000..4869cfeabbde --- /dev/null +++ b/app/boards/shields/microdox/microdox.dtsi @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "microdox_common.dtsi" + +/ { + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + row-gpios + = <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; diff --git a/app/boards/shields/microdox/microdox.keymap b/app/boards/shields/microdox/microdox.keymap new file mode 100644 index 000000000000..c9298ff8cf4b --- /dev/null +++ b/app/boards/shields/microdox/microdox.keymap @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ----------------------------------------------------------------------------------------- +// | Q | W | E | R | T | | Y | U | I | O | P | +// | A | S | D | F | G | | H | J | K | L | ; | +// | Z | X | C | V | B | | N | M | , | . | / | +// | GUI | NAV | SHFT | | SPC | SYM | ALT | + bindings = < + &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P + &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI + &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH + &kp LGUI &mo 1 &kp LSHFT &kp SPACE &mo 2 &kp RALT + >; + }; + nav_layer { +// ----------------------------------------------------------------------------------------- +// |BTCLR| | ESC | ~ | | | TAB | HOME | UP | END | DEL | +// | BT1 | GUI | ALT | CTRL | NUM | | / | LEFT | DOWN | RGT | BKSP | +// | BT2 | | | | | | \ | ENT | | | | +// | | | | | | | | + bindings = < + &bt BT_CLR &trans &kp ESC &kp TILDE &trans &kp TAB &kp HOME &kp UP &kp END &kp DEL + &bt BT_SEL 0 &kp K_CMENU &kp RALT &kp LCTRL &mo 3 &kp FSLH &kp LEFT &kp DOWN &kp RIGHT &kp BSPC + &bt BT_SEL 1 &trans &trans &trans &trans &kp BSLH &kp RET &trans &trans &trans + &trans &trans &trans &trans &trans &trans + >; + }; + + sym_layer { +// ----------------------------------------------------------------------------------------- +// | ! | @ | # | $ | % | | ^ | & | * | ( | ) | +// | | | | | | | - | = | { | } | "|" | +// | | | | | | | _ | + | [ | ] | \ | +// | GUI | | SPC | | ENT | | ALT | + bindings = < + &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp KP_MULTIPLY &kp LPAR &kp RPAR + &trans &trans &trans &trans &trans &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp PIPE + &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp BSLH + &kp LGUI &trans &kp SPACE &kp RET &trans &kp RALT + >; + }; + +// This layer is unreachable until "tri layer state" is sorted out. +// Leaving it here for completeness. + num_layer { +// ----------------------------------------------------------------------------------------- +// | | | | | | | A | 7 | 8 | 9 | D | +// | | | | | | | B | 4 | 5 | 6 | E | +// | | | | | | | C | 1 | 2 | 3 | F | +// | | | | | 0 | . | | + bindings = < + &trans &trans &trans &trans &trans &kp A &kp N7 &kp N8 &kp N9 &kp D + &trans &trans &trans &trans &trans &kp B &kp N4 &kp N5 &kp N6 &kp E + &trans &trans &trans &trans &trans &kp C &kp N1 &kp N2 &kp N3 &kp F + &trans &trans &trans &kp N0 &kp DOT &trans + >; + }; + }; +}; diff --git a/app/boards/shields/microdox/microdox.zmk.yml b/app/boards/shields/microdox/microdox.zmk.yml new file mode 100644 index 000000000000..389fbca494f0 --- /dev/null +++ b/app/boards/shields/microdox/microdox.zmk.yml @@ -0,0 +1,13 @@ +file_format: "1" +id: microdox +name: Microdox +type: shield +url: https://boardsource.xyz/store/5f2e7e4a2902de7151494f92 +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display +siblings: + - microdox_left + - microdox_right diff --git a/app/boards/shields/microdox/microdox_common.dtsi b/app/boards/shields/microdox/microdox_common.dtsi new file mode 100644 index 000000000000..1a762aae6dec --- /dev/null +++ b/app/boards/shields/microdox/microdox_common.dtsi @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zephyr,display = &oled; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <10>; + rows = <4>; +// | SW1 | SW2 | SW3 | SW4 | SW5 | | SW5 | SW4 | SW3 | SW2 | SW1 | +// | SW6 | SW7 | SW8 | SW9 | SW10 | | SW10 | SW9 | SW8 | SW7 | SW6 | +// | SW11 | SW12 | SW13 | SW14 | SW15 | | SW15 | SW14 | SW13 | SW12 | SW11 | +// | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) + RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) + >; + }; + + // TODO: per-key RGB node(s)? +}; + +&pro_micro_i2c { + status = "okay"; + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/microdox/microdox_left.conf b/app/boards/shields/microdox/microdox_left.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/microdox/microdox_left.overlay b/app/boards/shields/microdox/microdox_left.overlay new file mode 100644 index 000000000000..d38f50da8761 --- /dev/null +++ b/app/boards/shields/microdox/microdox_left.overlay @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "microdox.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 21 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/microdox/microdox_right.conf b/app/boards/shields/microdox/microdox_right.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/microdox/microdox_right.overlay b/app/boards/shields/microdox/microdox_right.overlay new file mode 100644 index 000000000000..4dd29016de81 --- /dev/null +++ b/app/boards/shields/microdox/microdox_right.overlay @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "microdox.dtsi" + +&default_transform { + col-offset = <5>; +}; + +&oled { + segment-remap; + com-invdir; +}; + +&kscan0 { + col-gpios + = <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 21 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/microdox/microdox_v2.conf b/app/boards/shields/microdox/microdox_v2.conf new file mode 100644 index 000000000000..0d38398c0293 --- /dev/null +++ b/app/boards/shields/microdox/microdox_v2.conf @@ -0,0 +1,6 @@ +# Uncomment the following lines to enable the Microdox RGB Underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y + +# Uncomment the following line to enable the Microdox OLED Display +# CONFIG_ZMK_DISPLAY=y diff --git a/app/boards/shields/microdox/microdox_v2.dtsi b/app/boards/shields/microdox/microdox_v2.dtsi new file mode 100644 index 000000000000..6eb7efa58f44 --- /dev/null +++ b/app/boards/shields/microdox/microdox_v2.dtsi @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "microdox_common.dtsi" + +/ { + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + }; +}; diff --git a/app/boards/shields/microdox/microdox_v2.zmk.yml b/app/boards/shields/microdox/microdox_v2.zmk.yml new file mode 100644 index 000000000000..1b9b65b33e41 --- /dev/null +++ b/app/boards/shields/microdox/microdox_v2.zmk.yml @@ -0,0 +1,13 @@ +file_format: "1" +id: microdox_v2 +name: Microdox V2 +type: shield +url: https://boardsource.xyz/store/5f2e7e4a2902de7151494f92 +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display +siblings: + - microdox_v2_left + - microdox_v2_right diff --git a/app/boards/shields/microdox/microdox_v2_left.conf b/app/boards/shields/microdox/microdox_v2_left.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/microdox/microdox_v2_left.overlay b/app/boards/shields/microdox/microdox_v2_left.overlay new file mode 100644 index 000000000000..83326f6fdc23 --- /dev/null +++ b/app/boards/shields/microdox/microdox_v2_left.overlay @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "microdox_v2.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + ; + row-gpios + = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; +}; diff --git a/app/boards/shields/microdox/microdox_v2_right.conf b/app/boards/shields/microdox/microdox_v2_right.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/microdox/microdox_v2_right.overlay b/app/boards/shields/microdox/microdox_v2_right.overlay new file mode 100644 index 000000000000..412c42f63f4b --- /dev/null +++ b/app/boards/shields/microdox/microdox_v2_right.overlay @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "microdox.dtsi" + +&default_transform { + col-offset = <5>; +}; + +&oled { + segment-remap; + com-invdir; +}; + +&kscan0 { + col-gpios + = <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 21 GPIO_ACTIVE_HIGH> + ; + row-gpios + = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; +}; diff --git a/app/boards/shields/murphpad/Kconfig.defconfig b/app/boards/shields/murphpad/Kconfig.defconfig new file mode 100644 index 000000000000..80e65351dad7 --- /dev/null +++ b/app/boards/shields/murphpad/Kconfig.defconfig @@ -0,0 +1,39 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_MURPHPAD + +config ZMK_KEYBOARD_NAME + default "MurphPad" + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif diff --git a/app/boards/shields/murphpad/Kconfig.shield b/app/boards/shields/murphpad/Kconfig.shield new file mode 100644 index 000000000000..1c961aeadc85 --- /dev/null +++ b/app/boards/shields/murphpad/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_MURPHPAD + def_bool $(shields_list_contains,murphpad) \ No newline at end of file diff --git a/app/boards/shields/murphpad/boards/nice_nano.conf b/app/boards/shields/murphpad/boards/nice_nano.conf new file mode 100644 index 000000000000..dda71c13f518 --- /dev/null +++ b/app/boards/shields/murphpad/boards/nice_nano.conf @@ -0,0 +1,3 @@ +# Uncomment both to enable underglow +CONFIG_ZMK_RGB_UNDERGLOW=y +CONFIG_WS2812_STRIP=y diff --git a/app/boards/shields/murphpad/boards/nice_nano.overlay b/app/boards/shields/murphpad/boards/nice_nano.overlay new file mode 100644 index 000000000000..be8ff5290fb7 --- /dev/null +++ b/app/boards/shields/murphpad/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/murphpad/boards/nice_nano_v2.overlay b/app/boards/shields/murphpad/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..be8ff5290fb7 --- /dev/null +++ b/app/boards/shields/murphpad/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/murphpad/murphpad.conf b/app/boards/shields/murphpad/murphpad.conf new file mode 100644 index 000000000000..bdcd42552cda --- /dev/null +++ b/app/boards/shields/murphpad/murphpad.conf @@ -0,0 +1,9 @@ +# Uncomment to turn on logging, and set ZMK logging to debug output +# CONFIG_ZMK_USB_LOGGING=y + +# Uncomment both to enable encoder +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# Uncomment to enable OLED +CONFIG_ZMK_DISPLAY=y \ No newline at end of file diff --git a/app/boards/shields/murphpad/murphpad.keymap b/app/boards/shields/murphpad/murphpad.keymap new file mode 100644 index 000000000000..069eeea3ba8c --- /dev/null +++ b/app/boards/shields/murphpad/murphpad.keymap @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + + +#define TIMEOUT 300 + +&encoder_1 { + status = "okay"; +}; + +&encoder_2 { + status = "okay"; +}; + +/ { + combos { + compatible = "zmk,combos"; + combo_btclr { + timeout-ms = ; + key-positions = <1 6>; + bindings = <&bt BT_CLR>; + }; + combo_reset { + timeout-ms = ; + key-positions = <1 3>; + bindings = <&sys_reset>; + }; + combo_bootloader { + timeout-ms = ; + key-positions = <1 2>; + bindings = <&bootloader>; + }; + combo_bt_nxt { + timeout-ms = ; + key-positions = <1 4>; + bindings = <&bt BT_NXT>; + }; + }; + + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&encoder_1 &encoder_2>; + triggers-per-rotation = <20>; + }; + + + keymap0: keymap { + compatible = "zmk,keymap"; + + default_layer { + display-name = "default layer"; + bindings = < + &bt BT_CLR &kp TAB &kp F5 &kp LC(LA(C)) &kp LG(D) + &rgb_ug RGB_TOG &kp ESC &kp KP_DIVIDE &kp KP_MULTIPLY &kp KP_MINUS + &rgb_ug RGB_EFF &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_PLUS + &kp C_MUTE &kp KP_N4 &kp KP_N5 &kp KP_N6 &trans + &mo 1 &kp KP_N1 &kp KP_N2 &kp KP_N3 &kp KP_ENTER + &kp BSPC &kp KP_N0 &trans &kp KP_DOT &trans + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + + }; + + fn_layer { + display-name = "fn layer"; + bindings = < + &trans &trans &trans &trans &trans + &trans &kp KP_NUM &trans &trans &trans + &trans &trans &trans &trans &trans + &bt BT_CLR &trans &trans &trans &trans + &trans &trans &trans &trans &trans + &kp DEL &trans &trans &trans &trans + >; + sensor-bindings = <&inc_dec_kp PG_UP PG_DN &inc_dec_kp C_VOL_UP C_VOL_DN>; + + }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/murphpad/murphpad.overlay b/app/boards/shields/murphpad/murphpad.overlay new file mode 100644 index 000000000000..f098ec8b017f --- /dev/null +++ b/app/boards/shields/murphpad/murphpad.overlay @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zephyr,display = &oled; + zmk,kscan = &kscan0; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + col-gpios + = <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + ; + }; + + encoder_1: encoder_1 { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + encoder_2: encoder_2 { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/murphpad/murphpad.zmk.yml b/app/boards/shields/murphpad/murphpad.zmk.yml new file mode 100644 index 000000000000..2dda83d90e6c --- /dev/null +++ b/app/boards/shields/murphpad/murphpad.zmk.yml @@ -0,0 +1,12 @@ +file_format: "1" +id: murphpad +name: MurphPad +type: shield +url: https://mechwild.com/product/murphpad/ +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder + - underglow diff --git a/app/boards/shields/naked60/Kconfig.defconfig b/app/boards/shields/naked60/Kconfig.defconfig new file mode 100644 index 000000000000..ff5978bc5274 --- /dev/null +++ b/app/boards/shields/naked60/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_NAKED60 + +config ZMK_KEYBOARD_NAME + default "Naked60BMP" + +endif \ No newline at end of file diff --git a/app/boards/shields/naked60/Kconfig.shield b/app/boards/shields/naked60/Kconfig.shield new file mode 100644 index 000000000000..61053686a1bf --- /dev/null +++ b/app/boards/shields/naked60/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_NAKED60 + def_bool $(shields_list_contains,naked60) diff --git a/app/boards/shields/naked60/naked60.conf b/app/boards/shields/naked60/naked60.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/naked60/naked60.keymap b/app/boards/shields/naked60/naked60.keymap new file mode 100644 index 000000000000..1c212cd4544c --- /dev/null +++ b/app/boards/shields/naked60/naked60.keymap @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + // ---------------------------------------------------------------------------------------------------------- + // | ESC | 1 | 2 | 3 | 4 | 5 |-------|-------| 6 | 7 | 8 | 9 | 0 | BSPC | + // | TAB | Q | W | E | R | T |-------|-------| Y | U | I | O | P | \ | + // | SHIFT | A | S | D | F | G |-------|-------| H | J | K | L | ; | ' | + // | CTRL | Z | X | C | V | B |-------|-------| N | M | , | . | / | ENTER | + // |-------|ADJUST| LCTL | LALT | LGUI | LOWR | SPACE | SPACE | RAIS | LARW | DARW | UARW | RARW |-------| + + + bindings = < + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSLH + &kp LSHFT &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LCTRL &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RET + &mo 3 &kp LCTRL &kp LALT &kp LGUI &mo 1 &kp SPACE &kp SPACE &mo 2 &kp LEFT &kp DOWN &kp UP &kp RIGHT + >; + }; + + lower { + // ---------------------------------------------------------------------------------------------------------- + // | ESC | F2 | F3 | F4 | F5 | F6 |-------|-------| F7 | F8 | F9 | F10 | F11 | F12 | + // | ~ | ! | @ | # | $ | % |-------|-------| ^ | & | * | ( | ) | DEL | + // | | F1 | F2 | F3 | F4 | F5 |-------|-------| F6 | _ | + | { | } | | | + // | | F7 | F8 | F9 | F10 | F11 |-------|-------| F12 | LS(#) |LS(|) | | | | + // |-------| | | | | | | | | NEXT | Vol- | Vol+ | PLAY |-------| + bindings = < + &kp ESC &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 + &kp TILDE &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp ASTRK &kp LPAR &kp RPAR &kp DEL + &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp UNDER &kp PLUS &kp LBRC &kp RBRC &kp PIPE + &trans &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp LS(NON_US_HASH) &kp LS(NON_US_BSLH) &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &mo 3 &kp C_NEXT &kp C_VOL_DN &kp C_VOL_UP &kp C_PLAY_PAUSE + >; + }; + + raise { + // ---------------------------------------------------------------------------------------------------------- + // | ESC | F2 | F3 | F4 | F5 | F6 |-------|-------| F7 | F8 | F9 | F10 | F11 | F12 | + // | ~ | 1 | 2 | 3 | 4 | 5 |-------|-------| 6 | 7 | 8 | 9 | 0 | DEL | + // | DEL | F1 | F2 | F3 | F4 | F5 |-------|-------| F6 | - | = | [ | ] | \ | + // | | F7 | F8 | F9 | F10 | F11 |-------|-------| F12 | # | | | | | | + // |-------| | | | | | | | | | | | |-------| + bindings = < + &kp ESC &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 + &kp TILDE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp DEL + &kp DEL &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH + &trans &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp NON_US_HASH &kp NON_US_BSLH &trans &trans &trans + &trans &trans &trans &trans &mo 3 &trans &trans &trans &trans &trans &trans &trans + >; + }; + + adjust { + // ---------------------------------------------------------------------------------------------------------- + // |tog(4)| F2 | F3 | F4 | F5 | F6 |------|------| F7 | F8 | F9 | F10 | F11 | F12 | + // | | NA | NA | NA | NA | NA |------|------| NA | NA | NA | NA | NA |LALT(PRTSN)| + // | | NA | NA | NA | NA | NA |------|------| NA | NA | NA | NA | NA | PRTSN | + // | | NA | NA | NA | NA | NA |------|------| NA | NA | NA | NA | NA |LCTRL(DEL) | + // |------| | | | | |BOOTLD|BOOTLD| | | | | |-----------| + bindings = < + &tog 4 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 + &trans &none &none &none &none &none &none &none &none &none &none &kp LA(PSCRN) + &trans &none &none &none &none &none &none &none &none &none &none &kp PSCRN + &trans &none &none &none &none &none &none &none &none &none &none &kp LC(DEL) + &trans &trans &trans &trans &trans &bootloader &bootloader &trans &trans &trans &trans &trans + >; + }; + + flock { + // ---------------------------------------------------------------------------------------------------------- + // |tog(4) | F2 | F3 | F4 | F5 | F6 |-------|-------| F7 | F8 | F9 | F10 | F11 | | + // |out tog|BT_SEL 0|BT_SEL 1|BT_SEL 2|BT_SEL 3|BT_SEL 4|-------|-------|BT_PRV|BT_NXT|BT_CLR| | | | + // | | | | | | |-------|-------| | | | | | | + // | | | | | | |-------|-------| | | | | | | + // |-------| | | | | | | | | | | | |------| + bindings = < + &tog 4 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &trans + &out OUT_TOG &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &bt BT_PRV &bt BT_NXT &bt BT_CLR &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/naked60/naked60.overlay b/app/boards/shields/naked60/naked60.overlay new file mode 100644 index 000000000000..843c867f1094 --- /dev/null +++ b/app/boards/shields/naked60/naked60.overlay @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + chosen { + zmk,kscan = &kscan0; + }; + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + col-gpios + = <&pro_micro 21 GPIO_ACTIVE_HIGH> // col 0 + , <&pro_micro 20 GPIO_ACTIVE_HIGH> // col 1 + , <&pro_micro 19 GPIO_ACTIVE_HIGH> // col 2 + , <&pro_micro 18 GPIO_ACTIVE_HIGH> // col 3 + , <&pro_micro 15 GPIO_ACTIVE_HIGH> // col 4 + , <&pro_micro 14 GPIO_ACTIVE_HIGH> // col 5 + , <&pro_micro 16 GPIO_ACTIVE_HIGH> // col 6 + , <&pro_micro 6 GPIO_ACTIVE_HIGH> // col 7 + , <&pro_micro 7 GPIO_ACTIVE_HIGH> // col 8 + , <&pro_micro 8 GPIO_ACTIVE_HIGH> // col 9 + , <&pro_micro 9 GPIO_ACTIVE_HIGH> // col 10 + , <&pro_micro 1 GPIO_ACTIVE_HIGH> // col 11 + ; + + row-gpios + = <&pro_micro 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row 0 + , <&pro_micro 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row 1 + , <&pro_micro 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row 2 + , <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row 3 + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row 4 + ; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/naked60/naked60.zmk.yml b/app/boards/shields/naked60/naked60.zmk.yml new file mode 100644 index 000000000000..932c229841c4 --- /dev/null +++ b/app/boards/shields/naked60/naked60.zmk.yml @@ -0,0 +1,8 @@ +file_format: "1" +id: naked60 +name: Naked60 +type: shield +url: https://salicylic-acid3.hatenablog.com/ +requires: [pro_micro] +features: + - keys diff --git a/app/boards/shields/nibble/Kconfig.defconfig b/app/boards/shields/nibble/Kconfig.defconfig new file mode 100644 index 000000000000..19bddec77b87 --- /dev/null +++ b/app/boards/shields/nibble/Kconfig.defconfig @@ -0,0 +1,39 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_NIBBLE + +config ZMK_KEYBOARD_NAME + default "NIBBLE" + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif diff --git a/app/boards/shields/nibble/Kconfig.shield b/app/boards/shields/nibble/Kconfig.shield new file mode 100644 index 000000000000..cb6fd15ec880 --- /dev/null +++ b/app/boards/shields/nibble/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_NIBBLE + def_bool $(shields_list_contains,nibble) diff --git a/app/boards/shields/nibble/README.md b/app/boards/shields/nibble/README.md new file mode 100644 index 000000000000..42646f970994 --- /dev/null +++ b/app/boards/shields/nibble/README.md @@ -0,0 +1,29 @@ +# Building ZMK for the Nibble + +Some general notes/commands for building standard nibble layouts from the assembly documentation. + +## LED Notes + +If you built your nibble without the LEDs _and_ are using a nice!nano board, you'll need to change the following in your local nibble config or add them to the end of the file. + +``` +CONFIG_ZMK_RGB_UNDERGLOW=n +CONFIG_WS2812_STRIP=n +``` + +## Encoder Notes + +If you built your nibble without an encoder, you'll need to change the following in your local nibble config or add them to the end of the file. + +``` +CONFIG_EC11=n +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=n +``` + +## OLED Builds + +If using an OLED screen, you'll need to change the following in your local nibble config or add them to the end of the file. + +``` +CONFIG_ZMK_DISPLAY=y +``` diff --git a/app/boards/shields/nibble/boards/nice_nano.conf b/app/boards/shields/nibble/boards/nice_nano.conf new file mode 100644 index 000000000000..14bed3d0fa35 --- /dev/null +++ b/app/boards/shields/nibble/boards/nice_nano.conf @@ -0,0 +1,4 @@ +# Enable underglow +CONFIG_ZMK_RGB_UNDERGLOW=y +# Use the STRIP config specific to the LEDs you're using +CONFIG_WS2812_STRIP=y \ No newline at end of file diff --git a/app/boards/shields/nibble/boards/nice_nano.overlay b/app/boards/shields/nibble/boards/nice_nano.overlay new file mode 100644 index 000000000000..3849a8fb1a2c --- /dev/null +++ b/app/boards/shields/nibble/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/nibble/boards/nice_nano_v2.overlay b/app/boards/shields/nibble/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..3849a8fb1a2c --- /dev/null +++ b/app/boards/shields/nibble/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/nibble/boards/proton_c.conf b/app/boards/shields/nibble/boards/proton_c.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/nibble/nibble.conf b/app/boards/shields/nibble/nibble.conf new file mode 100644 index 000000000000..4c15b1851def --- /dev/null +++ b/app/boards/shields/nibble/nibble.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Enable Encoders +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y diff --git a/app/boards/shields/nibble/nibble.keymap b/app/boards/shields/nibble/nibble.keymap new file mode 100644 index 000000000000..8b25c5a4133d --- /dev/null +++ b/app/boards/shields/nibble/nibble.keymap @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&encoder_1>; + triggers-per-rotation = <20>; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + display-name = "Default"; + + sensor-bindings = <&inc_dec_kp C_VOLUME_UP C_VOLUME_DOWN>; + + bindings = < + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp HOME +&kp C_MUTE &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp DEL +&trans &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET &kp PG_UP +&trans &kp LSHFT &trans &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp PG_DN +&trans &kp LCTRL &kp LGUI &kp LALT &kp SPACE &mo 1 &kp RALT &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT + >; + }; + function_layer { + display-name = "Function"; + + sensor-bindings = <&inc_dec_kp C_VOLUME_UP C_VOLUME_DOWN>; + + bindings = < + &kp TILDE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &trans &kp END +&kp C_MUTE &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &bootloader +&bt BT_CLR &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&bt BT_PRV &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&bt BT_NXT &trans &trans &trans &trans &trans &trans &trans &kp C_PREV &kp C_PP &kp C_NEXT + >; + }; + }; +}; diff --git a/app/boards/shields/nibble/nibble.overlay b/app/boards/shields/nibble/nibble.overlay new file mode 100644 index 000000000000..8b5a90dac7b5 --- /dev/null +++ b/app/boards/shields/nibble/nibble.overlay @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zephyr,display = &oled; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + encoder_1: encoder_1 { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + steps = <80>; + status = "okay"; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-demux"; + polling-interval-msec = <25>; + input-gpios + = <&pro_micro 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; + output-gpios + = <&pro_micro 21 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + ; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <16>; + rows = <5>; + + map = < + RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,15) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) RC(1,14) RC(1,15) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,14) RC(2,15) +RC(3,0) RC(3,1) RC(0,0) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) RC(3,14) RC(3,15) +RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,6) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,14) RC(4,15) + >; + }; +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/nibble/nibble.zmk.yml b/app/boards/shields/nibble/nibble.zmk.yml new file mode 100644 index 000000000000..cfc1409e53bc --- /dev/null +++ b/app/boards/shields/nibble/nibble.zmk.yml @@ -0,0 +1,9 @@ +file_format: "1" +id: nibble +name: Nibble +type: shield +url: https://nullbits.co/nibble/ +requires: [pro_micro] +features: + - keys + - encoder diff --git a/app/boards/shields/nice_view/CMakeLists.txt b/app/boards/shields/nice_view/CMakeLists.txt new file mode 100644 index 000000000000..694242b2ec19 --- /dev/null +++ b/app/boards/shields/nice_view/CMakeLists.txt @@ -0,0 +1,13 @@ +if(CONFIG_ZMK_DISPLAY AND CONFIG_NICE_VIEW_WIDGET_STATUS) + zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/include) + zephyr_library_sources(custom_status_screen.c) + zephyr_library_sources(widgets/bolt.c) + zephyr_library_sources(widgets/util.c) + + if(NOT CONFIG_ZMK_SPLIT OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL) + zephyr_library_sources(widgets/status.c) + else() + zephyr_library_sources(widgets/art.c) + zephyr_library_sources(widgets/peripheral_status.c) + endif() +endif() diff --git a/app/boards/shields/nice_view/Kconfig.defconfig b/app/boards/shields/nice_view/Kconfig.defconfig new file mode 100644 index 000000000000..53edc1ccc7f2 --- /dev/null +++ b/app/boards/shields/nice_view/Kconfig.defconfig @@ -0,0 +1,52 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_NICE_VIEW + +config LV_Z_VDB_SIZE + default 100 + +config LV_Z_DPI + default 161 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +choice ZMK_DISPLAY_WORK_QUEUE + default ZMK_DISPLAY_WORK_QUEUE_DEDICATED +endchoice + +choice ZMK_DISPLAY_STATUS_SCREEN + default ZMK_DISPLAY_STATUS_SCREEN_CUSTOM +endchoice + +config ZMK_DISPLAY_STATUS_SCREEN_CUSTOM + imply NICE_VIEW_WIDGET_STATUS + +config NICE_VIEW_WIDGET_STATUS + bool "Custom nice!view status widget" + select LV_FONT_MONTSERRAT_16 + select LV_USE_IMG + select LV_USE_CANVAS + +config NICE_VIEW_WIDGET_INVERTED + bool "Invert custom status widget colors" + +if !ZMK_SPLIT || ZMK_SPLIT_ROLE_CENTRAL + +config NICE_VIEW_WIDGET_STATUS + select LV_FONT_MONTSERRAT_18 + select LV_FONT_MONTSERRAT_14 + select LV_FONT_UNSCII_8 + select ZMK_WPM + +endif # !ZMK_SPLIT || ZMK_SPLIT_ROLE_CENTRAL + +config ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN + select LV_FONT_MONTSERRAT_26 + +endif # SHIELD_NICE_VIEW diff --git a/app/boards/shields/nice_view/Kconfig.shield b/app/boards/shields/nice_view/Kconfig.shield new file mode 100644 index 000000000000..fbe4fde873c3 --- /dev/null +++ b/app/boards/shields/nice_view/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_NICE_VIEW + def_bool $(shields_list_contains,nice_view) diff --git a/app/boards/shields/nice_view/README.md b/app/boards/shields/nice_view/README.md new file mode 100644 index 000000000000..00abfbfab1ef --- /dev/null +++ b/app/boards/shields/nice_view/README.md @@ -0,0 +1,15 @@ +# nice!view + +The nice!view is a low-power, high refresh rate display meant to replace I2C OLEDs traditionally used. + +This shield requires that an `&nice_view_spi` labeled SPI bus is provided with _at least_ MOSI, SCK, and CS pins defined. + +## Disable custom widget + +The nice!view shield includes a custom vertical widget. To use the built-in ZMK one, add the following item to your `.conf` file: + +``` +CONFIG_ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN=y +CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_26=y +CONFIG_LV_FONT_DEFAULT_MONTSERRAT_26=y +``` diff --git a/app/boards/shields/nice_view/custom_status_screen.c b/app/boards/shields/nice_view/custom_status_screen.c new file mode 100644 index 000000000000..c08da0eb5115 --- /dev/null +++ b/app/boards/shields/nice_view/custom_status_screen.c @@ -0,0 +1,28 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include "widgets/status.h" + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if IS_ENABLED(CONFIG_NICE_VIEW_WIDGET_STATUS) +static struct zmk_widget_status status_widget; +#endif + +lv_obj_t *zmk_display_status_screen() { + + lv_obj_t *screen; + screen = lv_obj_create(NULL); + +#if IS_ENABLED(CONFIG_NICE_VIEW_WIDGET_STATUS) + zmk_widget_status_init(&status_widget, screen); + lv_obj_align(zmk_widget_status_obj(&status_widget), LV_ALIGN_TOP_LEFT, 0, 0); +#endif + + return screen; +} diff --git a/app/boards/shields/nice_view/nice_view.conf b/app/boards/shields/nice_view/nice_view.conf new file mode 100644 index 000000000000..e6f9158f137a --- /dev/null +++ b/app/boards/shields/nice_view/nice_view.conf @@ -0,0 +1,4 @@ +# Enable nice!view +CONFIG_ZMK_DISPLAY=y +# Disable idle blanking +CONFIG_ZMK_DISPLAY_BLANK_ON_IDLE=n diff --git a/app/boards/shields/nice_view/nice_view.overlay b/app/boards/shields/nice_view/nice_view.overlay new file mode 100644 index 000000000000..e1965569f560 --- /dev/null +++ b/app/boards/shields/nice_view/nice_view.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +&nice_view_spi { + status = "okay"; + nice_view: ls0xx@0 { + compatible = "sharp,ls0xx"; + spi-max-frequency = <1000000>; + reg = <0>; + width = <160>; + height = <68>; + }; +}; + +/ { + chosen { + zephyr,display = &nice_view; + }; +}; diff --git a/app/boards/shields/nice_view/nice_view.zmk.yml b/app/boards/shields/nice_view/nice_view.zmk.yml new file mode 100644 index 000000000000..04b98a8ac5b2 --- /dev/null +++ b/app/boards/shields/nice_view/nice_view.zmk.yml @@ -0,0 +1,8 @@ +file_format: "1" +id: nice_view +name: nice!view +type: shield +url: https://nicekeyboards.com/nice-view +requires: [nice_view_header] +features: + - display diff --git a/app/boards/shields/nice_view/widgets/art.c b/app/boards/shields/nice_view/widgets/art.c new file mode 100644 index 000000000000..56c8914629f5 --- /dev/null +++ b/app/boards/shields/nice_view/widgets/art.c @@ -0,0 +1,229 @@ +/* + * + * Copyright (c) 2023 Collin Hodge + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BALLOON +#define LV_ATTRIBUTE_IMG_BALLOON +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BALLOON uint8_t + balloon_map[] = { +#if CONFIG_NICE_VIEW_WIDGET_INVERTED + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ +#else + 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ + 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ +#endif + + 0xfe, 0xaa, 0x0a, 0x2a, 0x9f, 0xff, 0xff, 0xff, 0xfa, 0xea, 0xaa, 0xae, 0xba, 0xff, 0xff, + 0xfb, 0xff, 0xf0, 0xf1, 0x55, 0x05, 0x15, 0x47, 0xff, 0xff, 0xff, 0xf5, 0xd5, 0x55, 0x5f, + 0x7f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xa4, 0xaa, 0x8a, 0x8a, 0xa1, 0xff, 0xff, 0xfb, 0xea, + 0xaa, 0xaa, 0xbe, 0xbf, 0xef, 0xfb, 0xfb, 0xff, 0xf0, 0x54, 0x55, 0x05, 0x45, 0x54, 0xff, + 0xff, 0x7d, 0x55, 0xd5, 0x75, 0x7f, 0x7f, 0xdf, 0xff, 0xff, 0xff, 0xf0, 0xae, 0x2a, 0x82, + 0xa0, 0xaa, 0x3f, 0xff, 0xfe, 0xaa, 0xea, 0xbb, 0xfe, 0xbf, 0xff, 0xfb, 0xfb, 0xfe, 0xf0, + 0x5f, 0x55, 0x01, 0x50, 0x54, 0x1f, 0xff, 0x7f, 0x55, 0xd5, 0x7f, 0xff, 0x7f, 0xd7, 0xff, + 0xfd, 0xfd, 0xf0, 0x2f, 0xff, 0x20, 0x28, 0x00, 0x0f, 0xff, 0xae, 0xaa, 0xaa, 0xbf, 0xff, + 0xff, 0xeb, 0xfb, 0xff, 0xff, 0xf0, 0x0e, 0x01, 0x50, 0x14, 0x00, 0x3f, 0xff, 0x57, 0x55, + 0xd5, 0x7f, 0xff, 0x7f, 0xd7, 0xfd, 0xff, 0xfd, 0xf0, 0x1e, 0x01, 0xa8, 0x0a, 0x00, 0xff, + 0xff, 0xaf, 0xaa, 0xaa, 0xff, 0xff, 0xff, 0xaf, 0xfb, 0xff, 0xff, 0xf0, 0x1f, 0xf9, 0x50, + 0x01, 0x03, 0xff, 0xff, 0x57, 0x55, 0xd5, 0x7d, 0xff, 0x7f, 0xdf, 0xfd, 0xff, 0xfd, 0xf0, + 0x9f, 0xf9, 0xa8, 0x00, 0x8f, 0xff, 0xfe, 0xaf, 0xaa, 0xaa, 0xff, 0xff, 0xfd, 0xbf, 0xfb, + 0xff, 0xfb, 0xf0, 0x5a, 0x01, 0x54, 0x00, 0x3f, 0xff, 0xff, 0x7f, 0x5d, 0xd5, 0xfd, 0xff, + 0xfd, 0xdf, 0xfd, 0xff, 0xfd, 0xf0, 0x8e, 0x01, 0xaa, 0x00, 0x7f, 0xff, 0xfe, 0xbf, 0xae, + 0xef, 0xff, 0xff, 0xfb, 0xef, 0xfb, 0xff, 0xfa, 0xf0, 0xcf, 0xff, 0xf4, 0x00, 0xf7, 0xff, + 0xff, 0x7f, 0x5d, 0xff, 0xff, 0xff, 0xfd, 0xdf, 0xff, 0xff, 0xfd, 0xf0, 0xae, 0x01, 0x2a, + 0x00, 0xfb, 0xff, 0xff, 0xbf, 0xae, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfa, 0xf0, + 0xde, 0x01, 0x35, 0x01, 0xfb, 0xff, 0xff, 0x7f, 0x5d, 0xfd, 0xbf, 0xff, 0xff, 0xdf, 0xfd, + 0xff, 0xdd, 0xf0, 0xa7, 0xff, 0xea, 0x81, 0xfc, 0xff, 0x7f, 0xbe, 0xbe, 0xff, 0xe3, 0xff, + 0xff, 0xef, 0xff, 0xf9, 0x3e, 0xf0, 0x56, 0x01, 0x55, 0x41, 0xff, 0x7f, 0xff, 0xff, 0xfd, + 0xfd, 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xfc, 0x7d, 0xf0, 0xa6, 0x01, 0x2a, 0x88, 0xfe, 0xff, + 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xfc, 0xfe, 0xf0, 0x52, 0x79, 0x15, + 0x44, 0x7d, 0xff, 0xff, 0xfd, 0x7f, 0xbd, 0xff, 0xff, 0xfc, 0x00, 0x07, 0xf8, 0xfd, 0xf0, + 0x22, 0x69, 0x2a, 0xa0, 0x3d, 0xff, 0xff, 0xfa, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xe2, 0x48, + 0xfa, 0xff, 0xf0, 0x42, 0x59, 0x15, 0x54, 0x1b, 0xff, 0xff, 0xf7, 0xff, 0xbd, 0xf7, 0xff, + 0xff, 0x95, 0x55, 0x37, 0x7d, 0xf0, 0x02, 0x69, 0x0a, 0xa2, 0x1f, 0xfe, 0xff, 0xee, 0xff, + 0xff, 0xfc, 0xff, 0xff, 0x2a, 0x4a, 0x9f, 0xff, 0xf0, 0x03, 0xff, 0x55, 0x11, 0x4f, 0xff, + 0xff, 0x55, 0x7f, 0xfd, 0xff, 0x00, 0xfc, 0x55, 0x55, 0x4f, 0xff, 0xf0, 0x02, 0x01, 0xaa, + 0x88, 0x8f, 0xde, 0xff, 0xaa, 0xbf, 0xfe, 0xff, 0xff, 0x00, 0xa8, 0x02, 0xa7, 0xff, 0xf0, + 0x02, 0x01, 0x55, 0x55, 0x47, 0xff, 0x7f, 0xd5, 0x5f, 0xff, 0xff, 0xff, 0xc8, 0x47, 0x5c, + 0x53, 0xff, 0xf0, 0x82, 0x49, 0xaa, 0x8a, 0xa7, 0xfe, 0xff, 0xea, 0xbf, 0xff, 0xff, 0xff, + 0xb0, 0x3f, 0x5f, 0x89, 0xff, 0xf0, 0xc2, 0x49, 0x55, 0x45, 0x53, 0xff, 0xff, 0xf5, 0x5f, + 0xff, 0xff, 0xfe, 0x70, 0x7f, 0x5f, 0xe5, 0xff, 0xf0, 0xe2, 0x41, 0xa2, 0xa2, 0xab, 0xfe, + 0xfb, 0xfa, 0xaf, 0xef, 0xff, 0xf9, 0xe2, 0xbf, 0x5f, 0xfa, 0xff, 0xf0, 0xe2, 0x41, 0x51, + 0x51, 0x51, 0xff, 0x77, 0xfd, 0x57, 0xf9, 0xff, 0xe7, 0x85, 0x7f, 0x5f, 0xfc, 0xff, 0xf0, + 0xe3, 0xff, 0xf2, 0xa0, 0xa8, 0xff, 0xfb, 0xbe, 0xaf, 0xfe, 0x1e, 0x80, 0x6a, 0x80, 0x00, + 0x7e, 0xff, 0xb0, 0xe2, 0x60, 0x11, 0x50, 0x54, 0x7f, 0xff, 0xfd, 0x57, 0xff, 0xe0, 0x1f, + 0xc4, 0x15, 0x55, 0x06, 0x7f, 0x70, 0xee, 0x60, 0x18, 0xa8, 0x2a, 0x1f, 0xff, 0xfe, 0xaf, + 0xff, 0xe8, 0xf0, 0x00, 0x0a, 0x4a, 0xa8, 0x7f, 0xf0, 0xdf, 0xff, 0xf1, 0x54, 0x15, 0x43, + 0xff, 0xff, 0x5f, 0xff, 0xe8, 0x7b, 0xc0, 0x05, 0x55, 0x55, 0x7f, 0x70, 0xff, 0x81, 0x28, + 0xaa, 0x0a, 0xa1, 0xff, 0xfe, 0xbf, 0xf7, 0xea, 0x09, 0xe0, 0x0a, 0x4a, 0xaa, 0x7f, 0xf0, + 0xff, 0x81, 0x50, 0x54, 0x05, 0x54, 0x7f, 0xff, 0x7f, 0xfc, 0xe8, 0x4b, 0xc0, 0x05, 0x55, + 0x55, 0x7f, 0x70, 0xfe, 0x7f, 0x28, 0xaa, 0x00, 0xa8, 0xff, 0xfe, 0xbf, 0xff, 0x0a, 0xf0, + 0x00, 0x02, 0x4a, 0xa8, 0x7e, 0xb0, 0xfe, 0x7f, 0x14, 0x55, 0x00, 0x03, 0xff, 0xf7, 0x5f, + 0x7f, 0xe0, 0x1f, 0xc4, 0x01, 0x55, 0x06, 0x7f, 0x70, 0xff, 0x81, 0x08, 0x2a, 0x80, 0x07, + 0xff, 0xf6, 0xaf, 0xff, 0xfe, 0x80, 0x6a, 0x80, 0x00, 0x7e, 0xff, 0xb0, 0x7f, 0x81, 0x14, + 0x55, 0x40, 0x0f, 0xff, 0xed, 0x57, 0x7f, 0xff, 0xe7, 0x85, 0x55, 0x5f, 0xfc, 0xff, 0x70, + 0xbf, 0xff, 0xe8, 0x2a, 0xa8, 0x1f, 0xff, 0xf6, 0xae, 0xff, 0xff, 0xf9, 0xea, 0xaa, 0x5f, + 0xfa, 0xff, 0xf0, 0x5e, 0x01, 0x24, 0x15, 0x54, 0x3f, 0xff, 0xf5, 0x57, 0x7f, 0xfb, 0xfe, + 0xf0, 0x55, 0x5f, 0xe5, 0xff, 0x70, 0xbe, 0x01, 0x22, 0x2a, 0xa0, 0xff, 0xff, 0xba, 0xae, + 0xff, 0xfe, 0x1f, 0x30, 0x2a, 0x0f, 0x89, 0xbf, 0xf0, 0x5f, 0xff, 0xe5, 0x15, 0x41, 0xff, + 0xff, 0xd5, 0x57, 0x7f, 0xff, 0xe0, 0x48, 0x05, 0x54, 0x53, 0xff, 0xf0, 0xbe, 0x01, 0xa2, + 0x02, 0x03, 0xff, 0xff, 0xea, 0xaa, 0xbf, 0xff, 0xff, 0x80, 0x00, 0x02, 0xa7, 0xbf, 0xf0, + 0x5e, 0x01, 0x41, 0x00, 0x06, 0xfd, 0xff, 0xd5, 0x55, 0x5f, 0xff, 0xff, 0xfc, 0x00, 0x40, + 0x4f, 0xff, 0xf0, 0xbe, 0x49, 0x20, 0x80, 0x0f, 0x7f, 0xfe, 0xea, 0xaa, 0xbe, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x1f, 0xbf, 0xf0, 0x7e, 0x49, 0x50, 0x00, 0x0f, 0x7f, 0xff, 0xd5, 0x55, + 0x5f, 0x83, 0xff, 0xff, 0x80, 0x40, 0x3f, 0xff, 0xf0, 0xfe, 0x41, 0x28, 0x00, 0x0f, 0xbf, + 0xff, 0xeb, 0xaa, 0xbf, 0xfc, 0x00, 0x03, 0xe0, 0x00, 0xff, 0xbf, 0xf0, 0xfe, 0x41, 0x14, + 0x00, 0x1f, 0xdf, 0xff, 0xd5, 0xd5, 0x57, 0xff, 0xff, 0xfc, 0x00, 0x07, 0xff, 0xdf, 0xf0, + 0xff, 0xff, 0x08, 0x00, 0x1f, 0x3f, 0xdf, 0xeb, 0xaa, 0xab, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xbf, 0xf0, 0xfe, 0x01, 0x14, 0x40, 0x3e, 0xff, 0xbf, 0xf5, 0x55, 0x57, 0xdf, 0xff, + 0xf9, 0xff, 0xff, 0xff, 0xdf, 0xf0, 0xfe, 0x01, 0x0a, 0x20, 0x3f, 0xff, 0xdf, 0xfa, 0xaa, + 0xab, 0xbf, 0xff, 0xf3, 0xff, 0xff, 0xdf, 0xbf, 0xf0, 0xde, 0x7f, 0x05, 0x10, 0x7f, 0xff, + 0xff, 0xfd, 0x55, 0x55, 0xdf, 0xff, 0xe4, 0xff, 0xff, 0xbf, 0x7f, 0xf0, 0xee, 0x7e, 0x02, + 0x88, 0x7f, 0xff, 0xff, 0xfa, 0xaa, 0xab, 0xbf, 0xff, 0xe3, 0xff, 0xbf, 0xbf, 0xbf, 0xf0, + 0xde, 0x05, 0x41, 0x54, 0x3f, 0xff, 0xff, 0xdd, 0x55, 0x55, 0xff, 0xff, 0xd7, 0xff, 0xdf, + 0x7f, 0x7f, 0xf0, 0xee, 0x06, 0xa2, 0xaa, 0x3f, 0xff, 0xff, 0xbe, 0xaa, 0xab, 0xbf, 0xff, + 0xf7, 0xff, 0xbf, 0x3f, 0xbf, 0xf0, 0xde, 0x7d, 0x55, 0x55, 0x1f, 0xfb, 0xff, 0xff, 0x55, + 0x55, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xbf, 0xff, 0xf0, 0xfe, 0x7f, 0xaa, 0xaa, 0x8f, 0xff, + 0xff, 0xba, 0xaa, 0xab, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xdf, 0xbf, 0xf0, 0xfe, 0x01, 0x55, + 0x55, 0x47, 0xff, 0xff, 0xf7, 0xd5, 0x57, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xfe, 0x01, 0xaa, 0xaa, 0xa1, 0xff, 0xff, 0xbf, 0xea, 0xab, 0xff, 0xff, 0xff, 0xff, 0xbf, + 0xff, 0xff, 0xf0, 0xff, 0xff, 0x55, 0x55, 0x54, 0xff, 0xff, 0x5f, 0xf5, 0x57, 0xff, 0xfd, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xda, 0xaa, 0xaa, 0xaa, 0x7f, 0xff, 0xbf, 0xfa, + 0xab, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0x9d, 0x55, 0x55, 0x00, 0xff, + 0xff, 0x7f, 0xfd, 0x57, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xbf, 0xa2, + 0xa8, 0x03, 0xff, 0xfb, 0xbf, 0xfa, 0xaa, 0xbf, 0xfb, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0x3f, 0xc0, 0x00, 0x07, 0xff, 0xff, 0x5f, 0xfd, 0x57, 0x57, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf0, 0xff, 0x3f, 0x80, 0x00, 0x0f, 0xff, 0xfb, 0xaf, 0xfe, 0xae, 0xaa, 0xfb, + 0xff, 0xbf, 0xff, 0xff, 0xff, 0xf0, 0xf6, 0x7f, 0xc0, 0x00, 0x0f, 0xff, 0xff, 0x57, 0xfd, + 0x55, 0x55, 0x77, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xf0, +}; + +const lv_img_dsc_t balloon = { + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .header.always_zero = 0, + .header.reserved = 0, + .header.w = 140, + .header.h = 68, + .data_size = 1232, + .data = balloon_map, +}; + +#ifndef LV_ATTRIBUTE_IMG_MOUNTAIN +#define LV_ATTRIBUTE_IMG_MOUNTAIN +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_MOUNTAIN uint8_t + mountain_map[] = { +#if CONFIG_NICE_VIEW_WIDGET_INVERTED + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ +#else + 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ + 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ +#endif + + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x90, 0x00, 0x30, 0x80, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xa0, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x10, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf4, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0x10, 0x80, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x40, 0x00, 0x00, 0x01, 0xfe, 0x03, 0xe0, 0x0f, 0x9e, 0x01, 0x90, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe8, 0x00, 0x00, 0x00, 0xff, 0x07, 0xe0, 0x1f, + 0x9e, 0x00, 0x90, 0x80, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x80, 0x00, 0x00, 0x7f, + 0x8f, 0xe0, 0x1f, 0xbe, 0x00, 0x90, 0x80, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, + 0x00, 0x00, 0x3f, 0xcf, 0xf0, 0x1f, 0xbc, 0x00, 0x90, 0x80, 0x7f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xcf, 0xf0, 0x3f, 0xbc, 0x00, 0x90, 0x80, 0x7f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe8, 0x00, 0x00, 0x1f, 0xe7, 0xf0, 0x7f, 0x3c, 0x00, 0x90, + 0x80, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x0f, 0xe7, 0xf8, 0x7f, + 0x78, 0x01, 0xb0, 0x80, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xec, 0x00, 0x00, 0x00, 0x07, + 0xf3, 0xf8, 0x3f, 0x78, 0x03, 0xd0, 0x80, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xc0, 0x00, + 0x00, 0x00, 0x07, 0xfb, 0xf8, 0x3f, 0xf8, 0x0f, 0x90, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xff, + 0xec, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfd, 0xfc, 0x3f, 0xf8, 0x0f, 0x10, 0xc0, 0x1e, 0xff, + 0xff, 0xff, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xfc, 0x3f, 0xf0, 0x0e, 0x10, + 0xc0, 0x0c, 0x27, 0xff, 0xff, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x7f, + 0xf0, 0x1e, 0x30, 0xc0, 0x00, 0x1f, 0xff, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xfe, 0x7f, 0xf3, 0xfc, 0x50, 0xe0, 0x00, 0x3f, 0xff, 0xfa, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x7f, 0xf7, 0xf8, 0x90, 0xe0, 0x00, 0x7f, 0xfe, 0xb0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x7f, 0xe7, 0xf1, 0x90, 0xe0, 0x00, 0x7f, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x7f, 0xef, 0xe3, 0x90, + 0xf0, 0x00, 0x7f, 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0x7f, + 0xff, 0xe7, 0x90, 0xb0, 0x10, 0xff, 0xff, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xff, 0xbf, 0xff, 0xcf, 0x90, 0xf0, 0x30, 0xff, 0xff, 0xff, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0xff, 0xf9, 0xff, 0x9f, 0x90, 0xb0, 0x30, 0xff, 0xff, 0xff, 0xf2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf6, 0xff, 0x3e, 0x90, 0xf8, 0x70, 0xff, + 0xff, 0xff, 0xff, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf6, 0xfe, 0x7c, 0x90, + 0xf8, 0x78, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf9, + 0xfe, 0xf8, 0x90, 0xa8, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0xff, 0xfd, 0xf3, 0x90, 0xdc, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xe8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xfb, 0xef, 0x90, 0xf5, 0xac, 0xff, 0xff, 0xff, 0xfe, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x90, 0xff, 0xd6, 0x7f, + 0xff, 0xff, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0x90, + 0xff, 0xfa, 0x7f, 0xff, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0x90, 0xdd, 0xff, 0x7f, 0xff, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0xea, 0xbf, 0x3f, 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xf0, 0x10, 0xff, 0x4f, 0xbf, 0xf5, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x10, 0xff, 0xff, 0x9f, + 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf0, + 0xff, 0xb0, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0xff, 0xff, 0x90, 0xcd, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x1f, 0xff, 0xff, 0x90, 0xb2, 0xe0, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x7f, 0xff, 0xff, 0x90, 0xff, 0xc0, 0x3f, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xff, 0xff, 0xff, 0x90, 0xfe, 0xc0, 0x7f, + 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0xff, 0xff, 0x7c, 0x90, + 0xfd, 0x80, 0xff, 0xfd, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc3, 0xff, + 0xff, 0xb8, 0x90, 0xff, 0x80, 0xff, 0xff, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3f, 0x87, 0xff, 0xff, 0xc8, 0x90, 0x9f, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7f, 0x1f, 0xff, 0xff, 0xe0, 0x90, 0x86, 0x01, 0xff, 0xff, 0xd0, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xfe, 0x3f, 0xff, 0xff, 0xe0, 0x90, 0x80, 0x01, 0xff, + 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x06, 0x19, 0x83, 0xfe, 0x7f, 0xff, 0xff, 0xf0, 0x90, + 0x80, 0x01, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x7f, 0xc7, 0xee, 0x7f, 0xff, + 0xff, 0xf8, 0x90, 0x80, 0x1a, 0xbf, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x98, 0xff, 0xff, + 0xc6, 0x7f, 0xff, 0xff, 0xfc, 0x90, 0x80, 0x3f, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0xf1, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff, 0xfe, 0x90, 0x80, 0x3f, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0xe3, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x90, 0x80, 0x7f, 0xfe, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc7, 0xff, 0xfe, 0x18, 0xff, 0xef, 0xff, 0xff, 0x90, + 0x80, 0x7f, 0xff, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x8f, 0xff, 0xfc, 0x7f, 0xff, 0xef, + 0xfd, 0xff, 0x90, 0x80, 0xff, 0xff, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x9f, 0xff, 0xf8, + 0xff, 0xff, 0xef, 0xfc, 0xf7, 0x90, 0x80, 0xff, 0xff, 0xff, 0x60, 0x00, 0x00, 0x00, 0x3f, + 0x1f, 0xff, 0xf1, 0xff, 0xff, 0xcf, 0xfc, 0xe1, 0x90, 0x80, 0xff, 0xff, 0xff, 0xf4, 0x00, + 0x00, 0x00, 0x7f, 0x3f, 0xff, 0xe3, 0xff, 0xff, 0xcf, 0xfe, 0x60, 0x90, 0x81, 0xff, 0xff, + 0xff, 0xfe, 0x80, 0x00, 0x00, 0x7f, 0x3f, 0xff, 0xc7, 0xff, 0xff, 0xdf, 0xfe, 0x40, 0x90, + 0x81, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x01, 0xfe, 0x3f, 0xff, 0xcf, 0xbf, 0xff, 0xdf, + 0xfe, 0x00, 0x90, 0x81, 0xff, 0xff, 0xff, 0xff, 0x40, 0x00, 0x07, 0xfe, 0x7f, 0xff, 0x8f, + 0x7f, 0xff, 0x9f, 0xfe, 0x00, 0x90, 0x80, 0xff, 0xff, 0xff, 0xe6, 0x00, 0x00, 0x1f, 0xfe, + 0x7f, 0xff, 0x1e, 0xff, 0xff, 0x91, 0xfe, 0x00, 0x90, 0x80, 0xff, 0xff, 0xfe, 0xc0, 0x00, + 0x00, 0x3f, 0xfc, 0x7f, 0xfe, 0x3c, 0xff, 0xff, 0x81, 0xff, 0x00, 0x90, 0x80, 0x7f, 0xff, + 0xec, 0x00, 0x00, 0x3c, 0xff, 0xf8, 0xff, 0xfc, 0x79, 0xfd, 0xff, 0x80, 0xff, 0x00, 0x90, + 0x80, 0x27, 0xff, 0x80, 0x00, 0x00, 0x7f, 0xff, 0xf9, 0xff, 0xfc, 0xf3, 0xfb, 0xff, 0x00, + 0xff, 0x00, 0x90, 0x80, 0x5f, 0xff, 0xd8, 0x00, 0x00, 0xff, 0xff, 0xf1, 0xff, 0xc8, 0xe7, + 0xf3, 0xff, 0x00, 0x7f, 0x00, 0x90, 0x80, 0xff, 0xff, 0xfd, 0x80, 0x01, 0xff, 0xff, 0xe3, + 0xff, 0x81, 0xcf, 0xf7, 0xff, 0x00, 0x7f, 0x00, 0x90, 0x80, 0xff, 0xff, 0xff, 0xd8, 0x03, + 0xff, 0xff, 0x87, 0xff, 0x03, 0x8f, 0xe7, 0xff, 0x00, 0x3f, 0x81, 0x90, 0x81, 0xff, 0xff, + 0xff, 0xfe, 0x83, 0xff, 0xfe, 0x0f, 0xfe, 0x3f, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0x10, + 0x80, 0x00, 0x00, 0x00, 0x2f, 0xc6, 0x00, 0x00, 0x38, 0x00, 0x60, 0x00, 0x48, 0x00, 0x00, + 0x00, 0x00, 0x10, 0xc0, 0x00, 0x00, 0x00, 0x17, 0xf4, 0x00, 0x00, 0xe0, 0x00, 0xc0, 0x00, + 0x88, 0x00, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, +}; + +const lv_img_dsc_t mountain = { + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .header.always_zero = 0, + .header.reserved = 0, + .header.w = 140, + .header.h = 68, + .data_size = 1232, + .data = mountain_map, +}; diff --git a/app/boards/shields/nice_view/widgets/bolt.c b/app/boards/shields/nice_view/widgets/bolt.c new file mode 100644 index 000000000000..74dcc2b00c62 --- /dev/null +++ b/app/boards/shields/nice_view/widgets/bolt.c @@ -0,0 +1,45 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BOLT +#define LV_ATTRIBUTE_IMG_BOLT +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BOLT uint8_t bolt_map[] = { +#if CONFIG_NICE_VIEW_WIDGET_INVERTED + 0x00, 0x00, 0x00, 0x00, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + 0xff, 0xff, 0xff, 0xff, /*Color of index 2*/ + 0x00, 0x00, 0x00, 0x00, /*Color of index 3*/ +#else + 0x00, 0x00, 0x00, 0x00, /*Color of index 0*/ + 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 2*/ + 0x00, 0x00, 0x00, 0x00, /*Color of index 3*/ +#endif + + 0x00, 0x14, 0x00, 0x00, 0x64, 0x00, 0x00, 0x64, 0x00, 0x01, 0xa4, 0x00, 0x01, 0xa4, + 0x00, 0x06, 0xa4, 0x00, 0x06, 0xa4, 0x00, 0x1a, 0xa5, 0x54, 0x1a, 0xaa, 0xa4, 0x6a, + 0xaa, 0x90, 0x55, 0x6a, 0x90, 0x00, 0x6a, 0x40, 0x00, 0x6a, 0x40, 0x00, 0x69, 0x00, + 0x00, 0x69, 0x00, 0x00, 0x64, 0x00, 0x00, 0x64, 0x00, 0x00, 0x50, 0x00, +}; + +const lv_img_dsc_t bolt = { + .header.cf = LV_IMG_CF_INDEXED_2BIT, + .header.always_zero = 0, + .header.reserved = 0, + .header.w = 11, + .header.h = 18, + .data_size = 70, + .data = bolt_map, +}; diff --git a/app/boards/shields/nice_view/widgets/peripheral_status.c b/app/boards/shields/nice_view/widgets/peripheral_status.c new file mode 100644 index 000000000000..4c0c22637be9 --- /dev/null +++ b/app/boards/shields/nice_view/widgets/peripheral_status.c @@ -0,0 +1,128 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include "peripheral_status.h" +#include +#include +#include +#include +#include +#include +#include + +LV_IMG_DECLARE(balloon); +LV_IMG_DECLARE(mountain); + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); + +struct peripheral_status_state { + bool connected; +}; + +static void draw_top(lv_obj_t *widget, lv_color_t cbuf[], const struct status_state *state) { + lv_obj_t *canvas = lv_obj_get_child(widget, 0); + + lv_draw_label_dsc_t label_dsc; + init_label_dsc(&label_dsc, LVGL_FOREGROUND, &lv_font_montserrat_16, LV_TEXT_ALIGN_RIGHT); + lv_draw_rect_dsc_t rect_black_dsc; + init_rect_dsc(&rect_black_dsc, LVGL_BACKGROUND); + + // Fill background + lv_canvas_draw_rect(canvas, 0, 0, CANVAS_SIZE, CANVAS_SIZE, &rect_black_dsc); + + // Draw battery + draw_battery(canvas, state); + + // Draw output status + lv_canvas_draw_text(canvas, 0, 0, CANVAS_SIZE, &label_dsc, + state->connected ? LV_SYMBOL_WIFI : LV_SYMBOL_CLOSE); + + // Rotate canvas + rotate_canvas(canvas, cbuf); +} + +static void set_battery_status(struct zmk_widget_status *widget, + struct battery_status_state state) { +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + widget->state.charging = state.usb_present; +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + + widget->state.battery = state.level; + + draw_top(widget->obj, widget->cbuf, &widget->state); +} + +static void battery_status_update_cb(struct battery_status_state state) { + struct zmk_widget_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_battery_status(widget, state); } +} + +static struct battery_status_state battery_status_get_state(const zmk_event_t *eh) { + return (struct battery_status_state) { + .level = bt_bas_get_battery_level(), +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + .usb_present = zmk_usb_is_powered(), +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + }; +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_battery_status, struct battery_status_state, + battery_status_update_cb, battery_status_get_state) + +ZMK_SUBSCRIPTION(widget_battery_status, zmk_battery_state_changed); +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) +ZMK_SUBSCRIPTION(widget_battery_status, zmk_usb_conn_state_changed); +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + +static struct peripheral_status_state get_state(const zmk_event_t *_eh) { + return (struct peripheral_status_state){.connected = zmk_split_bt_peripheral_is_connected()}; +} + +static void set_connection_status(struct zmk_widget_status *widget, + struct peripheral_status_state state) { + widget->state.connected = state.connected; + + draw_top(widget->obj, widget->cbuf, &widget->state); +} + +static void output_status_update_cb(struct peripheral_status_state state) { + struct zmk_widget_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_connection_status(widget, state); } +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_peripheral_status, struct peripheral_status_state, + output_status_update_cb, get_state) +ZMK_SUBSCRIPTION(widget_peripheral_status, zmk_split_peripheral_status_changed); + +int zmk_widget_status_init(struct zmk_widget_status *widget, lv_obj_t *parent) { + widget->obj = lv_obj_create(parent); + lv_obj_set_size(widget->obj, 160, 68); + lv_obj_t *top = lv_canvas_create(widget->obj); + lv_obj_align(top, LV_ALIGN_TOP_RIGHT, 0, 0); + lv_canvas_set_buffer(top, widget->cbuf, CANVAS_SIZE, CANVAS_SIZE, LV_IMG_CF_TRUE_COLOR); + + lv_obj_t *art = lv_img_create(widget->obj); + bool random = sys_rand32_get() & 1; + lv_img_set_src(art, random ? &balloon : &mountain); + lv_obj_align(art, LV_ALIGN_TOP_LEFT, 0, 0); + + sys_slist_append(&widgets, &widget->node); + widget_battery_status_init(); + widget_peripheral_status_init(); + + return 0; +} + +lv_obj_t *zmk_widget_status_obj(struct zmk_widget_status *widget) { return widget->obj; } diff --git a/app/boards/shields/nice_view/widgets/peripheral_status.h b/app/boards/shields/nice_view/widgets/peripheral_status.h new file mode 100644 index 000000000000..815963572b4d --- /dev/null +++ b/app/boards/shields/nice_view/widgets/peripheral_status.h @@ -0,0 +1,22 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include +#include +#include "util.h" + +struct zmk_widget_status { + sys_snode_t node; + lv_obj_t *obj; + lv_color_t cbuf[CANVAS_SIZE * CANVAS_SIZE]; + struct status_state state; +}; + +int zmk_widget_status_init(struct zmk_widget_status *widget, lv_obj_t *parent); +lv_obj_t *zmk_widget_status_obj(struct zmk_widget_status *widget); diff --git a/app/boards/shields/nice_view/widgets/status.c b/app/boards/shields/nice_view/widgets/status.c new file mode 100644 index 000000000000..96b7d450a7da --- /dev/null +++ b/app/boards/shields/nice_view/widgets/status.c @@ -0,0 +1,331 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include "status.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); + +struct output_status_state { + struct zmk_endpoint_instance selected_endpoint; + int active_profile_index; + bool active_profile_connected; + bool active_profile_bonded; +}; + +struct layer_status_state { + uint8_t index; + const char *label; +}; + +struct wpm_status_state { + uint8_t wpm; +}; + +static void draw_top(lv_obj_t *widget, lv_color_t cbuf[], const struct status_state *state) { + lv_obj_t *canvas = lv_obj_get_child(widget, 0); + + lv_draw_label_dsc_t label_dsc; + init_label_dsc(&label_dsc, LVGL_FOREGROUND, &lv_font_montserrat_16, LV_TEXT_ALIGN_RIGHT); + lv_draw_label_dsc_t label_dsc_wpm; + init_label_dsc(&label_dsc_wpm, LVGL_FOREGROUND, &lv_font_unscii_8, LV_TEXT_ALIGN_RIGHT); + lv_draw_rect_dsc_t rect_black_dsc; + init_rect_dsc(&rect_black_dsc, LVGL_BACKGROUND); + lv_draw_rect_dsc_t rect_white_dsc; + init_rect_dsc(&rect_white_dsc, LVGL_FOREGROUND); + lv_draw_line_dsc_t line_dsc; + init_line_dsc(&line_dsc, LVGL_FOREGROUND, 1); + + // Fill background + lv_canvas_draw_rect(canvas, 0, 0, CANVAS_SIZE, CANVAS_SIZE, &rect_black_dsc); + + // Draw battery + draw_battery(canvas, state); + + // Draw output status + char output_text[10] = {}; + + switch (state->selected_endpoint.transport) { + case ZMK_TRANSPORT_USB: + strcat(output_text, LV_SYMBOL_USB); + break; + case ZMK_TRANSPORT_BLE: + if (state->active_profile_bonded) { + if (state->active_profile_connected) { + strcat(output_text, LV_SYMBOL_WIFI); + } else { + strcat(output_text, LV_SYMBOL_CLOSE); + } + } else { + strcat(output_text, LV_SYMBOL_SETTINGS); + } + break; + } + + lv_canvas_draw_text(canvas, 0, 0, CANVAS_SIZE, &label_dsc, output_text); + + // Draw WPM + lv_canvas_draw_rect(canvas, 0, 21, 68, 42, &rect_white_dsc); + lv_canvas_draw_rect(canvas, 1, 22, 66, 40, &rect_black_dsc); + + char wpm_text[6] = {}; + snprintf(wpm_text, sizeof(wpm_text), "%d", state->wpm[9]); + lv_canvas_draw_text(canvas, 42, 52, 24, &label_dsc_wpm, wpm_text); + + int max = 0; + int min = 256; + + for (int i = 0; i < 10; i++) { + if (state->wpm[i] > max) { + max = state->wpm[i]; + } + if (state->wpm[i] < min) { + min = state->wpm[i]; + } + } + + int range = max - min; + if (range == 0) { + range = 1; + } + + lv_point_t points[10]; + for (int i = 0; i < 10; i++) { + points[i].x = 2 + i * 7; + points[i].y = 60 - (state->wpm[i] - min) * 36 / range; + } + lv_canvas_draw_line(canvas, points, 10, &line_dsc); + + // Rotate canvas + rotate_canvas(canvas, cbuf); +} + +static void draw_middle(lv_obj_t *widget, lv_color_t cbuf[], const struct status_state *state) { + lv_obj_t *canvas = lv_obj_get_child(widget, 1); + + lv_draw_rect_dsc_t rect_black_dsc; + init_rect_dsc(&rect_black_dsc, LVGL_BACKGROUND); + lv_draw_rect_dsc_t rect_white_dsc; + init_rect_dsc(&rect_white_dsc, LVGL_FOREGROUND); + lv_draw_arc_dsc_t arc_dsc; + init_arc_dsc(&arc_dsc, LVGL_FOREGROUND, 2); + lv_draw_arc_dsc_t arc_dsc_filled; + init_arc_dsc(&arc_dsc_filled, LVGL_FOREGROUND, 9); + lv_draw_label_dsc_t label_dsc; + init_label_dsc(&label_dsc, LVGL_FOREGROUND, &lv_font_montserrat_18, LV_TEXT_ALIGN_CENTER); + lv_draw_label_dsc_t label_dsc_black; + init_label_dsc(&label_dsc_black, LVGL_BACKGROUND, &lv_font_montserrat_18, LV_TEXT_ALIGN_CENTER); + + // Fill background + lv_canvas_draw_rect(canvas, 0, 0, CANVAS_SIZE, CANVAS_SIZE, &rect_black_dsc); + + // Draw circles + int circle_offsets[5][2] = { + {13, 13}, {55, 13}, {34, 34}, {13, 55}, {55, 55}, + }; + + for (int i = 0; i < 5; i++) { + bool selected = i == state->active_profile_index; + + lv_canvas_draw_arc(canvas, circle_offsets[i][0], circle_offsets[i][1], 13, 0, 359, + &arc_dsc); + + if (selected) { + lv_canvas_draw_arc(canvas, circle_offsets[i][0], circle_offsets[i][1], 9, 0, 359, + &arc_dsc_filled); + } + + char label[2]; + snprintf(label, sizeof(label), "%d", i + 1); + lv_canvas_draw_text(canvas, circle_offsets[i][0] - 8, circle_offsets[i][1] - 10, 16, + (selected ? &label_dsc_black : &label_dsc), label); + } + + // Rotate canvas + rotate_canvas(canvas, cbuf); +} + +static void draw_bottom(lv_obj_t *widget, lv_color_t cbuf[], const struct status_state *state) { + lv_obj_t *canvas = lv_obj_get_child(widget, 2); + + lv_draw_rect_dsc_t rect_black_dsc; + init_rect_dsc(&rect_black_dsc, LVGL_BACKGROUND); + lv_draw_label_dsc_t label_dsc; + init_label_dsc(&label_dsc, LVGL_FOREGROUND, &lv_font_montserrat_14, LV_TEXT_ALIGN_CENTER); + + // Fill background + lv_canvas_draw_rect(canvas, 0, 0, CANVAS_SIZE, CANVAS_SIZE, &rect_black_dsc); + + // Draw layer + if (state->layer_label == NULL) { + char text[9] = {}; + + sprintf(text, "LAYER %i", state->layer_index); + + lv_canvas_draw_text(canvas, 0, 5, 68, &label_dsc, text); + } else { + lv_canvas_draw_text(canvas, 0, 5, 68, &label_dsc, state->layer_label); + } + + // Rotate canvas + rotate_canvas(canvas, cbuf); +} + +static void set_battery_status(struct zmk_widget_status *widget, + struct battery_status_state state) { +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + widget->state.charging = state.usb_present; +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + + widget->state.battery = state.level; + + draw_top(widget->obj, widget->cbuf, &widget->state); +} + +static void battery_status_update_cb(struct battery_status_state state) { + struct zmk_widget_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_battery_status(widget, state); } +} + +static struct battery_status_state battery_status_get_state(const zmk_event_t *eh) { + return (struct battery_status_state) { + .level = bt_bas_get_battery_level(), +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + .usb_present = zmk_usb_is_powered(), +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + }; +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_battery_status, struct battery_status_state, + battery_status_update_cb, battery_status_get_state) + +ZMK_SUBSCRIPTION(widget_battery_status, zmk_battery_state_changed); +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) +ZMK_SUBSCRIPTION(widget_battery_status, zmk_usb_conn_state_changed); +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + +static void set_output_status(struct zmk_widget_status *widget, + const struct output_status_state *state) { + widget->state.selected_endpoint = state->selected_endpoint; + widget->state.active_profile_index = state->active_profile_index; + widget->state.active_profile_connected = state->active_profile_connected; + widget->state.active_profile_bonded = state->active_profile_bonded; + + draw_top(widget->obj, widget->cbuf, &widget->state); + draw_middle(widget->obj, widget->cbuf2, &widget->state); +} + +static void output_status_update_cb(struct output_status_state state) { + struct zmk_widget_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_output_status(widget, &state); } +} + +static struct output_status_state output_status_get_state(const zmk_event_t *_eh) { + return (struct output_status_state){ + .selected_endpoint = zmk_endpoints_selected(), + .active_profile_index = zmk_ble_active_profile_index(), + .active_profile_connected = zmk_ble_active_profile_is_connected(), + .active_profile_bonded = !zmk_ble_active_profile_is_open(), + }; +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_output_status, struct output_status_state, + output_status_update_cb, output_status_get_state) +ZMK_SUBSCRIPTION(widget_output_status, zmk_endpoint_changed); + +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) +ZMK_SUBSCRIPTION(widget_output_status, zmk_usb_conn_state_changed); +#endif +#if defined(CONFIG_ZMK_BLE) +ZMK_SUBSCRIPTION(widget_output_status, zmk_ble_active_profile_changed); +#endif + +static void set_layer_status(struct zmk_widget_status *widget, struct layer_status_state state) { + widget->state.layer_index = state.index; + widget->state.layer_label = state.label; + + draw_bottom(widget->obj, widget->cbuf3, &widget->state); +} + +static void layer_status_update_cb(struct layer_status_state state) { + struct zmk_widget_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_layer_status(widget, state); } +} + +static struct layer_status_state layer_status_get_state(const zmk_event_t *eh) { + uint8_t index = zmk_keymap_highest_layer_active(); + return (struct layer_status_state){.index = index, .label = zmk_keymap_layer_name(index)}; +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_layer_status, struct layer_status_state, layer_status_update_cb, + layer_status_get_state) + +ZMK_SUBSCRIPTION(widget_layer_status, zmk_layer_state_changed); + +static void set_wpm_status(struct zmk_widget_status *widget, struct wpm_status_state state) { + for (int i = 0; i < 9; i++) { + widget->state.wpm[i] = widget->state.wpm[i + 1]; + } + widget->state.wpm[9] = state.wpm; + + draw_top(widget->obj, widget->cbuf, &widget->state); +} + +static void wpm_status_update_cb(struct wpm_status_state state) { + struct zmk_widget_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_wpm_status(widget, state); } +} + +struct wpm_status_state wpm_status_get_state(const zmk_event_t *eh) { + return (struct wpm_status_state){.wpm = zmk_wpm_get_state()}; +}; + +ZMK_DISPLAY_WIDGET_LISTENER(widget_wpm_status, struct wpm_status_state, wpm_status_update_cb, + wpm_status_get_state) +ZMK_SUBSCRIPTION(widget_wpm_status, zmk_wpm_state_changed); + +int zmk_widget_status_init(struct zmk_widget_status *widget, lv_obj_t *parent) { + widget->obj = lv_obj_create(parent); + lv_obj_set_size(widget->obj, 160, 68); + lv_obj_t *top = lv_canvas_create(widget->obj); + lv_obj_align(top, LV_ALIGN_TOP_RIGHT, 0, 0); + lv_canvas_set_buffer(top, widget->cbuf, CANVAS_SIZE, CANVAS_SIZE, LV_IMG_CF_TRUE_COLOR); + lv_obj_t *middle = lv_canvas_create(widget->obj); + lv_obj_align(middle, LV_ALIGN_TOP_LEFT, 24, 0); + lv_canvas_set_buffer(middle, widget->cbuf2, CANVAS_SIZE, CANVAS_SIZE, LV_IMG_CF_TRUE_COLOR); + lv_obj_t *bottom = lv_canvas_create(widget->obj); + lv_obj_align(bottom, LV_ALIGN_TOP_LEFT, -44, 0); + lv_canvas_set_buffer(bottom, widget->cbuf3, CANVAS_SIZE, CANVAS_SIZE, LV_IMG_CF_TRUE_COLOR); + + sys_slist_append(&widgets, &widget->node); + widget_battery_status_init(); + widget_output_status_init(); + widget_layer_status_init(); + widget_wpm_status_init(); + + return 0; +} + +lv_obj_t *zmk_widget_status_obj(struct zmk_widget_status *widget) { return widget->obj; } diff --git a/app/boards/shields/nice_view/widgets/status.h b/app/boards/shields/nice_view/widgets/status.h new file mode 100644 index 000000000000..53a22518d736 --- /dev/null +++ b/app/boards/shields/nice_view/widgets/status.h @@ -0,0 +1,24 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include +#include +#include "util.h" + +struct zmk_widget_status { + sys_snode_t node; + lv_obj_t *obj; + lv_color_t cbuf[CANVAS_SIZE * CANVAS_SIZE]; + lv_color_t cbuf2[CANVAS_SIZE * CANVAS_SIZE]; + lv_color_t cbuf3[CANVAS_SIZE * CANVAS_SIZE]; + struct status_state state; +}; + +int zmk_widget_status_init(struct zmk_widget_status *widget, lv_obj_t *parent); +lv_obj_t *zmk_widget_status_obj(struct zmk_widget_status *widget); diff --git a/app/boards/shields/nice_view/widgets/util.c b/app/boards/shields/nice_view/widgets/util.c new file mode 100644 index 000000000000..b4915ab767f4 --- /dev/null +++ b/app/boards/shields/nice_view/widgets/util.c @@ -0,0 +1,69 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include +#include "util.h" + +LV_IMG_DECLARE(bolt); + +void rotate_canvas(lv_obj_t *canvas, lv_color_t cbuf[]) { + static lv_color_t cbuf_tmp[CANVAS_SIZE * CANVAS_SIZE]; + memcpy(cbuf_tmp, cbuf, sizeof(cbuf_tmp)); + lv_img_dsc_t img; + img.data = (void *)cbuf_tmp; + img.header.cf = LV_IMG_CF_TRUE_COLOR; + img.header.w = CANVAS_SIZE; + img.header.h = CANVAS_SIZE; + + lv_canvas_fill_bg(canvas, LVGL_BACKGROUND, LV_OPA_COVER); + lv_canvas_transform(canvas, &img, 900, LV_IMG_ZOOM_NONE, -1, 0, CANVAS_SIZE / 2, + CANVAS_SIZE / 2, true); +} + +void draw_battery(lv_obj_t *canvas, const struct status_state *state) { + lv_draw_rect_dsc_t rect_black_dsc; + init_rect_dsc(&rect_black_dsc, LVGL_BACKGROUND); + lv_draw_rect_dsc_t rect_white_dsc; + init_rect_dsc(&rect_white_dsc, LVGL_FOREGROUND); + + lv_canvas_draw_rect(canvas, 0, 2, 29, 12, &rect_white_dsc); + lv_canvas_draw_rect(canvas, 1, 3, 27, 10, &rect_black_dsc); + lv_canvas_draw_rect(canvas, 2, 4, (state->battery + 2) / 4, 8, &rect_white_dsc); + lv_canvas_draw_rect(canvas, 30, 5, 3, 6, &rect_white_dsc); + lv_canvas_draw_rect(canvas, 31, 6, 1, 4, &rect_black_dsc); + + if (state->charging) { + lv_draw_img_dsc_t img_dsc; + lv_draw_img_dsc_init(&img_dsc); + lv_canvas_draw_img(canvas, 9, -1, &bolt, &img_dsc); + } +} + +void init_label_dsc(lv_draw_label_dsc_t *label_dsc, lv_color_t color, const lv_font_t *font, + lv_text_align_t align) { + lv_draw_label_dsc_init(label_dsc); + label_dsc->color = color; + label_dsc->font = font; + label_dsc->align = align; +} + +void init_rect_dsc(lv_draw_rect_dsc_t *rect_dsc, lv_color_t bg_color) { + lv_draw_rect_dsc_init(rect_dsc); + rect_dsc->bg_color = bg_color; +} + +void init_line_dsc(lv_draw_line_dsc_t *line_dsc, lv_color_t color, uint8_t width) { + lv_draw_line_dsc_init(line_dsc); + line_dsc->color = color; + line_dsc->width = width; +} + +void init_arc_dsc(lv_draw_arc_dsc_t *arc_dsc, lv_color_t color, uint8_t width) { + lv_draw_arc_dsc_init(arc_dsc); + arc_dsc->color = color; + arc_dsc->width = width; +} diff --git a/app/boards/shields/nice_view/widgets/util.h b/app/boards/shields/nice_view/widgets/util.h new file mode 100644 index 000000000000..fbcb616fad37 --- /dev/null +++ b/app/boards/shields/nice_view/widgets/util.h @@ -0,0 +1,47 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include +#include + +#define CANVAS_SIZE 68 + +#define LVGL_BACKGROUND \ + IS_ENABLED(CONFIG_NICE_VIEW_WIDGET_INVERTED) ? lv_color_black() : lv_color_white() +#define LVGL_FOREGROUND \ + IS_ENABLED(CONFIG_NICE_VIEW_WIDGET_INVERTED) ? lv_color_white() : lv_color_black() + +struct status_state { + uint8_t battery; + bool charging; +#if !IS_ENABLED(CONFIG_ZMK_SPLIT) || IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) + struct zmk_endpoint_instance selected_endpoint; + int active_profile_index; + bool active_profile_connected; + bool active_profile_bonded; + uint8_t layer_index; + const char *layer_label; + uint8_t wpm[10]; +#else + bool connected; +#endif +}; + +struct battery_status_state { + uint8_t level; +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + bool usb_present; +#endif +}; + +void rotate_canvas(lv_obj_t *canvas, lv_color_t cbuf[]); +void draw_battery(lv_obj_t *canvas, const struct status_state *state); +void init_label_dsc(lv_draw_label_dsc_t *label_dsc, lv_color_t color, const lv_font_t *font, + lv_text_align_t align); +void init_rect_dsc(lv_draw_rect_dsc_t *rect_dsc, lv_color_t bg_color); +void init_line_dsc(lv_draw_line_dsc_t *line_dsc, lv_color_t color, uint8_t width); +void init_arc_dsc(lv_draw_arc_dsc_t *arc_dsc, lv_color_t color, uint8_t width); diff --git a/app/boards/shields/nice_view_adapter/Kconfig.defconfig b/app/boards/shields/nice_view_adapter/Kconfig.defconfig new file mode 100644 index 000000000000..fb23f20ccd27 --- /dev/null +++ b/app/boards/shields/nice_view_adapter/Kconfig.defconfig @@ -0,0 +1,2 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT diff --git a/app/boards/shields/nice_view_adapter/Kconfig.shield b/app/boards/shields/nice_view_adapter/Kconfig.shield new file mode 100644 index 000000000000..f95a209cbff5 --- /dev/null +++ b/app/boards/shields/nice_view_adapter/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_NICE_VIEW_ADAPTER + def_bool $(shields_list_contains,nice_view_adapter) diff --git a/app/boards/shields/nice_view_adapter/README.md b/app/boards/shields/nice_view_adapter/README.md new file mode 100644 index 000000000000..fe0a6f0760f2 --- /dev/null +++ b/app/boards/shields/nice_view_adapter/README.md @@ -0,0 +1,11 @@ +# nice!view Adapter + +This shield is used as an adapter between the nice!view and existing shields/boards that expose an I2C OLED header. + +To use this shield, you should add this shield to your list of shields _before_ `nice_view`. + +The nice!view will use the SDA/SCL pins of the OLED, and then the adapter expects a final pin to be "bodged" from your microcontroller to the nice!view CS pin. This adapter assumes that the CS pin bodged is the `&pro_micro 1` pin or "D1", which is the top left pin when looking at the front of the board. If you can't use this pin, you'll need to override the `cs-gpios` for the `&nice_view_spi` bus (in your `zmk-config` keymap for example) or you will want to define your own `&nice_view_spi` bus without using this adapter. + +``` +west build -b nice_nano_v2 -- -DSHIELD="lily58_left nice_view_adapter nice_view" +``` diff --git a/app/boards/shields/nice_view_adapter/boards/bluemicro840_v1.overlay b/app/boards/shields/nice_view_adapter/boards/bluemicro840_v1.overlay new file mode 100644 index 000000000000..706cffbebea2 --- /dev/null +++ b/app/boards/shields/nice_view_adapter/boards/bluemicro840_v1.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + spi0_default: spi0_default { + group1 { + psels = , + , + ; + }; + }; + spi0_sleep: spi0_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; + +nice_view_spi: &spi0 { + compatible = "nordic,nrf-spim"; + pinctrl-0 = <&spi0_default>; + pinctrl-1 = <&spi0_sleep>; + pinctrl-names = "default", "sleep"; + cs-gpios = <&pro_micro 1 GPIO_ACTIVE_HIGH>; +}; + +&pro_micro_i2c { + status = "disabled"; +}; diff --git a/app/boards/shields/nice_view_adapter/boards/mikoto_520.overlay b/app/boards/shields/nice_view_adapter/boards/mikoto_520.overlay new file mode 100644 index 000000000000..e00b599c61c3 --- /dev/null +++ b/app/boards/shields/nice_view_adapter/boards/mikoto_520.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + spi0_default: spi0_default { + group1 { + psels = , + , + ; + }; + }; + spi0_sleep: spi0_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; + +nice_view_spi: &spi0 { + compatible = "nordic,nrf-spim"; + pinctrl-0 = <&spi0_default>; + pinctrl-1 = <&spi0_sleep>; + pinctrl-names = "default", "sleep"; + cs-gpios = <&pro_micro 1 GPIO_ACTIVE_HIGH>; +}; + +&pro_micro_i2c { + status = "disabled"; +}; diff --git a/app/boards/shields/nice_view_adapter/boards/nice_nano.overlay b/app/boards/shields/nice_view_adapter/boards/nice_nano.overlay new file mode 100644 index 000000000000..45ba34dedebc --- /dev/null +++ b/app/boards/shields/nice_view_adapter/boards/nice_nano.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + spi0_default: spi0_default { + group1 { + psels = , + , + ; + }; + }; + spi0_sleep: spi0_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; + +nice_view_spi: &spi0 { + compatible = "nordic,nrf-spim"; + pinctrl-0 = <&spi0_default>; + pinctrl-1 = <&spi0_sleep>; + pinctrl-names = "default", "sleep"; + cs-gpios = <&pro_micro 1 GPIO_ACTIVE_HIGH>; +}; + +&pro_micro_i2c { + status = "disabled"; +}; diff --git a/app/boards/shields/nice_view_adapter/boards/nice_nano_v2.overlay b/app/boards/shields/nice_view_adapter/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..45ba34dedebc --- /dev/null +++ b/app/boards/shields/nice_view_adapter/boards/nice_nano_v2.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + spi0_default: spi0_default { + group1 { + psels = , + , + ; + }; + }; + spi0_sleep: spi0_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; + +nice_view_spi: &spi0 { + compatible = "nordic,nrf-spim"; + pinctrl-0 = <&spi0_default>; + pinctrl-1 = <&spi0_sleep>; + pinctrl-names = "default", "sleep"; + cs-gpios = <&pro_micro 1 GPIO_ACTIVE_HIGH>; +}; + +&pro_micro_i2c { + status = "disabled"; +}; diff --git a/app/boards/shields/nice_view_adapter/boards/nrfmicro_11.overlay b/app/boards/shields/nice_view_adapter/boards/nrfmicro_11.overlay new file mode 100644 index 000000000000..706cffbebea2 --- /dev/null +++ b/app/boards/shields/nice_view_adapter/boards/nrfmicro_11.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + spi0_default: spi0_default { + group1 { + psels = , + , + ; + }; + }; + spi0_sleep: spi0_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; + +nice_view_spi: &spi0 { + compatible = "nordic,nrf-spim"; + pinctrl-0 = <&spi0_default>; + pinctrl-1 = <&spi0_sleep>; + pinctrl-names = "default", "sleep"; + cs-gpios = <&pro_micro 1 GPIO_ACTIVE_HIGH>; +}; + +&pro_micro_i2c { + status = "disabled"; +}; diff --git a/app/boards/shields/nice_view_adapter/boards/nrfmicro_11_flipped.overlay b/app/boards/shields/nice_view_adapter/boards/nrfmicro_11_flipped.overlay new file mode 100644 index 000000000000..5b5dbfb1c3b8 --- /dev/null +++ b/app/boards/shields/nice_view_adapter/boards/nrfmicro_11_flipped.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + spi0_default: spi0_default { + group1 { + psels = , + , + ; + }; + }; + spi0_sleep: spi0_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; + +nice_view_spi: &spi0 { + compatible = "nordic,nrf-spim"; + pinctrl-0 = <&spi0_default>; + pinctrl-1 = <&spi0_sleep>; + pinctrl-names = "default", "sleep"; + cs-gpios = <&pro_micro 1 GPIO_ACTIVE_HIGH>; +}; + +&pro_micro_i2c { + status = "disabled"; +}; diff --git a/app/boards/shields/nice_view_adapter/boards/nrfmicro_13.overlay b/app/boards/shields/nice_view_adapter/boards/nrfmicro_13.overlay new file mode 100644 index 000000000000..706cffbebea2 --- /dev/null +++ b/app/boards/shields/nice_view_adapter/boards/nrfmicro_13.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + spi0_default: spi0_default { + group1 { + psels = , + , + ; + }; + }; + spi0_sleep: spi0_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; + +nice_view_spi: &spi0 { + compatible = "nordic,nrf-spim"; + pinctrl-0 = <&spi0_default>; + pinctrl-1 = <&spi0_sleep>; + pinctrl-names = "default", "sleep"; + cs-gpios = <&pro_micro 1 GPIO_ACTIVE_HIGH>; +}; + +&pro_micro_i2c { + status = "disabled"; +}; diff --git a/app/boards/shields/nice_view_adapter/boards/puchi_ble_v1.overlay b/app/boards/shields/nice_view_adapter/boards/puchi_ble_v1.overlay new file mode 100644 index 000000000000..706cffbebea2 --- /dev/null +++ b/app/boards/shields/nice_view_adapter/boards/puchi_ble_v1.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + spi0_default: spi0_default { + group1 { + psels = , + , + ; + }; + }; + spi0_sleep: spi0_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; + +nice_view_spi: &spi0 { + compatible = "nordic,nrf-spim"; + pinctrl-0 = <&spi0_default>; + pinctrl-1 = <&spi0_sleep>; + pinctrl-names = "default", "sleep"; + cs-gpios = <&pro_micro 1 GPIO_ACTIVE_HIGH>; +}; + +&pro_micro_i2c { + status = "disabled"; +}; diff --git a/app/boards/shields/nice_view_adapter/nice_view_adapter.conf b/app/boards/shields/nice_view_adapter/nice_view_adapter.conf new file mode 100644 index 000000000000..c5fe224e2627 --- /dev/null +++ b/app/boards/shields/nice_view_adapter/nice_view_adapter.conf @@ -0,0 +1,2 @@ +# Disable OLED +CONFIG_SSD1306=n diff --git a/app/boards/shields/nice_view_adapter/nice_view_adapter.overlay b/app/boards/shields/nice_view_adapter/nice_view_adapter.overlay new file mode 100644 index 000000000000..2b82df5ca7c7 --- /dev/null +++ b/app/boards/shields/nice_view_adapter/nice_view_adapter.overlay @@ -0,0 +1,5 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ diff --git a/app/boards/shields/nice_view_adapter/nice_view_adapter.zmk.yml b/app/boards/shields/nice_view_adapter/nice_view_adapter.zmk.yml new file mode 100644 index 000000000000..e63b01e5ab00 --- /dev/null +++ b/app/boards/shields/nice_view_adapter/nice_view_adapter.zmk.yml @@ -0,0 +1,7 @@ +file_format: "1" +id: nice_view_adapter +name: nice!view adapter +type: shield +url: https://nicekeyboards.com/nice-view +requires: [i2c_oled] +exposes: [nice_view_header] diff --git a/app/boards/shields/osprette/Kconfig.defconfig b/app/boards/shields/osprette/Kconfig.defconfig new file mode 100644 index 000000000000..d765b76485b0 --- /dev/null +++ b/app/boards/shields/osprette/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_OSPRETTE + +config ZMK_KEYBOARD_NAME + default "Osprette" + +endif diff --git a/app/boards/shields/osprette/Kconfig.shield b/app/boards/shields/osprette/Kconfig.shield new file mode 100644 index 000000000000..1e9cc87b1399 --- /dev/null +++ b/app/boards/shields/osprette/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_OSPRETTE + def_bool $(shields_list_contains,osprette) diff --git a/app/boards/shields/osprette/osprette.conf b/app/boards/shields/osprette/osprette.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/osprette/osprette.keymap b/app/boards/shields/osprette/osprette.keymap new file mode 100644 index 000000000000..9c9213b6ff24 --- /dev/null +++ b/app/boards/shields/osprette/osprette.keymap @@ -0,0 +1,113 @@ +/* +* Copyright (c) 2021 The ZMK Contributors +* +* SPDX-License-Identifier: MIT +*/ + +#include +#include +#include + +#define MAIN 0 +#define SYM 1 +#define NAV 2 +#define BT 3 + +&mt { + flavor = "tap-preferred"; + tapping_term_ms = <140>; +}; + +/ { + combos { + compatible = "zmk,combos"; + + combo_esc { + timeout-ms = <100>; + key-positions = <21 22>; + bindings = <&kp ESC>; + }; + + combo_tab { + timeout-ms = <100>; + key-positions = <22 23>; + bindings = <&kp TAB>; + }; + + combo_minus { + timeout-ms = <100>; + key-positions = <26 27>; + bindings = <&kp MINUS>; + }; + + combo_underscore { + timeout-ms = <100>; + key-positions = <26 28>; + bindings = <&kp UNDERSCORE>; + }; + + combo_colon { + timeout-ms = <100>; + key-positions = <7 8>; + bindings = <&kp COLON>; + }; + + combo_semicolon { + timeout-ms = <100>; + key-positions = <6 8>; + bindings = <&kp SEMICOLON>; + }; + + combo_backslash { + timeout-ms = <100>; + key-positions = <27 28>; + bindings = <&kp BSLH>; + }; + + combo_grave { + timeout-ms = <100>; + key-positions = <8 9>; + bindings = <&kp GRAVE>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + MAIN_layer { + bindings = < + &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O + &kp Q &kp A &kp S &kp D < SYM F &kp G &kp H < SYM J &kp K &kp L &kp SQT &kp P + &mt LSHFT Z &mt LALT X &mt LCTRL C &mt LGUI V &kp B &kp N &mt RGUI M &mt RCTRL COMMA &mt RALT DOT &mt RSHFT FSLH + < BT ENTER < NAV SPACE &sk RSHFT &kp BSPC + >; + }; + + SYM_layer { + bindings = < + &kp N7 &kp N8 &kp N9 &kp STAR &kp DLLR &kp LBRC &kp RBRC &kp HASH + &kp AMPS &kp EXCL &kp N1 &kp N2 &kp N3 &kp EQUAL &kp LT &kp LPAR &kp RPAR &kp GT &kp PIPE &none + &kp CARET &kp N4 &kp N5 &kp N6 &kp PLUS &kp TILDE &kp LBKT &kp RBKT &kp AT &kp PRCNT + &kp DOT &kp N0 &trans &none + >; + }; + + NAV_layer { + bindings = < + &kp C_VOL_DN &kp C_VOL_UP &kp C_NEXT &kp C_PP &none &kp F7 &kp F8 &kp F9 + &kp C_PREV &kp LEFT &kp DOWN &kp UP &kp RIGHT &kp LC(TAB) &kp PSCRN &kp F1 &kp F2 &kp F3 &kp F10 &kp F12 + &kp HOME &kp PG_DN &kp PG_UP &kp END &kp LS(LC(TAB)) &kp CAPS &kp F4 &kp F5 &kp F6 &kp F11 + &none &none &trans &kp DEL + >; + }; + + BT_layer { + bindings = < + &none &none &none &none &none &none &none &none + &none &none &none &none &none &none &none &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &none + &none &none &none &none &none &none &bt BT_CLR &none &none &none + &none &none &none &none + >; + }; + }; +}; diff --git a/app/boards/shields/osprette/osprette.overlay b/app/boards/shields/osprette/osprette.overlay new file mode 100644 index 000000000000..e972e4daa425 --- /dev/null +++ b/app/boards/shields/osprette/osprette.overlay @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <10>; + rows = <4>; + map = < + RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) +RC(0,0) RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(0,9) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) + RC(3,3) RC(3,4) RC(3,5) RC(3,6) + >; + }; + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "row2col"; + + col-gpios + = <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + row-gpios + = <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + ; + }; +}; diff --git a/app/boards/shields/osprette/osprette.zmk.yml b/app/boards/shields/osprette/osprette.zmk.yml new file mode 100644 index 000000000000..a144c22f941d --- /dev/null +++ b/app/boards/shields/osprette/osprette.zmk.yml @@ -0,0 +1,8 @@ +file_format: "1" +id: osprette +name: Osprette +type: shield +url: https://github.com/smores56/osprette/ +requires: [pro_micro] +features: + - keys diff --git a/app/boards/shields/pancake/Kconfig.defconfig b/app/boards/shields/pancake/Kconfig.defconfig new file mode 100644 index 000000000000..47f5e6820c1b --- /dev/null +++ b/app/boards/shields/pancake/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_PANCAKE + +config ZMK_KEYBOARD_NAME + default "Pancake" + +endif \ No newline at end of file diff --git a/app/boards/shields/pancake/Kconfig.shield b/app/boards/shields/pancake/Kconfig.shield new file mode 100644 index 000000000000..ca00d303852a --- /dev/null +++ b/app/boards/shields/pancake/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_PANCAKE + def_bool $(shields_list_contains,pancake) \ No newline at end of file diff --git a/app/boards/shields/pancake/pancake.conf b/app/boards/shields/pancake/pancake.conf new file mode 100644 index 000000000000..67b8cb5ca5f5 --- /dev/null +++ b/app/boards/shields/pancake/pancake.conf @@ -0,0 +1 @@ +# CONFIG_ZMK_USB_LOGGING=y \ No newline at end of file diff --git a/app/boards/shields/pancake/pancake.keymap b/app/boards/shields/pancake/pancake.keymap new file mode 100644 index 000000000000..e5ca437263a1 --- /dev/null +++ b/app/boards/shields/pancake/pancake.keymap @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +#define DEF 0 +#define LWR 1 +#define RSE 2 +#define FNC 3 + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSPC + &kp TAB &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SQT &kp SEMI + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp UP &kp ENTER + &kp LCTRL &kp LALT &kp LGUI &mo FNC &mo LWR &kp SPACE &kp SPACE &mo RSE &kp SLASH &kp LEFT &kp DOWN &kp RIGHT + >; + }; + + lower_layer { + bindings = < + &kp TILDE &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp STAR &kp LPAR &kp RPAR &kp BSPC + &trans &trans &trans &trans &trans &trans &trans &trans &kp UNDER &kp PLUS &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp LBRC &kp RBRC &kp C_VOL_UP &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp QMARK &trans &kp C_VOL_DN &trans + >; + }; + + raise_layer { + bindings = < + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp BSPC + &trans &trans &trans &trans &trans &trans &trans &trans &kp MINUS &kp EQUAL &trans &kp BSLH + &trans &trans &trans &trans &trans &trans &trans &trans &kp LBKT &kp RBKT &kp C_VOL_UP &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp C_VOL_DN &trans + >; + }; + + function_layer { + bindings = < + &bootloader &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp MINUS &kp F11 &kp F12 &trans + &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans + &out OUT_BLE &out OUT_USB &out OUT_TOG &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + }; + }; +}; diff --git a/app/boards/shields/pancake/pancake.overlay b/app/boards/shields/pancake/pancake.overlay new file mode 100644 index 000000000000..0ceb2d5c6f70 --- /dev/null +++ b/app/boards/shields/pancake/pancake.overlay @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + chosen { + zmk,kscan = &kscan0; + }; + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + col-gpios + = <&pro_micro 21 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 3 GPIO_ACTIVE_HIGH> + , <&pro_micro 2 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; diff --git a/app/boards/shields/pancake/pancake.zmk.yml b/app/boards/shields/pancake/pancake.zmk.yml new file mode 100644 index 000000000000..21cc544456a0 --- /dev/null +++ b/app/boards/shields/pancake/pancake.zmk.yml @@ -0,0 +1,8 @@ +file_format: "1" +id: pancake +name: Pancake +type: shield +url: https://mkultra.click/pancake-keyboard-kit +requires: [pro_micro] +features: + - keys diff --git a/app/boards/shields/qaz/Kconfig.defconfig b/app/boards/shields/qaz/Kconfig.defconfig new file mode 100644 index 000000000000..c84180bf5311 --- /dev/null +++ b/app/boards/shields/qaz/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_QAZ + +config ZMK_KEYBOARD_NAME + default "QAZ" + +endif \ No newline at end of file diff --git a/app/boards/shields/qaz/Kconfig.shield b/app/boards/shields/qaz/Kconfig.shield new file mode 100644 index 000000000000..7cc8f1e4ed2f --- /dev/null +++ b/app/boards/shields/qaz/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_QAZ + def_bool $(shields_list_contains,qaz) diff --git a/app/boards/shields/qaz/qaz.conf b/app/boards/shields/qaz/qaz.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/qaz/qaz.keymap b/app/boards/shields/qaz/qaz.keymap new file mode 100644 index 000000000000..c887fb033290 --- /dev/null +++ b/app/boards/shields/qaz/qaz.keymap @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +#define DEFAULT 0 +#define NUM_SYM 1 +#define NAV 2 + +/ { + behaviors { + hm: homerow_mods { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + tapping-term-ms = <225>; + flavor = "tap-preferred"; + bindings = <&kp>, <&kp>; + }; + }; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P + &hm LGUI A &hm LALT S &hm LCTRL D &hm LSHFT F &kp G &kp H &hm RSHFT J &hm RCTRL K &hm RALT L &hm RGUI RET + &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT + &kp LSHFT &kp LGUI &kp LALT < NAV RET < NUM_SYM SPACE &kp COLON &kp SQT &kp FSLH + >; + }; + num_sym { + bindings = < + &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 + &trans &trans &trans &trans &trans &trans &trans &trans &kp EQUAL &kp MINUS + &kp DEL &none &none &none &none &none &none &none &kp DOT + &bootloader &sys_reset &none &trans &trans &kp RET &trans &kp FSLH + >; + }; + + nav { + bindings = < + &bt BT_CLR &bt BT_NXT &bt BT_PRV &none &none &none &none &kp UP &none &kp BSPC + &trans &trans &trans &trans &none &none &kp LEFT &kp DOWN &kp RIGHT &none + &none &none &none &none &none &none &none &none &none + &none &none &none &trans &trans &kp RET &trans &kp FSLH + >; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/qaz/qaz.overlay b/app/boards/shields/qaz/qaz.overlay new file mode 100644 index 000000000000..814e5e1a0a16 --- /dev/null +++ b/app/boards/shields/qaz/qaz.overlay @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <7>; + rows = <6>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(4,0) RC(4,1) RC(4,2) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(5,0) RC(5,1) RC(5,2) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(4,3) RC(5,3) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(4,4) + >; + }; + + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + col-gpios + = <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 1 GPIO_ACTIVE_HIGH> + , <&pro_micro 0 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; + +}; \ No newline at end of file diff --git a/app/boards/shields/qaz/qaz.zmk.yml b/app/boards/shields/qaz/qaz.zmk.yml new file mode 100644 index 000000000000..3305e3da9960 --- /dev/null +++ b/app/boards/shields/qaz/qaz.zmk.yml @@ -0,0 +1,8 @@ +file_format: "1" +id: qaz +name: QAZ +type: shield +url: https://www.cbkbd.com/product/qaz-keyboard-kit +requires: [pro_micro] +features: + - keys diff --git a/app/boards/shields/quefrency/Kconfig.defconfig b/app/boards/shields/quefrency/Kconfig.defconfig new file mode 100644 index 000000000000..db618287bb67 --- /dev/null +++ b/app/boards/shields/quefrency/Kconfig.defconfig @@ -0,0 +1,20 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + + +if SHIELD_QUEFRENCY_LEFT + +config ZMK_KEYBOARD_NAME + default "Quefrency" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_QUEFRENCY_LEFT || SHIELD_QUEFRENCY_RIGHT + +config ZMK_SPLIT + default y + +endif \ No newline at end of file diff --git a/app/boards/shields/quefrency/Kconfig.shield b/app/boards/shields/quefrency/Kconfig.shield new file mode 100644 index 000000000000..d30d30f14905 --- /dev/null +++ b/app/boards/shields/quefrency/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_QUEFRENCY_LEFT + def_bool $(shields_list_contains,quefrency_left) + +config SHIELD_QUEFRENCY_RIGHT + def_bool $(shields_list_contains,quefrency_right) diff --git a/app/boards/shields/quefrency/quefrency.conf b/app/boards/shields/quefrency/quefrency.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/quefrency/quefrency.dtsi b/app/boards/shields/quefrency/quefrency.dtsi new file mode 100644 index 000000000000..f7dc4489918d --- /dev/null +++ b/app/boards/shields/quefrency/quefrency.dtsi @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + + zmk,matrix_transform = &default_transform; + }; + + /* + * This transform correspondsto the 60% left without macro keypad and 65% right, even this + * combination of PCBs can have keys in different locations based on configuration. + */ + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <15>; + rows = <6>; + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) /**/ RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,14) RC(5,13) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) /**/RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) RC(1,14) RC(5,14) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) /**/ RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,14) RC(2,13) +RC(3,0) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) /**/ RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,12) RC(3,13) RC(3,14) RC(3,11) +RC(4,0) RC(4,1) RC(4,2) RC(4,4) RC(4,6) /**/ RC(4,7) RC(4,10) RC(4,11) RC(4,12) RC(4,13) RC(4,14) RC(4,9) + >; + }; +}; diff --git a/app/boards/shields/quefrency/quefrency.keymap b/app/boards/shields/quefrency/quefrency.keymap new file mode 100644 index 000000000000..7d519ad4573f --- /dev/null +++ b/app/boards/shields/quefrency/quefrency.keymap @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + +// ---------------------------------------------- ----------------------------------------------------- +// | ESC | 1 | 2 | 3 | 4 | 5 | 6 | | 7 | 8 | 9 | 0 | - | = | BKSPC | ` | +// | TAB | Q | W | E | R | T | | Y | U | I | O | P | [ | ] | \ | DEL | +// | LCTRL | A | S | D | F | G | | H | J | K | L | ; | ' | ENTER | PGUP | +// | SHIFT | Z | X | C | V | B | | N | M | , | . | / | RSHFT | UP | PGDN | +// | LCTRL | LGUI | LALT | SPACE | FN | | SPACE | RALT | FN | RCTRL | LFT | DWN | RGHT | +// ------------------------------------------- ------------------------------------------------------ + + default_layer { + bindings = < + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 /**/ &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp GRAVE + &kp TAB &kp Q &kp W &kp E &kp R &kp T /**/ &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp HOME + &kp LCTRL &kp A &kp S &kp D &kp F &kp G /**/ &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET &kp PG_UP + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B /**/ &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp PG_DN + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &mo 1 /**/ &kp SPACE &kp RALT &mo 1 &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT + >; + }; + +// ---------------------------------------------- ----------------------------------------------------- +// |BT_CLR| F1 | F2 | F3 | F4 | F5 | F6 | | F7 | F8 | F9 | F10 | F11 | F12 | |BT_CLR| +// | | BT-0 | BT-1| BT-2 | | | | | | | | | | | | | +// | | | | | | | | | | | | | | | | +// | | | | | | | | | | | | | | | | +// | | | | | | | | | | | | | | +// ------------------------------------------- ------------------------------------------------------ + + fn_layer { + bindings = < + &bt BT_CLR &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 /**/ &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &trans &bt BT_CLR + &trans &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &trans &trans /**/ &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans /**/ &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans /**/ &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans /**/ &trans &trans &trans &trans &trans &trans &trans + >; + }; + }; +}; diff --git a/app/boards/shields/quefrency/quefrency.zmk.yml b/app/boards/shields/quefrency/quefrency.zmk.yml new file mode 100644 index 000000000000..e70ae68e68c2 --- /dev/null +++ b/app/boards/shields/quefrency/quefrency.zmk.yml @@ -0,0 +1,12 @@ +file_format: "1" +id: quefrency +name: Quefrency Rev. 1 +type: shield +url: https://github.com/keebio/quefrency-rev1-pcb +requires: [pro_micro] +features: + - keys + - encoder +siblings: + - quefrency_left + - quefrency_right diff --git a/app/boards/shields/quefrency/quefrency_left.conf b/app/boards/shields/quefrency/quefrency_left.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/quefrency/quefrency_left.overlay b/app/boards/shields/quefrency/quefrency_left.overlay new file mode 100644 index 000000000000..cf7958410c60 --- /dev/null +++ b/app/boards/shields/quefrency/quefrency_left.overlay @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "quefrency.dtsi" + +/ { + /* This kscan is for the 60% left half without macro keys the + * macro pad layout may require different column and row pins + */ + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + + col-gpios + = <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; diff --git a/app/boards/shields/quefrency/quefrency_right.conf b/app/boards/shields/quefrency/quefrency_right.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/quefrency/quefrency_right.overlay b/app/boards/shields/quefrency/quefrency_right.overlay new file mode 100644 index 000000000000..446a614a2291 --- /dev/null +++ b/app/boards/shields/quefrency/quefrency_right.overlay @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "quefrency.dtsi" + +&default_transform { + col-offset = <7>; +}; + +/ { + + /* This kscan is for the 65% right half the 60% right half + * may require different column and row pins + */ + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + + + col-gpios + = <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; diff --git a/app/boards/shields/redox/Kconfig.defconfig b/app/boards/shields/redox/Kconfig.defconfig new file mode 100644 index 000000000000..32e30ad513dc --- /dev/null +++ b/app/boards/shields/redox/Kconfig.defconfig @@ -0,0 +1,18 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT +if SHIELD_REDOX_LEFT + +config ZMK_KEYBOARD_NAME + default "Redox" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_REDOX_LEFT || SHIELD_REDOX_RIGHT + +config ZMK_SPLIT + default y + +endif \ No newline at end of file diff --git a/app/boards/shields/redox/Kconfig.shield b/app/boards/shields/redox/Kconfig.shield new file mode 100644 index 000000000000..8e6c601d74c2 --- /dev/null +++ b/app/boards/shields/redox/Kconfig.shield @@ -0,0 +1,7 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT +config SHIELD_REDOX_LEFT + def_bool $(shields_list_contains,redox_left) + +config SHIELD_REDOX_RIGHT + def_bool $(shields_list_contains,redox_right) diff --git a/app/boards/shields/redox/boards/nice_nano.overlay b/app/boards/shields/redox/boards/nice_nano.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/redox/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/redox/boards/nice_nano_v2.overlay b/app/boards/shields/redox/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/redox/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/redox/redox.conf b/app/boards/shields/redox/redox.conf new file mode 100644 index 000000000000..a1837ef9fa30 --- /dev/null +++ b/app/boards/shields/redox/redox.conf @@ -0,0 +1,3 @@ +# Uncomment the following lines to enable the Redox RGB Underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y \ No newline at end of file diff --git a/app/boards/shields/redox/redox.dtsi b/app/boards/shields/redox/redox.dtsi new file mode 100644 index 000000000000..bf5ec9e843a9 --- /dev/null +++ b/app/boards/shields/redox/redox.dtsi @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <14>; + rows = <5>; +// | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | +// | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | SW13 | | SW13 | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | +// | SW14 | SW15 | SW16 | SW17 | SW18 | SW19 | SW20 | | SW20 | SW19 | SW18 | SW17 | SW16 | SW15 | SW14 | +// | SW21 | SW22 | SW23 | SW24 | SW25 | SW26 | SW27 | SW28 | | SW28 | SW27 | SW26 | SW25 | SW24 | SW23 | SW22 | SW21 | +// | SW29 | SW30 | SW31 | SW32 | SW33 | SW34 | SW35 | | SW35 | SW34 | SW33 | SW32 | SW31 | SW30 | SW29 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(0,6) RC(0,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(1,6) RC(1,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(2,6) RC(3,6) RC(3,7) RC(2,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) RC(3,13) +RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,13) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + }; + +}; diff --git a/app/boards/shields/redox/redox.keymap b/app/boards/shields/redox/redox.keymap new file mode 100644 index 000000000000..c88f703beab1 --- /dev/null +++ b/app/boards/shields/redox/redox.keymap @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap" ; + + default_layer { +// -------------------------------------------------------------------------------------------------------------------------------- +// | ESC | 1 | 2 | 3 | 4 | 5 | --- | 6 | 7 | 8 | 9 | 0 | BKSP | +// | TAB | Q | W | E | R | T | ( | --- | ) | Y | U | I | O | P | - | +// | CTRL | A | S | D | F | G | [ | --- | ] | H | J | K | L | ; | ' | +// | SHIFT | Z | X | C | V | B | PG_UP | PG_DOWN | --- | HOME | END | N | M | , | . | / | SHFT(RET) | +// | CRTL | ALT | GUI | LOWER | GUI | LOWER | SPACE | --- | DEL | SPACE | RAISE | LEFT | DOWN | UP | RIGHT | + bindings = < + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp LPAR &kp RPAR &kp Y &kp U &kp I &kp O &kp P &kp MINUS + &kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp LBKT &kp RBKT &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp PG_UP &kp PG_DN &kp HOME &kp END &kp N &kp M &kp COMMA &kp DOT &kp FSLH &mt RSHFT RET + &kp LCTRL &kp LALT &kp LGUI &mo 3 &kp LGUI &mo 1 &kp SPACE &kp DEL &kp SPACE &mo 2 &kp LEFT &kp DOWN &kp UP &kp RIGHT + >; + + }; + + lower_layer { +// -------------------------------------------------------------------------------------------------------------------------- +// | ESC | 1 | 2 | 3 | 4 | 5 | --- | 6 | 7 | 8 | 9 | 0 | DEL | +// | ESC | 1 | 2 | 3 | 4 | 5 | ( | --- | ) | 6 | 7 | 8 | 9 | 0 | DEL | +// | CTRL | - | = | [ | ] | \ | [ | --- | ] | * | 4 | 5 | 6 | + | - | +// | SHIFT | ESC | GUI | COPY | PASTE | | PG_UP | PG_DOWN | --- | HOME | END | \ | 1 | 2 | 3 | RET | RET | +// | CRTL | ALT | GUI | LOWER | GUI | LOWER | SPACE | --- | DEL | 0 | RAISE | LEFT | DOWN | UP | RIGHT | + bindings = < + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &trans &trans &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp DEL + &trans &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH &trans &trans &kp KP_MULTIPLY &kp N4 &kp N5 &kp N6 &kp KP_PLUS &kp KP_MINUS + &trans &kp ESC &kp LGUI &kp LG(C) &kp LG(V) &kp GRAVE &trans &trans &trans &trans &kp KP_DIVIDE &kp N1 &kp N2 &kp N3 &kp RET &kp RET + &trans &trans &trans &trans &trans &trans &trans &trans &kp N0 &mo 3 &trans &trans &trans &trans + >; + }; + + raise_layer { +// ---------------------------------------------------------------------------------------------------------------------------- +// | ESC | 1 | 2 | 3 | 4 | 5 | --- | 6 | 7 | 8 | 9 | 0 | DEL | +// | ESC | ! | @ | # | $ | % | ( | --- | ) | ^ | & | * | ( | ) | DEL | +// | CTRL | _ | + | { | } | "|" | [ | --- | ] | HOME | PGUP | PRSC | UP | ` | ~ | +// | SHIFT | ESC | GUI | ( | ) | | PG_UP | PG_DOWN | --- | HOME | END | END | PGDN | LEFT | DOWN | RIGHT | RET | +// | CRTL | ALT | GUI | LOWER | GUI | LOWER | SPACE | --- | DEL | SPACE | RAISE | LEFT | DOWN | UP | RIGHT | + bindings = < + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &kp ESC &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &trans &trans &kp CARET &kp AMPS &kp ASTRK &kp LPAR &kp RPAR &kp DEL + &trans &kp UNDER &kp PLUS &kp LBRC &kp RBRC &kp PIPE &trans &trans &kp HOME &kp PG_UP &kp PSCRN &kp UP &kp GRAVE &kp TILDE + &trans &kp ESC &kp LGUI &kp LPAR &kp RPAR &kp TILDE &trans &trans &trans &trans &kp END &kp PG_DN &kp LEFT &kp DOWN &kp RIGHT &kp RET + &trans &trans &trans &mo 3 &trans &mo 3 &trans &trans &trans &trans &trans &trans &trans &trans + >; + }; + + adjust_layer { +// ----------------------------------------------------------------------------------------- +// | F1 | F2 | F3 | F4 | F5 | F6 | --- | F7 | F8 | F9 | F10 | F11 | F12 | +// | TAB | | | | | | BOOTL | --- | ) | BT1 | BT2 | BT3 | BT4 | BT5 | OUTPUT TGL | +// | CTRL | MUTE | Vol Dn | Vol Up | Play/Pause | | RESET | --- | ] | F1 | F2 | F3 | F4 | F5 | F6 | +// | SHIFT | PSCRN | PSCRN | CAPS | | | PG_UP | PG_DOWN | --- | HOME | END | F7 | F8 | F9 | F10 | F11 | F12 | +// | CRTL | ALT | GUI | LOWER | GUI | LOWER | SPACE | --- | DEL | SPACE | RAISE | LEFT | DOWN | UP | RIGHT | + bindings = < + &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 + &trans &none &none &none &none &none &bootloader &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &out OUT_TOG + &trans &kp K_MUTE &kp C_VOL_DN &kp C_VOL_UP &kp C_PLAY_PAUSE &none &sys_reset &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 + &trans &kp PSCRN &kp PSCRN &kp CLCK &none &none &trans &trans &trans &trans &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + }; + }; +}; diff --git a/app/boards/shields/redox/redox.zmk.yml b/app/boards/shields/redox/redox.zmk.yml new file mode 100644 index 000000000000..fd22971deefe --- /dev/null +++ b/app/boards/shields/redox/redox.zmk.yml @@ -0,0 +1,12 @@ +file_format: "1" +id: redox +name: Redox +type: shield +url: https://github.com/mattdibi/redox-keyboard +requires: [pro_micro] +features: + - keys + - underglow +siblings: + - redox_left + - redox_right diff --git a/app/boards/shields/redox/redox_left.overlay b/app/boards/shields/redox/redox_left.overlay new file mode 100644 index 000000000000..d68029d8805c --- /dev/null +++ b/app/boards/shields/redox/redox_left.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "redox.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/redox/redox_right.overlay b/app/boards/shields/redox/redox_right.overlay new file mode 100644 index 000000000000..09b146377d4e --- /dev/null +++ b/app/boards/shields/redox/redox_right.overlay @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "redox.dtsi" + +&default_transform { + col-offset = <7>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/reviung34/Kconfig.defconfig b/app/boards/shields/reviung34/Kconfig.defconfig new file mode 100644 index 000000000000..5dc26b4f0658 --- /dev/null +++ b/app/boards/shields/reviung34/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_REVIUNG34 + +config ZMK_KEYBOARD_NAME + default "REVIUNG34" + +endif diff --git a/app/boards/shields/reviung34/Kconfig.shield b/app/boards/shields/reviung34/Kconfig.shield new file mode 100644 index 000000000000..f3c63a157c18 --- /dev/null +++ b/app/boards/shields/reviung34/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_REVIUNG34 + def_bool $(shields_list_contains,reviung34) diff --git a/app/boards/shields/reviung34/README.md b/app/boards/shields/reviung34/README.md new file mode 100644 index 000000000000..e62c52d65e35 --- /dev/null +++ b/app/boards/shields/reviung34/README.md @@ -0,0 +1,13 @@ +# REVIUNG34 + +REVIUNG34 is a 33-34 key unibody split keyboard by [gtips](https://github.com/gtips). An in-stock version can be found at [Little Keyboards](https://www.littlekeyboards.com/products/reviung34-analyst-keyboard-kit). + +By default, the 2x1u layout is used. To use to the 1x2u layout, add the following to your keymap: + +``` +/ { + chosen { + zmk,matrix_transform = &single_2u_transform; + }; +}; +``` diff --git a/app/boards/shields/reviung34/boards/nice_nano_v2.overlay b/app/boards/shields/reviung34/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..d14b95db76b4 --- /dev/null +++ b/app/boards/shields/reviung34/boards/nice_nano_v2.overlay @@ -0,0 +1,47 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <9>; /* number of LEDs */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/reviung34/reviung34.conf b/app/boards/shields/reviung34/reviung34.conf new file mode 100644 index 000000000000..289f070ba3f7 --- /dev/null +++ b/app/boards/shields/reviung34/reviung34.conf @@ -0,0 +1,3 @@ +# Uncomment the following lines to enable RGB underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y diff --git a/app/boards/shields/reviung34/reviung34.keymap b/app/boards/shields/reviung34/reviung34.keymap new file mode 100644 index 000000000000..9a0d982dcd7f --- /dev/null +++ b/app/boards/shields/reviung34/reviung34.keymap @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +/ { + chosen { + // 34 keys. + zmk,matrix_transform = &dual_1u_transform; + + // 33 keys. Center two thumb keys replaced by a single 2u key. Remember to adjust your + // keymap accordingly! + // zmk,matrix_transform = &single_2u_transform; + }; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + base { + display-name = "Base"; + bindings = < +&kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P +&kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI +&mt LSHFT Z &mt LCTRL X &mt LALT C &kp V &kp B &kp N &kp M &mt RALT COMMA &mt RCTRL DOT &mt RSHFT SLASH + &kp LGUI < 1 BSPC < 2 SPACE &mo 3 + >; + }; + + lower { + display-name = "Lower"; + bindings = < +&kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp ASTRK &kp LPAR &kp RPAR +&trans &kp TILDE &kp DQT &kp PIPE &trans &trans &kp UNDER &kp PLUS &kp LBRC &kp RBRC +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &mo 4 &trans + >; + }; + + upper { + display-name = "Upper"; + bindings = < +&kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 +&trans &kp GRAVE &kp SQT &kp BSLH &trans &trans &kp MINUS &kp EQUAL &kp LBKT &kp RBKT +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &mo 4 &trans &trans + >; + }; + + function { + display-name = "Function"; + bindings = < +&kp TAB &trans &kp C_VOL_UP &trans &trans &trans &trans &trans &trans &kp ENTER +&kp ESC &kp C_BRI_DN &kp C_VOL_DN &kp C_BRI_UP &trans &trans &kp LEFT &kp DOWN &kp UP &kp RIGHT +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &kp C_PWR &trans &trans + >; + }; + + meta { + display-name = "Meta"; + bindings = < +&rgb_ug RGB_HUI &rgb_ug RGB_SAI &rgb_ug RGB_BRI &rgb_ug RGB_SPI &rgb_ug RGB_EFF &none &none &none &none &none +&rgb_ug RGB_HUD &rgb_ug RGB_SAD &rgb_ug RGB_BRD &rgb_ug RGB_SPD &rgb_ug RGB_EFR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 +&none &none &rgb_ug RGB_TOG &none &none &none &none &bt BT_CLR &none &none + &none &trans &trans &none + >; + }; + }; +}; diff --git a/app/boards/shields/reviung34/reviung34.overlay b/app/boards/shields/reviung34/reviung34.overlay new file mode 100644 index 000000000000..6b1eb16f0fbe --- /dev/null +++ b/app/boards/shields/reviung34/reviung34.overlay @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &dual_1u_transform; + }; + + dual_1u_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <9>; + rows = <4>; + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(3,5) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(3,6) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(3,7) + RC(3,2) RC(3,3) RC(3,4) RC(3,8) + >; + }; + + single_2u_transform: keymap_transform_1 { + compatible = "zmk,matrix-transform"; + columns = <9>; + rows = <4>; + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(3,5) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(3,6) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(3,7) + RC(3,2) RC(3,4) RC(3,8) + >; + }; + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + col-gpios + = <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; diff --git a/app/boards/shields/reviung34/reviung34.zmk.yml b/app/boards/shields/reviung34/reviung34.zmk.yml new file mode 100644 index 000000000000..76ed745d9793 --- /dev/null +++ b/app/boards/shields/reviung34/reviung34.zmk.yml @@ -0,0 +1,9 @@ +file_format: "1" +id: reviung34 +name: REVIUNG34 +type: shield +url: https://github.com/gtips/reviung/tree/master/reviung34 +requires: [pro_micro] +features: + - keys + - underglow diff --git a/app/boards/shields/reviung41/Kconfig.defconfig b/app/boards/shields/reviung41/Kconfig.defconfig new file mode 100644 index 000000000000..0625cb210f7e --- /dev/null +++ b/app/boards/shields/reviung41/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_REVIUNG41 + +config ZMK_KEYBOARD_NAME + default "Reviung41" + +endif diff --git a/app/boards/shields/reviung41/Kconfig.shield b/app/boards/shields/reviung41/Kconfig.shield new file mode 100644 index 000000000000..e51f9e647432 --- /dev/null +++ b/app/boards/shields/reviung41/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_REVIUNG41 + def_bool $(shields_list_contains,reviung41) diff --git a/app/boards/shields/reviung41/boards/nice_nano.overlay b/app/boards/shields/reviung41/boards/nice_nano.overlay new file mode 100644 index 000000000000..591800642786 --- /dev/null +++ b/app/boards/shields/reviung41/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <11>; + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/reviung41/boards/nice_nano_v2.overlay b/app/boards/shields/reviung41/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..591800642786 --- /dev/null +++ b/app/boards/shields/reviung41/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <11>; + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/reviung41/reviung41.conf b/app/boards/shields/reviung41/reviung41.conf new file mode 100644 index 000000000000..289f070ba3f7 --- /dev/null +++ b/app/boards/shields/reviung41/reviung41.conf @@ -0,0 +1,3 @@ +# Uncomment the following lines to enable RGB underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y diff --git a/app/boards/shields/reviung41/reviung41.keymap b/app/boards/shields/reviung41/reviung41.keymap new file mode 100644 index 000000000000..12f15ad4d17e --- /dev/null +++ b/app/boards/shields/reviung41/reviung41.keymap @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ------------------------------------------------------------------------------------- +// | TAB | Q | W | E | R | T | | Y | U | I | O | P | BKSP | +// | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | +// | SHFT | Z | X | C | V | B | | N | M | , | . | / | SHFT(RET) | +// | ALT | LWR | SPC | RSE | ALT | + bindings = < + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSPC + &kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &mt RSHFT RET + &kp LALT &mo 1 &kp SPACE &mo 2 &kp RGUI + >; + }; + + lower_layer { +// ------------------------------------------------------------------------------------ +// | | ! | @ | # | $ | % | | ^ | & | * | ( | ) | DEL | +// | | _ | + | { | } | "|" | | LFT | DWN | UP | RGT | ` | ~ | +// | | ESC | GUI | ALT | CAPS| " | | HOME| END | PGUP| PGDN| PRSC| SHFT(SPACE) | +// | | | RET | ADJ | | + bindings = < + &trans &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp ASTRK &kp LPAR &kp RPAR &kp DEL + &trans &kp UNDER &kp PLUS &kp LBRC &kp RBRC &kp PIPE &kp LEFT &kp DOWN &kp UP &kp RIGHT &kp GRAVE &kp TILDE + &trans &kp ESC &kp LGUI &kp LALT &kp CLCK &kp DQT &kp HOME &kp END &kp PG_UP &kp PG_DN &kp PSCRN &mt RSHFT SPACE + &trans &trans &kp RET &mo 3 &trans + >; + }; + + raise_layer { +// ---------------------------------------------------------------------------- +// | | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | DEL | +// | | - | = | [ | ] | \ | | F1 | F2 | F3 | F4 | F5 | F6 | +// | | ESC | GUI | ALT | CAPS| " | | F7 | F8 | F9 | F10 | F11 | F12 | +// | | ADJ | BKSP | | | + bindings = < + &trans &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp DEL + &trans &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 + &trans &kp ESC &kp LGUI &kp RALT &kp CLCK &kp DQT &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 + &trans &mo 3 &kp BSPC &trans &trans + >; + }; + + adjust_layer { +// ----------------------------------------------------------------------------------------- +// | RGB BRI+ | RGB SAT+ | RGB HUE+ | RGB ANI+ | | RGB TOG | | BT1 | BT2 | BT3 | BT4 | BT5 | BT CLR | +// | RGB BRI- | RGB SAT- | RGB HUE- | RGB ANI- | | | | | | | | | | +// | | | | | | | | RESET | | | | | | +// | | | | | | + bindings = < + &rgb_ug RGB_BRI &rgb_ug RGB_SAI &rgb_ug RGB_HUI &rgb_ug RGB_EFF &none &rgb_ug RGB_TOG &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &bt BT_CLR + &rgb_ug RGB_BRD &rgb_ug RGB_SAD &rgb_ug RGB_HUD &rgb_ug RGB_EFR &none &none &none &none &none &none &none &none + &none &none &none &none &none &none &sys_reset &none &none &none &none &none + &trans &trans &tog 3 &trans &trans + >; + }; + }; +}; diff --git a/app/boards/shields/reviung41/reviung41.overlay b/app/boards/shields/reviung41/reviung41.overlay new file mode 100644 index 000000000000..0aecf61959d6 --- /dev/null +++ b/app/boards/shields/reviung41/reviung41.overlay @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <6>; + rows = <7>; + + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(5,0) RC(5,1) RC(5,2) RC(5,3) RC(5,4) RC(5,5) + RC(6,0) RC(6,1) RC(6,2) RC(6,3) RC(6,4) + >; + }; + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + col-gpios + = <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; diff --git a/app/boards/shields/reviung41/reviung41.zmk.yml b/app/boards/shields/reviung41/reviung41.zmk.yml new file mode 100644 index 000000000000..9783b9d94c0a --- /dev/null +++ b/app/boards/shields/reviung41/reviung41.zmk.yml @@ -0,0 +1,8 @@ +file_format: "1" +id: reviung41 +name: REVIUNG41 +type: shield +url: https://github.com/gtips/reviung/tree/master/reviung41 +requires: [pro_micro] +features: + - keys diff --git a/app/boards/shields/reviung5/Kconfig.defconfig b/app/boards/shields/reviung5/Kconfig.defconfig new file mode 100644 index 000000000000..9477db396360 --- /dev/null +++ b/app/boards/shields/reviung5/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_REVIUNG5 + +config ZMK_KEYBOARD_NAME + default "Reviung5" + +endif \ No newline at end of file diff --git a/app/boards/shields/reviung5/Kconfig.shield b/app/boards/shields/reviung5/Kconfig.shield new file mode 100644 index 000000000000..2ecf47b2fdea --- /dev/null +++ b/app/boards/shields/reviung5/Kconfig.shield @@ -0,0 +1,4 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT +config SHIELD_REVIUNG5 + def_bool $(shields_list_contains,reviung5) \ No newline at end of file diff --git a/app/boards/shields/reviung5/reviung5.conf b/app/boards/shields/reviung5/reviung5.conf new file mode 100644 index 000000000000..a8b4a868b2c3 --- /dev/null +++ b/app/boards/shields/reviung5/reviung5.conf @@ -0,0 +1,3 @@ +# Encoder support. Uncomment to enable. +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y diff --git a/app/boards/shields/reviung5/reviung5.keymap b/app/boards/shields/reviung5/reviung5.keymap new file mode 100644 index 000000000000..31c89cbcef3e --- /dev/null +++ b/app/boards/shields/reviung5/reviung5.keymap @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +#define BASE 0 +#define BLE 1 + +/ { + keymap { + compatible = "zmk,keymap"; + + base_layer { + display-name = "BASE"; + bindings = < + // ╭─────────────┬──────────────┬──────────────────┬─────────────┬─────────────╮ + &mo BLE &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE + // ╰─────────────┴──────────────┴──────────────────┴─────────────┴─────────────╯ + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + ble_layer { + display-name = "BLE"; + bindings = < + // ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮ + &trans &out OUT_TOG &bt BT_PRV &bt BT_NXT &bt BT_CLR + // ╰─────────────┴─────────────┴─────────────┴─────────────┴─────────────╯ + >; + }; + }; +}; diff --git a/app/boards/shields/reviung5/reviung5.overlay b/app/boards/shields/reviung5/reviung5.overlay new file mode 100644 index 000000000000..b21a634a1b71 --- /dev/null +++ b/app/boards/shields/reviung5/reviung5.overlay @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <5>; + rows = <1>; + + map = ; + }; + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + col-gpios + = <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; + + encoder: encoder { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + status = "okay"; + }; + + sensors: sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&encoder>; + triggers-per-rotation = <20>; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/reviung5/reviung5.zmk.yml b/app/boards/shields/reviung5/reviung5.zmk.yml new file mode 100644 index 000000000000..9be3811f9342 --- /dev/null +++ b/app/boards/shields/reviung5/reviung5.zmk.yml @@ -0,0 +1,9 @@ +file_format: "1" +id: reviung5 +name: REVIUNG5 +type: shield +url: https://github.com/gtips/reviung/tree/master/reviung5 +requires: [pro_micro] +features: + - keys + - encoder diff --git a/app/boards/shields/reviung53/Kconfig.defconfig b/app/boards/shields/reviung53/Kconfig.defconfig new file mode 100644 index 000000000000..efac69b7f40f --- /dev/null +++ b/app/boards/shields/reviung53/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_REVIUNG53 + +config ZMK_KEYBOARD_NAME + default "Reviung53" + +endif diff --git a/app/boards/shields/reviung53/Kconfig.shield b/app/boards/shields/reviung53/Kconfig.shield new file mode 100644 index 000000000000..0b0613e2331f --- /dev/null +++ b/app/boards/shields/reviung53/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_REVIUNG53 + def_bool $(shields_list_contains,reviung53) diff --git a/app/boards/shields/reviung53/boards/nice_nano.overlay b/app/boards/shields/reviung53/boards/nice_nano.overlay new file mode 100644 index 000000000000..24905ac2e917 --- /dev/null +++ b/app/boards/shields/reviung53/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/reviung53/boards/nice_nano_v2.overlay b/app/boards/shields/reviung53/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..24905ac2e917 --- /dev/null +++ b/app/boards/shields/reviung53/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/reviung53/reviung53.conf b/app/boards/shields/reviung53/reviung53.conf new file mode 100644 index 000000000000..289f070ba3f7 --- /dev/null +++ b/app/boards/shields/reviung53/reviung53.conf @@ -0,0 +1,3 @@ +# Uncomment the following lines to enable RGB underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y diff --git a/app/boards/shields/reviung53/reviung53.keymap b/app/boards/shields/reviung53/reviung53.keymap new file mode 100644 index 000000000000..d00ca6b975b4 --- /dev/null +++ b/app/boards/shields/reviung53/reviung53.keymap @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +/ { + conditional_layers { + compatible = "zmk,conditional-layers"; + tri_layer { + if-layers = <1 2>; + then-layer = <3>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ---------------------------------------------------------------------------------------- +// | | | ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | DEL | +// | TAB | Q | W | E | R | T | Y | U | I | O | P | BKSP | +// | CAPS | A | S | D | F | G | H | J | K | L | ; | RET | +// | SHFT | Z | X | C | V | B | N | M | , | . | SHFT(/) | +// | CTRL | GUI | ALT | LOWER(SPACE) | RAISE(SPACE)| ALT | GUI | CTRL(\) | +// | + bindings = < + &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp DEL + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSPC + &kp CAPS &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp RET + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &mt RSHFT FSLH + &kp LCTRL &kp LCMD &kp LALT < 1 SPACE < 2 SPACE &kp RALT &kp RCMD &mt RCTRL BSLH + >; + }; + + lower_layer { +// -------------------------------------------------------------------------------------------- +// | | | | F9 | F10 | F11 | F12 | INS | PAU | SCR | PSCR | | +// | ~ | ! | @ | # | $ | % | ^ | & | * | ( | ) | | +// | NAV | | | | | | | _ | + | { | } | " | +// | | | | | | | | | | | ? | +// | | | | | | | | | | +// | + bindings = < + &trans &kp F9 &kp F10 &kp F11 &kp F12 &kp INS &kp PAUSE_BREAK &kp SLCK &kp PSCRN &trans + &kp TILDE &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp ASTRK &kp LPAR &kp RPAR &trans + &mo 4 &none &none &none &none &none &none &kp UNDER &kp PLUS &kp LBRC &kp RBRC &kp DQT + &trans &none &none &none &none &none &none &none &none &none &kp QMARK + &trans &trans &trans &trans &trans &trans &trans &kp PIPE + >; + }; + + raise_layer { +// -------------------------------------------------------------------------------------- +// | | | | F9 | F10 | F11 | F12 | MUTE | VOL+ | VOL- | PLAY | | +// | ` | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | | +// | NAV | | | | | | | - | = | [ | ] | ' | +// | | | | | | | | + | < | > | : | +// | | | | | | | | | | +// | + bindings = < + &trans &kp F9 &kp F10 &kp F11 &kp F12 &kp C_MUTE &kp C_VOL_UP &kp C_VOL_DN &kp C_PLAY &trans + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &trans + &mo 4 &none &none &none &none &none &none &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp SQT + &trans &none &none &none &none &none &none &kp PLUS &kp LT &kp GT &kp COLON + &trans &trans &trans &trans &trans &trans &trans &kp PIPE + >; + }; + + adjust_layer { +// ------------------------------------------------------------------------------------------------------------------------ +// | | | BT CLR | BT1 | BT2 | BT3 | BT4 | BT5 | | | | BT CLR | +// | RGB BRI+ | RGB SAT+ | RGB HUE+ | RGB ANI+ | | RGB TOG | | | | | | | +// | RGB BRI- | RGB SAT- | RGB HUE- | RGB ANI- | | | | | | | | | +// | | | | | | | BOOT | | | | | +// | | | | | | | | | +// | + bindings = < + &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &none &none &none &bt BT_CLR + &rgb_ug RGB_BRI &rgb_ug RGB_SAI &rgb_ug RGB_HUI &rgb_ug RGB_EFF &none &rgb_ug RGB_TOG &none &none &none &none &none &none + &rgb_ug RGB_BRD &rgb_ug RGB_SAD &rgb_ug RGB_HUD &rgb_ug RGB_EFR &none &none &none &none &none &none &none &none + &trans &none &none &none &none &none &bootloader &none &none &none &none + &trans &trans &trans &trans &trans &none &none &none + >; + }; + + nav_layer { +// ------------------------------------------------------------------------------------------------------------------------ +// | | | ESC | | | | | | | | | DEL | +// | TAB | | UP | | | | | | | | | BSPC | +// | NAV | LEFT | DOWN | RIGHT | | | LEFT | DOWN | UP | RIGHT | | ENTER | +// | SHIFT | | | | | | HOME | END | PGUP | PGDN | SHIFT | +// | CTRL | GUI | ALT | SPACE | SPACE | ALT | GUI | CTRL | +// | + bindings = < + &kp ESC &none &none &none &none &none &none &none &none &kp DEL + &kp TAB &none &kp UP &none &none &none &none &none &none &none &none &kp BSPC + &trans &kp LEFT &kp DOWN &kp RIGHT &none &none &kp LEFT &kp DOWN &kp UP &kp RIGHT &none &kp RET + &kp LSHFT &none &none &none &none &none &kp HOME &kp END &kp PG_UP &kp PG_DN &kp RSHFT + &kp LCTRL &kp LCMD &kp LALT &kp SPACE &kp SPACE &kp LALT &kp RCMD &kp RCTRL + >; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/reviung53/reviung53.overlay b/app/boards/shields/reviung53/reviung53.overlay new file mode 100644 index 000000000000..8c11c061de2f --- /dev/null +++ b/app/boards/shields/reviung53/reviung53.overlay @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <8>; + rows = <7>; + + map = < + RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(4,0) RC(4,1) RC(4,2) RC(4,3) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(4,4) RC(4,5) RC(4,6) RC(4,7) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(5,0) RC(5,1) RC(5,2) RC(5,3) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(5,4) RC(5,5) RC(5,6) +RC(6,0) RC(6,1) RC(6,2) RC(6,3) RC(6,4) RC(6,5) RC(6,6) RC(6,7) + >; + }; + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + col-gpios + = <&pro_micro 21 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&pro_micro 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + }; +}; diff --git a/app/boards/shields/reviung53/reviung53.zmk.yml b/app/boards/shields/reviung53/reviung53.zmk.yml new file mode 100644 index 000000000000..e670755c7747 --- /dev/null +++ b/app/boards/shields/reviung53/reviung53.zmk.yml @@ -0,0 +1,9 @@ +file_format: "1" +id: reviung53 +name: REVIUNG53 +type: shield +url: https://github.com/gtips/reviung/tree/master/reviung53 +requires: [pro_micro] +features: + - keys + - underglow diff --git a/app/boards/shields/romac/Kconfig.defconfig b/app/boards/shields/romac/Kconfig.defconfig new file mode 100644 index 000000000000..5cd94faa7770 --- /dev/null +++ b/app/boards/shields/romac/Kconfig.defconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2020 Pete Johanson, Richard Jones +# SPDX-License-Identifier: MIT + +if SHIELD_ROMAC + +config ZMK_KEYBOARD_NAME + default "RoMac" + +endif + diff --git a/app/boards/shields/romac/Kconfig.shield b/app/boards/shields/romac/Kconfig.shield new file mode 100644 index 000000000000..9bdd2c5f520a --- /dev/null +++ b/app/boards/shields/romac/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2020 Pete Johanson, Richard Jones +# SPDX-License-Identifier: MIT + +config SHIELD_ROMAC + def_bool $(shields_list_contains,romac) diff --git a/app/boards/shields/romac/romac.conf b/app/boards/shields/romac/romac.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/romac/romac.keymap b/app/boards/shields/romac/romac.keymap new file mode 100644 index 000000000000..e48368a817c3 --- /dev/null +++ b/app/boards/shields/romac/romac.keymap @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ------------------- +// | 7 | 8 | 9 | +// | 4 | 5 | 6 | +// | 1 | 2 | 3 | +// | MO(1) | 0 | . | +// ---------------------- + bindings = < + &kp N7 &kp N8 &kp N9 + &kp N4 &kp N5 &kp N6 + &kp N1 &kp N2 &kp N3 + &mo 1 &kp N0 &kp DOT + >; + }; + + nav_layer { +// ----------------------- +// | BTNXT | HOME | PGUP | +// | BTPRV | END | PGDN | +// | BTCLR | _ | _ | +// | _ | _ | RET | +// ----------------------- + bindings = < + &bt BT_NXT &kp HOME &kp PG_UP + &bt BT_PRV &kp END &kp PG_DN + &bt BT_CLR &trans &trans + &trans &trans &kp RET + >; + }; + }; +}; + diff --git a/app/boards/shields/romac/romac.overlay b/app/boards/shields/romac/romac.overlay new file mode 100644 index 000000000000..3d99e51bfe96 --- /dev/null +++ b/app/boards/shields/romac/romac.overlay @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 Pete Johanson, Richard Jones + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + col-gpios + = <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + ; + + }; +}; + diff --git a/app/boards/shields/romac/romac.zmk.yml b/app/boards/shields/romac/romac.zmk.yml new file mode 100644 index 000000000000..b2f95d878770 --- /dev/null +++ b/app/boards/shields/romac/romac.zmk.yml @@ -0,0 +1,8 @@ +file_format: "1" +id: romac +name: Romac Macropad +type: shield +url: https://mechboards.co.uk/shop/kits/romac-macro-pad/ +requires: [pro_micro] +features: + - keys diff --git a/app/boards/shields/romac_plus/Kconfig.defconfig b/app/boards/shields/romac_plus/Kconfig.defconfig new file mode 100644 index 000000000000..442bc0bdf529 --- /dev/null +++ b/app/boards/shields/romac_plus/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_ROMAC_PLUS + +config ZMK_KEYBOARD_NAME + default "RoMac+ v4" + +endif \ No newline at end of file diff --git a/app/boards/shields/romac_plus/Kconfig.shield b/app/boards/shields/romac_plus/Kconfig.shield new file mode 100644 index 000000000000..277f1eb38859 --- /dev/null +++ b/app/boards/shields/romac_plus/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_ROMAC_PLUS + def_bool $(shields_list_contains,romac_plus) diff --git a/app/boards/shields/romac_plus/boards/nice_nano.overlay b/app/boards/shields/romac_plus/boards/nice_nano.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/romac_plus/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/romac_plus/boards/nice_nano_v2.overlay b/app/boards/shields/romac_plus/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/romac_plus/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/romac_plus/romac_plus.conf b/app/boards/shields/romac_plus/romac_plus.conf new file mode 100644 index 000000000000..d784dc48ba00 --- /dev/null +++ b/app/boards/shields/romac_plus/romac_plus.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Uncomment to enable encoder +#CONFIG_EC11=y +#CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y \ No newline at end of file diff --git a/app/boards/shields/romac_plus/romac_plus.dtsi b/app/boards/shields/romac_plus/romac_plus.dtsi new file mode 100644 index 000000000000..12fd4387c902 --- /dev/null +++ b/app/boards/shields/romac_plus/romac_plus.dtsi @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <3>; + rows = <4>; + + map = < +RC(0,0) RC(0,1) RC(0,2) +RC(1,0) RC(1,1) RC(1,2) +RC(2,0) RC(2,1) RC(2,2) +RC(3,0) RC(3,1) RC(3,2) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; + + left_encoder: encoder_left { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + sensors: sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder>; + triggers-per-rotation = <20>; + }; + + // TODO: per-key RGB node(s)? +}; \ No newline at end of file diff --git a/app/boards/shields/romac_plus/romac_plus.keymap b/app/boards/shields/romac_plus/romac_plus.keymap new file mode 100644 index 000000000000..039f6eb61952 --- /dev/null +++ b/app/boards/shields/romac_plus/romac_plus.keymap @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// -------------------------- +// | 7 | 8 | 9 | +// | 4 | 5 | 6 | +// | 1 | 2 | 3 | +// | M_PLAY | 0 | MO(1) | +// -------------------------- + bindings = < + &kp N7 &kp N8 &kp N9 + &kp N4 &kp N5 &kp N6 + &kp N1 &kp N2 &kp N3 + &kp C_PP &kp N0 &mo 1 + >; + + sensor-bindings = <&inc_dec_kp C_NEXT C_PREV>; + }; + + nav_layer { +// -------------------------- +// | BT_CLR | HOME | PGUP | +// | _ | END | PGDN | +// | _ | _ | _ | +// | _ | _ | _ | +// -------------------------- + bindings = < + &bt BT_CLR &kp HOME &kp PG_UP + &trans &kp END &kp PG_DN + &trans &trans &trans + &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp A B>; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/romac_plus/romac_plus.overlay b/app/boards/shields/romac_plus/romac_plus.overlay new file mode 100644 index 000000000000..229b4a2cfe88 --- /dev/null +++ b/app/boards/shields/romac_plus/romac_plus.overlay @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "romac_plus.dtsi" + +/ { + chosen { + zmk,kscan = &kscan0; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + + col-gpios + = <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 21 GPIO_ACTIVE_HIGH> + ; + }; + +}; + +&left_encoder { + status = "okay"; +}; \ No newline at end of file diff --git a/app/boards/shields/romac_plus/romac_plus.zmk.yml b/app/boards/shields/romac_plus/romac_plus.zmk.yml new file mode 100644 index 000000000000..b9984e5de9cd --- /dev/null +++ b/app/boards/shields/romac_plus/romac_plus.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: romac_plus +name: Romac+ Macropad +type: shield +url: https://example.org +requires: [pro_micro] +features: + - keys + - encoder + - display diff --git a/app/boards/shields/settings_reset/Kconfig.defconfig b/app/boards/shields/settings_reset/Kconfig.defconfig new file mode 100644 index 000000000000..05f3b406bd0e --- /dev/null +++ b/app/boards/shields/settings_reset/Kconfig.defconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_SETTINGS_RESET + +config ZMK_KEYBOARD_NAME + default "SETTINGS RESET" + +endif + diff --git a/app/boards/shields/settings_reset/Kconfig.shield b/app/boards/shields/settings_reset/Kconfig.shield new file mode 100644 index 000000000000..b1e6ed0e4647 --- /dev/null +++ b/app/boards/shields/settings_reset/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_SETTINGS_RESET + def_bool $(shields_list_contains,settings_reset) diff --git a/app/boards/shields/settings_reset/settings_reset.conf b/app/boards/shields/settings_reset/settings_reset.conf new file mode 100644 index 000000000000..8052a6cf2583 --- /dev/null +++ b/app/boards/shields/settings_reset/settings_reset.conf @@ -0,0 +1 @@ +CONFIG_ZMK_BLE_CLEAR_BONDS_ON_START=y diff --git a/app/boards/shields/settings_reset/settings_reset.keymap b/app/boards/shields/settings_reset/settings_reset.keymap new file mode 100644 index 000000000000..1206ef1e3639 --- /dev/null +++ b/app/boards/shields/settings_reset/settings_reset.keymap @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = <&sys_reset>; + }; + }; +}; + + diff --git a/app/boards/shields/settings_reset/settings_reset.overlay b/app/boards/shields/settings_reset/settings_reset.overlay new file mode 100644 index 000000000000..8e12956222aa --- /dev/null +++ b/app/boards/shields/settings_reset/settings_reset.overlay @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &settings_reset_kscan; + }; + + settings_reset_kscan: settings_reset_kscan { + compatible = "zmk,kscan-mock"; + columns = <1>; + rows = <0>; + + events = <>; + }; + +}; + diff --git a/app/boards/shields/snap/Kconfig.defconfig b/app/boards/shields/snap/Kconfig.defconfig new file mode 100644 index 000000000000..e21111e969a7 --- /dev/null +++ b/app/boards/shields/snap/Kconfig.defconfig @@ -0,0 +1,49 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_SNAP_LEFT + +config ZMK_KEYBOARD_NAME + default "SNAP" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_SNAP_LEFT || SHIELD_SNAP_RIGHT + +config ZMK_SPLIT + default y + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif diff --git a/app/boards/shields/snap/Kconfig.shield b/app/boards/shields/snap/Kconfig.shield new file mode 100644 index 000000000000..edbd1b57cd7d --- /dev/null +++ b/app/boards/shields/snap/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_SNAP_LEFT + def_bool $(shields_list_contains,snap_left) + +config SHIELD_SNAP_RIGHT + def_bool $(shields_list_contains,snap_right) diff --git a/app/boards/shields/snap/boards/nice_nano.overlay b/app/boards/shields/snap/boards/nice_nano.overlay new file mode 100644 index 000000000000..924151c719fa --- /dev/null +++ b/app/boards/shields/snap/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/snap/boards/nice_nano_v2.overlay b/app/boards/shields/snap/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..924151c719fa --- /dev/null +++ b/app/boards/shields/snap/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/snap/snap.conf b/app/boards/shields/snap/snap.conf new file mode 100644 index 000000000000..e76bccb48156 --- /dev/null +++ b/app/boards/shields/snap/snap.conf @@ -0,0 +1,17 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Uncomment these two lines to add support for encoders to your firmware +# and enable the encoders +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# Uncomment the following line to enable the OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment the following lines to enable the RGB underglow +# CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER=n +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y +# CONFIG_ZMK_RGB_UNDERGLOW_HUE_STEP=5 +# CONFIG_ZMK_RGB_UNDERGLOW_SPD_START=1 \ No newline at end of file diff --git a/app/boards/shields/snap/snap.dtsi b/app/boards/shields/snap/snap.dtsi new file mode 100644 index 000000000000..ef466723b9eb --- /dev/null +++ b/app/boards/shields/snap/snap.dtsi @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zephyr,display = &oled; + zmk,kscan = &kscan_composite; + zmk,matrix_transform = &default_transform; + }; + + left_encoder: encoder_left { + compatible = "alps,ec11"; + steps = <80>; + status = "disabled"; + }; + + right_encoder: encoder_right { + compatible = "alps,ec11"; + steps = <80>; + status = "disabled"; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <17>; + rows = <6>; + +// | R0C06L | R0C05L | R0C04L | R0C03L | R0C02L | R0C01L | R0C00L | | R0C15R | R0C14R | R0C13R | R0C12R | R0C11R | R0C10R | R0C09R | R0C08R | +// R1C07L | R1C06L | R1C05L | R1C04L | R1C03L | R1C02L | R1C01L | R1C00L | | R1C15R | R1C14R | R1C13R | R1C12R | R1C11R | R1C10R | R1C09R | R1C08R | R2C0XR | +// R2C07L | R2C06L | R2C05L | R2C04L | R2C03L | R2C02L | R2C00L | | R2C15R | R2C14R | R2C13R | R2C12R | R2C11R | R2C10R | R2C09R | R3C08R | R2C08R | +// R3C07L | R3C06L | R3C05L | R3C04L | R3C03L | R3C02L | R3C00L | | R3C15R | R3C14R | R3C13R | R3C12R | R3C11R | R3C10R | R3C09R | R4C08R | +// R4C07L | R4C06L | R4C05L | R4C04L | R4C03L | R4C02L | R4C01L | R4C00L | | R4C15R | R4C14R | R4C13R | R4C12R | R4C11R | R4C10R | R4C09R | R5C08R | +// R5C07L | R5C06L | R5C05L | R5C04L | R5C02L | R5C00L | | R5C15R | R5C14R | R5C13R | R5C12R | R5C11R | R5C10R | R5C09R | + + map = < + RC(0,6) RC(0,5) RC(0,4) RC(0,3) RC(0,2) RC(0,1) RC(0,0) RC(0,15) RC(0,14) RC(0,13) RC(0,12) RC(0,11) RC(0,10) RC(0,9) RC(0,8) +RC(1,7) RC(1,6) RC(1,5) RC(1,4) RC(1,3) RC(1,2) RC(1,1) RC(1,0) RC(1,15) RC(1,14) RC(1,13) RC(1,12) RC(1,11) RC(1,10) RC(1,9) RC(1,8) RC(1,16) +RC(2,7) RC(2,6) RC(2,5) RC(2,4) RC(2,3) RC(2,2) RC(2,0) RC(2,15) RC(2,14) RC(2,13) RC(2,12) RC(2,11) RC(2,10) RC(2,9) RC(3,8) RC(2,8) +RC(3,7) RC(3,6) RC(3,5) RC(3,4) RC(3,3) RC(3,2) RC(3,0) RC(3,15) RC(3,14) RC(3,13) RC(3,12) RC(3,11) RC(3,10) RC(3,9) RC(4,8) +RC(4,7) RC(4,6) RC(4,5) RC(4,4) RC(4,3) RC(4,2) RC(4,1) RC(4,0) RC(4,15) RC(4,14) RC(4,13) RC(4,12) RC(4,11) RC(4,10) RC(4,9) RC(5,8) +RC(5,7) RC(5,6) RC(5,5) RC(5,4) RC(5,2) RC(5,0) RC(5,15) RC(5,14) RC(5,13) RC(5,12) RC(5,11) RC(5,10) RC(5,9) + >; + }; + + kscan_composite: kscan { + compatible = "zmk,kscan-composite"; + rows = <6>; + columns = <17>; + + demux { + kscan = <&kscan_demux>; + }; + }; + + kscan_demux: kscan_demux { + compatible = "zmk,kscan-gpio-demux"; + polling-interval-msec = <25>; + }; +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/snap/snap.keymap b/app/boards/shields/snap/snap.keymap new file mode 100644 index 000000000000..8a95beda1538 --- /dev/null +++ b/app/boards/shields/snap/snap.keymap @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +/ { + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + triggers-per-rotation = <20>; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + display-name = "Default"; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp C_VOL_UP C_VOL_DN>; + bindings = < + &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp KP_NUM &kp PAUSE_BREAK +&kp C_MUTE &kp TILDE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp DEL &kp HOME +&kp F13 &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp END +&kp F14 &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET &kp PG_UP +&kp F15 &kp LSHFT &kp NUHS &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp PG_DN +&kp F16 &kp LCTRL &kp LGUI &kp LALT &mo 1 &kp SPACE &kp BSPC &mo 1 &kp RALT &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT + >; + }; + + function_layer { + display-name = "Function"; + sensor-bindings = <&inc_dec_kp C_NEXT C_PREV &inc_dec_kp C_NEXT C_PREV>; + bindings = < + &bootloader &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &bootloader +&kp C_PP &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp C_PP +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &rgb_ug RGB_TOG &rgb_ug RGB_BRI &rgb_ug RGB_EFF +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &rgb_ug RGB_HUD &rgb_ug RGB_BRD &rgb_ug RGB_HUI + >; + }; + }; +}; diff --git a/app/boards/shields/snap/snap.zmk.yml b/app/boards/shields/snap/snap.zmk.yml new file mode 100644 index 000000000000..718c7ba2ce59 --- /dev/null +++ b/app/boards/shields/snap/snap.zmk.yml @@ -0,0 +1,15 @@ +file_format: "1" +id: snap +name: SNAP +type: shield +url: https://nullbits.co/snap +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder + - underglow +siblings: + - snap_left + - snap_right diff --git a/app/boards/shields/snap/snap_left.overlay b/app/boards/shields/snap/snap_left.overlay new file mode 100644 index 000000000000..abbe945045ab --- /dev/null +++ b/app/boards/shields/snap/snap_left.overlay @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "snap.dtsi" + +&kscan_demux { + input-gpios + = <&pro_micro 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 21 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; + output-gpios + = <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + ; +}; + +&left_encoder { + a-gpios = <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + status = "okay"; +}; + +&oled { + segment-remap; + com-invdir; +}; diff --git a/app/boards/shields/snap/snap_right.overlay b/app/boards/shields/snap/snap_right.overlay new file mode 100644 index 000000000000..b303316a9063 --- /dev/null +++ b/app/boards/shields/snap/snap_right.overlay @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "snap.dtsi" + +/ { +kscan_direct: kscan_direct { + compatible = "zmk,kscan-gpio-direct"; + input-gpios + = <&pro_micro 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; + }; +}; + +&default_transform { + col-offset = <8>; +}; + +&kscan_composite { + direct { + kscan = <&kscan_direct>; + row-offset = <1>; + column-offset = <8>; + }; +}; + +&kscan_demux { + input-gpios + = <&pro_micro 21 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 20 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 19 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 18 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; + output-gpios + = <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 4 GPIO_ACTIVE_HIGH> + ; +}; + +&right_encoder { + a-gpios = <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + status = "okay"; +}; diff --git a/app/boards/shields/sofle/Kconfig.defconfig b/app/boards/shields/sofle/Kconfig.defconfig new file mode 100644 index 000000000000..4e7bf88488ee --- /dev/null +++ b/app/boards/shields/sofle/Kconfig.defconfig @@ -0,0 +1,55 @@ +# Copyright (c) 2020 Ryan Cross +# SPDX-License-Identifier: MIT + +if SHIELD_SOFLE_LEFT + +config ZMK_KEYBOARD_NAME + default "Sofle" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_SOFLE_LEFT || SHIELD_SOFLE_RIGHT + +config ZMK_SPLIT + default y + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +if ZMK_RGB_UNDERGLOW + +config WS2812_STRIP + default y +endif + +endif diff --git a/app/boards/shields/sofle/Kconfig.shield b/app/boards/shields/sofle/Kconfig.shield new file mode 100644 index 000000000000..a865e8396259 --- /dev/null +++ b/app/boards/shields/sofle/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2020 Ryan Cross +# SPDX-License-Identifier: MIT + +config SHIELD_SOFLE_LEFT + def_bool $(shields_list_contains,sofle_left) + +config SHIELD_SOFLE_RIGHT + def_bool $(shields_list_contains,sofle_right) diff --git a/app/boards/shields/sofle/boards/nice_nano.overlay b/app/boards/shields/sofle/boards/nice_nano.overlay new file mode 100644 index 000000000000..f00f59f43979 --- /dev/null +++ b/app/boards/shields/sofle/boards/nice_nano.overlay @@ -0,0 +1,50 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <36>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = < + LED_COLOR_ID_GREEN + LED_COLOR_ID_RED + LED_COLOR_ID_BLUE + >; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/sofle/boards/nice_nano_v2.overlay b/app/boards/shields/sofle/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..f00f59f43979 --- /dev/null +++ b/app/boards/shields/sofle/boards/nice_nano_v2.overlay @@ -0,0 +1,50 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <36>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = < + LED_COLOR_ID_GREEN + LED_COLOR_ID_RED + LED_COLOR_ID_BLUE + >; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/sofle/boards/nrfmicro_11.overlay b/app/boards/shields/sofle/boards/nrfmicro_11.overlay new file mode 100644 index 000000000000..f00f59f43979 --- /dev/null +++ b/app/boards/shields/sofle/boards/nrfmicro_11.overlay @@ -0,0 +1,50 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <36>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = < + LED_COLOR_ID_GREEN + LED_COLOR_ID_RED + LED_COLOR_ID_BLUE + >; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/sofle/boards/nrfmicro_13.overlay b/app/boards/shields/sofle/boards/nrfmicro_13.overlay new file mode 100644 index 000000000000..f00f59f43979 --- /dev/null +++ b/app/boards/shields/sofle/boards/nrfmicro_13.overlay @@ -0,0 +1,50 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <36>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = < + LED_COLOR_ID_GREEN + LED_COLOR_ID_RED + LED_COLOR_ID_BLUE + >; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/sofle/sofle.conf b/app/boards/shields/sofle/sofle.conf new file mode 100644 index 000000000000..1f74aa339fc0 --- /dev/null +++ b/app/boards/shields/sofle/sofle.conf @@ -0,0 +1,17 @@ +# Copyright (c) 2020 Ryan Cross +# SPDX-License-Identifier: MIT + +# Uncomment the following line to enable the Sofle OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment these two lines to add support for encoders +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# Uncomment this line below to add rgb underglow / backlight support +# CONFIG_ZMK_RGB_UNDERGLOW=y + +# Uncomment the line below to disable external power toggling by the underglow. +# By default toggling the underglow on and off also toggles external power +# on and off. This also causes the display to turn off. +# CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER=n diff --git a/app/boards/shields/sofle/sofle.dtsi b/app/boards/shields/sofle/sofle.dtsi new file mode 100644 index 000000000000..c9bf5c8eb374 --- /dev/null +++ b/app/boards/shields/sofle/sofle.dtsi @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2020 Pete Johanson, Ryan Cross + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zephyr,display = &oled; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <16>; + rows = <4>; +// | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | +// | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | +// | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | +// | SW24 | SW23 | SW22 | SW21 | SW20 | SW19 | SW25 | | SW25 | SW19 | SW20 | SW21 | SW22 | SW23 | SW24 | +// | SW30 | SW29 | SW28 | SW27 | SW26 | | SW26 | SW27 | SW28 | SW29 | SW30 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; + + left_encoder: encoder_left { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + right_encoder: encoder_right { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + sensors: sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + triggers-per-rotation = <20>; + }; +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/sofle/sofle.keymap b/app/boards/shields/sofle/sofle.keymap new file mode 100644 index 000000000000..ed9f0f4f42c7 --- /dev/null +++ b/app/boards/shields/sofle/sofle.keymap @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +#define BASE 0 +#define LOWER 1 +#define RAISE 2 +#define ADJUST 3 + +/ { + + // Activate ADJUST layer by pressing raise and lower + conditional_layers { + compatible = "zmk,conditional-layers"; + adjust_layer { + if-layers = ; + then-layer = ; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + display-name = "default"; +// ------------------------------------------------------------------------------------------------------------ +// | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | | +// | ESC | Q | W | E | R | T | | Y | U | I | O | P | BKSPC | +// | TAB | A | S | D | F | G | | H | J | K | L | ; | ' | +// | SHIFT | Z | X | C | V | B | MUTE | | | N | M | , | . | / | SHIFT | +// | GUI | ALT | CTRL | LOWER| ENTER | | SPACE | RAISE| CTRL | ALT | GUI | + bindings = < +&kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &none +&kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSPC +&kp TAB &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT +&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp C_MUTE &none &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LGUI &kp LALT &kp LCTRL &mo LOWER &kp RET &kp SPACE &mo RAISE &kp RCTRL &kp RALT &kp RGUI + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + + lower_layer { + display-name = "lower"; +// TODO: Some binds are waiting for shifted keycode support. +// ------------------------------------------------------------------------------------------------------------ +// | | F1 | F2 | F3 | F4 | F5 | | F6 | F7 | F8 | F9 | F10 | F11 | +// | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | F12 | +// | | ! | @ | # | $ | % | | ^ | & | * | ( | ) | | | +// | | = | - | + | { | } | | | | [ | ] | ; | : | \ | | +// | | | | | | | | | | | | + bindings = < +&trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 +&kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp F12 +&trans &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp KP_MULTIPLY &kp LPAR &kp RPAR &kp PIPE +&trans &kp EQUAL &kp MINUS &kp KP_PLUS &kp LBRC &kp RBRC &trans &trans &kp LBKT &kp RBKT &kp SEMI &kp COLON &kp BSLH &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + + raise_layer { + display-name = "raise"; +// ------------------------------------------------------------------------------------------------------------ +// | BTCLR | BT1 | BT2 | BT3 | BT4 | BT5 | | | | | | | | +// | | INS | PSCR | GUI | | | | PGUP | | ^ | | | | +// | | ALT | CTRL | SHIFT | | CAPS | | PGDN | <- | v | -> | DEL | BKSPC | +// | | UNDO | CUT | COPY | PASTE | | | | | | | | | | | +// | | | | | | | | | | | | + bindings = < +&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans +&trans &kp INS &kp PSCRN &kp K_CMENU &trans &trans &kp PG_UP &trans &kp UP &trans &kp N0 &trans +&trans &kp LALT &kp LCTRL &kp LSHFT &trans &kp CLCK &kp PG_DN &kp LEFT &kp DOWN &kp RIGHT &kp DEL &kp BSPC +&trans &kp K_UNDO &kp K_CUT &kp K_COPY &kp K_PASTE &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + + adjust_layer { +// ---------------------------------------------------------------------------------------------------------------------------- +// | BTCLR | BT1 | BT2 | BT3 | BT4 | BT5 | | | | | | | | +// | EXTPWR | RGB_HUD | RGB_HUI | RGB_SAD | RGB_SAI | RGB_EFF | | | | | | | | +// | | RGB_BRD | RGB_BRI | | | | | | | | | | | +// | | | | | | | RGB_TOG | | | | | | | | | +// | | | | | | | | | | | | + display-name = "adjust"; + bindings = < +&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &none &none &none &none &none &none +&ext_power EP_TOG &rgb_ug RGB_HUD &rgb_ug RGB_HUI &rgb_ug RGB_SAD &rgb_ug RGB_SAI &rgb_ug RGB_EFF &none &none &none &none &none &none +&none &rgb_ug RGB_BRD &rgb_ug RGB_BRI &none &none &none &none &none &none &none &none &none +&none &none &none &none &none &none &rgb_ug RGB_TOG &none &none &none &none &none &none &none + &none &none &none &none &none &none &none &none &none &none + >; + }; + + }; +}; diff --git a/app/boards/shields/sofle/sofle.zmk.yml b/app/boards/shields/sofle/sofle.zmk.yml new file mode 100644 index 000000000000..47b66d6777ce --- /dev/null +++ b/app/boards/shields/sofle/sofle.zmk.yml @@ -0,0 +1,15 @@ +file_format: "1" +id: sofle +name: Sofle +type: shield +url: https://github.com/josefadamcik/SofleKeyboard +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder + - underglow +siblings: + - sofle_left + - sofle_right diff --git a/app/boards/shields/sofle/sofle_left.conf b/app/boards/shields/sofle/sofle_left.conf new file mode 100644 index 000000000000..e81372014f30 --- /dev/null +++ b/app/boards/shields/sofle/sofle_left.conf @@ -0,0 +1,2 @@ +# Copyright (c) 2020 Ryan Cross +# SPDX-License-Identifier: MIT diff --git a/app/boards/shields/sofle/sofle_left.overlay b/app/boards/shields/sofle/sofle_left.overlay new file mode 100644 index 000000000000..057e60503610 --- /dev/null +++ b/app/boards/shields/sofle/sofle_left.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2020 Ryan Cross + * + * SPDX-License-Identifier: MIT + */ + +#include "sofle.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + ; +}; + +&left_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/sofle/sofle_right.conf b/app/boards/shields/sofle/sofle_right.conf new file mode 100644 index 000000000000..e81372014f30 --- /dev/null +++ b/app/boards/shields/sofle/sofle_right.conf @@ -0,0 +1,2 @@ +# Copyright (c) 2020 Ryan Cross +# SPDX-License-Identifier: MIT diff --git a/app/boards/shields/sofle/sofle_right.overlay b/app/boards/shields/sofle/sofle_right.overlay new file mode 100644 index 000000000000..65e5f3307304 --- /dev/null +++ b/app/boards/shields/sofle/sofle_right.overlay @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020 Ryan Cross + * + * SPDX-License-Identifier: MIT + */ + +#include "sofle.dtsi" + +&default_transform { + col-offset = <6>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + ; +}; + +&right_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/splitkb_aurora_corne/Kconfig.defconfig b/app/boards/shields/splitkb_aurora_corne/Kconfig.defconfig new file mode 100644 index 000000000000..a28792c7bb1b --- /dev/null +++ b/app/boards/shields/splitkb_aurora_corne/Kconfig.defconfig @@ -0,0 +1,55 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_SPLITKB_AURORA_CORNE_LEFT + +config ZMK_KEYBOARD_NAME + default "Aurora Corne" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif # SHIELD_SPLITKB_AURORA_CORNE_LEFT + +if SHIELD_SPLITKB_AURORA_CORNE_LEFT || SHIELD_SPLITKB_AURORA_CORNE_RIGHT + +config ZMK_SPLIT + default y + +config ZMK_RGB_UNDERGLOW + select WS2812_STRIP + select SPI + +config ZMK_DISPLAY + +if ZMK_DISPLAY + +config SSD1306 + default y + +config I2C + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif # SHIELD_SPLITKB_AURORA_CORNE_LEFT || SHIELD_SPLITKB_AURORA_CORNE_RIGHT diff --git a/app/boards/shields/splitkb_aurora_corne/Kconfig.shield b/app/boards/shields/splitkb_aurora_corne/Kconfig.shield new file mode 100644 index 000000000000..1efcdf002125 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_corne/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_SPLITKB_AURORA_CORNE_LEFT + def_bool $(shields_list_contains,splitkb_aurora_corne_left) + +config SHIELD_SPLITKB_AURORA_CORNE_RIGHT + def_bool $(shields_list_contains,splitkb_aurora_corne_right) diff --git a/app/boards/shields/splitkb_aurora_corne/boards/nice_nano.overlay b/app/boards/shields/splitkb_aurora_corne/boards/nice_nano.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_corne/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_corne/boards/nice_nano_v2.overlay b/app/boards/shields/splitkb_aurora_corne/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_corne/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.conf b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.conf new file mode 100644 index 000000000000..bb2b843ddfd4 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.conf @@ -0,0 +1,9 @@ +# Uncomment these two line to add support for encoders to your firmware +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# Uncomment the following line to enable the Kyria OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment the following lines to enable RGB underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y diff --git a/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.dtsi b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.dtsi new file mode 100644 index 000000000000..7911f151814d --- /dev/null +++ b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.dtsi @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + + chosen { + zephyr,display = &oled; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <12>; + rows = <4>; +// | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | +// | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | +// | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | +// | SW19 | SW20 | SW21 | | SW21 | SW20 | SW19 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) + RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) + >; + }; + + five_column_transform: keymap_transform_1 { + compatible = "zmk,matrix-transform"; + columns = <10>; + rows = <4>; +// | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | +// | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | +// | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | +// | SW19 | SW20 | SW21 | | SW21 | SW20 | SW19 | + map = < +RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) +RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) +RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) + RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) + >; + }; + + left_encoder: left_encoder { + compatible = "alps,ec11"; + steps = <80>; + status = "disabled"; + + a-gpios = <&pro_micro 4 GPIO_PULL_UP>; + b-gpios = <&pro_micro 5 GPIO_PULL_UP>; + }; + + right_encoder: right_encoder { + compatible = "alps,ec11"; + steps = <80>; + status = "disabled"; + + a-gpios = <&pro_micro 19 GPIO_PULL_UP>; + b-gpios = <&pro_micro 18 GPIO_PULL_UP>; + }; + + sensors: sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + triggers-per-rotation = <20>; + }; +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.keymap b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.keymap new file mode 100644 index 000000000000..0555cf41757c --- /dev/null +++ b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.keymap @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ----------------------------------------------------------------------------------------- +// | TAB | Q | W | E | R | T | | Y | U | I | O | P | BKSP | +// | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | +// | SHFT | Z | X | C | V | B | | N | M | , | . | / | ESC | +// | GUI | LWR | SPC | | ENT | RSE | ALT | + bindings = < + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSPC + &kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp ESC + &kp LGUI &mo 1 &kp SPACE &kp RET &mo 2 &kp RALT + >; + }; + lower_layer { +// ----------------------------------------------------------------------------------------- +// | TAB | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | BKSP | +// | BTCLR| BT1 | BT2 | BT3 | BT4 | BT5 | | LFT | DWN | UP | RGT | | | +// | SHFT | | | | | | | | | | | | | +// | GUI | | SPC | | ENT | | ALT | + bindings = < + &kp TAB &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp BSPC + &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &kp LEFT &kp DOWN &kp UP &kp RIGHT &trans &trans + &kp LSHFT &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &kp LGUI &trans &kp SPACE &kp RET &trans &kp RALT + >; + }; + + raise_layer { +// ----------------------------------------------------------------------------------------- +// | TAB | ! | @ | # | $ | % | | ^ | & | * | ( | ) | BKSP | +// | CTRL | | | | | | | - | = | [ | ] | \ | ` | +// | SHFT | | | | | | | _ | + | { | } | "|" | ~ | +// | GUI | | SPC | | ENT | | ALT | + bindings = < + &kp TAB &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp KP_MULTIPLY &kp LPAR &kp RPAR &kp BSPC + &kp LCTRL &trans &trans &trans &trans &trans &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH &kp GRAVE + &kp LSHFT &trans &trans &trans &trans &trans &kp UNDER &kp PLUS &kp LBRC &kp RBRC &kp PIPE &kp TILDE + &kp LGUI &trans &kp SPACE &kp RET &trans &kp RALT + >; + }; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.zmk.yml b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.zmk.yml new file mode 100644 index 000000000000..cc14182696d1 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.zmk.yml @@ -0,0 +1,12 @@ +file_format: "1" +id: splitkb_aurora_corne +name: splitkb.com Aurora Corne +type: shield +url: https://splitkb.com/products/aurora-corne-pcb-kit +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys +siblings: + - splitkb_aurora_corne_left + - splitkb_aurora_corne_right diff --git a/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne_left.overlay b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne_left.overlay new file mode 100644 index 000000000000..df930cd25473 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne_left.overlay @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "splitkb_aurora_corne.dtsi" + +/ { + chosen { + zmk,kscan = &kscan; + }; + + kscan: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 6 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 7 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 8 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 9 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + ; + + col-gpios + = <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + ; + }; +}; + +&left_encoder { + status = "okay"; +}; + + diff --git a/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne_right.overlay b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne_right.overlay new file mode 100644 index 000000000000..3823cdfb76ea --- /dev/null +++ b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne_right.overlay @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "splitkb_aurora_corne.dtsi" + +/ { + chosen { + zmk,kscan = &kscan; + }; + + kscan: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 15 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 14 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 16 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 10 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + ; + + col-gpios + = <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 4 GPIO_ACTIVE_HIGH> + ; + }; +}; + +&right_encoder { + status = "okay"; +}; + +&default_transform { + col-offset = <6>; +}; + +&five_column_transform { + col-offset = <6>; +}; diff --git a/app/boards/shields/splitkb_aurora_helix/Kconfig.defconfig b/app/boards/shields/splitkb_aurora_helix/Kconfig.defconfig new file mode 100644 index 000000000000..6d7a55691e2a --- /dev/null +++ b/app/boards/shields/splitkb_aurora_helix/Kconfig.defconfig @@ -0,0 +1,53 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_SPLITKB_AURORA_HELIX_LEFT + +config ZMK_KEYBOARD_NAME + default "Aurora Helix" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif # SHIELD_SPLITKB_AURORA_HELIX_LEFT + +if SHIELD_SPLITKB_AURORA_HELIX_LEFT || SHIELD_SPLITKB_AURORA_HELIX_RIGHT + +config ZMK_SPLIT + default y + +config ZMK_RGB_UNDERGLOW + select WS2812_STRIP + select SPI + +if ZMK_DISPLAY + +config SSD1306 + default y + +config I2C + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_DPI_DEF + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif # SHIELD_SPLITKB_AURORA_HELIX_LEFT || SHIELD_SPLITKB_AURORA_HELIX_RIGHT diff --git a/app/boards/shields/splitkb_aurora_helix/Kconfig.shield b/app/boards/shields/splitkb_aurora_helix/Kconfig.shield new file mode 100644 index 000000000000..c64ef8798e18 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_helix/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_SPLITKB_AURORA_HELIX_LEFT + def_bool $(shields_list_contains,splitkb_aurora_helix_left) + +config SHIELD_SPLITKB_AURORA_HELIX_RIGHT + def_bool $(shields_list_contains,splitkb_aurora_helix_right) diff --git a/app/boards/shields/splitkb_aurora_helix/boards/nice_nano.overlay b/app/boards/shields/splitkb_aurora_helix/boards/nice_nano.overlay new file mode 100644 index 000000000000..8228d530c823 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_helix/boards/nice_nano.overlay @@ -0,0 +1,45 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <6>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_helix/boards/nice_nano_v2.overlay b/app/boards/shields/splitkb_aurora_helix/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..8228d530c823 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_helix/boards/nice_nano_v2.overlay @@ -0,0 +1,45 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <6>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.conf b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.conf new file mode 100644 index 000000000000..af482abcc4ba --- /dev/null +++ b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.conf @@ -0,0 +1,9 @@ +# Uncomment these two line to add support for encoders to your firmware +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# Uncomment the following line to enable the OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment the following line to enable RGB underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y diff --git a/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.dtsi b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.dtsi new file mode 100644 index 000000000000..29b6dddea368 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.dtsi @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + + chosen { + zephyr,display = &oled; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <14>; + rows = <5>; + // | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | + // | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | + // | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | + // | SW19 | SW20 | SW21 | SW22 | SW23 | SW24 | SW25 | | SW25 | SW24 | SW23 | SW22 | SW21 | SW20 | SW19 | + // | SW26 | SW27 | SW28 | SW29 | SW30 | SW31 | SW32 | | SW32 | SW31 | SW30 | SW29 | SW28 | SW27 | SW26 | + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) RC(3,13) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,13) + >; + }; + + left_encoder: left_encoder { + compatible = "alps,ec11"; + steps = <144>; + status = "disabled"; + + a-gpios = <&pro_micro 7 GPIO_PULL_UP>; + b-gpios = <&pro_micro 8 GPIO_PULL_UP>; + }; + + right_encoder: right_encoder { + compatible = "alps,ec11"; + steps = <144>; + status = "disabled"; + + a-gpios = <&pro_micro 16 GPIO_PULL_UP>; + b-gpios = <&pro_micro 14 GPIO_PULL_UP>; + }; + + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + triggers-per-rotation = <36>; + }; +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.keymap b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.keymap new file mode 100644 index 000000000000..edec8fec3068 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.keymap @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include +#include + +#define DEFAULT 0 +#define LOWER 1 +#define RAISE 2 +#define ADJUST 3 + +/* Uncomment this block if using RGB +&led_strip { + chain-length = <6>; + // chain-length = <38>; // Uncomment if using both per-key and underglow LEDs + // chain-length = <32>; // Uncomment if using only per-key LEDs. +}; + */ + +/* NOTE: At the time of the creation of this keymap, there are no specified codes for 'eisuu' and 'kana' input in ZMK. +However, 'LANG1' and 'LANG2' are fully-functioning candidates for 'kana' and 'eisuu' input respectively. +As such, those are in use within the default layer at this time.*/ + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + // --------------------------------------------------------------------------------------------------------------------------------- + // | GRAVE | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | DEL | + // | TAB | Q | W | E | R | T | | Y | U | I | O | P | BSPC | + // | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | + // | SHIFT | Z | X | C | V | B | LBKT | | RBKT | N | M | , | . | / | RET | + // | ADJUST | ESC | ALT | LGUI | EISUU | LOWER | SPACE | | SPACE | RAISE | KANA | LEFT | DOWN | UP | RIGHT | + bindings = < + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp DEL + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSPC + &kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LBKT &kp RBKT &kp N &kp M &kp COMMA &kp PERIOD &kp SLASH &kp RET + &mo ADJUST &kp ESC &kp LALT &kp LGUI &kp LANG2 &mo LOWER &kp SPACE &kp SPACE &mo RAISE &kp LANG1 &kp LEFT &kp DOWN &kp UP &kp RIGHT + >; + }; + lower_layer { + // --------------------------------------------------------------------------------------------------------------------------------- + // | | | | | | | | | | | | | | + // | ~ | ! | @ | # | $ | % | | ^ | & | * | ( | ) | | + // | | | | | | | | | _ | + | { | } | PIPE | + // | | | | | | | ( | | ) | | | | HOME | END | | + // | | | | | | | | | | | | | | | | + bindings = < + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &kp TILDE &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp ASTRK &kp LPAR &kp RPAR &trans + &trans &trans &trans &trans &trans &trans &trans &kp UNDER &kp PLUS &kp LBRC &kp RBRC &kp PIPE + &trans &trans &trans &trans &trans &trans &kp LPAR &kp RPAR &trans &trans &trans &kp HOME &kp END &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + }; + raise_layer { + // --------------------------------------------------------------------------------------------------------------------------------- + // | | | | | | | | | | | | | | + // | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | DEL | + // | | F1 | F2 | F3 | F4 | F5 | | F6 | - | = | [ | ] | \ | + // | | F7 | F8 | F9 | F10 | F11 | | | | F12 | | PSCRN | PG_DN | PG_UP | | + // | | | | | | | | | | | | NEXT | VOL- | VOL+ | PLAY | + bindings = < + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp DEL + &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH + &trans &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &trans &trans &kp F12 &trans &kp PSCRN &kp PG_DN &kp PG_UP &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp C_NEXT &kp C_VOL_DN &kp C_VOL_UP &kp C_PP + >; + }; + adjust_layer { + // --------------------------------------------------------------------------------------------------------------------------------- + // | ` | ! | @ | # | $ | % | | ^ | & | * | ( | ) | EP TOG | + // | BT CLR | BT SEL0 | BT SEL1 | BT SEL2 | BGT SEL3 | BT SEL4 | | RGB EFF+ | RGB HUE+ | RGB SAT+ | RGB SPD+ | RGB BRI+ | RGB TOG | + // | BT NXT | OUT TOG | OUT USB | OUT BLE | | | | RGB EFF- | RGB HUE- | RGB SAT- | RGB SPD- | RGB BRI- | | + // | BT PRV | | | | | | { | | } | | | | | | | + // | | | | | | | | | | | | | | | | + bindings = < + &kp GRAVE &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp ASTRK &kp LPAR &kp RPAR &ext_power EP_TOG + &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &rgb_ug RGB_EFF &rgb_ug RGB_HUI &rgb_ug RGB_SAI &rgb_ug RGB_SPI &rgb_ug RGB_BRI &rgb_ug RGB_TOG + &bt BT_NXT &out OUT_TOG &out OUT_USB &out OUT_BLE &trans &trans &rgb_ug RGB_EFR &rgb_ug RGB_HUD &rgb_ug RGB_SAD &rgb_ug RGB_SPD &rgb_ug RGB_BRD &trans + &bt BT_PRV &trans &trans &trans &trans &trans &kp LBRC &kp RBRC &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + }; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.zmk.yml b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.zmk.yml new file mode 100644 index 000000000000..d83c74ecca85 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.zmk.yml @@ -0,0 +1,15 @@ +file_format: "1" +id: splitkb_aurora_helix +name: splitkb.com Aurora Helix +type: shield +url: https://splitkb.com/products/aurora-helix-pcb-kit +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder + - underglow +siblings: + - splitkb_aurora_helix_left + - splitkb_aurora_helix_right diff --git a/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix_left.overlay b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix_left.overlay new file mode 100644 index 000000000000..59d825530efc --- /dev/null +++ b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix_left.overlay @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "splitkb_aurora_helix.dtsi" + +/ { + chosen { + zmk,kscan = &kscan; + }; + + kscan: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 21 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 20 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 4 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 5 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 6 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + ; + + col-gpios + = <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + ; + }; +}; + +&left_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix_right.overlay b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix_right.overlay new file mode 100644 index 000000000000..95cea9ecc3ce --- /dev/null +++ b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix_right.overlay @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "splitkb_aurora_helix.dtsi" + +/ { + chosen { + zmk,kscan = &kscan; + }; + + kscan: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 21 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 20 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 19 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 18 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 15 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + ; + + col-gpios + = <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 4 GPIO_ACTIVE_HIGH> + ; + }; +}; + +&right_encoder { + status = "okay"; +}; + +&default_transform { + col-offset = <7>; +}; diff --git a/app/boards/shields/splitkb_aurora_lily58/Kconfig.defconfig b/app/boards/shields/splitkb_aurora_lily58/Kconfig.defconfig new file mode 100644 index 000000000000..e54e2b4332ff --- /dev/null +++ b/app/boards/shields/splitkb_aurora_lily58/Kconfig.defconfig @@ -0,0 +1,55 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_SPLITKB_AURORA_LILY58_LEFT + +config ZMK_KEYBOARD_NAME + default "Aurora Lily58" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif # SHIELD_SPLITKB_AURORA_LILY58_LEFT + +if SHIELD_SPLITKB_AURORA_LILY58_LEFT || SHIELD_SPLITKB_AURORA_LILY58_RIGHT + +config ZMK_SPLIT + default y + +config ZMK_RGB_UNDERGLOW + select WS2812_STRIP + select SPI + +config ZMK_DISPLAY + +if ZMK_DISPLAY + +config SSD1306 + default y + +config I2C + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif # SHIELD_SPLITKB_AURORA_LILY58_LEFT || SHIELD_SPLITKB_AURORA_LILY58_RIGHT diff --git a/app/boards/shields/splitkb_aurora_lily58/Kconfig.shield b/app/boards/shields/splitkb_aurora_lily58/Kconfig.shield new file mode 100644 index 000000000000..a64f47dca155 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_lily58/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_SPLITKB_AURORA_LILY58_LEFT + def_bool $(shields_list_contains,splitkb_aurora_lily58_left) + +config SHIELD_SPLITKB_AURORA_LILY58_RIGHT + def_bool $(shields_list_contains,splitkb_aurora_lily58_right) diff --git a/app/boards/shields/splitkb_aurora_lily58/boards/nice_nano.overlay b/app/boards/shields/splitkb_aurora_lily58/boards/nice_nano.overlay new file mode 100644 index 000000000000..fa6ac6dc34b1 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_lily58/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <5>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_lily58/boards/nice_nano_v2.overlay b/app/boards/shields/splitkb_aurora_lily58/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..0845226602bd --- /dev/null +++ b/app/boards/shields/splitkb_aurora_lily58/boards/nice_nano_v2.overlay @@ -0,0 +1,45 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <5>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58.conf b/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58.conf new file mode 100644 index 000000000000..d456100ab747 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58.conf @@ -0,0 +1,9 @@ +# Uncomment these two line to add support for encoders to your firmware +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# Uncomment the following line to enable the OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment the following lines to enable RGB underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y diff --git a/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58.dtsi b/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58.dtsi new file mode 100644 index 000000000000..fb993dbb6330 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58.dtsi @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + + chosen { + zephyr,display = &oled; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <14>; + rows = <5>; +// | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | +// | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | +// | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | +// | SW24 | SW23 | SW22 | SW21 | SW20 | SW19 | SW25 | | SW25 | SW19 | SW20 | SW21 | SW22 | SW23 | SW24 | +// | SW29 | SW28 | SW27 | SW26 | | SW26 | SW27 | SW28 | SW29 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,1) RC(4,10) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) + RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) + >; + }; + + left_encoder: left_encoder { + compatible = "alps,ec11"; + steps = <80>; + status = "disabled"; + + a-gpios = <&pro_micro 5 GPIO_PULL_UP>; + b-gpios = <&pro_micro 4 GPIO_PULL_UP>; + }; + + right_encoder: right_encoder { + compatible = "alps,ec11"; + steps = <80>; + status = "disabled"; + + a-gpios = <&pro_micro 18 GPIO_PULL_UP>; + b-gpios = <&pro_micro 19 GPIO_PULL_UP>; + }; + + sensors: sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + triggers-per-rotation = <20>; + }; +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58.keymap b/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58.keymap new file mode 100644 index 000000000000..b8a9103b1d65 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58.keymap @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ------------------------------------------------------------------------------------------------------------ +// | ESC | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | ` | +// | TAB | Q | W | E | R | T | | Y | U | I | O | P | - | +// | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | +// | SHIFT | Z | X | C | V | B | "[" | | "]" | N | M | , | . | / | SHIFT | +// | ALT | GUI | LOWER| SPACE | | ENTER | RAISE| BSPC | GUI | + bindings = < +&kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp GRAVE +&kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp MINUS +&kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT +&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LBKT &kp RBKT &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LALT &kp LGUI &mo 1 &kp SPACE &kp RET &mo 2 &kp BSPC &kp RGUI + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + lower_layer { +// ------------------------------------------------------------------------------------------------------------ +// | BTCLR | BT1 | BT2 | BT3 | BT4 | BT5 | | | | | | | | +// | F1 | F2 | F3 | F4 | F5 | F6 | | F7 | F8 | F9 | F10 | F11 | F12 | +// | ` | ! | @ | # | $ | % | | ^ | & | * | ( | ) | ~ | +// | | | | | | | | | | | _ | + | { | } | "|" | +// | | | | | | | | | | + bindings = < +&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans +&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 +&kp GRAVE &kp EXCL &kp AT &kp HASH &kp DOLLAR &kp PRCNT &kp CARET &kp AMPS &kp STAR &kp LPAR &kp RPAR &kp TILDE +&trans &ext_power EP_ON &ext_power EP_OFF &ext_power EP_TOG &trans &trans &trans &trans &trans &kp MINUS &kp PLUS &kp LBRC &kp RBRC &kp PIPE + &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + raise_layer { +// ------------------------------------------------------------------------------------------------------------ +// | | | | | | | | | | | | | | +// | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | | +// | F1 | F2 | F3 | F4 | F5 | F6 | | | <- | v | ^ | -> | | +// | F7 | F8 | F9 | F10 | F11 | F12 | | | | + | - | = | [ | ] | \ | +// | | | | | | | | | | + bindings = < +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &trans +&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &trans &kp LEFT &kp DOWN &kp UP &kp RIGHT &trans +&kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &trans &trans &kp KP_PLUS &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH + &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58.zmk.yml b/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58.zmk.yml new file mode 100644 index 000000000000..47d49a4c9274 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58.zmk.yml @@ -0,0 +1,12 @@ +file_format: "1" +id: splitkb_aurora_lily58 +name: splitkb.com Aurora Lily58 +type: shield +url: https://splitkb.com/products/aurora-lily58-pcb-kit +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys +siblings: + - splitkb_aurora_lily58_left + - splitkb_aurora_lily58_right diff --git a/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58_left.overlay b/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58_left.overlay new file mode 100644 index 000000000000..fc38bbcbc765 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58_left.overlay @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "splitkb_aurora_lily58.dtsi" + +/ { + chosen { + zmk,kscan = &kscan; + }; + + kscan: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "row2col"; + + row-gpios + = <&pro_micro 21 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + ; + + col-gpios + = <&pro_micro 9 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 18 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 15 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 14 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 16 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 10 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + ; + }; +}; + +&left_encoder { + status = "okay"; +}; + + diff --git a/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58_right.overlay b/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58_right.overlay new file mode 100644 index 000000000000..c9a96491ee98 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58_right.overlay @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "splitkb_aurora_lily58.dtsi" + +/ { + chosen { + zmk,kscan = &kscan; + }; + + kscan: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "row2col"; + + row-gpios + = <&pro_micro 21 GPIO_ACTIVE_HIGH> + , <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + ; + + col-gpios + = <&pro_micro 9 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 8 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 7 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 6 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 5 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 15 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + ; + }; +}; + +&right_encoder { + status = "okay"; +}; + +&default_transform { + col-offset = <6>; +}; diff --git a/app/boards/shields/splitkb_aurora_sofle/Kconfig.defconfig b/app/boards/shields/splitkb_aurora_sofle/Kconfig.defconfig new file mode 100644 index 000000000000..b53c4c8dc16e --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sofle/Kconfig.defconfig @@ -0,0 +1,53 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_SPLITKB_AURORA_SOFLE_LEFT + +config ZMK_KEYBOARD_NAME + default "Aurora Sofle" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif # SHIELD_SPLITKB_AURORA_SOFLE_LEFT + +if SHIELD_SPLITKB_AURORA_SOFLE_LEFT || SHIELD_SPLITKB_AURORA_SOFLE_RIGHT + +config ZMK_SPLIT + default y + +config ZMK_RGB_UNDERGLOW + select WS2812_STRIP + select SPI + +if ZMK_DISPLAY + +config SSD1306 + default y + +config I2C + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_DPI_DEF + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif # SHIELD_SPLITKB_AURORA_SOFLE_LEFT || SHIELD_SPLITKB_AURORA_SOFLE_RIGHT diff --git a/app/boards/shields/splitkb_aurora_sofle/Kconfig.shield b/app/boards/shields/splitkb_aurora_sofle/Kconfig.shield new file mode 100644 index 000000000000..c72e95d9d0f6 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sofle/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_SPLITKB_AURORA_SOFLE_LEFT + def_bool $(shields_list_contains,splitkb_aurora_sofle_left) + +config SHIELD_SPLITKB_AURORA_SOFLE_RIGHT + def_bool $(shields_list_contains,splitkb_aurora_sofle_right) diff --git a/app/boards/shields/splitkb_aurora_sofle/boards/nice_nano.overlay b/app/boards/shields/splitkb_aurora_sofle/boards/nice_nano.overlay new file mode 100644 index 000000000000..8228d530c823 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sofle/boards/nice_nano.overlay @@ -0,0 +1,45 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <6>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_sofle/boards/nice_nano_v2.overlay b/app/boards/shields/splitkb_aurora_sofle/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..8228d530c823 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sofle/boards/nice_nano_v2.overlay @@ -0,0 +1,45 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <6>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.conf b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.conf new file mode 100644 index 000000000000..d456100ab747 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.conf @@ -0,0 +1,9 @@ +# Uncomment these two line to add support for encoders to your firmware +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# Uncomment the following line to enable the OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment the following lines to enable RGB underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y diff --git a/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.dtsi b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.dtsi new file mode 100644 index 000000000000..c064456a2351 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.dtsi @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + + chosen { + zephyr,display = &oled; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <14>; + rows = <5>; +// | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | +// | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | +// | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | +// | SW24 | SW23 | SW22 | SW21 | SW20 | SW19 | SW25 | | SW25 | SW19 | SW20 | SW21 | SW22 | SW23 | SW24 | +// | SW30 | SW29 | SW28 | SW27 | SW26 | | SW26 | SW27 | SW28 | SW29 | SW30 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) + >; + }; + + left_encoder: left_encoder { + compatible = "alps,ec11"; + steps = <144>; + status = "disabled"; + + a-gpios = <&pro_micro 16 GPIO_PULL_UP>; + b-gpios = <&pro_micro 10 GPIO_PULL_UP>; + }; + + right_encoder: right_encoder { + compatible = "alps,ec11"; + steps = <144>; + status = "disabled"; + + a-gpios = <&pro_micro 16 GPIO_PULL_UP>; + b-gpios = <&pro_micro 10 GPIO_PULL_UP>; + }; + + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + triggers-per-rotation = <36>; + }; +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.keymap b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.keymap new file mode 100644 index 000000000000..231274167623 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.keymap @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +/* Uncomment this block if using RGB +&led_strip { + chain-length = <6>; + // chain-length = <35>; // Uncomment if using both per-key and underglow LEDs + // chain-length = <29>; // Uncomment if using only per-key LEDs. +}; + */ + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ------------------------------------------------------------------------------------------------------------ +// | ESC | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | ` | +// | TAB | Q | W | E | R | T | | Y | U | I | O | P | - | +// | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | +// | SHIFT | Z | X | C | V | B | "[" | | "]" | N | M | , | . | / | SHIFT | +// |CTRL | ALT | GUI | LOWER| SPACE | | ENTER | RAISE| BSPC | GUI | RALT | + bindings = < +&kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp GRAVE +&kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp MINUS +&kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT +&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LBKT &kp RBKT &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LCTRL &kp LALT &kp LGUI &mo 1 &kp SPACE &kp RET &mo 2 &kp BSPC &kp RGUI &kp RALT + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + lower_layer { +// ------------------------------------------------------------------------------------------------------------ +// | BTCLR | BT1 | BT2 | BT3 | BT4 | BT5 | | | | | | | | +// | F1 | F2 | F3 | F4 | F5 | F6 | | F7 | F8 | F9 | F10 | F11 | F12 | +// | ` | ! | @ | # | $ | % | | ^ | & | * | ( | ) | ~ | +// | | | | | | | | | | | _ | + | { | } | "|" | +// | | | | | | | | | | | | + bindings = < +&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans +&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 +&kp GRAVE &kp EXCL &kp AT &kp HASH &kp DOLLAR &kp PRCNT &kp CARET &kp AMPS &kp STAR &kp LPAR &kp RPAR &kp TILDE +&trans &ext_power EP_ON &ext_power EP_OFF &ext_power EP_TOG &trans &trans &trans &trans &trans &kp MINUS &kp PLUS &kp LBRC &kp RBRC &kp PIPE + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + raise_layer { +// ------------------------------------------------------------------------------------------------------------ +// | | | | | | | | | | | | | | +// | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | | +// | F1 | F2 | F3 | F4 | F5 | F6 | | | <- | v | ^ | -> | | +// | F7 | F8 | F9 | F10 | F11 | F12 | | | | + | - | = | [ | ] | \ | +// | | | | | | | | | | | | + bindings = < +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &trans +&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &trans &kp LEFT &kp DOWN &kp UP &kp RIGHT &trans +&kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &trans &trans &kp KP_PLUS &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.zmk.yml b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.zmk.yml new file mode 100644 index 000000000000..d832d3e1053a --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.zmk.yml @@ -0,0 +1,15 @@ +file_format: "1" +id: splitkb_aurora_sofle +name: splitkb.com Aurora Sofle +type: shield +url: https://splitkb.com/products/aurora-sofle-pcb-kit +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder + - underglow +siblings: + - splitkb_aurora_sofle_left + - splitkb_aurora_sofle_right diff --git a/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle_left.overlay b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle_left.overlay new file mode 100644 index 000000000000..024c9e75b29b --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle_left.overlay @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "splitkb_aurora_sofle.dtsi" + +/ { + chosen { + zmk,kscan = &kscan; + }; + + kscan: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 20 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 15 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 18 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 19 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 14 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + ; + + col-gpios + = <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 4 GPIO_ACTIVE_HIGH> + ; + }; +}; + +&left_encoder { + status = "okay"; +}; + + diff --git a/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle_right.overlay b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle_right.overlay new file mode 100644 index 000000000000..58df0026f068 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle_right.overlay @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "splitkb_aurora_sofle.dtsi" + +/ { + chosen { + zmk,kscan = &kscan; + }; + + kscan: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 14 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 15 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 18 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 19 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 20 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + ; + + col-gpios + = <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + ; + }; +}; + +&right_encoder { + status = "okay"; +}; + +&default_transform { + col-offset = <6>; +}; diff --git a/app/boards/shields/splitkb_aurora_sweep/Kconfig.defconfig b/app/boards/shields/splitkb_aurora_sweep/Kconfig.defconfig new file mode 100644 index 000000000000..83cb1bf687c8 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sweep/Kconfig.defconfig @@ -0,0 +1,55 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_SPLITKB_AURORA_SWEEP_LEFT + +config ZMK_KEYBOARD_NAME + default "Aurora Sweep" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif # SHIELD_SPLITKB_AURORA_SWEEP_LEFT + +if SHIELD_SPLITKB_AURORA_SWEEP_LEFT || SHIELD_SPLITKB_AURORA_SWEEP_RIGHT + +config ZMK_SPLIT + default y + +config ZMK_RGB_UNDERGLOW + select WS2812_STRIP + select SPI + +config ZMK_DISPLAY + +if ZMK_DISPLAY + +config SSD1306 + default y + +config I2C + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif # SHIELD_SPLITKB_AURORA_SWEEP_LEFT || SHIELD_SPLITKB_AURORA_SWEEP_RIGHT diff --git a/app/boards/shields/splitkb_aurora_sweep/Kconfig.shield b/app/boards/shields/splitkb_aurora_sweep/Kconfig.shield new file mode 100644 index 000000000000..7d92134ccd9b --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sweep/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_SPLITKB_AURORA_SWEEP_LEFT + def_bool $(shields_list_contains,splitkb_aurora_sweep_left) + +config SHIELD_SPLITKB_AURORA_SWEEP_RIGHT + def_bool $(shields_list_contains,splitkb_aurora_sweep_right) diff --git a/app/boards/shields/splitkb_aurora_sweep/boards/nice_nano.overlay b/app/boards/shields/splitkb_aurora_sweep/boards/nice_nano.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sweep/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_sweep/boards/nice_nano_v2.overlay b/app/boards/shields/splitkb_aurora_sweep/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..424a617b2371 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sweep/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.conf b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.conf new file mode 100644 index 000000000000..bb2b843ddfd4 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.conf @@ -0,0 +1,9 @@ +# Uncomment these two line to add support for encoders to your firmware +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# Uncomment the following line to enable the Kyria OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment the following lines to enable RGB underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y diff --git a/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.dtsi b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.dtsi new file mode 100644 index 000000000000..404782c74c4f --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.dtsi @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + + chosen { + zephyr,display = &oled; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <10>; + rows = <4>; + map = < + RC(0,4) RC(0,3) RC(0,2) RC(0,1) RC(0,0) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) + RC(1,4) RC(1,3) RC(1,2) RC(1,1) RC(1,0) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) + RC(2,4) RC(2,3) RC(2,2) RC(2,1) RC(2,0) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) + RC(3,1) RC(3,0) RC(3,5) RC(3,6) + >; + }; + + left_encoder1: left_encoder1 { + compatible = "alps,ec11"; + steps = <80>; + status = "disabled"; + }; + + left_encoder2: left_encoder2 { + compatible = "alps,ec11"; + steps = <80>; + status = "disabled"; + }; + + right_encoder1: right_encoder1 { + compatible = "alps,ec11"; + steps = <80>; + status = "disabled"; + }; + + right_encoder2: right_encoder2 { + compatible = "alps,ec11"; + steps = <80>; + status = "disabled"; + }; + + sensors: sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder1 &right_encoder1>; + triggers-per-rotation = <20>; + }; +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.keymap b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.keymap new file mode 100644 index 000000000000..4b57beac6440 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.keymap @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + + +&mt { + // flavor = "tap-preferred"; + // tapping_term_ms = <200>; +}; + +/ { + + combos { + compatible = "zmk,combos"; + combo_esc { + timeout-ms = <50>; + key-positions = <0 1>; + bindings = <&kp ESC>; + }; + + combo_tab { + timeout-ms = <50>; + key-positions = <10 11>; + bindings = <&kp TAB>; + }; + + combo_ralt { + timeout-ms = <50>; + key-positions = <17 16>; + bindings = <&kp RALT>; + }; + + combo_lalt { + timeout-ms = <50>; + key-positions = <11 12>; + bindings = <&kp LALT>; + }; + + combo_lgui { + timeout-ms = <50>; + key-positions = <12 13>; + bindings = <&kp LGUI>; + }; + + + combo_rgui { + timeout-ms = <50>; + key-positions = <17 18>; + bindings = <&kp RGUI>; + }; + + + + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P + &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp QUOT + &mt LSFT Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT &mt LSFT RET + &mo 1 &kp LCTL &kp SPC &mo 2 + >; + }; + + left_layer { + bindings = < + &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 &kp NUM_5 &kp NUM_6 &kp NUM_7 &kp NUM_8 &kp NUM_9 &kp NUM_0 + &kp TAB &kp LC(S) &kp DQT &kp PIPE2 &kp HASH &kp MINUS &kp EQL &kp LBKT &kp RBKT &kp DEL + &kp ESC &kp TILDE &kp NON_US_BSLH &kp NON_US_HASH &kp TILDE2 &kp MINUS &kp GRAVE &kp LBKT &kp RBKT &kp DEL + &mo 1 &kp LGUI &kp RGUI &mo 2 + >; + }; + + right_layer { + bindings = < + &kp BANG &kp ATSN &kp HASH &kp DLLR &kp PRCT &kp CRRT &kp AMPS &kp KMLT &kp LPRN &kp RPRN + &kp HASH &kp QMARK &kp FSLH &kp COLN &kp SCLN &kp MINUS &kp KP_EQUAL &kp LBRC &kp RBRC &kp BKSP + &kp LSFT &kp KPLS &kp LBKT &kp RBKT &kp BSLH &kp UNDER &kp LEFT &kp DOWN &kp UP &kp RIGHT + &mo 3 &kp LCTL &kp SPC &mo 2 + >; + }; + + tri_layer { + bindings = < + &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 &kp NUM_5 &trans &trans &trans &trans &trans + &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &trans &kp PG_UP &kp K_VOL_UP &kp K_MUTE &trans + &bt BT_CLR &bt BT_NXT &bt BT_PRV &kp F6 &kp F7 &trans &kp PG_DN &kp K_VOL_DN &trans &trans + &trans &trans &trans &trans + >; + }; + + }; +}; diff --git a/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.zmk.yml b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.zmk.yml new file mode 100644 index 000000000000..97d3c53b55da --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.zmk.yml @@ -0,0 +1,12 @@ +file_format: "1" +id: splitkb_aurora_sweep +name: splitkb.com Aurora Sweep +type: shield +url: https://splitkb.com/products/aurora-sweep-pcb-kit +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys +siblings: + - splitkb_aurora_sweep_left + - splitkb_aurora_sweep_right diff --git a/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep_left.overlay b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep_left.overlay new file mode 100644 index 000000000000..4a1bec902afb --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep_left.overlay @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "splitkb_aurora_sweep.dtsi" + +/ { + chosen { + zmk,kscan = &kscan; + }; + + kscan: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "row2col"; + + row-gpios + = <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + ; + + col-gpios + = <&pro_micro 10 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 4 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 5 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 6 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 7 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + ; + }; +}; + +&left_encoder1 { + status = "okay"; + a-gpios = <&pro_micro 9 GPIO_PULL_UP>; + b-gpios = <&pro_micro 8 GPIO_PULL_UP>; +}; + +&left_encoder2 { + status = "okay"; + a-gpios = <&pro_micro 14 GPIO_PULL_UP>; + b-gpios = <&pro_micro 16 GPIO_PULL_UP>; +}; + diff --git a/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep_right.overlay b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep_right.overlay new file mode 100644 index 000000000000..c36554776170 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep_right.overlay @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "splitkb_aurora_sweep.dtsi" + +/ { + chosen { + zmk,kscan = &kscan; + }; + + kscan: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "row2col"; + + row-gpios + = <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + ; + + col-gpios + = <&pro_micro 9 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 8 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 7 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 6 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 5 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + ; + }; +}; + +&right_encoder1 { + status = "okay"; + a-gpios = <&pro_micro 16 GPIO_PULL_UP>; + b-gpios = <&pro_micro 10 GPIO_PULL_UP>; +}; + +&right_encoder2 { + status = "okay"; + a-gpios = <&pro_micro 20 GPIO_PULL_UP>; + b-gpios = <&pro_micro 4 GPIO_PULL_UP>; +}; + +&default_transform { + col-offset = <5>; +}; diff --git a/app/boards/shields/splitreus62/Kconfig.defconfig b/app/boards/shields/splitreus62/Kconfig.defconfig new file mode 100644 index 000000000000..52d62c9d8e98 --- /dev/null +++ b/app/boards/shields/splitreus62/Kconfig.defconfig @@ -0,0 +1,21 @@ + +# Copyright (c) 2020 Derek Schmell +# SPDX-License-Identifier: MIT + + +if SHIELD_SPLITREUS62_LEFT + +config ZMK_KEYBOARD_NAME + default "Splitreus62" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_SPLITREUS62_LEFT || SHIELD_SPLITREUS62_RIGHT + +config ZMK_SPLIT + default y + +endif diff --git a/app/boards/shields/splitreus62/Kconfig.shield b/app/boards/shields/splitreus62/Kconfig.shield new file mode 100644 index 000000000000..951ab9fb9a14 --- /dev/null +++ b/app/boards/shields/splitreus62/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2020 Derek Schmell +# SPDX-License-Identifier: MIT + +config SHIELD_SPLITREUS62_LEFT + def_bool $(shields_list_contains,splitreus62_left) + +config SHIELD_SPLITREUS62_RIGHT + def_bool $(shields_list_contains,splitreus62_right) diff --git a/app/boards/shields/splitreus62/splitreus62.conf b/app/boards/shields/splitreus62/splitreus62.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/splitreus62/splitreus62.dtsi b/app/boards/shields/splitreus62/splitreus62.dtsi new file mode 100644 index 000000000000..4a1a58a5ba20 --- /dev/null +++ b/app/boards/shields/splitreus62/splitreus62.dtsi @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 Derek Schmell + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <12>; + rows = <6>; +// | SW0 | SW5 | SW10 | SW15 | SW20 | SW25 | SW25 | SW20 | SW15 | SW10 | SW5 | SW1 | +// | SW1 | SW6 | SW11 | SW16 | SW21 | SW26 | SW26 | SW21 | SW16 | SW11 | SW6 | SW2 | +// | SW2 | SW7 | SW12 | SW17 | SW22 | SW27 | SW27 | SW22 | SW17 | SW12 | SW7 | SW3 | +// | SW3 | SW8 | SW13 | SW18 | SW23 | SW28 | SW28 | SW23 | SW18 | SW13 | SW8 | SW4 | +// | SW4 | SW9 | SW14 | SW19 | SW24 | SW29 | SW29 | SW24 | SW19 | SW14 | SW9 | SW5 | +// SW30 | SW30 + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) +RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) + RC(5,5) RC(5,6) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "row2col"; + row-gpios + = <&pro_micro 1 GPIO_ACTIVE_HIGH > + , <&pro_micro 0 GPIO_ACTIVE_HIGH> + , <&pro_micro 2 GPIO_ACTIVE_HIGH> + , <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + ; + + }; +}; diff --git a/app/boards/shields/splitreus62/splitreus62.keymap b/app/boards/shields/splitreus62/splitreus62.keymap new file mode 100644 index 000000000000..c7bdb4439aa1 --- /dev/null +++ b/app/boards/shields/splitreus62/splitreus62.keymap @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ------------------------------------------------------------------------------------------------------------ +// | ESC | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | - | +// | TAB | Q | W | E | R | T | | Y | U | I | O | P | \ | +// | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | +// | SHIFT | Z | X | C | V | B | | N | M | , | . | / | SHIFT | +// | LCTL | LGUI | LALT | GRAV | | EQL | DEL | BKSP| | RET | SPC | LBKT | RBKT | LBKT | HOME | END | + bindings = < +&kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS +&kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSLH +&kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT +&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT +&kp LCTRL &kp LGUI &kp LALT &kp GRAVE &kp EQUAL &kp DEL &kp SPACE &kp LBKT &kp RBKT &kp MINUS &kp HOME &kp END + &kp BSPC &kp RET + >; + }; + }; +}; diff --git a/app/boards/shields/splitreus62/splitreus62.zmk.yml b/app/boards/shields/splitreus62/splitreus62.zmk.yml new file mode 100644 index 000000000000..b1ee991cb53c --- /dev/null +++ b/app/boards/shields/splitreus62/splitreus62.zmk.yml @@ -0,0 +1,11 @@ +file_format: "1" +id: splitreus62 +name: Splitreus62 +type: shield +url: https://github.com/Na-Cly/splitreus62 +requires: [pro_micro] +features: + - keys +siblings: + - splitreus62_left + - splitreus62_right diff --git a/app/boards/shields/splitreus62/splitreus62_left.conf b/app/boards/shields/splitreus62/splitreus62_left.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/splitreus62/splitreus62_left.overlay b/app/boards/shields/splitreus62/splitreus62_left.overlay new file mode 100644 index 000000000000..992eb0db9bb4 --- /dev/null +++ b/app/boards/shields/splitreus62/splitreus62_left.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2020 Derek Schmell + * + * SPDX-License-Identifier: MIT + */ + +#include "splitreus62.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; +}; diff --git a/app/boards/shields/splitreus62/splitreus62_right.conf b/app/boards/shields/splitreus62/splitreus62_right.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/splitreus62/splitreus62_right.overlay b/app/boards/shields/splitreus62/splitreus62_right.overlay new file mode 100644 index 000000000000..d83db26d6d9f --- /dev/null +++ b/app/boards/shields/splitreus62/splitreus62_right.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2020 Derek Schmell + * + * SPDX-License-Identifier: MIT + */ + +#include "splitreus62.dtsi" + +&default_transform { + col-offset = <6>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; +}; diff --git a/app/boards/shields/tg4x/Kconfig.defconfig b/app/boards/shields/tg4x/Kconfig.defconfig new file mode 100644 index 000000000000..6312c080a2c0 --- /dev/null +++ b/app/boards/shields/tg4x/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_TG4X + +config ZMK_KEYBOARD_NAME + default "TG4x" + +endif diff --git a/app/boards/shields/tg4x/Kconfig.shield b/app/boards/shields/tg4x/Kconfig.shield new file mode 100644 index 000000000000..d7fc1c13c6a2 --- /dev/null +++ b/app/boards/shields/tg4x/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_TG4X + def_bool $(shields_list_contains,tg4x) diff --git a/app/boards/shields/tg4x/README.md b/app/boards/shields/tg4x/README.md new file mode 100644 index 000000000000..12709fde0b30 --- /dev/null +++ b/app/boards/shields/tg4x/README.md @@ -0,0 +1,11 @@ +# TG4x + +Standard setup for the [TG4x](https://github.com/MythosMann/tg4x/) 40% keyboard. + +## Board Revision and Layout Notes + +This TG4x implementation is for... + +- rev 2.1 of the board +- Split spacebar with 2.25U on the left and 2.75U on the right +- 2U right shift diff --git a/app/boards/shields/tg4x/boards/nice_nano.conf b/app/boards/shields/tg4x/boards/nice_nano.conf new file mode 100644 index 000000000000..7b0779480eca --- /dev/null +++ b/app/boards/shields/tg4x/boards/nice_nano.conf @@ -0,0 +1,7 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Enable underglow +CONFIG_ZMK_RGB_UNDERGLOW=y +# Use the STRIP config specific to the LEDs you're using +CONFIG_WS2812_STRIP=y \ No newline at end of file diff --git a/app/boards/shields/tg4x/boards/nice_nano.overlay b/app/boards/shields/tg4x/boards/nice_nano.overlay new file mode 100644 index 000000000000..84441899991f --- /dev/null +++ b/app/boards/shields/tg4x/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/tg4x/boards/nice_nano_v2.overlay b/app/boards/shields/tg4x/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..84441899991f --- /dev/null +++ b/app/boards/shields/tg4x/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/tg4x/tg4x.conf b/app/boards/shields/tg4x/tg4x.conf new file mode 100644 index 000000000000..9d65bb600f52 --- /dev/null +++ b/app/boards/shields/tg4x/tg4x.conf @@ -0,0 +1,2 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT \ No newline at end of file diff --git a/app/boards/shields/tg4x/tg4x.keymap b/app/boards/shields/tg4x/tg4x.keymap new file mode 100644 index 000000000000..5c71ae5c91c4 --- /dev/null +++ b/app/boards/shields/tg4x/tg4x.keymap @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + behaviors { + ht: hold_tap { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + tapping-term-ms = <200>; + flavor = "tap-preferred"; + bindings = <&kp>, <&kp>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < +&kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp SEMI &kp BSPC +&ht CAPS TAB &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp APOS &kp RET +&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp RSHFT +&kp LCTRL &kp LGUI &kp LALT < 1 SPACE &kp SPACE &kp RALT &kp RGUI &mo 2 &kp RCTRL + >; + }; + + function_layer { + bindings = < +&kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp DEL +&none &kp HOME &kp PG_UP &trans &trans &trans &kp LBKT &kp RBKT &kp EQUAL &kp BSLH &kp FSLH &trans +&trans &kp END &kp PG_DN &trans &trans &trans &trans &trans &trans &kp UP &trans +&trans &trans &trans &trans &trans &trans &kp LEFT &kp DOWN &kp RIGHT + >; + }; + + other_layer { + bindings = < +&kp PRINTSCREEN &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&trans &bt BT_CLR &bt BT_PRV &bt BT_NXT &trans &trans &trans &trans &bootloader &sys_reset &trans +&trans &trans &trans &trans &trans &kp C_VOL_UP &kp C_VOL_DN &kp C_PP + >; + }; + + }; +}; diff --git a/app/boards/shields/tg4x/tg4x.overlay b/app/boards/shields/tg4x/tg4x.overlay new file mode 100644 index 000000000000..e53275c644b6 --- /dev/null +++ b/app/boards/shields/tg4x/tg4x.overlay @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + col-gpios + = <&pro_micro 1 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 21 GPIO_ACTIVE_HIGH> + ; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + rows = <8>; + columns = <7>; + + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(5,0) RC(5,1) RC(5,2) RC(5,3) RC(5,4) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(6,0) RC(6,1) RC(6,2) RC(6,4) +RC(3,0) RC(3,1) RC(3,2) RC(3,4) RC(3,5) RC(7,1) RC(7,2) RC(7,3) RC(7,4) + >; + }; + + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; +}; diff --git a/app/boards/shields/tg4x/tg4x.zmk.yml b/app/boards/shields/tg4x/tg4x.zmk.yml new file mode 100644 index 000000000000..ec7c72fb3adc --- /dev/null +++ b/app/boards/shields/tg4x/tg4x.zmk.yml @@ -0,0 +1,8 @@ +file_format: "1" +id: tg4x +name: TG4x +type: shield +url: https://github.com/MythosMann/tg4x +requires: [pro_micro] +features: + - keys diff --git a/app/boards/shields/tidbit/Kconfig.defconfig b/app/boards/shields/tidbit/Kconfig.defconfig new file mode 100644 index 000000000000..393fbef1bf29 --- /dev/null +++ b/app/boards/shields/tidbit/Kconfig.defconfig @@ -0,0 +1,40 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_TIDBIT + +config ZMK_KEYBOARD_NAME + default "tidbit" + + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif diff --git a/app/boards/shields/tidbit/Kconfig.shield b/app/boards/shields/tidbit/Kconfig.shield new file mode 100644 index 000000000000..dc811bb2e960 --- /dev/null +++ b/app/boards/shields/tidbit/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_TIDBIT + def_bool $(shields_list_contains,tidbit) diff --git a/app/boards/shields/tidbit/README.md b/app/boards/shields/tidbit/README.md new file mode 100644 index 000000000000..c68d38b9f174 --- /dev/null +++ b/app/boards/shields/tidbit/README.md @@ -0,0 +1,41 @@ +# Building ZMK for the Tidbit + +Some general notes/commands for building standard tidbit layouts from the assembly documentation. + +## Standard "Non Dense" Build + +``` +west build -p -d build/tidbit/default --board nice_nano -- -DSHIELD=tidbit +``` + +## Dense "19 keys" Build + +``` +west build -p -d build/tidbit/19_key --board nice_nano -- -DSHIELD=tidbit_19key +``` + +## LED Notes + +If you built your tidbit without the LEDs _and_ are using a nice!nano board, you'll need to change the following in your local tidbit config or add them to the end of the file. + +``` +CONFIG_ZMK_RGB_UNDERGLOW=n +CONFIG_WS2812_STRIP=n +``` + +## Encoder Notes + +If you built your tidbit without encoders, you'll need to change the following in your local tidbit config or add them to the end of the file. + +``` +CONFIG_EC11=n +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=n +``` + +## OLED Builds + +If using an OLED screen, you'll need to change the following in your local tidbit config or add them to the end of the file. + +``` +CONFIG_ZMK_DISPLAY=y +``` diff --git a/app/boards/shields/tidbit/boards/nice_nano.conf b/app/boards/shields/tidbit/boards/nice_nano.conf new file mode 100644 index 000000000000..14bed3d0fa35 --- /dev/null +++ b/app/boards/shields/tidbit/boards/nice_nano.conf @@ -0,0 +1,4 @@ +# Enable underglow +CONFIG_ZMK_RGB_UNDERGLOW=y +# Use the STRIP config specific to the LEDs you're using +CONFIG_WS2812_STRIP=y \ No newline at end of file diff --git a/app/boards/shields/tidbit/boards/nice_nano.overlay b/app/boards/shields/tidbit/boards/nice_nano.overlay new file mode 100644 index 000000000000..b08954339337 --- /dev/null +++ b/app/boards/shields/tidbit/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/tidbit/boards/nice_nano_v2.overlay b/app/boards/shields/tidbit/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..b08954339337 --- /dev/null +++ b/app/boards/shields/tidbit/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/tidbit/boards/proton_c.conf b/app/boards/shields/tidbit/boards/proton_c.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/boards/shields/tidbit/tidbit.conf b/app/boards/shields/tidbit/tidbit.conf new file mode 100644 index 000000000000..2909a855b011 --- /dev/null +++ b/app/boards/shields/tidbit/tidbit.conf @@ -0,0 +1,11 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Enable Encoders +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# Enable underglow +#CONFIG_ZMK_RGB_UNDERGLOW=y +# Use the STRIP config specific to the LEDs you're using +#CONFIG_WS2812_STRIP=y diff --git a/app/boards/shields/tidbit/tidbit.dtsi b/app/boards/shields/tidbit/tidbit.dtsi new file mode 100644 index 000000000000..110c3fc8734b --- /dev/null +++ b/app/boards/shields/tidbit/tidbit.dtsi @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "row2col"; + + row-gpios + = <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + col-gpios + = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <4>; + rows = <5>; + + map = < + RC(0,1) RC(0,2) RC(0,3) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) + >; + }; + + encoder_1_top_row: encoder_1_top_row { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + encoder_1: encoder_1 { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + encoder_2: encoder_2 { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + encoder_3: encoder_3 { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + encoder_4: encoder_4 { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + chosen { + zephyr,display = &oled; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/tidbit/tidbit.keymap b/app/boards/shields/tidbit/tidbit.keymap new file mode 100644 index 000000000000..a98a2eaa28ea --- /dev/null +++ b/app/boards/shields/tidbit/tidbit.keymap @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +&encoder_1_top_row { + status = "okay"; +}; + +/ { + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&encoder_1_top_row>; + triggers-per-rotation = <20>; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp KP_NUMLOCK &kp KP_ASTERISK &kp KP_MINUS + &kp KP_NUMBER_7 &kp KP_NUMBER_8 &kp KP_NUMBER_9 &kp KP_PLUS + &kp KP_NUMBER_4 &kp KP_NUMBER_5 &kp KP_NUMBER_6 &none + &kp KP_NUMBER_1 &kp KP_NUMBER_2 &kp KP_NUMBER_3 < 1 KP_ENTER + &none &kp KP_NUMBER_0 &kp KP_DOT &none + >; + + sensor-bindings = <&inc_dec_kp C_VOLUME_UP C_VOLUME_DOWN>; + }; + + func_layer { + bindings = < + &none &sys_reset &bootloader + &out OUT_TOG &out OUT_USB &out OUT_BLE &none + &bt BT_SEL 0 &bt BT_PRV &bt BT_NXT &bt BT_CLR + &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &tog 0 + &kp C_MUTE &none &none &none + >; + + sensor-bindings = <&inc_dec_kp C_VOLUME_UP C_VOLUME_DOWN>; + }; + }; +}; diff --git a/app/boards/shields/tidbit/tidbit.overlay b/app/boards/shields/tidbit/tidbit.overlay new file mode 100644 index 000000000000..dc425618ca5b --- /dev/null +++ b/app/boards/shields/tidbit/tidbit.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "tidbit.dtsi" diff --git a/app/boards/shields/tidbit/tidbit.zmk.yml b/app/boards/shields/tidbit/tidbit.zmk.yml new file mode 100644 index 000000000000..393effb929da --- /dev/null +++ b/app/boards/shields/tidbit/tidbit.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: tidbit +name: Tidbit Numpad +type: shield +url: https://nullbits.co/tidbit/ +requires: [pro_micro] +features: + - keys + - encoder + - display diff --git a/app/boards/shields/tidbit/tidbit_19key.conf b/app/boards/shields/tidbit/tidbit_19key.conf new file mode 100644 index 000000000000..2909a855b011 --- /dev/null +++ b/app/boards/shields/tidbit/tidbit_19key.conf @@ -0,0 +1,11 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Enable Encoders +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# Enable underglow +#CONFIG_ZMK_RGB_UNDERGLOW=y +# Use the STRIP config specific to the LEDs you're using +#CONFIG_WS2812_STRIP=y diff --git a/app/boards/shields/tidbit/tidbit_19key.keymap b/app/boards/shields/tidbit/tidbit_19key.keymap new file mode 100644 index 000000000000..1be71e7a9b72 --- /dev/null +++ b/app/boards/shields/tidbit/tidbit_19key.keymap @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "tidbit.dtsi" +#include +#include +#include +#include + +&encoder_4 { + status = "okay"; +}; + +/ { + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&encoder_4>; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &tog 1 &kp KP_NUMLOCK &kp KP_SLASH + &kp KP_NUMBER_7 &kp KP_NUMBER_8 &kp KP_NUMBER_9 &kp KP_ASTERISK + &kp KP_NUMBER_4 &kp KP_NUMBER_5 &kp KP_NUMBER_6 &kp KP_MINUS + &kp KP_NUMBER_1 &kp KP_NUMBER_2 &kp KP_NUMBER_3 &kp KP_PLUS + &kp C_MUTE &kp KP_NUMBER_0 &kp KP_DOT &kp KP_ENTER + >; + + sensor-bindings = <&inc_dec_kp C_VOLUME_UP C_VOLUME_DOWN>; + }; + + func_layer { + bindings = < + &tog 0 &sys_reset &bootloader + &out OUT_TOG &out OUT_USB &out OUT_BLE &none + &bt BT_SEL 0 &bt BT_PRV &bt BT_NXT &bt BT_CLR + &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &none + &kp C_MUTE &none &none &none + >; + + sensor-bindings = <&inc_dec_kp C_VOLUME_UP C_VOLUME_DOWN>; + }; + }; +}; diff --git a/app/boards/shields/tidbit/tidbit_19key.overlay b/app/boards/shields/tidbit/tidbit_19key.overlay new file mode 100644 index 000000000000..dc46233ed779 --- /dev/null +++ b/app/boards/shields/tidbit/tidbit_19key.overlay @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "tidbit.dtsi" +#include "tidbit_19key.keymap" diff --git a/app/boards/shields/two_percent_milk/Kconfig.defconfig b/app/boards/shields/two_percent_milk/Kconfig.defconfig new file mode 100644 index 000000000000..1046f53c1faa --- /dev/null +++ b/app/boards/shields/two_percent_milk/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_TWO_PERCENT_MILK + +config ZMK_KEYBOARD_NAME + default "2% Milk" + +endif diff --git a/app/boards/shields/two_percent_milk/Kconfig.shield b/app/boards/shields/two_percent_milk/Kconfig.shield new file mode 100644 index 000000000000..b6fbcfdcc46d --- /dev/null +++ b/app/boards/shields/two_percent_milk/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_TWO_PERCENT_MILK + def_bool $(shields_list_contains,two_percent_milk) diff --git a/app/boards/shields/two_percent_milk/boards/nice_nano.overlay b/app/boards/shields/two_percent_milk/boards/nice_nano.overlay new file mode 100644 index 000000000000..b08954339337 --- /dev/null +++ b/app/boards/shields/two_percent_milk/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/two_percent_milk/boards/nice_nano_v2.overlay b/app/boards/shields/two_percent_milk/boards/nice_nano_v2.overlay new file mode 100644 index 000000000000..b08954339337 --- /dev/null +++ b/app/boards/shields/two_percent_milk/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/two_percent_milk/boards/nrfmicro_11.overlay b/app/boards/shields/two_percent_milk/boards/nrfmicro_11.overlay new file mode 100644 index 000000000000..26079169c834 --- /dev/null +++ b/app/boards/shields/two_percent_milk/boards/nrfmicro_11.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi1_default: spi1_default { + group1 { + psels = ; + }; + }; + + spi1_sleep: spi1_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi1 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi1_default>; + pinctrl-1 = <&spi1_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/two_percent_milk/boards/nrfmicro_11_flipped.overlay b/app/boards/shields/two_percent_milk/boards/nrfmicro_11_flipped.overlay new file mode 100644 index 000000000000..e1218ffd1f2b --- /dev/null +++ b/app/boards/shields/two_percent_milk/boards/nrfmicro_11_flipped.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi1_default: spi1_default { + group1 { + psels = ; + }; + }; + + spi1_sleep: spi1_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi1 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi1_default>; + pinctrl-1 = <&spi1_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/two_percent_milk/boards/nrfmicro_13.overlay b/app/boards/shields/two_percent_milk/boards/nrfmicro_13.overlay new file mode 100644 index 000000000000..26079169c834 --- /dev/null +++ b/app/boards/shields/two_percent_milk/boards/nrfmicro_13.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi1_default: spi1_default { + group1 { + psels = ; + }; + }; + + spi1_sleep: spi1_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi1 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi1_default>; + pinctrl-1 = <&spi1_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/two_percent_milk/two_percent_milk.conf b/app/boards/shields/two_percent_milk/two_percent_milk.conf new file mode 100644 index 000000000000..4baccacfdf3d --- /dev/null +++ b/app/boards/shields/two_percent_milk/two_percent_milk.conf @@ -0,0 +1,9 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Uncomment the following lines to enable RGB Underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y + +# Uncomment the following line to turn on logging, and set ZMK logging to debug output +# CONFIG_ZMK_USB_LOGGING=y \ No newline at end of file diff --git a/app/boards/shields/two_percent_milk/two_percent_milk.keymap b/app/boards/shields/two_percent_milk/two_percent_milk.keymap new file mode 100644 index 000000000000..132793b39876 --- /dev/null +++ b/app/boards/shields/two_percent_milk/two_percent_milk.keymap @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp X + &kp Z + >; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/two_percent_milk/two_percent_milk.overlay b/app/boards/shields/two_percent_milk/two_percent_milk.overlay new file mode 100644 index 000000000000..474150ef2fad --- /dev/null +++ b/app/boards/shields/two_percent_milk/two_percent_milk.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + chosen { + zmk,kscan = &kscan0; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-direct"; + + input-gpios + = <&pro_micro 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; + + }; + +}; \ No newline at end of file diff --git a/app/boards/shields/two_percent_milk/two_percent_milk.zmk.yml b/app/boards/shields/two_percent_milk/two_percent_milk.zmk.yml new file mode 100644 index 000000000000..c53c2df2a609 --- /dev/null +++ b/app/boards/shields/two_percent_milk/two_percent_milk.zmk.yml @@ -0,0 +1,8 @@ +file_format: "1" +id: two_percent_milk +name: 2% Milk +type: shield +url: https://github.com/Spaceboards/SpaceboardsHardware/tree/master/Keyboards/2%25%20Milk +requires: [pro_micro] +features: + - keys diff --git a/app/boards/shields/waterfowl/Kconfig.defconfig b/app/boards/shields/waterfowl/Kconfig.defconfig new file mode 100644 index 000000000000..dbee82b87d76 --- /dev/null +++ b/app/boards/shields/waterfowl/Kconfig.defconfig @@ -0,0 +1,47 @@ + +if SHIELD_WATERFOWL_LEFT + +config ZMK_KEYBOARD_NAME + default "Waterfowl" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_WATERFOWL_LEFT || SHIELD_WATERFOWL_RIGHT + +config ZMK_SPLIT + default y + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif diff --git a/app/boards/shields/waterfowl/Kconfig.shield b/app/boards/shields/waterfowl/Kconfig.shield new file mode 100644 index 000000000000..ec01a626376e --- /dev/null +++ b/app/boards/shields/waterfowl/Kconfig.shield @@ -0,0 +1,9 @@ +#Copyright (c) 2022 The ZMK Contributors +#SPDX-License-Identifier: MIT + + +config SHIELD_WATERFOWL_LEFT + def_bool $(shields_list_contains,waterfowl_left) + +config SHIELD_WATERFOWL_RIGHT + def_bool $(shields_list_contains,waterfowl_right) diff --git a/app/boards/shields/waterfowl/waterfowl.conf b/app/boards/shields/waterfowl/waterfowl.conf new file mode 100644 index 000000000000..449e0b1fe261 --- /dev/null +++ b/app/boards/shields/waterfowl/waterfowl.conf @@ -0,0 +1,6 @@ +# Uncomment these two line to add support for encoders to your firmware +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# Uncomment the following line to enable the Waterfowl OLED Display +# CONFIG_ZMK_DISPLAY=y diff --git a/app/boards/shields/waterfowl/waterfowl.dtsi b/app/boards/shields/waterfowl/waterfowl.dtsi new file mode 100644 index 000000000000..bbe60acd5b7e --- /dev/null +++ b/app/boards/shields/waterfowl/waterfowl.dtsi @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zephyr,display = &oled; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <16>; + rows = <4>; +// | MX5 | MX4 | MX3 | MX2 | MX1 | | MX1 | MX2 | MX3 | MX4 | MX5 | +// | MX10 | MX9 | MX8 | MX7 | MX6 | | MX6 | MX7 | MX8 | MX9 | MX10 | +// | MX15 | MX14 | MX13 | MX12 | MX11 | | MX11 | MX12 | MX13 | MX14 | MX15 | +// | MX20 | MX19 | MX18 | MX17 | MX16 | | MX16 | MX17 | MX18 | MX19 | MX20 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; + + roller_left_encoder: encoder_left_roller { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + dial_left_encoder: encoder_left_dial { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + roller_right_encoder: encoder_right_roller { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + dial_right_encoder: encoder_right_dial { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + sensors { + compatible = "zmk,keymap-sensors"; + triggers-per-rotation = <20>; + sensors = < + &roller_left_encoder + &dial_left_encoder + &dial_right_encoder + &roller_right_encoder + >; + }; + + // TODO: RGB node(s) +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <64>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <63>; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/waterfowl/waterfowl.keymap b/app/boards/shields/waterfowl/waterfowl.keymap new file mode 100644 index 000000000000..197a34fa1829 --- /dev/null +++ b/app/boards/shields/waterfowl/waterfowl.keymap @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +/* QWERTY + * + * ,----------------------------------. ,----------------------------------. + * | Q | W | E | R | T | | Y | U | I | O | P | + * |------+------+------+------+------| |------+------+------+------+------| + * | A | S | D | F | G | | H | J | K | L | ; | + * |------+------+------+------+------| ,-----. ,-----. |------+------+------+------+------| + * | Z | X | C | V | B | | 2 | | 3 | | N | M | , | . | / | + * `----------------------------------' `-----' `-----' `----------------------------------' + * ,-----. ,--------------------. ,--------------------. ,-----. + * | 1 | | DEL | SPACE | TAB | | ESC | BS | ENTER | | 4 | + * `-----' `--------------------' `--------------------' `-----' + */ + bindings = < + &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P + &mt LGUI A &mt LALT S &mt LCTRL D &mt LSHFT F &kp G &kp H &mt LSHFT J &mt LCTRL K &mt LALT L &mt LGUI SEMI + &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH + &kp N1 < 3 DEL < 1 SPACE &kp TAB &kp N2 &kp N3 &kp ESC &kp BSPC < 2 RET &kp N4 + >; + + sensor-bindings = < + &inc_dec_kp PAGE_DOWN PAGE_UP + &inc_dec_kp C_VOL_DN C_VOL_UP + &inc_dec_kp DOWN UP + &inc_dec_kp LEFT RIGHT + >; + }; + + navnum_layer { +/* NAVNUM + * + * ,----------------------------------. ,----------------------------------. + * | | PgUp | UP | PgDn | | | / | 7 | 8 | 9 | - | + * |------+------+------+------+------| |------+------+------+------+------| + * | Home | Left | Down | Right| End | | = | 4 | 5 | 6 | + | + * |------+------+------+------+------| ,-----. ,-----. |------+------+------+------+------| + * | | | INS | | | | 2 | | 3 | | 0 | 1 | 2 | 3 | * | + * `----------------------------------' `-----' `-----' `----------------------------------' + * ,-----. ,--------------------. ,--------------------. ,-----. + * | 1 | | DEL | SPACE | MO(3)| | ESC | BS | ENTER | | 4 | + * `-----' `--------------------' `--------------------' `-----' + */ + bindings = < + &trans &kp PG_UP &kp UP &kp PG_DN &trans &kp FSLH &kp N7 &kp N8 &kp N9 &kp MINUS + &kp HOME &kp LEFT &kp DOWN &kp RIGHT &kp END &kp EQUAL &kp N4 &kp N5 &kp N6 &kp PLUS + &trans &trans &kp INS &trans &trans &kp N0 &kp N1 &kp N2 &kp N3 &kp ASTERISK + &kp N1 < 3 DEL < 1 SPACE &kp TAB &kp N2 &kp N3 &kp ESC &kp BSPC < 2 RET &kp N4 + >; + + sensor-bindings = < + &inc_dec_kp PAGE_DOWN PAGE_UP + &inc_dec_kp C_VOL_DN C_VOL_UP + &inc_dec_kp DOWN UP + &inc_dec_kp LEFT RIGHT + >; + }; + + symbol_layer { +/* SYM + * + * ,----------------------------------. ,----------------------------------. + * | % | @ | [ | ] | \ | | | | ^ | | | + * |------+------+------+------+------| |------+------+------+------+------| + * | # | ! | ( | ) | | | | _ | ' | " | ~ | ` | + * |------+------+------+------+------| ,-----. ,-----. |------+------+------+------+------| + * | $ | | { | } | & | | 2 | | 3 | | | | | | | + * `----------------------------------' `-----' `-----' `----------------------------------' + * ,-----. ,--------------------. ,--------------------. ,-----. + * | 1 | | DEL | SPACE | TAB | | ESC | BS | ENTER | | 4 | + * `-----' `--------------------' `--------------------' `-----' + */ + bindings = < + &kp PRCNT &kp AT &kp LBKT &kp RBKT &kp NON_US_BSLH &trans &trans &kp CARET &trans &trans + &kp HASH &kp EXCL &kp LPAR &kp RPAR &kp PIPE &kp UNDER &kp APOS &kp DOUBLE_QUOTES &kp TILDE &kp GRAVE + &kp DLLR &trans &kp LBRC &kp RBRC &kp AMPS &trans &trans &trans &trans &trans + &kp N1 < 3 DEL < 1 SPACE &kp TAB &kp N2 &kp N3 &kp ESC &kp BSPC < 2 RET &kp N4 + >; + + sensor-bindings = < + &inc_dec_kp PAGE_DOWN PAGE_UP + &inc_dec_kp C_VOL_DN C_VOL_UP + &inc_dec_kp DOWN UP + &inc_dec_kp LEFT RIGHT + >; + }; + + function_layer { +/* FUNC + * + * ,----------------------------------. ,----------------------------------. + * | | | BTCLR| | Reset| | Reset| F7 | F8 | F9 | F11 | + * |------+------+------+------+------| |------+------+------+------+------| + * | BT0 | BT1 | BT2 | BT3 | BT4 | | | F4 | F5 | F6 | F12 | + * |------+------+------+------+------| ,-----. ,-----. |------+------+------+------+------| + * | | | | | | | 2 | | 3 | | F10 | F1 | F2 | F3 | F13 | + * `----------------------------------' `-----' `-----' `----------------------------------' + * ,-----. ,--------------------. ,--------------------. ,-----. + * | 1 | | DEL | SPACE | TAB | | ESC | BS | ENTER | | 4 | + * `-----' `--------------------' `--------------------' `-----' + */ + bindings = < + &trans &trans &bt BT_CLR &trans &sys_reset &sys_reset &kp F7 &kp F8 &kp F9 &kp F11 + &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &kp F4 &kp F5 &kp F6 &kp F12 + &trans &trans &trans &trans &trans &kp F10 &kp F1 &kp F2 &kp F3 &kp F13 + &kp N1 < 3 DEL < 1 SPACE &kp TAB &kp N2 &kp N3 &kp ESC &kp BSPC < 2 RET &kp N4 + >; + + sensor-bindings = < + &inc_dec_kp PAGE_DOWN PAGE_UP + &inc_dec_kp C_VOL_DN C_VOL_UP + &inc_dec_kp DOWN UP + &inc_dec_kp LEFT RIGHT + >; + }; + + }; +}; diff --git a/app/boards/shields/waterfowl/waterfowl.zmk.yml b/app/boards/shields/waterfowl/waterfowl.zmk.yml new file mode 100644 index 000000000000..3cd4868686d4 --- /dev/null +++ b/app/boards/shields/waterfowl/waterfowl.zmk.yml @@ -0,0 +1,14 @@ +file_format: "1" +id: waterfowl +name: Waterfowl +type: shield +url: https://waterfowl.bio.link/ +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder +siblings: + - waterfowl_left + - waterfowl_right diff --git a/app/boards/shields/waterfowl/waterfowl_left.conf b/app/boards/shields/waterfowl/waterfowl_left.conf new file mode 100644 index 000000000000..2f561d0de354 --- /dev/null +++ b/app/boards/shields/waterfowl/waterfowl_left.conf @@ -0,0 +1,2 @@ +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y \ No newline at end of file diff --git a/app/boards/shields/waterfowl/waterfowl_left.overlay b/app/boards/shields/waterfowl/waterfowl_left.overlay new file mode 100644 index 000000000000..d58c28763748 --- /dev/null +++ b/app/boards/shields/waterfowl/waterfowl_left.overlay @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "waterfowl.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 21 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + ; +}; + +&roller_left_encoder { + status = "okay"; +}; + +&dial_left_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/waterfowl/waterfowl_right.conf b/app/boards/shields/waterfowl/waterfowl_right.conf new file mode 100644 index 000000000000..2f561d0de354 --- /dev/null +++ b/app/boards/shields/waterfowl/waterfowl_right.conf @@ -0,0 +1,2 @@ +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y \ No newline at end of file diff --git a/app/boards/shields/waterfowl/waterfowl_right.overlay b/app/boards/shields/waterfowl/waterfowl_right.overlay new file mode 100644 index 000000000000..cb23b29ac9f9 --- /dev/null +++ b/app/boards/shields/waterfowl/waterfowl_right.overlay @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "waterfowl.dtsi" + +&default_transform { + col-offset = <5>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 21 GPIO_ACTIVE_HIGH> + ; +}; + +&roller_right_encoder { + status = "okay"; +}; + +&dial_right_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/zmk_uno/Kconfig.defconfig b/app/boards/shields/zmk_uno/Kconfig.defconfig new file mode 100644 index 000000000000..cccca1d2dee4 --- /dev/null +++ b/app/boards/shields/zmk_uno/Kconfig.defconfig @@ -0,0 +1,23 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_ZMK_UNO_BASE + +config ZMK_KEYBOARD_NAME + default "ZMK Uno" + +config ZMK_BACKLIGHT + select LED + select LED_GPIO + +config SHIELD_SSD1306_128X64 + select ZMK_DISPLAY + +config SHIELD_SSD1306_128X32 + select ZMK_DISPLAY + +config ZMK_RGB_UNDERGLOW + select WS2812_STRIP + select SPI + +endif diff --git a/app/boards/shields/zmk_uno/Kconfig.shield b/app/boards/shields/zmk_uno/Kconfig.shield new file mode 100644 index 000000000000..0b0b3d73f73e --- /dev/null +++ b/app/boards/shields/zmk_uno/Kconfig.shield @@ -0,0 +1,20 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_ZMK_UNO_BASE + bool + +config SHIELD_ZMK_UNO + def_bool $(shields_list_contains,zmk_uno) + select SHIELD_ZMK_UNO_BASE + +config SHIELD_ZMK_UNO_SPLIT_LEFT + def_bool $(shields_list_contains,zmk_uno_split_left) + select SHIELD_ZMK_UNO_BASE + select ZMK_SPLIT + select ZMK_SPLIT_ROLE_CENTRAL + +config SHIELD_ZMK_UNO_SPLIT_RIGHT + def_bool $(shields_list_contains,zmk_uno_split_right) + select SHIELD_ZMK_UNO_BASE + select ZMK_SPLIT \ No newline at end of file diff --git a/app/boards/shields/zmk_uno/boards/nrf52840dk_nrf52840.overlay b/app/boards/shields/zmk_uno/boards/nrf52840dk_nrf52840.overlay new file mode 100644 index 000000000000..5ac7af7c5327 --- /dev/null +++ b/app/boards/shields/zmk_uno/boards/nrf52840dk_nrf52840.overlay @@ -0,0 +1,24 @@ + +/ { + // First, delete the existing basic GPIO based instance. + /delete-node/ encoder; +}; + +&pinctrl { + qdec_default: qdec_default { + group1 { + psels = , + ; + bias-pull-up; + }; + }; +}; + +// Set up the QDEC hardware based driver and give it the same label as the deleted node. +encoder: &qdec0 { + status = "okay"; + led-pre = <0>; + steps = <80>; + pinctrl-0 = <&qdec_default>; + pinctrl-names = "default"; +}; diff --git a/app/boards/shields/zmk_uno/zmk_uno.conf b/app/boards/shields/zmk_uno/zmk_uno.conf new file mode 100644 index 000000000000..0c46ea988346 --- /dev/null +++ b/app/boards/shields/zmk_uno/zmk_uno.conf @@ -0,0 +1,20 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +CONFIG_LOG=y +CONFIG_ZMK_LOG_LEVEL_DBG=y + +CONFIG_ZMK_BLE_PASSKEY_ENTRY=n + +# Uncomment for Single color backlight +# CONFIG_ZMK_BACKLIGHT=y + +# Uncomment for RGB +# CONFIG_ZMK_RGB_UNDERGLOW=y + +# Uncomment for Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment these two lines to enable encoder support +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y diff --git a/app/boards/shields/zmk_uno/zmk_uno.dtsi b/app/boards/shields/zmk_uno/zmk_uno.dtsi new file mode 100644 index 000000000000..63deb06a4d17 --- /dev/null +++ b/app/boards/shields/zmk_uno/zmk_uno.dtsi @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +&arduino_i2c { + status = "okay"; +}; + +nice_view_spi: &arduino_spi { + status = "okay"; + + cs-gpios = <&arduino_header 16 GPIO_ACTIVE_HIGH>; + + // Needed so the nice_view shield will enhance the existing node which falls *first* + // on the bus, properly picking up the first `cs-gpios` specifier. + ls0xx@0 { + reg = <0>; + }; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <7>; /* 4 underglow + 3 per-key LEDs */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,kscan = &kscan_matrix_comp; + zmk,backlight = &backlight; + zmk,underglow = &led_strip; + zmk,matrix-transform = &matrix_transform; + }; + + // Commented out until we add more powerful power domain support + // external_power { + // compatible = "zmk,ext-power-generic"; + // init-delay-ms = <200>; + // control-gpios = <&arduino_header 1 GPIO_ACTIVE_LOW>; + // }; + + rgb_power { + compatible = "zmk,ext-power-generic"; + init-delay-ms = <200>; + control-gpios = <&arduino_header 1 GPIO_ACTIVE_LOW>; + }; + + backlight: gpioleds { + compatible = "gpio-leds"; + gpio_led_0 { + gpios = <&arduino_header 12 GPIO_ACTIVE_HIGH>; + }; + }; + + matrix_transform: matrix_transform { + compatible = "zmk,matrix-transform"; + rows = <3>; + columns = <4>; + + map = < + RC(0,0) RC(0,1) + RC(1,0) RC(1,1) + RC(2,0) RC(2,1) RC(2,2) + >; + }; + + direct_matrix_transform: direct_matrix_transform { + compatible = "zmk,matrix-transform"; + rows = <3>; + columns = <4>; + + map = < + RC(0,0) RC(0,1) + RC(0,2) RC(0,3) + RC(1,0) RC(1,1) RC(1,2) + >; + }; + + + kscan_matrix_comp: kscan_matrix_comp { + compatible = "zmk,kscan-composite"; + rows = <1>; + columns = <7>; + + matrix { + kscan = <&kscan_matrix>; + }; + + toggle { + kscan = <&kscan_sp3t_toggle>; + row-offset = <2>; + }; + + }; + + kscan_direct_comp: kscan_direct_comp { + compatible = "zmk,kscan-composite"; + status = "disabled"; + + matrix { + kscan = <&kscan_direct>; + }; + + toggle { + kscan = <&kscan_sp3t_toggle>; + row-offset = <1>; + }; + + }; + + kscan_matrix: kscan_matrix { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + + col-gpios + = <&arduino_header 10 GPIO_ACTIVE_HIGH> + , <&arduino_header 9 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&arduino_header 13 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&arduino_header 11 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + }; + + kscan_direct: kscan_direct { + compatible = "zmk,kscan-gpio-direct"; + status = "disabled"; + + input-gpios + = <&arduino_header 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&arduino_header 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&arduino_header 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&arduino_header 11 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; + + }; + + kscan_sp3t_toggle: kscan_sp3t_toggle { + compatible = "zmk,kscan-gpio-direct"; + toggle-mode; + + input-gpios + = <&arduino_header 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&arduino_header 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&arduino_header 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; + }; + + encoder: encoder { + steps = <80>; + compatible = "alps,ec11"; + a-gpios = <&arduino_header 15 GPIO_PULL_UP>; + b-gpios = <&arduino_header 14 GPIO_PULL_UP>; + }; +}; diff --git a/app/boards/shields/zmk_uno/zmk_uno.keymap b/app/boards/shields/zmk_uno/zmk_uno.keymap new file mode 100644 index 000000000000..0e0fc7954c19 --- /dev/null +++ b/app/boards/shields/zmk_uno/zmk_uno.keymap @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include +#include +#include + +// Uncomment the following block if using the "Direct Wire" jumper to switch the matrix to a direct wire. + +/* :REMOVE ME + +&kscan_direct_comp { status = "okay"; }; +&kscan_direct { status = "okay"; }; +&kscan_matrix_comp { status = "disabled"; }; +&kscan_matrix { status = "disabled"; }; + +/ { + chosen { + zmk,matrix-transform = &direct_matrix_transform; + zmk,kscan = &kscan_direct_comp; + }; +}; + +REMOVE ME: */ + + +/ { + macros { + ZMK_MACRO(ble_zero, + wait-ms = <1>; + tap-ms = <1>; + bindings = <&out OUT_BLE &bt BT_SEL 0>; + ) + ZMK_MACRO(ble_one, + wait-ms = <1>; + tap-ms = <1>; + bindings = <&out OUT_BLE &bt BT_SEL 1>; + ) + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &bl BL_TOG + &rgb_ug RGB_EFF &bt BT_CLR + + &out OUT_USB &ble_zero &ble_one + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + }; +}; diff --git a/app/boards/shields/zmk_uno/zmk_uno.overlay b/app/boards/shields/zmk_uno/zmk_uno.overlay new file mode 100644 index 000000000000..07181280015b --- /dev/null +++ b/app/boards/shields/zmk_uno/zmk_uno.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + #include "zmk_uno.dtsi" + +/ { + chosen { + zmk,matrix-transform = &matrix_transform; + }; + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&encoder>; + triggers-per-rotation = <20>; + left { + triggers-per-rotation = <20>; + }; + }; + +}; diff --git a/app/boards/shields/zmk_uno/zmk_uno.zmk.yml b/app/boards/shields/zmk_uno/zmk_uno.zmk.yml new file mode 100644 index 000000000000..cee108facbf8 --- /dev/null +++ b/app/boards/shields/zmk_uno/zmk_uno.zmk.yml @@ -0,0 +1,10 @@ +file_format: "1" +id: zmk_uno +name: ZMK Uno +type: shield +url: https://github.com/zmkfirmware/zmk-uno +requires: [arduino_uno] +features: + - keys + - encoder + - display diff --git a/app/boards/shields/zmk_uno/zmk_uno_split.dtsi b/app/boards/shields/zmk_uno/zmk_uno_split.dtsi new file mode 100644 index 000000000000..f84aacc8e970 --- /dev/null +++ b/app/boards/shields/zmk_uno/zmk_uno_split.dtsi @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + #include "zmk_uno.dtsi" + + left_encoder: &encoder { + status = "disabled"; + }; + + / { + chosen { + zmk,matrix-transform = &split_matrix_transform; + }; + + split_matrix_transform: split_matrix_transform { + compatible = "zmk,matrix-transform"; + rows = <3>; + columns = <4>; + + map = < + RC(0,0) RC(0,1) + RC(1,0) RC(1,1) + RC(2,0) RC(2,1) RC(2,2) + RC(3,0) RC(3,1) + RC(4,0) RC(4,1) + RC(5,0) RC(5,1) RC(5,2) + >; + }; + + split_direct_matrix_transform: split_direct_matrix_transform { + compatible = "zmk,matrix-transform"; + rows = <3>; + columns = <4>; + + map = < + RC(0,0) RC(0,1) + RC(0,2) RC(0,3) + RC(1,0) RC(1,1) RC(1,2) + RC(2,0) RC(2,1) + RC(2,2) RC(2,3) + RC(3,0) RC(3,1) RC(3,2) + >; + }; + + right_encoder: right_encoder { + steps = <80>; + status = "disabled"; + compatible = "alps,ec11"; + a-gpios = <&arduino_header 15 GPIO_PULL_UP>; + b-gpios = <&arduino_header 14 GPIO_PULL_UP>; + }; + + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&encoder &right_encoder>; + triggers-per-rotation = <20>; + }; + }; diff --git a/app/boards/shields/zmk_uno/zmk_uno_split.keymap b/app/boards/shields/zmk_uno/zmk_uno_split.keymap new file mode 100644 index 000000000000..05f0ffb0b040 --- /dev/null +++ b/app/boards/shields/zmk_uno/zmk_uno_split.keymap @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include +#include +#include + +// Uncomment the following block if using the "Direct Wire" jumper to switch the matrix to a direct wire. + +/* :REMOVE ME + +&kscan_direct_comp { status = "okay"; }; +&kscan_direct { status = "okay"; }; +&kscan_matrix_comp { status = "disabled"; }; +&kscan_matrix { status = "disabled"; }; + +/ { + chosen { + zmk,matrix-transform = &split_direct_matrix_transform; + zmk,kscan = &kscan_direct_comp; + }; +}; + +REMOVE ME: */ + + +/ { + macros { + ZMK_MACRO(ble_zero, + wait-ms = <1>; + tap-ms = <1>; + bindings = <&out OUT_BLE &bt BT_SEL 0>; + ) + ZMK_MACRO(ble_one, + wait-ms = <1>; + tap-ms = <1>; + bindings = <&out OUT_BLE &bt BT_SEL 1>; + ) + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &bl BL_TOG + &rgb_ug RGB_EFF &bt BT_CLR + + &out OUT_USB &ble_zero &ble_one + + &kp C &kp D + &kp E &kp F + &none &none &none + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + }; +}; diff --git a/app/boards/shields/zmk_uno/zmk_uno_split_left.conf b/app/boards/shields/zmk_uno/zmk_uno_split_left.conf new file mode 100644 index 000000000000..0c46ea988346 --- /dev/null +++ b/app/boards/shields/zmk_uno/zmk_uno_split_left.conf @@ -0,0 +1,20 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +CONFIG_LOG=y +CONFIG_ZMK_LOG_LEVEL_DBG=y + +CONFIG_ZMK_BLE_PASSKEY_ENTRY=n + +# Uncomment for Single color backlight +# CONFIG_ZMK_BACKLIGHT=y + +# Uncomment for RGB +# CONFIG_ZMK_RGB_UNDERGLOW=y + +# Uncomment for Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment these two lines to enable encoder support +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y diff --git a/app/boards/shields/zmk_uno/zmk_uno_split_left.overlay b/app/boards/shields/zmk_uno/zmk_uno_split_left.overlay new file mode 100644 index 000000000000..5782e612d92a --- /dev/null +++ b/app/boards/shields/zmk_uno/zmk_uno_split_left.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "zmk_uno_split.dtsi" + +&left_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/zmk_uno/zmk_uno_split_right.conf b/app/boards/shields/zmk_uno/zmk_uno_split_right.conf new file mode 100644 index 000000000000..0c46ea988346 --- /dev/null +++ b/app/boards/shields/zmk_uno/zmk_uno_split_right.conf @@ -0,0 +1,20 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +CONFIG_LOG=y +CONFIG_ZMK_LOG_LEVEL_DBG=y + +CONFIG_ZMK_BLE_PASSKEY_ENTRY=n + +# Uncomment for Single color backlight +# CONFIG_ZMK_BACKLIGHT=y + +# Uncomment for RGB +# CONFIG_ZMK_RGB_UNDERGLOW=y + +# Uncomment for Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment these two lines to enable encoder support +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y diff --git a/app/boards/shields/zmk_uno/zmk_uno_split_right.overlay b/app/boards/shields/zmk_uno/zmk_uno_split_right.overlay new file mode 100644 index 000000000000..9c2e7d7f2eef --- /dev/null +++ b/app/boards/shields/zmk_uno/zmk_uno_split_right.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "zmk_uno_split.dtsi" + +&split_matrix_transform { + row-offset = <3>; +}; + +&split_direct_matrix_transform { + row-offset = <2>; +}; + +&right_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/zodiark/Kconfig.defconfig b/app/boards/shields/zodiark/Kconfig.defconfig new file mode 100644 index 000000000000..e7538c418152 --- /dev/null +++ b/app/boards/shields/zodiark/Kconfig.defconfig @@ -0,0 +1,49 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_ZODIARK_LEFT + +config ZMK_KEYBOARD_NAME + default "Zodiark" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_ZODIARK_LEFT || SHIELD_ZODIARK_RIGHT + +config ZMK_SPLIT + default y + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif diff --git a/app/boards/shields/zodiark/Kconfig.shield b/app/boards/shields/zodiark/Kconfig.shield new file mode 100644 index 000000000000..0eb4e8add0fe --- /dev/null +++ b/app/boards/shields/zodiark/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_ZODIARK_LEFT + def_bool $(shields_list_contains,zodiark_left) + +config SHIELD_ZODIARK_RIGHT + def_bool $(shields_list_contains,zodiark_right) diff --git a/app/boards/shields/zodiark/zodiark.conf b/app/boards/shields/zodiark/zodiark.conf new file mode 100644 index 000000000000..6478485000e7 --- /dev/null +++ b/app/boards/shields/zodiark/zodiark.conf @@ -0,0 +1,9 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Uncomment the following line to enable the Zodiark OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment these two lines to add support for encoders +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y diff --git a/app/boards/shields/zodiark/zodiark.dtsi b/app/boards/shields/zodiark/zodiark.dtsi new file mode 100644 index 000000000000..6e91778e7ad7 --- /dev/null +++ b/app/boards/shields/zodiark/zodiark.dtsi @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zephyr,display = &oled; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <18>; + rows = <4>; +// | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | +// | SW13 | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | SW13 | +// | SW20 | SW19 | SW18 | SW17 | SW16 | SW15 | SW14 | | SW14 | SW15 | SW16 | SW17 | SW18 | SW19 | SW20 | +// | SW28 | SW27 | SW26 | SW25 | SW24 | SW23 | SW22 | SW21 | | SW21 | SW22 | SW23 | SW24 | SW25 | SW26 | SW27 | SW28 | +// | SW35 | SW34 | SW33 | SW32 | SW31 | SW30 | SW29 | | SW29 | SW30 | SW31 | SW32 | SW33 | SW34 | SW35 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(0,6) RC(0,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(1,6) RC(1,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(2,6) RC(3,6) RC(3,7) RC(2,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) RC(3,13) +RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,13) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; + + left_encoder: encoder_left { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + right_encoder: encoder_right { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + sensors: sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + triggers-per-rotation = <20>; + }; +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <64>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/zodiark/zodiark.keymap b/app/boards/shields/zodiark/zodiark.keymap new file mode 100644 index 000000000000..82639edc8f6f --- /dev/null +++ b/app/boards/shields/zodiark/zodiark.keymap @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ------------------------------------------------------------------------------------------------------------ +// | ESC | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | BKSPC | +// | TAB | Q | W | E | R | T | [ | | ] | Y | U | I | O | P | \ | +// | CAPS | A | S | D | F | G | - | | = | H | J | K | L | ; | ' | +// | SHIFT | Z | X | C | V | B | ` | MUTE | | PRNT | DEL | N | M | , | . | / | ENTER | +// | CTRL | ALT | GUI | MENU | LOWER| SPACE | ENTER | | ENTER | SPACE | RAISE| LEFT | DOWN | UP | RIGHT | + bindings = < +&kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp BSPC +&kp TAB &kp Q &kp W &kp E &kp R &kp T &kp LBKT &kp RBKT &kp Y &kp U &kp I &kp O &kp P &kp BSLH +&kp TAB &kp A &kp S &kp D &kp F &kp G &kp MINUS &kp EQUAL &kp H &kp J &kp K &kp L &kp SEMI &kp SQT +&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp GRAVE &kp C_MUTE &kp PSCRN &kp DEL &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RET +&kp LCTRL &kp LALT &kp LGUI &kp K_CMENU &mo 1 &kp SPACE &kp RET &kp RET &kp SPACE &mo 2 &kp LEFT &kp DOWN &kp UP &kp RIGHT + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + + lower_layer { +// ------------------------------------------------------------------------------------------------------------ +// | | F1 | F2 | F3 | F4 | F5 | | F6 | F7 | F8 | F9 | F10 | F11 | +// | N.LC | 7 | 8 | 9 |PRTSC | SCRLK| | | | PAUSE| | 7 | 8 | 9 | F12 | +// | | 4 | 5 | 6 | INS | HOME | | | | PGUP| | 4 | 5 | 6 | | +// | | 1 | 2 | 3 | DEL | END | | | | | | PGDN| | 1 | 2 | 3 | | +// | | 0 | . | Enter| | | | | | | | 0 | . | Enter | | + bindings = < +&trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 +&kp KP_NUM &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp PSCRN &kp SLCK &trans &trans &kp PAUSE_BREAK &trans &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp F12 +&trans &kp KP_N4 &kp KP_N5 &kp KP_N6 &kp INS &kp HOME &trans &trans &kp PG_UP &trans &kp KP_N4 &kp KP_N5 &kp KP_N6 &trans +&trans &kp KP_N1 &kp KP_N2 &kp KP_N3 &kp DEL &kp END &trans &trans &trans &trans &kp PG_DN &trans &kp KP_N1 &kp KP_N2 &kp KP_N3 &trans +&trans &kp KP_N0 &kp KP_DOT &kp KP_ENTER &trans &trans &trans &trans &trans &trans &kp KP_N0 &kp KP_DOT &kp KP_ENTER &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + + raise_layer { +// ------------------------------------------------------------------------------------------------------------ +// |BTCLR | BT1 | BT2 | BT3 | BT4 | BT5 | | | | | | | RESET | +// | | | | | | | | | | | | | | |BLOADER| +// | | | | | | | | | | | | | | | | +// | | | | | | | | | | | | | | | | | | +// | | | | | | | | | | | | | | | | + bindings = < +&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &sys_reset +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &bootloader +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + }; +}; diff --git a/app/boards/shields/zodiark/zodiark.zmk.yml b/app/boards/shields/zodiark/zodiark.zmk.yml new file mode 100644 index 000000000000..fc68588152ce --- /dev/null +++ b/app/boards/shields/zodiark/zodiark.zmk.yml @@ -0,0 +1,14 @@ +file_format: "1" +id: zodiark +name: Zodiark +type: shield +url: https://www.splitlogic.xyz/buildguides/zodiark-build-guide +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder +siblings: + - zodiark_left + - zodiark_right diff --git a/app/boards/shields/zodiark/zodiark_left.overlay b/app/boards/shields/zodiark/zodiark_left.overlay new file mode 100644 index 000000000000..1f866f781ed9 --- /dev/null +++ b/app/boards/shields/zodiark/zodiark_left.overlay @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "zodiark.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 2 GPIO_ACTIVE_HIGH> + , <&pro_micro 1 GPIO_ACTIVE_HIGH> + , <&pro_micro 0 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + ; +}; + +&left_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/zodiark/zodiark_right.overlay b/app/boards/shields/zodiark/zodiark_right.overlay new file mode 100644 index 000000000000..998f1e009613 --- /dev/null +++ b/app/boards/shields/zodiark/zodiark_right.overlay @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "zodiark.dtsi" + +&default_transform { + col-offset = <7>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 0 GPIO_ACTIVE_HIGH> + , <&pro_micro 1 GPIO_ACTIVE_HIGH> + , <&pro_micro 2 GPIO_ACTIVE_HIGH> + ; +}; + +&right_encoder { + status = "okay"; +}; diff --git a/app/boards/sparkfun_pro_micro_rp2040.conf b/app/boards/sparkfun_pro_micro_rp2040.conf new file mode 100644 index 000000000000..21c1893d91f4 --- /dev/null +++ b/app/boards/sparkfun_pro_micro_rp2040.conf @@ -0,0 +1,4 @@ +CONFIG_CONSOLE=n +CONFIG_SERIAL=n +CONFIG_UART_CONSOLE=n +CONFIG_ZMK_USB=y diff --git a/app/boards/sparkfun_pro_micro_rp2040.overlay b/app/boards/sparkfun_pro_micro_rp2040.overlay new file mode 100644 index 000000000000..b14e0d04d478 --- /dev/null +++ b/app/boards/sparkfun_pro_micro_rp2040.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "usb_console.dtsi" + +&pro_micro_serial { status = "disabled"; }; diff --git a/app/boards/usb_console.dtsi b/app/boards/usb_console.dtsi new file mode 100644 index 000000000000..adf3bd19bf1c --- /dev/null +++ b/app/boards/usb_console.dtsi @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + +/ { + chosen { + zephyr,console = &cdc_acm_uart; + }; +}; + +&usbd { + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + diff --git a/app/core-coverage.yml b/app/core-coverage.yml new file mode 100644 index 000000000000..4a60aad9cafb --- /dev/null +++ b/app/core-coverage.yml @@ -0,0 +1,35 @@ +board: + - nice_nano_v2 + - nrfmicro_13 + - proton_c +shield: + - corne_left + - corne_right + - romac + - settings_reset + - tidbit +include: + - board: bdn9_rev2 + - board: nice60 + - board: seeeduino_xiao_ble + shield: hummingbird + - board: nrf52840_m2 + shield: m60 + - board: planck_rev6 + - board: proton_c + shield: clueboard_california + - board: nice_nano_v2 + shield: kyria_left + cmake-args: "-DCONFIG_ZMK_DISPLAY=y" + nickname: "display" + - board: nice_nano_v2 + shield: kyria_right + cmake-args: "-DCONFIG_ZMK_DISPLAY=y" + nickname: "display" + - board: nice_nano + shield: romac_plus + cmake-args: "-DCONFIG_ZMK_RGB_UNDERGLOW=y -DCONFIG_WS2812_STRIP=y" + nickname: "underglow" + - board: nice_nano_v2 + shield: lily58_left nice_view_adapter nice_view + nickname: "niceview" diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi new file mode 100644 index 000000000000..23f2fee28068 --- /dev/null +++ b/app/dts/behaviors.dtsi @@ -0,0 +1,22 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/app/dts/behaviors/backlight.dtsi b/app/dts/behaviors/backlight.dtsi new file mode 100644 index 000000000000..54c83ff44c1e --- /dev/null +++ b/app/dts/behaviors/backlight.dtsi @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + / { + behaviors { + // Behavior can be invoked on peripherals, so name must be <= 8 characters. + /omit-if-no-ref/ bl: bcklight { + compatible = "zmk,behavior-backlight"; + #binding-cells = <2>; + }; + }; +}; diff --git a/app/dts/behaviors/bluetooth.dtsi b/app/dts/behaviors/bluetooth.dtsi new file mode 100644 index 000000000000..40557b7a28cc --- /dev/null +++ b/app/dts/behaviors/bluetooth.dtsi @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + behaviors { + /omit-if-no-ref/ bt: bluetooth { + compatible = "zmk,behavior-bluetooth"; + #binding-cells = <2>; + }; + }; +}; diff --git a/app/dts/behaviors/caps_word.dtsi b/app/dts/behaviors/caps_word.dtsi new file mode 100644 index 000000000000..795fbc08439b --- /dev/null +++ b/app/dts/behaviors/caps_word.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + behaviors { + /omit-if-no-ref/ caps_word: caps_word { + compatible = "zmk,behavior-caps-word"; + #binding-cells = <0>; + continue-list = ; + }; + }; +}; + diff --git a/app/dts/behaviors/ext_power.dtsi b/app/dts/behaviors/ext_power.dtsi new file mode 100644 index 000000000000..2ae1daf84a83 --- /dev/null +++ b/app/dts/behaviors/ext_power.dtsi @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + behaviors { + // Behavior can be invoked on peripherals, so name must be <= 8 characters. + ext_power: extpower { + compatible = "zmk,behavior-ext-power"; + #binding-cells = <1>; + }; + }; +}; diff --git a/app/dts/behaviors/gresc.dtsi b/app/dts/behaviors/gresc.dtsi new file mode 100644 index 000000000000..59a7329178f4 --- /dev/null +++ b/app/dts/behaviors/gresc.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + behaviors { + /omit-if-no-ref/ gresc: grave_escape { + compatible = "zmk,behavior-mod-morph"; + #binding-cells = <0>; + bindings = <&kp ESC>, <&kp GRAVE>; + mods = <(MOD_LGUI|MOD_LSFT|MOD_RGUI|MOD_RSFT)>; + }; + }; +}; diff --git a/app/dts/behaviors/key_press.dtsi b/app/dts/behaviors/key_press.dtsi new file mode 100644 index 000000000000..ddaf7eed3748 --- /dev/null +++ b/app/dts/behaviors/key_press.dtsi @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + behaviors { + /* DEPRECATED: `cp` will be removed in the future */ + /omit-if-no-ref/ cp: kp: key_press { + compatible = "zmk,behavior-key-press"; + #binding-cells = <1>; + }; + }; +}; diff --git a/app/dts/behaviors/key_repeat.dtsi b/app/dts/behaviors/key_repeat.dtsi new file mode 100644 index 000000000000..88910f6271c1 --- /dev/null +++ b/app/dts/behaviors/key_repeat.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + behaviors { + /omit-if-no-ref/ key_repeat: key_repeat { + compatible = "zmk,behavior-key-repeat"; + #binding-cells = <0>; + usage-pages = ; + }; + }; +}; + diff --git a/app/dts/behaviors/key_toggle.dtsi b/app/dts/behaviors/key_toggle.dtsi new file mode 100644 index 000000000000..a3e3f36f270a --- /dev/null +++ b/app/dts/behaviors/key_toggle.dtsi @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + behaviors { + /omit-if-no-ref/ kt: key_toggle { + compatible = "zmk,behavior-key-toggle"; + #binding-cells = <1>; + }; + }; +}; diff --git a/app/dts/behaviors/layer_tap.dtsi b/app/dts/behaviors/layer_tap.dtsi new file mode 100644 index 000000000000..dc953e9358bb --- /dev/null +++ b/app/dts/behaviors/layer_tap.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + behaviors { + /omit-if-no-ref/ lt: layer_tap { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <200>; + bindings = <&mo>, <&kp>; + }; + }; +}; diff --git a/app/dts/behaviors/macros.dtsi b/app/dts/behaviors/macros.dtsi new file mode 100644 index 000000000000..44bc7ab777f5 --- /dev/null +++ b/app/dts/behaviors/macros.dtsi @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define MACRO_PLACEHOLDER 0 +#define ZMK_MACRO(name,...) \ +name: name { \ + compatible = "zmk,behavior-macro"; \ + #binding-cells = <0>; \ + __VA_ARGS__ \ +}; + +#define ZMK_MACRO1(name,...) \ +name: name { \ + compatible = "zmk,behavior-macro-one-param"; \ + #binding-cells = <1>; \ + __VA_ARGS__ \ +}; + +#define ZMK_MACRO2(name,...) \ +name: name { \ + compatible = "zmk,behavior-macro-two-param"; \ + #binding-cells = <2>; \ + __VA_ARGS__ \ +}; + +/ { + behaviors { + macro_tap: macro_tap { + compatible = "zmk,macro-control-mode-tap"; + #binding-cells = <0>; + }; + + macro_press: macro_press { + compatible = "zmk,macro-control-mode-press"; + #binding-cells = <0>; + }; + + macro_release: macro_release { + compatible = "zmk,macro-control-mode-release"; + #binding-cells = <0>; + }; + + macro_tap_time: macro_tap_time { + compatible = "zmk,macro-control-tap-time"; + #binding-cells = <1>; + }; + + macro_wait_time: macro_wait_time { + compatible = "zmk,macro-control-wait-time"; + #binding-cells = <1>; + }; + + macro_pause_for_release: macro_pause_for_release { + compatible = "zmk,macro-pause-for-release"; + #binding-cells = <0>; + }; + + macro_param_1to1: macro_param_1to1 { + compatible = "zmk,macro-param-1to1"; + #binding-cells = <0>; + }; + + macro_param_1to2: macro_param_1to2 { + compatible = "zmk,macro-param-1to2"; + #binding-cells = <0>; + }; + + macro_param_2to1: macro_param_2to1 { + compatible = "zmk,macro-param-2to1"; + #binding-cells = <0>; + }; + + macro_param_2to2: macro_param_2to2 { + compatible = "zmk,macro-param-2to2"; + #binding-cells = <0>; + }; + }; +}; diff --git a/app/dts/behaviors/mod_tap.dtsi b/app/dts/behaviors/mod_tap.dtsi new file mode 100644 index 000000000000..38bb34fe5c41 --- /dev/null +++ b/app/dts/behaviors/mod_tap.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + behaviors { + /omit-if-no-ref/ mt: mod_tap { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "hold-preferred"; + tapping-term-ms = <200>; + bindings = <&kp>, <&kp>; + }; + }; +}; diff --git a/app/dts/behaviors/momentary_layer.dtsi b/app/dts/behaviors/momentary_layer.dtsi new file mode 100644 index 000000000000..6d85165dbb32 --- /dev/null +++ b/app/dts/behaviors/momentary_layer.dtsi @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + behaviors { + /omit-if-no-ref/ mo: momentary_layer { + compatible = "zmk,behavior-momentary-layer"; + #binding-cells = <1>; + }; + }; +}; diff --git a/app/dts/behaviors/mouse_key_press.dtsi b/app/dts/behaviors/mouse_key_press.dtsi new file mode 100644 index 000000000000..975c24aaafbd --- /dev/null +++ b/app/dts/behaviors/mouse_key_press.dtsi @@ -0,0 +1,8 @@ +/ { + behaviors { + /omit-if-no-ref/ mkp: mouse_key_press { + compatible = "zmk,behavior-mouse-key-press"; + #binding-cells = <1>; + }; + }; +}; diff --git a/app/dts/behaviors/none.dtsi b/app/dts/behaviors/none.dtsi new file mode 100644 index 000000000000..13d056f0cf29 --- /dev/null +++ b/app/dts/behaviors/none.dtsi @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + behaviors { + /omit-if-no-ref/ none: none { + compatible = "zmk,behavior-none"; + #binding-cells = <0>; + }; + }; +}; diff --git a/app/dts/behaviors/outputs.dtsi b/app/dts/behaviors/outputs.dtsi new file mode 100644 index 000000000000..f7737196719b --- /dev/null +++ b/app/dts/behaviors/outputs.dtsi @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + behaviors { + /omit-if-no-ref/ out: outputs { + compatible = "zmk,behavior-outputs"; + #binding-cells = <1>; + }; + }; +}; diff --git a/app/dts/behaviors/reset.dtsi b/app/dts/behaviors/reset.dtsi new file mode 100644 index 000000000000..e407b107b90f --- /dev/null +++ b/app/dts/behaviors/reset.dtsi @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + behaviors { + // Behavior can be invoked on peripherals, so name must be <= 8 characters. + sys_reset: sysreset { + compatible = "zmk,behavior-reset"; + #binding-cells = <0>; + }; + + // Behavior can be invoked on peripherals, so name must be <= 8 characters. + bootloader: bootload { + compatible = "zmk,behavior-reset"; + type = ; + #binding-cells = <0>; + }; + }; +}; diff --git a/app/dts/behaviors/rgb_underglow.dtsi b/app/dts/behaviors/rgb_underglow.dtsi new file mode 100644 index 000000000000..969518a6ff39 --- /dev/null +++ b/app/dts/behaviors/rgb_underglow.dtsi @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + behaviors { + // Behavior can be invoked on peripherals, so name must be <= 8 characters. + rgb_ug: rgb_ug { + compatible = "zmk,behavior-rgb-underglow"; + #binding-cells = <2>; + }; + }; +}; diff --git a/app/dts/behaviors/sensor_rotate_key_press.dtsi b/app/dts/behaviors/sensor_rotate_key_press.dtsi new file mode 100644 index 000000000000..d9bdbfe543b6 --- /dev/null +++ b/app/dts/behaviors/sensor_rotate_key_press.dtsi @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + behaviors { + /* DEPRECATED: `inc_dec_cp` will be removed in the future */ + /omit-if-no-ref/ inc_dec_cp: inc_dec_kp: enc_key_press { + compatible = "zmk,behavior-sensor-rotate-var"; + #sensor-binding-cells = <2>; + bindings = <&kp>, <&kp>; + }; + }; +}; diff --git a/app/dts/behaviors/sticky_key.dtsi b/app/dts/behaviors/sticky_key.dtsi new file mode 100644 index 000000000000..c8973d4df2cd --- /dev/null +++ b/app/dts/behaviors/sticky_key.dtsi @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + behaviors { + /omit-if-no-ref/ sk: sticky_key { + compatible = "zmk,behavior-sticky-key"; + #binding-cells = <1>; + release-after-ms = <1000>; + bindings = <&kp>; + ignore-modifiers; + }; + /omit-if-no-ref/ sl: sticky_layer { + compatible = "zmk,behavior-sticky-key"; + #binding-cells = <1>; + release-after-ms = <1000>; + bindings = <&mo>; + quick-release; + }; + }; + +}; + diff --git a/app/dts/behaviors/to_layer.dtsi b/app/dts/behaviors/to_layer.dtsi new file mode 100644 index 000000000000..904f023da534 --- /dev/null +++ b/app/dts/behaviors/to_layer.dtsi @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + behaviors { + /omit-if-no-ref/ to: to_layer { + compatible = "zmk,behavior-to-layer"; + #binding-cells = <1>; + }; + }; +}; diff --git a/app/dts/behaviors/toggle_layer.dtsi b/app/dts/behaviors/toggle_layer.dtsi new file mode 100644 index 000000000000..05f2988e08c3 --- /dev/null +++ b/app/dts/behaviors/toggle_layer.dtsi @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + behaviors { + /omit-if-no-ref/ tog: toggle_layer { + compatible = "zmk,behavior-toggle-layer"; + #binding-cells = <1>; + }; + }; +}; diff --git a/app/dts/behaviors/transparent.dtsi b/app/dts/behaviors/transparent.dtsi new file mode 100644 index 000000000000..3586f02afabe --- /dev/null +++ b/app/dts/behaviors/transparent.dtsi @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + behaviors { + /omit-if-no-ref/ trans: transparent { + compatible = "zmk,behavior-transparent"; + #binding-cells = <0>; + }; + }; +}; diff --git a/app/dts/bindings/behaviors/macro_base.yaml b/app/dts/bindings/behaviors/macro_base.yaml new file mode 100644 index 000000000000..236ee33d3b21 --- /dev/null +++ b/app/dts/bindings/behaviors/macro_base.yaml @@ -0,0 +1,13 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +properties: + bindings: + type: phandle-array + required: true + wait-ms: + type: int + description: The default time to wait (in milliseconds) before triggering the next behavior in the macro bindings list. + tap-ms: + type: int + description: The default time to wait (in milliseconds) between the press and release events on a tapped macro behavior binding diff --git a/app/dts/bindings/behaviors/one_param.yaml b/app/dts/bindings/behaviors/one_param.yaml new file mode 100644 index 000000000000..9a503e8a8151 --- /dev/null +++ b/app/dts/bindings/behaviors/one_param.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +properties: + label: + type: string + required: false + deprecated: true + "#binding-cells": + type: int + required: true + const: 1 + +binding-cells: + - param1 diff --git a/app/dts/bindings/behaviors/two_param.yaml b/app/dts/bindings/behaviors/two_param.yaml new file mode 100644 index 000000000000..4f342301bb3d --- /dev/null +++ b/app/dts/bindings/behaviors/two_param.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +properties: + label: + type: string + required: false + deprecated: true + "#binding-cells": + type: int + required: true + const: 2 + +binding-cells: + - param1 + - param2 diff --git a/app/dts/bindings/behaviors/zero_param.yaml b/app/dts/bindings/behaviors/zero_param.yaml new file mode 100644 index 000000000000..79d0dcaed3fe --- /dev/null +++ b/app/dts/bindings/behaviors/zero_param.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +properties: + label: + type: string + required: false + deprecated: true + "#binding-cells": + type: int + required: true + const: 0 diff --git a/app/dts/bindings/behaviors/zmk,behavior-backlight.yaml b/app/dts/bindings/behaviors/zmk,behavior-backlight.yaml new file mode 100644 index 000000000000..159a7c706988 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-backlight.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Backlight behavior + +compatible: "zmk,behavior-backlight" + +include: two_param.yaml diff --git a/app/dts/bindings/behaviors/zmk,behavior-bluetooth.yaml b/app/dts/bindings/behaviors/zmk,behavior-bluetooth.yaml new file mode 100644 index 000000000000..b357fbf68d7c --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-bluetooth.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Bluetooth Behavior + +compatible: "zmk,behavior-bluetooth" + +include: two_param.yaml diff --git a/app/dts/bindings/behaviors/zmk,behavior-caps-word.yaml b/app/dts/bindings/behaviors/zmk,behavior-caps-word.yaml new file mode 100644 index 000000000000..cc1dda013701 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-caps-word.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Caps word behavior + +compatible: "zmk,behavior-caps-word" + +include: zero_param.yaml + +properties: + continue-list: + type: array + required: true + mods: + type: int diff --git a/app/dts/bindings/behaviors/zmk,behavior-ext-power.yaml b/app/dts/bindings/behaviors/zmk,behavior-ext-power.yaml new file mode 100644 index 000000000000..69949d7fafab --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-ext-power.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: External power control Behavior + +compatible: "zmk,behavior-ext-power" + +include: one_param.yaml diff --git a/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml b/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml new file mode 100644 index 000000000000..575754116b1c --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml @@ -0,0 +1,47 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Hold or Tap behavior + +compatible: "zmk,behavior-hold-tap" + +include: two_param.yaml + +properties: + bindings: + type: phandles + required: true + tapping-term-ms: + type: int + tapping_term_ms: + type: int + deprecated: true + quick-tap-ms: + type: int + default: -1 + quick_tap_ms: + type: int + deprecated: true + global-quick-tap: + type: boolean + deprecated: true + require-prior-idle-ms: + type: int + default: -1 + flavor: + type: string + required: false + default: "hold-preferred" + enum: + - "hold-preferred" + - "balanced" + - "tap-preferred" + - "tap-unless-interrupted" + retro-tap: + type: boolean + hold-trigger-key-positions: + type: array + required: false + default: [] + hold-trigger-on-release: + type: boolean diff --git a/app/dts/bindings/behaviors/zmk,behavior-key-press.yaml b/app/dts/bindings/behaviors/zmk,behavior-key-press.yaml new file mode 100644 index 000000000000..5a40a8db1a73 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-key-press.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Key press/release behavior + +compatible: "zmk,behavior-key-press" + +include: one_param.yaml diff --git a/app/dts/bindings/behaviors/zmk,behavior-key-repeat.yaml b/app/dts/bindings/behaviors/zmk,behavior-key-repeat.yaml new file mode 100644 index 000000000000..10b3aa047fc2 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-key-repeat.yaml @@ -0,0 +1,13 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Key repeat behavior + +compatible: "zmk,behavior-key-repeat" + +include: zero_param.yaml + +properties: + usage-pages: + type: array + required: true diff --git a/app/dts/bindings/behaviors/zmk,behavior-key-toggle.yaml b/app/dts/bindings/behaviors/zmk,behavior-key-toggle.yaml new file mode 100644 index 000000000000..e3ec86f7a16f --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-key-toggle.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Key toggle behavior + +compatible: "zmk,behavior-key-toggle" + +include: one_param.yaml diff --git a/app/dts/bindings/behaviors/zmk,behavior-macro-one-param.yaml b/app/dts/bindings/behaviors/zmk,behavior-macro-one-param.yaml new file mode 100644 index 000000000000..4fe5a2fba1e1 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-macro-one-param.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Macro Behavior + +compatible: "zmk,behavior-macro-one-param" + +include: [one_param.yaml, macro_base.yaml] diff --git a/app/dts/bindings/behaviors/zmk,behavior-macro-two-param.yaml b/app/dts/bindings/behaviors/zmk,behavior-macro-two-param.yaml new file mode 100644 index 000000000000..ab6e32b48ecd --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-macro-two-param.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Macro Behavior + +compatible: "zmk,behavior-macro-two-param" + +include: [two_param.yaml, macro_base.yaml] diff --git a/app/dts/bindings/behaviors/zmk,behavior-macro.yaml b/app/dts/bindings/behaviors/zmk,behavior-macro.yaml new file mode 100644 index 000000000000..035dd943542f --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-macro.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Macro Behavior + +compatible: "zmk,behavior-macro" + +include: [zero_param.yaml, macro_base.yaml] diff --git a/app/dts/bindings/behaviors/zmk,behavior-mod-morph.yaml b/app/dts/bindings/behaviors/zmk,behavior-mod-morph.yaml new file mode 100644 index 000000000000..20235d045f73 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-mod-morph.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Mod Morph Behavior + +compatible: "zmk,behavior-mod-morph" + +include: zero_param.yaml + +properties: + bindings: + type: phandle-array + required: true + mods: + type: int + required: true + keep-mods: + type: int + required: false diff --git a/app/dts/bindings/behaviors/zmk,behavior-momentary-layer.yaml b/app/dts/bindings/behaviors/zmk,behavior-momentary-layer.yaml new file mode 100644 index 000000000000..5423e29c402a --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-momentary-layer.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Momentary layer on press/release behavior + +compatible: "zmk,behavior-momentary-layer" + +include: one_param.yaml diff --git a/app/dts/bindings/behaviors/zmk,behavior-mouse-key-press.yaml b/app/dts/bindings/behaviors/zmk,behavior-mouse-key-press.yaml new file mode 100644 index 000000000000..8540916b72a7 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-mouse-key-press.yaml @@ -0,0 +1,5 @@ +description: Mouse key press/release behavior + +compatible: "zmk,behavior-mouse-key-press" + +include: one_param.yaml diff --git a/app/dts/bindings/behaviors/zmk,behavior-none.yaml b/app/dts/bindings/behaviors/zmk,behavior-none.yaml new file mode 100644 index 000000000000..42d225879870 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-none.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: None Binding Behavior + +compatible: "zmk,behavior-none" + +include: zero_param.yaml diff --git a/app/dts/bindings/behaviors/zmk,behavior-outputs.yaml b/app/dts/bindings/behaviors/zmk,behavior-outputs.yaml new file mode 100644 index 000000000000..6bc0c8371993 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-outputs.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Output Selection Behavior + +compatible: "zmk,behavior-outputs" + +include: one_param.yaml diff --git a/app/dts/bindings/behaviors/zmk,behavior-reset.yaml b/app/dts/bindings/behaviors/zmk,behavior-reset.yaml new file mode 100644 index 000000000000..9eb7aa6a3c49 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-reset.yaml @@ -0,0 +1,13 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Keyboard Reset Behavior + +compatible: "zmk,behavior-reset" + +include: zero_param.yaml + +properties: + type: + type: int + default: 0 diff --git a/app/dts/bindings/behaviors/zmk,behavior-rgb-underglow.yaml b/app/dts/bindings/behaviors/zmk,behavior-rgb-underglow.yaml new file mode 100644 index 000000000000..d301998ac6eb --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-rgb-underglow.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: RGB Underglow Action + +compatible: "zmk,behavior-rgb-underglow" + +include: two_param.yaml diff --git a/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate-var.yaml b/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate-var.yaml new file mode 100644 index 000000000000..d286f9c4c1bb --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate-var.yaml @@ -0,0 +1,26 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Sensor rotate behavior + +compatible: "zmk,behavior-sensor-rotate-var" + +properties: + label: + type: string + required: false + deprecated: true + "#sensor-binding-cells": + type: int + required: true + const: 2 + bindings: + type: phandles + required: true + tap-ms: + type: int + default: 5 + +sensor-binding-cells: + - param1 + - param2 diff --git a/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate.yaml b/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate.yaml new file mode 100644 index 000000000000..dbb92c8bcfa7 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate.yaml @@ -0,0 +1,22 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Sensor rotate behavior + +compatible: "zmk,behavior-sensor-rotate" + +properties: + label: + type: string + required: false + deprecated: true + "#sensor-binding-cells": + type: int + required: true + const: 0 + bindings: + type: phandle-array + required: true + tap-ms: + type: int + default: 5 diff --git a/app/dts/bindings/behaviors/zmk,behavior-sticky-key.yaml b/app/dts/bindings/behaviors/zmk,behavior-sticky-key.yaml new file mode 100644 index 000000000000..172f20a2b18e --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-sticky-key.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Sticky key behavior + +compatible: "zmk,behavior-sticky-key" + +include: one_param.yaml + +properties: + bindings: + type: phandles + required: true + release-after-ms: + type: int + required: true + quick-release: + type: boolean + ignore-modifiers: + type: boolean diff --git a/app/dts/bindings/behaviors/zmk,behavior-tap-dance.yaml b/app/dts/bindings/behaviors/zmk,behavior-tap-dance.yaml new file mode 100644 index 000000000000..82e1517dac97 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-tap-dance.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Tap Dance Behavior + +compatible: "zmk,behavior-tap-dance" + +include: zero_param.yaml + +properties: + bindings: + type: phandle-array + required: true + tapping-term-ms: + type: int + default: 200 diff --git a/app/dts/bindings/behaviors/zmk,behavior-to-layer.yaml b/app/dts/bindings/behaviors/zmk,behavior-to-layer.yaml new file mode 100644 index 000000000000..cbafddf73a05 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-to-layer.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: To Layer + +compatible: "zmk,behavior-to-layer" + +include: one_param.yaml diff --git a/app/dts/bindings/behaviors/zmk,behavior-toggle-layer.yaml b/app/dts/bindings/behaviors/zmk,behavior-toggle-layer.yaml new file mode 100644 index 000000000000..0a9723f7bc5a --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-toggle-layer.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Toggle Layer + +compatible: "zmk,behavior-toggle-layer" + +include: one_param.yaml diff --git a/app/dts/bindings/behaviors/zmk,behavior-transparent.yaml b/app/dts/bindings/behaviors/zmk,behavior-transparent.yaml new file mode 100644 index 000000000000..97295fcce7bf --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-transparent.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Transparent Binding Behavior + +compatible: "zmk,behavior-transparent" + +include: zero_param.yaml diff --git a/app/dts/bindings/macros/zmk,macro-control-mode-press.yaml b/app/dts/bindings/macros/zmk,macro-control-mode-press.yaml new file mode 100644 index 000000000000..57603f3a14a3 --- /dev/null +++ b/app/dts/bindings/macros/zmk,macro-control-mode-press.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Set Macro To Press Mode + +compatible: "zmk,macro-control-mode-press" + +include: zero_param.yaml diff --git a/app/dts/bindings/macros/zmk,macro-control-mode-release.yaml b/app/dts/bindings/macros/zmk,macro-control-mode-release.yaml new file mode 100644 index 000000000000..cd4ee2b651bb --- /dev/null +++ b/app/dts/bindings/macros/zmk,macro-control-mode-release.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Set Macro To Release Mode + +compatible: "zmk,macro-control-mode-release" + +include: zero_param.yaml diff --git a/app/dts/bindings/macros/zmk,macro-control-mode-tap.yaml b/app/dts/bindings/macros/zmk,macro-control-mode-tap.yaml new file mode 100644 index 000000000000..dde32c91741a --- /dev/null +++ b/app/dts/bindings/macros/zmk,macro-control-mode-tap.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Set Macro To Tap Mode + +compatible: "zmk,macro-control-mode-tap" + +include: zero_param.yaml diff --git a/app/dts/bindings/macros/zmk,macro-control-tap-time.yaml b/app/dts/bindings/macros/zmk,macro-control-tap-time.yaml new file mode 100644 index 000000000000..f3bfcd5fd5e8 --- /dev/null +++ b/app/dts/bindings/macros/zmk,macro-control-tap-time.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Set Macro Tap Duration + +compatible: "zmk,macro-control-tap-time" + +include: one_param.yaml diff --git a/app/dts/bindings/macros/zmk,macro-control-wait-time.yaml b/app/dts/bindings/macros/zmk,macro-control-wait-time.yaml new file mode 100644 index 000000000000..45da69faa493 --- /dev/null +++ b/app/dts/bindings/macros/zmk,macro-control-wait-time.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Set Macro Wait Duration + +compatible: "zmk,macro-control-wait-time" + +include: one_param.yaml diff --git a/app/dts/bindings/macros/zmk,macro-param-1to1.yaml b/app/dts/bindings/macros/zmk,macro-param-1to1.yaml new file mode 100644 index 000000000000..ae0d54dfbebb --- /dev/null +++ b/app/dts/bindings/macros/zmk,macro-param-1to1.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Macro Parameter One Substituted Into Next Binding's First Parameter + +compatible: "zmk,macro-param-1to1" + +include: zero_param.yaml diff --git a/app/dts/bindings/macros/zmk,macro-param-1to2.yaml b/app/dts/bindings/macros/zmk,macro-param-1to2.yaml new file mode 100644 index 000000000000..1018526cbea4 --- /dev/null +++ b/app/dts/bindings/macros/zmk,macro-param-1to2.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Macro Parameter One Substituted Into Next Binding's Second Parameter + +compatible: "zmk,macro-param-1to2" + +include: zero_param.yaml diff --git a/app/dts/bindings/macros/zmk,macro-param-2to1.yaml b/app/dts/bindings/macros/zmk,macro-param-2to1.yaml new file mode 100644 index 000000000000..3ebf8fc905da --- /dev/null +++ b/app/dts/bindings/macros/zmk,macro-param-2to1.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Macro Parameter Two Substituted Into Next Binding's First Parameter + +compatible: "zmk,macro-param-2to1" + +include: zero_param.yaml diff --git a/app/dts/bindings/macros/zmk,macro-param-2to2.yaml b/app/dts/bindings/macros/zmk,macro-param-2to2.yaml new file mode 100644 index 000000000000..e3ebe40fb3a3 --- /dev/null +++ b/app/dts/bindings/macros/zmk,macro-param-2to2.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Macro Parameter Two Substituted Into Next Binding's Second Parameter + +compatible: "zmk,macro-param-2to2" + +include: zero_param.yaml diff --git a/app/dts/bindings/macros/zmk,macro-pause-for-release.yaml b/app/dts/bindings/macros/zmk,macro-pause-for-release.yaml new file mode 100644 index 000000000000..929e2a29f735 --- /dev/null +++ b/app/dts/bindings/macros/zmk,macro-pause-for-release.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Macro Pause Until Release Marker + +compatible: "zmk,macro-pause-for-release" + +include: zero_param.yaml diff --git a/app/dts/bindings/vendor-prefixes.txt b/app/dts/bindings/vendor-prefixes.txt new file mode 100644 index 000000000000..72066dfb94f4 --- /dev/null +++ b/app/dts/bindings/vendor-prefixes.txt @@ -0,0 +1 @@ +zmk ZMK Project \ No newline at end of file diff --git a/app/dts/bindings/zmk,combos.yaml b/app/dts/bindings/zmk,combos.yaml new file mode 100644 index 000000000000..f146ab7a2307 --- /dev/null +++ b/app/dts/bindings/zmk,combos.yaml @@ -0,0 +1,28 @@ +# Copyright (c) 2020, The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Combos container + +compatible: "zmk,combos" + +child-binding: + description: "A combo" + + properties: + bindings: + type: phandle-array + required: true + key-positions: + type: array + required: true + timeout-ms: + type: int + default: 50 + require-prior-idle-ms: + type: int + default: -1 + slow-release: + type: boolean + layers: + type: array + default: [-1] diff --git a/app/dts/bindings/zmk,conditional-layers.yaml b/app/dts/bindings/zmk,conditional-layers.yaml new file mode 100644 index 000000000000..7e79038ea334 --- /dev/null +++ b/app/dts/bindings/zmk,conditional-layers.yaml @@ -0,0 +1,17 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Conditional layers allow layer combinations to trigger additional layers + +compatible: "zmk,conditional-layers" + +child-binding: + description: "Single conditional layer that activates then-layer when if-layers are active" + + properties: + if-layers: + type: array + required: true + then-layer: + type: int + required: true diff --git a/app/dts/bindings/zmk,ext-power-generic.yaml b/app/dts/bindings/zmk,ext-power-generic.yaml new file mode 100644 index 000000000000..cb2a16b57ba4 --- /dev/null +++ b/app/dts/bindings/zmk,ext-power-generic.yaml @@ -0,0 +1,22 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: | + Generic driver for controlling the external power output + by toggling the control-gpio pin status + (Only in supported hardware) + +compatible: "zmk,ext-power-generic" + +properties: + control-gpios: + type: phandle-array + required: true + label: + type: string + required: false + deprecated: true + init-delay-ms: + type: int + description: Number of milliseconds to delay after initializing driver + required: false diff --git a/app/dts/bindings/zmk,keymap-sensors.yaml b/app/dts/bindings/zmk,keymap-sensors.yaml new file mode 100644 index 000000000000..5282f25b04ec --- /dev/null +++ b/app/dts/bindings/zmk,keymap-sensors.yaml @@ -0,0 +1,22 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: | + Allows defining the collection of sensors bound in the keymap layers + +compatible: "zmk,keymap-sensors" + +properties: + sensors: + type: phandles + required: false + triggers-per-rotation: + type: int + required: false + +child-binding: + description: Per-sensor configuration settings + properties: + triggers-per-rotation: + type: int + required: false diff --git a/app/dts/bindings/zmk,keymap.yaml b/app/dts/bindings/zmk,keymap.yaml new file mode 100644 index 000000000000..4c675d212376 --- /dev/null +++ b/app/dts/bindings/zmk,keymap.yaml @@ -0,0 +1,25 @@ +description: | + Allows defining a keymap composed of multiple layers + +compatible: "zmk,keymap" + +child-binding: + description: "A layer to be used in a keymap" + + properties: + display-name: + type: string + required: false + description: The name of this layer to show on displays + bindings: + type: phandle-array + required: true + sensor-bindings: + type: phandle-array + required: false + + label: + type: string + required: false + deprecated: true + description: Deprecated. Use "name" instead. diff --git a/app/dts/bindings/zmk,kscan-composite.yaml b/app/dts/bindings/zmk,kscan-composite.yaml new file mode 100644 index 000000000000..857ef34fa4f7 --- /dev/null +++ b/app/dts/bindings/zmk,kscan-composite.yaml @@ -0,0 +1,31 @@ +description: | + Allows composing multiple KSCAN devices into one virtual device + +compatible: "zmk,kscan-composite" + +properties: + label: + type: string + required: false + deprecated: true + rows: + type: int + columns: + type: int + +child-binding: + description: "Details of an included KSCAN devices" + + properties: + label: + type: string + required: false + deprecated: true + kscan: + type: phandle + row-offset: + type: int + default: 0 + column-offset: + type: int + default: 0 diff --git a/app/dts/bindings/zmk,kscan-mock.yaml b/app/dts/bindings/zmk,kscan-mock.yaml new file mode 100644 index 000000000000..2fe9360c71f3 --- /dev/null +++ b/app/dts/bindings/zmk,kscan-mock.yaml @@ -0,0 +1,21 @@ +description: | + Allows defining a mock keyboard scan driver that simulates periodic events. + +compatible: "zmk,kscan-mock" + +properties: + label: + type: string + required: false + deprecated: true + event-period: + type: int + description: Milliseconds between each generated event + events: + type: array + rows: + type: int + columns: + type: int + exit-after: + type: boolean diff --git a/app/dts/bindings/zmk,matrix-transform.yaml b/app/dts/bindings/zmk,matrix-transform.yaml new file mode 100644 index 000000000000..4392bf52e31e --- /dev/null +++ b/app/dts/bindings/zmk,matrix-transform.yaml @@ -0,0 +1,21 @@ +description: | + Defines a mapping from keymap logical positions to matrix physical positions + +compatible: "zmk,matrix-transform" + +properties: + columns: + type: int + required: true + rows: + type: int + required: true + col-offset: + type: int + default: 0 + row-offset: + type: int + default: 0 + map: + type: array + required: true diff --git a/app/dts/common/arduino_uno_pro_micro_map.dtsi b/app/dts/common/arduino_uno_pro_micro_map.dtsi new file mode 100644 index 000000000000..a6b8d792d1af --- /dev/null +++ b/app/dts/common/arduino_uno_pro_micro_map.dtsi @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/* This provies a mapping from Arduino Uno to Arduino Pro Micro pins for development */ + +/ { + pro_micro_d: connector_d { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &arduino_header 6 0> /* D0 */ + , <1 0 &arduino_header 7 0> /* D1 */ + , <2 0 &arduino_header 8 0> /* D2 */ + , <3 0 &arduino_header 9 0> /* D3 */ + , <4 0 &arduino_header 10 0> /* D4/A6 */ + , <5 0 &arduino_header 11 0> /* D5 */ + , <6 0 &arduino_header 12 0> /* D6/A7 */ + , <7 0 &arduino_header 13 0> /* D7 */ + , <8 0 &arduino_header 14 0> /* D8/A8 */ + , <9 0 &arduino_header 15 0> /* D9/A9 */ + , <10 0 &arduino_header 16 0> /* D10/A10 */ + , <16 0 &arduino_header 17 0> /* D16 */ + , <14 0 &arduino_header 18 0> /* D14 */ + , <15 0 &arduino_header 19 0> /* D15 */ + ; + }; + + pro_micro_a: connector_a { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &arduino_header 0 0> /* A0 */ + , <1 0 &arduino_header 1 0> /* A1 */ + , <2 0 &arduino_header 2 0> /* A2 */ + , <3 0 &arduino_header 3 0> /* A3 */ + ; + }; +}; + +pro_micro_i2c: &arduino_i2c {}; +pro_micro_spi: &arduino_spi {}; +pro_micro_serial: &arduino_serial {}; diff --git a/app/include/drivers/behavior.h b/app/include/drivers/behavior.h new file mode 100644 index 000000000000..3936da5e4be0 --- /dev/null +++ b/app/include/drivers/behavior.h @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @cond INTERNAL_HIDDEN + * + * Behavior driver API definition and system call entry points. + * + * (Internal use only.) + */ + +enum behavior_sensor_binding_process_mode { + BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_TRIGGER, + BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_DISCARD, +}; + +typedef int (*behavior_keymap_binding_callback_t)(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event); +typedef int (*behavior_sensor_keymap_binding_process_callback_t)( + struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, + enum behavior_sensor_binding_process_mode mode); +typedef int (*behavior_sensor_keymap_binding_accept_data_callback_t)( + struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, + const struct zmk_sensor_config *sensor_config, size_t channel_data_size, + const struct zmk_sensor_channel_data channel_data[channel_data_size]); + +enum behavior_locality { + BEHAVIOR_LOCALITY_CENTRAL, + BEHAVIOR_LOCALITY_EVENT_SOURCE, + BEHAVIOR_LOCALITY_GLOBAL +}; + +__subsystem struct behavior_driver_api { + enum behavior_locality locality; + behavior_keymap_binding_callback_t binding_convert_central_state_dependent_params; + behavior_keymap_binding_callback_t binding_pressed; + behavior_keymap_binding_callback_t binding_released; + behavior_sensor_keymap_binding_accept_data_callback_t sensor_binding_accept_data; + behavior_sensor_keymap_binding_process_callback_t sensor_binding_process; +}; +/** + * @endcond + */ + +struct zmk_behavior_ref { + const struct device *device; +}; + +/** + * Registers @p node_id as a behavior. + */ +#define BEHAVIOR_DEFINE(node_id) \ + static const STRUCT_SECTION_ITERABLE(zmk_behavior_ref, \ + _CONCAT(zmk_behavior_, DEVICE_DT_NAME_GET(node_id))) = { \ + .device = DEVICE_DT_GET(node_id), \ + } + +/** + * @brief Like DEVICE_DT_DEFINE(), but also registers the device as a behavior. + * + * @param node_id The devicetree node identifier. + * @param ... Other parameters as expected by DEVICE_DT_DEFINE. + */ +#define BEHAVIOR_DT_DEFINE(node_id, ...) \ + DEVICE_DT_DEFINE(node_id, __VA_ARGS__); \ + BEHAVIOR_DEFINE(node_id) + +/** + * @brief Like DEVICE_DT_INST_DEFINE(), but also registers the device as a behavior. + * + * @param inst Instance number. + * @param ... Other parameters as expected by DEVICE_DT_DEFINE. + */ +#define BEHAVIOR_DT_INST_DEFINE(inst, ...) \ + DEVICE_DT_INST_DEFINE(inst, __VA_ARGS__); \ + BEHAVIOR_DEFINE(DT_DRV_INST(inst)) + +/** + * Syscall wrapper for zmk_behavior_get_binding(). + * + * Use zmk_behavior_get_binding() in application code instead. + */ +__syscall const struct device *behavior_get_binding(const char *name); + +/** + * @brief Handle the keymap binding which needs to be converted from relative "toggle" to absolute + * "turn on" + * @param binding Pointer to the details so of the binding + * @param event The event that triggered use of the binding + * + * @retval 0 If successful. + * @retval Negative errno code if failure. + */ +__syscall int behavior_keymap_binding_convert_central_state_dependent_params( + struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event); + +static inline int z_impl_behavior_keymap_binding_convert_central_state_dependent_params( + struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { + const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); + const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api; + + if (api->binding_convert_central_state_dependent_params == NULL) { + return 0; + } + + return api->binding_convert_central_state_dependent_params(binding, event); +} + +/** + * @brief Determine where the behavior should be run + * @param behavior Pointer to the device structure for the driver instance. + * + * @retval Zero if successful. + * @retval Negative errno code if failure. + */ +__syscall int behavior_get_locality(const struct device *behavior, + enum behavior_locality *locality); + +static inline int z_impl_behavior_get_locality(const struct device *behavior, + enum behavior_locality *locality) { + if (behavior == NULL) { + return -EINVAL; + } + + const struct behavior_driver_api *api = (const struct behavior_driver_api *)behavior->api; + *locality = api->locality; + + return 0; +} + +/** + * @brief Handle the keymap binding being pressed + * @param dev Pointer to the device structure for the driver instance. + * @param param1 User parameter specified at time of behavior binding. + * @param param2 User parameter specified at time of behavior binding. + * + * @retval 0 If successful. + * @retval Negative errno code if failure. + */ +__syscall int behavior_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event); + +static inline int z_impl_behavior_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); + + if (dev == NULL) { + return -EINVAL; + } + + const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api; + + if (api->binding_pressed == NULL) { + return -ENOTSUP; + } + + return api->binding_pressed(binding, event); +} + +/** + * @brief Handle the assigned position being pressed + * @param dev Pointer to the device structure for the driver instance. + * @param param1 User parameter specified at time of behavior assignment. + * + * @retval 0 If successful. + * @retval Negative errno code if failure. + */ +__syscall int behavior_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event); + +static inline int z_impl_behavior_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); + + if (dev == NULL) { + return -EINVAL; + } + + const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api; + + if (api->binding_released == NULL) { + return -ENOTSUP; + } + + return api->binding_released(binding, event); +} + +/** + * @brief Handle the a sensor keymap binding processing any incoming data from the sensor + * @param binding Sensor keymap binding which was triggered. + * @param sensor Pointer to the sensor device structure for the sensor driver instance. + * @param virtual_key_position ZMK_KEYMAP_LEN + sensor number + * @param timestamp Time at which the binding was triggered. + * + * @retval 0 If successful. + * @retval Negative errno code if failure. + */ +__syscall int behavior_sensor_keymap_binding_accept_data( + struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, + const struct zmk_sensor_config *sensor_config, size_t channel_data_size, + const struct zmk_sensor_channel_data *channel_data); + +static inline int z_impl_behavior_sensor_keymap_binding_accept_data( + struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, + const struct zmk_sensor_config *sensor_config, size_t channel_data_size, + const struct zmk_sensor_channel_data *channel_data) { + const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); + + if (dev == NULL) { + return -EINVAL; + } + + const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api; + + if (api->sensor_binding_accept_data == NULL) { + return -ENOTSUP; + } + + return api->sensor_binding_accept_data(binding, event, sensor_config, channel_data_size, + channel_data); +} + +/** + * @brief Handle the keymap sensor binding being triggered after updating any local data + * @param dev Pointer to the device structure for the driver instance. + * @param param1 User parameter specified at time of behavior binding. + * @param param2 User parameter specified at time of behavior binding. + * + * @retval 0 If successful. + * @retval Negative errno code if failure. + */ +// clang-format off +__syscall int behavior_sensor_keymap_binding_process( + struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event, + enum behavior_sensor_binding_process_mode mode); +// clang-format on + +static inline int +z_impl_behavior_sensor_keymap_binding_process(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event, + enum behavior_sensor_binding_process_mode mode) { + const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); + + if (dev == NULL) { + return -EINVAL; + } + + const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api; + + if (api->sensor_binding_process == NULL) { + return -ENOTSUP; + } + + return api->sensor_binding_process(binding, event, mode); +} + +/** + * @} + */ + +#include diff --git a/app/include/drivers/ext_power.h b/app/include/drivers/ext_power.h new file mode 100644 index 000000000000..287679e16917 --- /dev/null +++ b/app/include/drivers/ext_power.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @cond INTERNAL_HIDDEN + * + * Behavior driver API definition and system call entry points. + * + * (Internal use only.) + */ + +typedef int (*ext_power_enable_t)(const struct device *dev); +typedef int (*ext_power_disable_t)(const struct device *dev); +typedef int (*ext_power_get_t)(const struct device *dev); + +__subsystem struct ext_power_api { + ext_power_enable_t enable; + ext_power_disable_t disable; + ext_power_get_t get; +}; +/** + * @endcond + */ + +/** + * @brief Enable the external power output + * @param dev Pointer to the device structure for the driver instance. + * + * @retval 0 If successful. + * @retval Negative errno code if failure. + */ +__syscall int ext_power_enable(const struct device *dev); + +static inline int z_impl_ext_power_enable(const struct device *dev) { + const struct ext_power_api *api = (const struct ext_power_api *)dev->api; + + if (api->enable == NULL) { + return -ENOTSUP; + } + + return api->enable(dev); +} + +/** + * @brief Disable the external power output + * @param dev Pointer to the device structure for the driver instance. + * + * @retval 0 If successful. + * @retval Negative errno code if failure. + */ +__syscall int ext_power_disable(const struct device *dev); + +static inline int z_impl_ext_power_disable(const struct device *dev) { + const struct ext_power_api *api = (const struct ext_power_api *)dev->api; + + if (api->disable == NULL) { + return -ENOTSUP; + } + + return api->disable(dev); +} + +/** + * @brief Get the current status of the external power output + * @param dev Pointer to the device structure for the driver instance. + * + * @retval 0 If ext power is disabled. + * @retval 1 if ext power is enabled. + * @retval Negative errno code if failure. + */ +__syscall int ext_power_get(const struct device *dev); + +static inline int z_impl_ext_power_get(const struct device *dev) { + const struct ext_power_api *api = (const struct ext_power_api *)dev->api; + + if (api->get == NULL) { + return -ENOTSUP; + } + + return api->get(dev); +} + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#include diff --git a/app/include/dt-bindings/zmk/backlight.h b/app/include/dt-bindings/zmk/backlight.h new file mode 100644 index 000000000000..0802e2ce4ccd --- /dev/null +++ b/app/include/dt-bindings/zmk/backlight.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define BL_ON_CMD 0 +#define BL_OFF_CMD 1 +#define BL_TOG_CMD 2 +#define BL_INC_CMD 3 +#define BL_DEC_CMD 4 +#define BL_CYCLE_CMD 5 +#define BL_SET_CMD 6 + +#define BL_ON BL_ON_CMD 0 +#define BL_OFF BL_OFF_CMD 0 +#define BL_TOG BL_TOG_CMD 0 +#define BL_INC BL_INC_CMD 0 +#define BL_DEC BL_DEC_CMD 0 +#define BL_CYCLE BL_CYCLE_CMD 0 +#define BL_SET BL_SET_CMD diff --git a/app/include/dt-bindings/zmk/bt.h b/app/include/dt-bindings/zmk/bt.h new file mode 100644 index 000000000000..7af89ddb011c --- /dev/null +++ b/app/include/dt-bindings/zmk/bt.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define BT_CLR_CMD 0 +#define BT_NXT_CMD 1 +#define BT_PRV_CMD 2 +#define BT_SEL_CMD 3 +// #define BT_FULL_RESET_CMD 4 +#define BT_DISC_CMD 5 + +/* +Note: Some future commands will include additional parameters, so we +defines these aliases up front. +*/ + +#define BT_CLR BT_CLR_CMD 0 +#define BT_NXT BT_NXT_CMD 0 +#define BT_PRV BT_PRV_CMD 0 +#define BT_SEL BT_SEL_CMD +#define BT_DISC BT_DISC_CMD diff --git a/app/include/dt-bindings/zmk/ext_power.h b/app/include/dt-bindings/zmk/ext_power.h new file mode 100644 index 000000000000..2a3e8460a6d3 --- /dev/null +++ b/app/include/dt-bindings/zmk/ext_power.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define EXT_POWER_OFF_CMD 0 +#define EXT_POWER_ON_CMD 1 +#define EXT_POWER_TOGGLE_CMD 2 + +#define EP_ON EXT_POWER_ON_CMD +#define EP_OFF EXT_POWER_OFF_CMD +#define EP_TOG EXT_POWER_TOGGLE_CMD diff --git a/app/include/dt-bindings/zmk/hid_usage.h b/app/include/dt-bindings/zmk/hid_usage.h new file mode 100644 index 000000000000..0555f004c11b --- /dev/null +++ b/app/include/dt-bindings/zmk/hid_usage.h @@ -0,0 +1,2566 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + * + * Based on HID Usage Tables 1.21, + * Copyright © 1996-2020, USB Implementers Forum, + * https://www.usb.org/sites/default/files/hut1_21.pdf + */ + +#pragma once + +/* Page 0x01: Generic Desktop */ +#define HID_USAGE_GD_UNDEFINED (0x00) +#define HID_USAGE_GD_POINTER (0x01) // CP +#define HID_USAGE_GD_MOUSE (0x02) // CA +#define HID_USAGE_GD_JOYSTICK (0x04) // CA +#define HID_USAGE_GD_GAMEPAD (0x05) // CA +#define HID_USAGE_GD_KEYBOARD (0x06) // CA +#define HID_USAGE_GD_KEYPAD (0x07) // CA +#define HID_USAGE_GD_MULTI_AXIS_CONTROLLER (0x08) // CA +#define HID_USAGE_GD_TABLET_PC_SYSTEM_CONTROLS (0x09) // CA +#define HID_USAGE_GD_WATER_COOLING_DEVICE (0x0A) // CA +#define HID_USAGE_GD_COMPUTER_CHASSIS_DEVICE (0x0B) // CA +#define HID_USAGE_GD_WIRELESS_RADIO_CONTROLS (0x0C) // CA +#define HID_USAGE_GD_PORTABLE_DEVICE_CONTROL (0x0D) // CA +#define HID_USAGE_GD_SYSTEM_MULTI_AXIS_CONTROLLER (0x0E) // CA +#define HID_USAGE_GD_SPATIAL_CONTROLLER (0x0F) // CA +#define HID_USAGE_GD_ASSISTIVE_CONTROL (0x10) // CA +#define HID_USAGE_GD_DEVICE_DOCK (0x11) // CA +#define HID_USAGE_GD_DOCKABLE_DEVICE (0x12) // CA +#define HID_USAGE_GD_X (0x30) // DV +#define HID_USAGE_GD_Y (0x31) // DV +#define HID_USAGE_GD_Z (0x32) // DV +#define HID_USAGE_GD_RX (0x33) // DV +#define HID_USAGE_GD_RY (0x34) // DV +#define HID_USAGE_GD_RZ (0x35) // DV +#define HID_USAGE_GD_SLIDER (0x36) // DV +#define HID_USAGE_GD_DIAL (0x37) // DV +#define HID_USAGE_GD_WHEEL (0x38) // DV +#define HID_USAGE_GD_HAT_SWITCH (0x39) // DV +#define HID_USAGE_GD_COUNTED_BUFFER (0x3A) // CL +#define HID_USAGE_GD_BYTE_COUNT (0x3B) // DV +#define HID_USAGE_GD_MOTION_WAKEUP (0x3C) // OSC, DF +#define HID_USAGE_GD_START (0x3D) // OOC +#define HID_USAGE_GD_SELECT (0x3E) // OOC +#define HID_USAGE_GD_VX (0x40) // DV +#define HID_USAGE_GD_VY (0x41) // DV +#define HID_USAGE_GD_VZ (0x42) // DV +#define HID_USAGE_GD_VBRX (0x43) // DV +#define HID_USAGE_GD_VBRY (0x44) // DV +#define HID_USAGE_GD_VBRZ (0x45) // DV +#define HID_USAGE_GD_VNO (0x46) // DV +#define HID_USAGE_GD_FEATURE_NOTIFICATION (0x47) // DV, DF +#define HID_USAGE_GD_RESOLUTION_MULTIPLIER (0x48) // DV +#define HID_USAGE_GD_QX (0x49) // DV +#define HID_USAGE_GD_QY (0x4A) // DV +#define HID_USAGE_GD_QZ (0x4B) // DV +#define HID_USAGE_GD_QW (0x4C) // DV +#define HID_USAGE_GD_SYSTEM_CONTROL (0x80) // CA +#define HID_USAGE_GD_SYSTEM_POWER_DOWN (0x81) // OSC +#define HID_USAGE_GD_SYSTEM_SLEEP (0x82) // OSC +#define HID_USAGE_GD_SYSTEM_WAKE_UP (0x83) // OSC +#define HID_USAGE_GD_SYSTEM_CONTEXT_MENU (0x84) // OSC +#define HID_USAGE_GD_SYSTEM_MAIN_MENU (0x85) // OSC +#define HID_USAGE_GD_SYSTEM_APP_MENU (0x86) // OSC +#define HID_USAGE_GD_SYSTEM_MENU_HELP (0x87) // OSC +#define HID_USAGE_GD_SYSTEM_MENU_EXIT (0x88) // OSC +#define HID_USAGE_GD_SYSTEM_MENU_SELECT (0x89) // OSC +#define HID_USAGE_GD_SYSTEM_MENU_RIGHT (0x8A) // RTC +#define HID_USAGE_GD_SYSTEM_MENU_LEFT (0x8B) // RTC +#define HID_USAGE_GD_SYSTEM_MENU_UP (0x8C) // RTC +#define HID_USAGE_GD_SYSTEM_MENU_DOWN (0x8D) // RTC +#define HID_USAGE_GD_SYSTEM_COLD_RESTART (0x8E) // OSC +#define HID_USAGE_GD_SYSTEM_WARM_RESTART (0x8F) // OSC +#define HID_USAGE_GD_D_PAD_UP (0x90) // OOC +#define HID_USAGE_GD_D_PAD_DOWN (0x91) // OOC +#define HID_USAGE_GD_D_PAD_RIGHT (0x92) // OOC +#define HID_USAGE_GD_D_PAD_LEFT (0x93) // OOC +#define HID_USAGE_GD_INDEX_TRIGGER (0x94) // MC, DV +#define HID_USAGE_GD_PALM_TRIGGER (0x95) // MC, DV +#define HID_USAGE_GD_THUMBSTICK (0x96) // CP +#define HID_USAGE_GD_SYSTEM_FUNCTION_SHIFT (0x97) // MC +#define HID_USAGE_GD_SYSTEM_FUNCTION_SHIFT_LOCK (0x98) // OOC +#define HID_USAGE_GD_SYSTEM_FUNCTION_SHIFT_LOCK_INDICATOR (0x99) // DV +#define HID_USAGE_GD_SYSTEM_DISMISS_NOTIFICATION (0x9A) // OSC +#define HID_USAGE_GD_SYSTEM_DO_NOT_DISTURB (0x9B) // OOC +#define HID_USAGE_GD_SYSTEM_DOCK (0xA0) // OSC +#define HID_USAGE_GD_SYSTEM_UNDOCK (0xA1) // OSC +#define HID_USAGE_GD_SYSTEM_SETUP (0xA2) // OSC +#define HID_USAGE_GD_SYSTEM_BREAK (0xA3) // OSC +#define HID_USAGE_GD_SYSTEM_DEBUGGER_BREAK (0xA4) // OSC +#define HID_USAGE_GD_APPLICATION_BREAK (0xA5) // OSC +#define HID_USAGE_GD_APPLICATION_DEBUGGER_BREAK (0xA6) // OSC +#define HID_USAGE_GD_SYSTEM_SPEAKER_MUTE (0xA7) // OSC +#define HID_USAGE_GD_SYSTEM_HIBERNATE (0xA8) // OSC +#define HID_USAGE_GD_SYSTEM_DISPLAY_INVERT (0xB0) // OSC +#define HID_USAGE_GD_SYSTEM_DISPLAY_INTERNAL (0xB1) // OSC +#define HID_USAGE_GD_SYSTEM_DISPLAY_EXTERNAL (0xB2) // OSC +#define HID_USAGE_GD_SYSTEM_DISPLAY_BOTH (0xB3) // OSC +#define HID_USAGE_GD_SYSTEM_DISPLAY_DUAL (0xB4) // OSC +#define HID_USAGE_GD_SYSTEM_DISPLAY_TOGGLE_INT_EXT_MODE (0xB5) // OSC +#define HID_USAGE_GD_SYSTEM_DISPLAY_SWAP_PRIMARY_SECONDARY (0xB6) // OSC +#define HID_USAGE_GD_SYSTEM_DISPLAY_TOGGLE_LCD_AUTOSCALE (0xB7) // OSC +#define HID_USAGE_GD_SENSOR_ZONE (0xC0) // CL +#define HID_USAGE_GD_RPM (0xC1) // DV +#define HID_USAGE_GD_COOLANT_LEVEL (0xC2) // DV +#define HID_USAGE_GD_COOLANT_CRITICAL_LEVEL (0xC3) // SV +#define HID_USAGE_GD_COOLANT_PUMP (0xC4) // US +#define HID_USAGE_GD_CHASSIS_ENCLOSURE (0xC5) // CL +#define HID_USAGE_GD_WIRELESS_RADIO_BUTTON (0xC6) // OOC +#define HID_USAGE_GD_WIRELESS_RADIO_LED (0xC7) // OOC +#define HID_USAGE_GD_WIRELESS_RADIO_SLIDER_SWITCH (0xC8) // OOC +#define HID_USAGE_GD_SYSTEM_DISPLAY_ROTATION_LOCK_BUTTON (0xC9) // OOC +#define HID_USAGE_GD_SYSTEM_DISPLAY_ROTATION_LOCK_SLIDER_SWITCH (0xCA) // OOC +#define HID_USAGE_GD_CONTROL_ENABLE (0xCB) // DF +#define HID_USAGE_GD_DOCKABLE_DEVICE_UNIQUE_ID (0xD0) // DV +#define HID_USAGE_GD_DOCKABLE_DEVICE_VENDOR_ID (0xD1) // DV +#define HID_USAGE_GD_DOCKABLE_DEVICE_PRIMARY_USAGE_PAGE (0xD2) // DV +#define HID_USAGE_GD_DOCKABLE_DEVICE_PRIMARY_USAGE_ID (0xD3) // DV +#define HID_USAGE_GD_DOCKABLE_DEVICE_DOCKING_STATE (0xD4) // DF +#define HID_USAGE_GD_DOCKABLE_DEVICE_DISPLAY_OCCLUSION (0xD5) // CL +#define HID_USAGE_GD_DOCKABLE_DEVICE_OBJECT_TYPE (0xD6) // DV + +/* Page 0x02: Simulation Controls */ +#define HID_USAGE_SIM_UNDEFINED (0x00) +#define HID_USAGE_SIM_FLIGHT_SIMULATION_DEVICE (0x01) // CA +#define HID_USAGE_SIM_AUTOMOBILE_SIMULATION_DEVICE (0x02) // CA +#define HID_USAGE_SIM_TANK_SIMULATION_DEVICE (0x03) // CA +#define HID_USAGE_SIM_SPACESHIP_SIMULATION_DEVICE (0x04) // CA +#define HID_USAGE_SIM_SUBMARINE_SIMULATION_DEVICE (0x05) // CA +#define HID_USAGE_SIM_SAILING_SIMULATION_DEVICE (0x06) // CA +#define HID_USAGE_SIM_MOTORCYCLE_SIMULATION_DEVICE (0x07) // CA +#define HID_USAGE_SIM_SPORTS_SIMULATION_DEVICE (0x08) // CA +#define HID_USAGE_SIM_AIRPLANE_SIMULATION_DEVICE (0x09) // CA +#define HID_USAGE_SIM_HELICOPTER_SIMULATION_DEVICE (0x0A) // CA +#define HID_USAGE_SIM_MAGIC_CARPET_SIMULATION_DEVICE (0x0B) // CA +#define HID_USAGE_SIM_BICYCLE_SIMULATION_DEVICE (0x0C) // CA +#define HID_USAGE_SIM_FLIGHT_CONTROL_STICK (0x20) // CA +#define HID_USAGE_SIM_FLIGHT_STICK (0x21) // CA +#define HID_USAGE_SIM_CYCLIC_CONTROL (0x22) // CP +#define HID_USAGE_SIM_CYCLIC_TRIM (0x23) // CP +#define HID_USAGE_SIM_FLIGHT_YOKE (0x24) // CA +#define HID_USAGE_SIM_TRACK_CONTROL (0x25) // CP +#define HID_USAGE_SIM_AILERON (0xB0) // DV +#define HID_USAGE_SIM_AILERON_TRIM (0xB1) // DV +#define HID_USAGE_SIM_ANTI_TORQUE_CONTROL (0xB2) // DV +#define HID_USAGE_SIM_AUTOPILOT_ENABLE (0xB3) // OOC +#define HID_USAGE_SIM_CHAFF_RELEASE (0xB4) // OSC +#define HID_USAGE_SIM_COLLECTIVE_CONTROL (0xB5) // DV +#define HID_USAGE_SIM_DIVE_BRAKE (0xB6) // DV +#define HID_USAGE_SIM_ELECTRONIC_COUNTERMEASURES (0xB7) // OOC +#define HID_USAGE_SIM_ELEVATOR (0xB8) // DV +#define HID_USAGE_SIM_ELEVATOR_TRIM (0xB9) // DV +#define HID_USAGE_SIM_RUDDER (0xBA) // DV +#define HID_USAGE_SIM_THROTTLE (0xBB) // DV +#define HID_USAGE_SIM_FLIGHT_COMMUNICATIONS (0xBC) // OOC +#define HID_USAGE_SIM_FLARE_RELEASE (0xBD) // OSC +#define HID_USAGE_SIM_LANDING_GEAR (0xBE) // OOC +#define HID_USAGE_SIM_TOE_BRAKE (0xBF) // DV +#define HID_USAGE_SIM_TRIGGER (0xC0) // MC +#define HID_USAGE_SIM_WEAPONS_ARM (0xC1) // OOC +#define HID_USAGE_SIM_WEAPONS_SELECT (0xC2) // OSC +#define HID_USAGE_SIM_WING_FLAPS (0xC3) // DV +#define HID_USAGE_SIM_ACCELERATOR (0xC4) // DV +#define HID_USAGE_SIM_BRAKE (0xC5) // DV +#define HID_USAGE_SIM_CLUTCH (0xC6) // DV +#define HID_USAGE_SIM_SHIFTER (0xC7) // DV +#define HID_USAGE_SIM_STEERING (0xC8) // DV +#define HID_USAGE_SIM_TURRET_DIRECTION (0xC9) // DV +#define HID_USAGE_SIM_BARREL_ELEVATION (0xCA) // DV +#define HID_USAGE_SIM_DIVE_PLANE (0xCB) // DV +#define HID_USAGE_SIM_BALLAST (0xCC) // DV +#define HID_USAGE_SIM_BICYCLE_CRANK (0xCD) // DV +#define HID_USAGE_SIM_HANDLE_BARS (0xCE) // DV +#define HID_USAGE_SIM_FRONT_BRAKE (0xCF) // DV +#define HID_USAGE_SIM_REAR_BRAKE (0xD0) // DV + +/* Page 0x03: VR Controls */ +#define HID_USAGE_VR_UNDEFINED (0x00) +#define HID_USAGE_VR_BELT (0x01) // CA +#define HID_USAGE_VR_BODY_SUIT (0x02) // CA +#define HID_USAGE_VR_FLEXOR (0x03) // CP +#define HID_USAGE_VR_GLOVE (0x04) // CA +#define HID_USAGE_VR_HEAD_TRACKER (0x05) // CP +#define HID_USAGE_VR_HEAD_MOUNTED_DISPLAY (0x06) // CA +#define HID_USAGE_VR_HAND_TRACKER (0x07) // CA +#define HID_USAGE_VR_OCULOMETER (0x08) // CA +#define HID_USAGE_VR_VEST (0x09) // CA +#define HID_USAGE_VR_ANIMATRONIC_DEVICE (0x0A) // CA +#define HID_USAGE_VR_STEREO_ENABLE (0x20) // OOC +#define HID_USAGE_VR_DISPLAY_ENABLE (0x21) // OOC + +/* Page 0x04: Sport Controls */ +#define HID_USAGE_SPORT_UNDEFINED (0x00) +#define HID_USAGE_SPORT_BASEBALL_BAT (0x01) // CA +#define HID_USAGE_SPORT_GOLF_CLUB (0x02) // CA +#define HID_USAGE_SPORT_ROWING_MACHINE (0x03) // CA +#define HID_USAGE_SPORT_TREADMILL (0x04) // CA +#define HID_USAGE_SPORT_OAR (0x30) // DV +#define HID_USAGE_SPORT_SLOPE (0x31) // DV +#define HID_USAGE_SPORT_RATE (0x32) // DV +#define HID_USAGE_SPORT_STICK_SPEED (0x33) // DV +#define HID_USAGE_SPORT_STICK_FACE_ANGLE (0x34) // DV +#define HID_USAGE_SPORT_STICK_HEEL_TOE (0x35) // DV +#define HID_USAGE_SPORT_STICK_FOLLOW_THROUGH (0x36) // DV +#define HID_USAGE_SPORT_STICK_TEMPO (0x37) // DV +#define HID_USAGE_SPORT_STICK_TYPE (0x38) // NAry +#define HID_USAGE_SPORT_STICK_HEIGHT (0x39) // DV +#define HID_USAGE_SPORT_PUTTER (0x50) // Sel +#define HID_USAGE_SPORT_1_IRON (0x51) // Sel +#define HID_USAGE_SPORT_2_IRON (0x52) // Sel +#define HID_USAGE_SPORT_3_IRON (0x53) // Sel +#define HID_USAGE_SPORT_4_IRON (0x54) // Sel +#define HID_USAGE_SPORT_5_IRON (0x55) // Sel +#define HID_USAGE_SPORT_6_IRON (0x56) // Sel +#define HID_USAGE_SPORT_7_IRON (0x57) // Sel +#define HID_USAGE_SPORT_8_IRON (0x58) // Sel +#define HID_USAGE_SPORT_9_IRON (0x59) // Sel +#define HID_USAGE_SPORT_10_IRON (0x5A) // Sel +#define HID_USAGE_SPORT_11_IRON (0x5B) // Sel +#define HID_USAGE_SPORT_SAND_WEDGE (0x5C) // Sel +#define HID_USAGE_SPORT_LOFT_WEDGE (0x5D) // Sel +#define HID_USAGE_SPORT_POWER_WEDGE (0x5E) // Sel +#define HID_USAGE_SPORT_1_WOOD (0x5F) // Sel +#define HID_USAGE_SPORT_3_WOOD (0x60) // Sel +#define HID_USAGE_SPORT_5_WOOD (0x61) // Sel +#define HID_USAGE_SPORT_7_WOOD (0x62) // Sel +#define HID_USAGE_SPORT_9_WOOD (0x63) // Sel + +/* Page 0x05: Game Controls */ +#define HID_USAGE_GAME_UNDEFINED (0x00) +#define HID_USAGE_GAME_3D_GAME_CONTROLLER (0x01) // CA +#define HID_USAGE_GAME_PINBALL_DEVICE (0x02) // CA +#define HID_USAGE_GAME_GUN_DEVICE (0x03) // CA +#define HID_USAGE_GAME_POINT_OF_VIEW (0x20) // CP +#define HID_USAGE_GAME_TURN_RIGHT_LEFT (0x21) // DV +#define HID_USAGE_GAME_PITCH_FORWARD_BACKWARD (0x22) // DV +#define HID_USAGE_GAME_ROLL_RIGHT_LEFT (0x23) // DV +#define HID_USAGE_GAME_MOVE_RIGHT_LEFT (0x24) // DV +#define HID_USAGE_GAME_MOVE_FORWARD_BACKWARD (0x25) // DV +#define HID_USAGE_GAME_MOVE_UP_DOWN (0x26) // DV +#define HID_USAGE_GAME_LEAN_RIGHT_LEFT (0x27) // DV +#define HID_USAGE_GAME_LEAN_FORWARD_BACKWARD (0x28) // DV +#define HID_USAGE_GAME_HEIGHT_OF_POV (0x29) // DV +#define HID_USAGE_GAME_FLIPPER (0x2A) // MC +#define HID_USAGE_GAME_SECONDARY_FLIPPER (0x2B) // MC +#define HID_USAGE_GAME_BUMP (0x2C) // MC +#define HID_USAGE_GAME_NEW_GAME (0x2D) // OSC +#define HID_USAGE_GAME_SHOOT_BALL (0x2E) // OSC +#define HID_USAGE_GAME_PLAYER (0x2F) // OSC +#define HID_USAGE_GAME_GUN_BOLT (0x30) // OOC +#define HID_USAGE_GAME_GUN_CLIP (0x31) // OOC +#define HID_USAGE_GAME_GUN_SELECTOR (0x32) // NAry +#define HID_USAGE_GAME_GUN_SINGLE_SHOT (0x33) // Sel +#define HID_USAGE_GAME_GUN_BURST (0x34) // Sel +#define HID_USAGE_GAME_GUN_AUTOMATIC (0x35) // Sel +#define HID_USAGE_GAME_GUN_SAFETY (0x36) // OOC +#define HID_USAGE_GAME_GAMEPAD_FIRE_JUMP (0x37) // CL +#define HID_USAGE_GAME_GAMEPAD_TRIGGER (0x39) // CL +#define HID_USAGE_GAME_FORM_FITTING_GAMEPAD (0x3A) // SF + +/* Page 0x06: Generic Device Controls */ +#define HID_USAGE_GDV_UNDEFINED (0x00) +#define HID_USAGE_GDV_BACKGROUND_NONUSER_CONTROLS (0x01) // CA +#define HID_USAGE_GDV_BATTERY_STRENGTH (0x20) // DV +#define HID_USAGE_GDV_WIRELESS_CHANNEL (0x21) // DV +#define HID_USAGE_GDV_WIRELESS_ID (0x22) // DV +#define HID_USAGE_GDV_DISCOVER_WIRELESS_CONTROL (0x23) // OSC +#define HID_USAGE_GDV_SECURITY_CODE_CHARACTER_ENTERED (0x24) // OSC +#define HID_USAGE_GDV_SECURITY_CODE_CHARACTER_ERASED (0x25) // OSC +#define HID_USAGE_GDV_SECURITY_CODE_CLEARED (0x26) // OSC +#define HID_USAGE_GDV_SEQUENCE_ID (0x27) // DV +#define HID_USAGE_GDV_SEQUENCE_ID_RESET (0x28) // DF +#define HID_USAGE_GDV_RF_SIGNAL_STRENGTH (0x29) // DV +#define HID_USAGE_GDV_SOFTWARE_VERSION (0x2A) // CL +#define HID_USAGE_GDV_PROTOCOL_VERSION (0x2B) // CL +#define HID_USAGE_GDV_HARDWARE_VERSION (0x2C) // CL +#define HID_USAGE_GDV_MAJOR (0x2D) // SV +#define HID_USAGE_GDV_MINOR (0x2E) // SV +#define HID_USAGE_GDV_REVISION (0x2F) // SV +#define HID_USAGE_GDV_HANDEDNESS (0x30) // NAry +#define HID_USAGE_GDV_EITHER_HAND (0x31) // Sel +#define HID_USAGE_GDV_LEFT_HAND (0x32) // Sel +#define HID_USAGE_GDV_RIGHT_HAND (0x33) // Sel +#define HID_USAGE_GDV_BOTH_HANDS (0x34) // Sel +#define HID_USAGE_GDV_GRIP_POSE_OFFSET (0x40) // CP +#define HID_USAGE_GDV_POINTER_POSE_OFFSET (0x41) // CP + +/* Page 0x07: Keyboard/Keypad */ +#define HID_USAGE_KEY_KEYBOARD_ERRORROLLOVER (0x01) // Sel +#define HID_USAGE_KEY_KEYBOARD_POSTFAIL (0x02) // Sel +#define HID_USAGE_KEY_KEYBOARD_ERRORUNDEFINED (0x03) // Sel +#define HID_USAGE_KEY_KEYBOARD_A (0x04) // Sel +#define HID_USAGE_KEY_KEYBOARD_B (0x05) // Sel +#define HID_USAGE_KEY_KEYBOARD_C (0x06) // Sel +#define HID_USAGE_KEY_KEYBOARD_D (0x07) // Sel +#define HID_USAGE_KEY_KEYBOARD_E (0x08) // Sel +#define HID_USAGE_KEY_KEYBOARD_F (0x09) // Sel +#define HID_USAGE_KEY_KEYBOARD_G (0x0A) // Sel +#define HID_USAGE_KEY_KEYBOARD_H (0x0B) // Sel +#define HID_USAGE_KEY_KEYBOARD_I (0x0C) // Sel +#define HID_USAGE_KEY_KEYBOARD_J (0x0D) // Sel +#define HID_USAGE_KEY_KEYBOARD_K (0x0E) // Sel +#define HID_USAGE_KEY_KEYBOARD_L (0x0F) // Sel +#define HID_USAGE_KEY_KEYBOARD_M (0x10) // Sel +#define HID_USAGE_KEY_KEYBOARD_N (0x11) // Sel +#define HID_USAGE_KEY_KEYBOARD_O (0x12) // Sel +#define HID_USAGE_KEY_KEYBOARD_P (0x13) // Sel +#define HID_USAGE_KEY_KEYBOARD_Q (0x14) // Sel +#define HID_USAGE_KEY_KEYBOARD_R (0x15) // Sel +#define HID_USAGE_KEY_KEYBOARD_S (0x16) // Sel +#define HID_USAGE_KEY_KEYBOARD_T (0x17) // Sel +#define HID_USAGE_KEY_KEYBOARD_U (0x18) // Sel +#define HID_USAGE_KEY_KEYBOARD_V (0x19) // Sel +#define HID_USAGE_KEY_KEYBOARD_W (0x1A) // Sel +#define HID_USAGE_KEY_KEYBOARD_X (0x1B) // Sel +#define HID_USAGE_KEY_KEYBOARD_Y (0x1C) // Sel +#define HID_USAGE_KEY_KEYBOARD_Z (0x1D) // Sel +#define HID_USAGE_KEY_KEYBOARD_1_AND_EXCLAMATION (0x1E) // Sel +#define HID_USAGE_KEY_KEYBOARD_2_AND_AT (0x1F) // Sel +#define HID_USAGE_KEY_KEYBOARD_3_AND_HASH (0x20) // Sel +#define HID_USAGE_KEY_KEYBOARD_4_AND_DOLLAR (0x21) // Sel +#define HID_USAGE_KEY_KEYBOARD_5_AND_PERCENT (0x22) // Sel +#define HID_USAGE_KEY_KEYBOARD_6_AND_CARET (0x23) // Sel +#define HID_USAGE_KEY_KEYBOARD_7_AND_AMPERSAND (0x24) // Sel +#define HID_USAGE_KEY_KEYBOARD_8_AND_ASTERISK (0x25) // Sel +#define HID_USAGE_KEY_KEYBOARD_9_AND_LEFT_PARENTHESIS (0x26) // Sel +#define HID_USAGE_KEY_KEYBOARD_0_AND_RIGHT_PARENTHESIS (0x27) // Sel +#define HID_USAGE_KEY_KEYBOARD_RETURN_ENTER (0x28) // Sel +#define HID_USAGE_KEY_KEYBOARD_ESCAPE (0x29) // Sel +#define HID_USAGE_KEY_KEYBOARD_DELETE_BACKSPACE (0x2A) // Sel +#define HID_USAGE_KEY_KEYBOARD_TAB (0x2B) // Sel +#define HID_USAGE_KEY_KEYBOARD_SPACEBAR (0x2C) // Sel +#define HID_USAGE_KEY_KEYBOARD_MINUS_AND_UNDERSCORE (0x2D) // Sel +#define HID_USAGE_KEY_KEYBOARD_EQUAL_AND_PLUS (0x2E) // Sel +#define HID_USAGE_KEY_KEYBOARD_LEFT_BRACKET_AND_LEFT_BRACE (0x2F) // Sel +#define HID_USAGE_KEY_KEYBOARD_RIGHT_BRACKET_AND_RIGHT_BRACE (0x30) // Sel +#define HID_USAGE_KEY_KEYBOARD_BACKSLASH_AND_PIPE (0x31) // Sel +#define HID_USAGE_KEY_KEYBOARD_NON_US_HASH_AND_TILDE (0x32) // Sel +#define HID_USAGE_KEY_KEYBOARD_SEMICOLON_AND_COLON (0x33) // Sel +#define HID_USAGE_KEY_KEYBOARD_APOSTROPHE_AND_QUOTE (0x34) // Sel +#define HID_USAGE_KEY_KEYBOARD_GRAVE_ACCENT_AND_TILDE (0x35) // Sel +#define HID_USAGE_KEY_KEYBOARD_COMMA_AND_LESS_THAN (0x36) // Sel +#define HID_USAGE_KEY_KEYBOARD_PERIOD_AND_GREATER_THAN (0x37) // Sel +#define HID_USAGE_KEY_KEYBOARD_SLASH_AND_QUESTION_MARK (0x38) // Sel +#define HID_USAGE_KEY_KEYBOARD_CAPS_LOCK (0x39) // Sel +#define HID_USAGE_KEY_KEYBOARD_F1 (0x3A) // Sel +#define HID_USAGE_KEY_KEYBOARD_F2 (0x3B) // Sel +#define HID_USAGE_KEY_KEYBOARD_F3 (0x3C) // Sel +#define HID_USAGE_KEY_KEYBOARD_F4 (0x3D) // Sel +#define HID_USAGE_KEY_KEYBOARD_F5 (0x3E) // Sel +#define HID_USAGE_KEY_KEYBOARD_F6 (0x3F) // Sel +#define HID_USAGE_KEY_KEYBOARD_F7 (0x40) // Sel +#define HID_USAGE_KEY_KEYBOARD_F8 (0x41) // Sel +#define HID_USAGE_KEY_KEYBOARD_F9 (0x42) // Sel +#define HID_USAGE_KEY_KEYBOARD_F10 (0x43) // Sel +#define HID_USAGE_KEY_KEYBOARD_F11 (0x44) // Sel +#define HID_USAGE_KEY_KEYBOARD_F12 (0x45) // Sel +#define HID_USAGE_KEY_KEYBOARD_PRINTSCREEN (0x46) // Sel +#define HID_USAGE_KEY_KEYBOARD_SCROLL_LOCK (0x47) // Sel +#define HID_USAGE_KEY_KEYBOARD_PAUSE (0x48) // Sel +#define HID_USAGE_KEY_KEYBOARD_INSERT (0x49) // Sel +#define HID_USAGE_KEY_KEYBOARD_HOME (0x4A) // Sel +#define HID_USAGE_KEY_KEYBOARD_PAGEUP (0x4B) // Sel +#define HID_USAGE_KEY_KEYBOARD_DELETE_FORWARD (0x4C) // Sel +#define HID_USAGE_KEY_KEYBOARD_END (0x4D) // Sel +#define HID_USAGE_KEY_KEYBOARD_PAGEDOWN (0x4E) // Sel +#define HID_USAGE_KEY_KEYBOARD_RIGHTARROW (0x4F) // Sel +#define HID_USAGE_KEY_KEYBOARD_LEFTARROW (0x50) // Sel +#define HID_USAGE_KEY_KEYBOARD_DOWNARROW (0x51) // Sel +#define HID_USAGE_KEY_KEYBOARD_UPARROW (0x52) // Sel +#define HID_USAGE_KEY_KEYPAD_NUM_LOCK_AND_CLEAR (0x53) // Sel +#define HID_USAGE_KEY_KEYPAD_SLASH (0x54) // Sel +#define HID_USAGE_KEY_KEYPAD_ASTERISK (0x55) // Sel +#define HID_USAGE_KEY_KEYPAD_MINUS (0x56) // Sel +#define HID_USAGE_KEY_KEYPAD_PLUS (0x57) // Sel +#define HID_USAGE_KEY_KEYPAD_ENTER (0x58) // Sel +#define HID_USAGE_KEY_KEYPAD_1_AND_END (0x59) // Sel +#define HID_USAGE_KEY_KEYPAD_2_AND_DOWN_ARROW (0x5A) // Sel +#define HID_USAGE_KEY_KEYPAD_3_AND_PAGEDN (0x5B) // Sel +#define HID_USAGE_KEY_KEYPAD_4_AND_LEFT_ARROW (0x5C) // Sel +#define HID_USAGE_KEY_KEYPAD_5 (0x5D) // Sel +#define HID_USAGE_KEY_KEYPAD_6_AND_RIGHT_ARROW (0x5E) // Sel +#define HID_USAGE_KEY_KEYPAD_7_AND_HOME (0x5F) // Sel +#define HID_USAGE_KEY_KEYPAD_8_AND_UP_ARROW (0x60) // Sel +#define HID_USAGE_KEY_KEYPAD_9_AND_PAGEUP (0x61) // Sel +#define HID_USAGE_KEY_KEYPAD_0_AND_INSERT (0x62) // Sel +#define HID_USAGE_KEY_KEYPAD_PERIOD_AND_DELETE (0x63) // Sel +#define HID_USAGE_KEY_KEYBOARD_NON_US_BACKSLASH_AND_PIPE (0x64) // Sel +#define HID_USAGE_KEY_KEYBOARD_APPLICATION (0x65) // Sel +#define HID_USAGE_KEY_KEYBOARD_POWER (0x66) // Sel +#define HID_USAGE_KEY_KEYPAD_EQUAL (0x67) // Sel +#define HID_USAGE_KEY_KEYBOARD_F13 (0x68) // Sel +#define HID_USAGE_KEY_KEYBOARD_F14 (0x69) // Sel +#define HID_USAGE_KEY_KEYBOARD_F15 (0x6A) // Sel +#define HID_USAGE_KEY_KEYBOARD_F16 (0x6B) // Sel +#define HID_USAGE_KEY_KEYBOARD_F17 (0x6C) // Sel +#define HID_USAGE_KEY_KEYBOARD_F18 (0x6D) // Sel +#define HID_USAGE_KEY_KEYBOARD_F19 (0x6E) // Sel +#define HID_USAGE_KEY_KEYBOARD_F20 (0x6F) // Sel +#define HID_USAGE_KEY_KEYBOARD_F21 (0x70) // Sel +#define HID_USAGE_KEY_KEYBOARD_F22 (0x71) // Sel +#define HID_USAGE_KEY_KEYBOARD_F23 (0x72) // Sel +#define HID_USAGE_KEY_KEYBOARD_F24 (0x73) // Sel +#define HID_USAGE_KEY_KEYBOARD_EXECUTE (0x74) // Sel +#define HID_USAGE_KEY_KEYBOARD_HELP (0x75) // Sel +#define HID_USAGE_KEY_KEYBOARD_MENU (0x76) // Sel +#define HID_USAGE_KEY_KEYBOARD_SELECT (0x77) // Sel +#define HID_USAGE_KEY_KEYBOARD_STOP (0x78) // Sel +#define HID_USAGE_KEY_KEYBOARD_AGAIN (0x79) // Sel +#define HID_USAGE_KEY_KEYBOARD_UNDO (0x7A) // Sel +#define HID_USAGE_KEY_KEYBOARD_CUT (0x7B) // Sel +#define HID_USAGE_KEY_KEYBOARD_COPY (0x7C) // Sel +#define HID_USAGE_KEY_KEYBOARD_PASTE (0x7D) // Sel +#define HID_USAGE_KEY_KEYBOARD_FIND (0x7E) // Sel +#define HID_USAGE_KEY_KEYBOARD_MUTE (0x7F) // Sel +#define HID_USAGE_KEY_KEYBOARD_VOLUME_UP (0x80) // Sel +#define HID_USAGE_KEY_KEYBOARD_VOLUME_DOWN (0x81) // Sel +#define HID_USAGE_KEY_KEYBOARD_LOCKING_CAPS_LOCK (0x82) // Sel +#define HID_USAGE_KEY_KEYBOARD_LOCKING_NUM_LOCK (0x83) // Sel +#define HID_USAGE_KEY_KEYBOARD_LOCKING_SCROLL_LOCK (0x84) // Sel +#define HID_USAGE_KEY_KEYPAD_COMMA (0x85) // Sel +#define HID_USAGE_KEY_KEYPAD_EQUAL_SIGN (0x86) // Sel +#define HID_USAGE_KEY_KEYBOARD_INTERNATIONAL1 (0x87) // Sel +#define HID_USAGE_KEY_KEYBOARD_INTERNATIONAL2 (0x88) // Sel +#define HID_USAGE_KEY_KEYBOARD_INTERNATIONAL3 (0x89) // Sel +#define HID_USAGE_KEY_KEYBOARD_INTERNATIONAL4 (0x8A) // Sel +#define HID_USAGE_KEY_KEYBOARD_INTERNATIONAL5 (0x8B) // Sel +#define HID_USAGE_KEY_KEYBOARD_INTERNATIONAL6 (0x8C) // Sel +#define HID_USAGE_KEY_KEYBOARD_INTERNATIONAL7 (0x8D) // Sel +#define HID_USAGE_KEY_KEYBOARD_INTERNATIONAL8 (0x8E) // Sel +#define HID_USAGE_KEY_KEYBOARD_INTERNATIONAL9 (0x8F) // Sel +#define HID_USAGE_KEY_KEYBOARD_LANG1 (0x90) // Sel +#define HID_USAGE_KEY_KEYBOARD_LANG2 (0x91) // Sel +#define HID_USAGE_KEY_KEYBOARD_LANG3 (0x92) // Sel +#define HID_USAGE_KEY_KEYBOARD_LANG4 (0x93) // Sel +#define HID_USAGE_KEY_KEYBOARD_LANG5 (0x94) // Sel +#define HID_USAGE_KEY_KEYBOARD_LANG6 (0x95) // Sel +#define HID_USAGE_KEY_KEYBOARD_LANG7 (0x96) // Sel +#define HID_USAGE_KEY_KEYBOARD_LANG8 (0x97) // Sel +#define HID_USAGE_KEY_KEYBOARD_LANG9 (0x98) // Sel +#define HID_USAGE_KEY_KEYBOARD_ALTERNATE_ERASE (0x99) // Sel +#define HID_USAGE_KEY_KEYBOARD_SYSREQ_ATTENTION (0x9A) // Sel +#define HID_USAGE_KEY_KEYBOARD_CANCEL (0x9B) // Sel +#define HID_USAGE_KEY_KEYBOARD_CLEAR (0x9C) // Sel +#define HID_USAGE_KEY_KEYBOARD_PRIOR (0x9D) // Sel +#define HID_USAGE_KEY_KEYBOARD_RETURN (0x9E) // Sel +#define HID_USAGE_KEY_KEYBOARD_SEPARATOR (0x9F) // Sel +#define HID_USAGE_KEY_KEYBOARD_OUT (0xA0) // Sel +#define HID_USAGE_KEY_KEYBOARD_OPER (0xA1) // Sel +#define HID_USAGE_KEY_KEYBOARD_CLEAR_AGAIN (0xA2) // Sel +#define HID_USAGE_KEY_KEYBOARD_CRSEL_PROPS (0xA3) // Sel +#define HID_USAGE_KEY_KEYBOARD_EXSEL (0xA4) // Sel +#define HID_USAGE_KEY_KEYPAD_00 (0xB0) // Sel +#define HID_USAGE_KEY_KEYPAD_000 (0xB1) // Sel +#define HID_USAGE_KEY_THOUSANDS_SEPARATOR (0xB2) // Sel +#define HID_USAGE_KEY_DECIMAL_SEPARATOR (0xB3) // Sel +#define HID_USAGE_KEY_CURRENCY_UNIT (0xB4) // Sel +#define HID_USAGE_KEY_CURRENCY_SUB_UNIT (0xB5) // Sel +#define HID_USAGE_KEY_KEYPAD_LEFT_PARENTHESIS (0xB6) // Sel +#define HID_USAGE_KEY_KEYPAD_RIGHT_PARENTHESIS (0xB7) // Sel +#define HID_USAGE_KEY_KEYPAD_LEFT_BRACE (0xB8) // Sel +#define HID_USAGE_KEY_KEYPAD_RIGHT_BRACE (0xB9) // Sel +#define HID_USAGE_KEY_KEYPAD_TAB (0xBA) // Sel +#define HID_USAGE_KEY_KEYPAD_BACKSPACE (0xBB) // Sel +#define HID_USAGE_KEY_KEYPAD_A (0xBC) // Sel +#define HID_USAGE_KEY_KEYPAD_B (0xBD) // Sel +#define HID_USAGE_KEY_KEYPAD_C (0xBE) // Sel +#define HID_USAGE_KEY_KEYPAD_D (0xBF) // Sel +#define HID_USAGE_KEY_KEYPAD_E (0xC0) // Sel +#define HID_USAGE_KEY_KEYPAD_F (0xC1) // Sel +#define HID_USAGE_KEY_KEYPAD_XOR (0xC2) // Sel +#define HID_USAGE_KEY_KEYPAD_CARET (0xC3) // Sel +#define HID_USAGE_KEY_KEYPAD_PERCENT (0xC4) // Sel +#define HID_USAGE_KEY_KEYPAD_LESS_THAN (0xC5) // Sel +#define HID_USAGE_KEY_KEYPAD_GREATER_THAN (0xC6) // Sel +#define HID_USAGE_KEY_KEYPAD_AMPERSAND (0xC7) // Sel +#define HID_USAGE_KEY_KEYPAD_AMPERSAND_AMPERSAND (0xC8) // Sel +#define HID_USAGE_KEY_KEYPAD_PIPE (0xC9) // Sel +#define HID_USAGE_KEY_KEYPAD_PIPE_PIPE (0xCA) // Sel +#define HID_USAGE_KEY_KEYPAD_COLON (0xCB) // Sel +#define HID_USAGE_KEY_KEYPAD_HASH (0xCC) // Sel +#define HID_USAGE_KEY_KEYPAD_SPACE (0xCD) // Sel +#define HID_USAGE_KEY_KEYPAD_AT (0xCE) // Sel +#define HID_USAGE_KEY_KEYPAD_EXCLAMATION (0xCF) // Sel +#define HID_USAGE_KEY_KEYPAD_MEMORY_STORE (0xD0) // Sel +#define HID_USAGE_KEY_KEYPAD_MEMORY_RECALL (0xD1) // Sel +#define HID_USAGE_KEY_KEYPAD_MEMORY_CLEAR (0xD2) // Sel +#define HID_USAGE_KEY_KEYPAD_MEMORY_ADD (0xD3) // Sel +#define HID_USAGE_KEY_KEYPAD_MEMORY_SUBTRACT (0xD4) // Sel +#define HID_USAGE_KEY_KEYPAD_MEMORY_MULTIPLY (0xD5) // Sel +#define HID_USAGE_KEY_KEYPAD_MEMORY_DIVIDE (0xD6) // Sel +#define HID_USAGE_KEY_KEYPAD_PLUS_MINUS (0xD7) // Sel +#define HID_USAGE_KEY_KEYPAD_CLEAR (0xD8) // Sel +#define HID_USAGE_KEY_KEYPAD_CLEAR_ENTRY (0xD9) // Sel +#define HID_USAGE_KEY_KEYPAD_BINARY (0xDA) // Sel +#define HID_USAGE_KEY_KEYPAD_OCTAL (0xDB) // Sel +#define HID_USAGE_KEY_KEYPAD_DECIMAL (0xDC) // Sel +#define HID_USAGE_KEY_KEYPAD_HEXADECIMAL (0xDD) // Sel +#define HID_USAGE_KEY_KEYBOARD_LEFTCONTROL (0xE0) // DV +#define HID_USAGE_KEY_KEYBOARD_LEFTSHIFT (0xE1) // DV +#define HID_USAGE_KEY_KEYBOARD_LEFTALT (0xE2) // DV +#define HID_USAGE_KEY_KEYBOARD_LEFT_GUI (0xE3) // DV +#define HID_USAGE_KEY_KEYBOARD_RIGHTCONTROL (0xE4) // DV +#define HID_USAGE_KEY_KEYBOARD_RIGHTSHIFT (0xE5) // DV +#define HID_USAGE_KEY_KEYBOARD_RIGHTALT (0xE6) // DV +#define HID_USAGE_KEY_KEYBOARD_RIGHT_GUI (0xE7) // DV + +/* Page 0x08: LED */ +#define HID_USAGE_LED_UNDEFINED (0x00) +#define HID_USAGE_LED_NUM_LOCK (0x01) // OOC +#define HID_USAGE_LED_CAPS_LOCK (0x02) // OOC +#define HID_USAGE_LED_SCROLL_LOCK (0x03) // OOC +#define HID_USAGE_LED_COMPOSE (0x04) // OOC +#define HID_USAGE_LED_KANA (0x05) // OOC +#define HID_USAGE_LED_POWER (0x06) // OOC +#define HID_USAGE_LED_SHIFT (0x07) // OOC +#define HID_USAGE_LED_DO_NOT_DISTURB (0x08) // OOC +#define HID_USAGE_LED_MUTE (0x09) // OOC +#define HID_USAGE_LED_TONE_ENABLE (0x0A) // OOC +#define HID_USAGE_LED_HIGH_CUT_FILTER (0x0B) // OOC +#define HID_USAGE_LED_LOW_CUT_FILTER (0x0C) // OOC +#define HID_USAGE_LED_EQUALIZER_ENABLE (0x0D) // OOC +#define HID_USAGE_LED_SOUND_FIELD_ON (0x0E) // OOC +#define HID_USAGE_LED_SURROUND_ON (0x0F) // OOC +#define HID_USAGE_LED_REPEAT (0x10) // OOC +#define HID_USAGE_LED_STEREO (0x11) // OOC +#define HID_USAGE_LED_SAMPLING_RATE_DETECT (0x12) // OOC +#define HID_USAGE_LED_SPINNING (0x13) // OOC +#define HID_USAGE_LED_CAV (0x14) // OOC +#define HID_USAGE_LED_CLV (0x15) // OOC +#define HID_USAGE_LED_RECORDING_FORMAT_DETECT (0x16) // OOC +#define HID_USAGE_LED_OFF_HOOK (0x17) // OOC +#define HID_USAGE_LED_RING (0x18) // OOC +#define HID_USAGE_LED_MESSAGE_WAITING (0x19) // OOC +#define HID_USAGE_LED_DATA_MODE (0x1A) // OOC +#define HID_USAGE_LED_BATTERY_OPERATION (0x1B) // OOC +#define HID_USAGE_LED_BATTERY_OK (0x1C) // OOC +#define HID_USAGE_LED_BATTERY_LOW (0x1D) // OOC +#define HID_USAGE_LED_SPEAKER (0x1E) // OOC +#define HID_USAGE_LED_HEAD_SET (0x1F) // OOC +#define HID_USAGE_LED_HOLD (0x20) // OOC +#define HID_USAGE_LED_MICROPHONE (0x21) // OOC +#define HID_USAGE_LED_COVERAGE (0x22) // OOC +#define HID_USAGE_LED_NIGHT_MODE (0x23) // OOC +#define HID_USAGE_LED_SEND_CALLS (0x24) // OOC +#define HID_USAGE_LED_CALL_PICKUP (0x25) // OOC +#define HID_USAGE_LED_CONFERENCE (0x26) // OOC +#define HID_USAGE_LED_STAND_BY (0x27) // OOC +#define HID_USAGE_LED_CAMERA_ON (0x28) // OOC +#define HID_USAGE_LED_CAMERA_OFF (0x29) // OOC +#define HID_USAGE_LED_ON_LINE (0x2A) // OOC +#define HID_USAGE_LED_OFF_LINE (0x2B) // OOC +#define HID_USAGE_LED_BUSY (0x2C) // OOC +#define HID_USAGE_LED_READY (0x2D) // OOC +#define HID_USAGE_LED_PAPER_OUT (0x2E) // OOC +#define HID_USAGE_LED_PAPER_JAM (0x2F) // OOC +#define HID_USAGE_LED_REMOTE (0x30) // OOC +#define HID_USAGE_LED_FORWARD (0x31) // OOC +#define HID_USAGE_LED_REVERSE (0x32) // OOC +#define HID_USAGE_LED_STOP (0x33) // OOC +#define HID_USAGE_LED_REWIND (0x34) // OOC +#define HID_USAGE_LED_FAST_FORWARD (0x35) // OOC +#define HID_USAGE_LED_PLAY (0x36) // OOC +#define HID_USAGE_LED_PAUSE (0x37) // OOC +#define HID_USAGE_LED_RECORD (0x38) // OOC +#define HID_USAGE_LED_ERROR (0x39) // OOC +#define HID_USAGE_LED_USAGE_SELECTED_INDICATOR (0x3A) // US +#define HID_USAGE_LED_USAGE_IN_USE_INDICATOR (0x3B) // US +#define HID_USAGE_LED_USAGE_MULTI_MODE_INDICATOR (0x3C) // UM +#define HID_USAGE_LED_INDICATOR_ON (0x3D) // Sel +#define HID_USAGE_LED_INDICATOR_FLASH (0x3E) // Sel +#define HID_USAGE_LED_INDICATOR_SLOW_BLINK (0x3F) // Sel +#define HID_USAGE_LED_INDICATOR_FAST_BLINK (0x40) // Sel +#define HID_USAGE_LED_INDICATOR_OFF (0x41) // Sel +#define HID_USAGE_LED_FLASH_ON_TIME (0x42) // DV +#define HID_USAGE_LED_SLOW_BLINK_ON_TIME (0x43) // DV +#define HID_USAGE_LED_SLOW_BLINK_OFF_TIME (0x44) // DV +#define HID_USAGE_LED_FAST_BLINK_ON_TIME (0x45) // DV +#define HID_USAGE_LED_FAST_BLINK_OFF_TIME (0x46) // DV +#define HID_USAGE_LED_USAGE_INDICATOR_COLOR (0x47) // UM +#define HID_USAGE_LED_INDICATOR_RED (0x48) // Sel +#define HID_USAGE_LED_INDICATOR_GREEN (0x49) // Sel +#define HID_USAGE_LED_INDICATOR_AMBER (0x4A) // Sel +#define HID_USAGE_LED_GENERIC_INDICATOR (0x4B) // OOC +#define HID_USAGE_LED_SYSTEM_SUSPEND (0x4C) // OOC +#define HID_USAGE_LED_EXTERNAL_POWER_CONNECTED (0x4D) // OOC +#define HID_USAGE_LED_INDICATOR_BLUE (0x4E) // Sel +#define HID_USAGE_LED_INDICATOR_ORANGE (0x4F) // Sel +#define HID_USAGE_LED_GOOD_STATUS (0x50) // OOC +#define HID_USAGE_LED_WARNING_STATUS (0x51) // OOC +#define HID_USAGE_LED_RGB_LED (0x52) // CL +#define HID_USAGE_LED_RED_LED_CHANNEL (0x53) // DV +#define HID_USAGE_LED_BLUE_LED_CHANNEL (0x54) // DV +#define HID_USAGE_LED_GREEN_LED_CHANNEL (0x55) // DV +#define HID_USAGE_LED_LED_INTENSITY (0x56) // DV +#define HID_USAGE_LED_PLAYER_INDICATOR (0x60) // NAry +#define HID_USAGE_LED_PLAYER_1 (0x61) // Sel +#define HID_USAGE_LED_PLAYER_2 (0x62) // Sel +#define HID_USAGE_LED_PLAYER_3 (0x63) // Sel +#define HID_USAGE_LED_PLAYER_4 (0x64) // Sel +#define HID_USAGE_LED_PLAYER_5 (0x65) // Sel +#define HID_USAGE_LED_PLAYER_6 (0x66) // Sel +#define HID_USAGE_LED_PLAYER_7 (0x67) // Sel +#define HID_USAGE_LED_PLAYER_8 (0x68) // Sel + +/* Page 0x0B: Telephony Device */ +#define HID_USAGE_TELEPHONY_UNDEFINED (0x00) +#define HID_USAGE_TELEPHONY_PHONE (0x01) // CA +#define HID_USAGE_TELEPHONY_ANSWERING_MACHINE (0x02) // CA +#define HID_USAGE_TELEPHONY_MESSAGE_CONTROLS (0x03) // CL +#define HID_USAGE_TELEPHONY_HANDSET (0x04) // CL +#define HID_USAGE_TELEPHONY_HEADSET (0x05) // CL +#define HID_USAGE_TELEPHONY_TELEPHONY_KEY_PAD (0x06) // NAry +#define HID_USAGE_TELEPHONY_PROGRAMMABLE_BUTTON (0x07) // NAry +#define HID_USAGE_TELEPHONY_HOOK_SWITCH (0x20) // OOC +#define HID_USAGE_TELEPHONY_FLASH (0x21) // MC +#define HID_USAGE_TELEPHONY_FEATURE (0x22) // OSC +#define HID_USAGE_TELEPHONY_HOLD (0x23) // OOC +#define HID_USAGE_TELEPHONY_REDIAL (0x24) // OSC +#define HID_USAGE_TELEPHONY_TRANSFER (0x25) // OSC +#define HID_USAGE_TELEPHONY_DROP (0x26) // OSC +#define HID_USAGE_TELEPHONY_PARK (0x27) // OOC +#define HID_USAGE_TELEPHONY_FORWARD_CALLS (0x28) // OOC +#define HID_USAGE_TELEPHONY_ALTERNATE_FUNCTION (0x29) // MC +#define HID_USAGE_TELEPHONY_LINE (0x2A) // OSC, NAry +#define HID_USAGE_TELEPHONY_SPEAKER_PHONE (0x2B) // OOC +#define HID_USAGE_TELEPHONY_CONFERENCE (0x2C) // OOC +#define HID_USAGE_TELEPHONY_RING_ENABLE (0x2D) // OOC +#define HID_USAGE_TELEPHONY_RING_SELECT (0x2E) // OSC +#define HID_USAGE_TELEPHONY_PHONE_MUTE (0x2F) // OOC +#define HID_USAGE_TELEPHONY_CALLER_ID (0x30) // MC +#define HID_USAGE_TELEPHONY_SEND (0x31) // OOC +#define HID_USAGE_TELEPHONY_SPEED_DIAL (0x50) // OSC +#define HID_USAGE_TELEPHONY_STORE_NUMBER (0x51) // OSC +#define HID_USAGE_TELEPHONY_RECALL_NUMBER (0x52) // OSC +#define HID_USAGE_TELEPHONY_PHONE_DIRECTORY (0x53) // OOC +#define HID_USAGE_TELEPHONY_VOICE_MAIL (0x70) // OOC +#define HID_USAGE_TELEPHONY_SCREEN_CALLS (0x71) // OOC +#define HID_USAGE_TELEPHONY_DO_NOT_DISTURB (0x72) // OOC +#define HID_USAGE_TELEPHONY_MESSAGE (0x73) // OSC +#define HID_USAGE_TELEPHONY_ANSWER_ON_OFF (0x74) // OOC +#define HID_USAGE_TELEPHONY_INSIDE_DIAL_TONE (0x90) // MC +#define HID_USAGE_TELEPHONY_OUTSIDE_DIAL_TONE (0x91) // MC +#define HID_USAGE_TELEPHONY_INSIDE_RING_TONE (0x92) // MC +#define HID_USAGE_TELEPHONY_OUTSIDE_RING_TONE (0x93) // MC +#define HID_USAGE_TELEPHONY_PRIORITY_RING_TONE (0x94) // MC +#define HID_USAGE_TELEPHONY_INSIDE_RINGBACK (0x95) // MC +#define HID_USAGE_TELEPHONY_PRIORITY_RINGBACK (0x96) // MC +#define HID_USAGE_TELEPHONY_LINE_BUSY_TONE (0x97) // MC +#define HID_USAGE_TELEPHONY_REORDER_TONE (0x98) // MC +#define HID_USAGE_TELEPHONY_CALL_WAITING_TONE (0x99) // MC +#define HID_USAGE_TELEPHONY_CONFIRMATION_TONE_1 (0x9A) // MC +#define HID_USAGE_TELEPHONY_CONFIRMATION_TONE_2 (0x9B) // MC +#define HID_USAGE_TELEPHONY_TONES_OFF (0x9C) // OOC +#define HID_USAGE_TELEPHONY_OUTSIDE_RINGBACK (0x9D) // MC +#define HID_USAGE_TELEPHONY_RINGER (0x9E) // OOC +#define HID_USAGE_TELEPHONY_PHONE_KEY_0 (0xB0) // Sel +#define HID_USAGE_TELEPHONY_PHONE_KEY_1 (0xB1) // Sel +#define HID_USAGE_TELEPHONY_PHONE_KEY_2 (0xB2) // Sel +#define HID_USAGE_TELEPHONY_PHONE_KEY_3 (0xB3) // Sel +#define HID_USAGE_TELEPHONY_PHONE_KEY_4 (0xB4) // Sel +#define HID_USAGE_TELEPHONY_PHONE_KEY_5 (0xB5) // Sel +#define HID_USAGE_TELEPHONY_PHONE_KEY_6 (0xB6) // Sel +#define HID_USAGE_TELEPHONY_PHONE_KEY_7 (0xB7) // Sel +#define HID_USAGE_TELEPHONY_PHONE_KEY_8 (0xB8) // Sel +#define HID_USAGE_TELEPHONY_PHONE_KEY_9 (0xB9) // Sel +#define HID_USAGE_TELEPHONY_PHONE_KEY_STAR (0xBA) // Sel +#define HID_USAGE_TELEPHONY_PHONE_KEY_POUND (0xBB) // Sel +#define HID_USAGE_TELEPHONY_PHONE_KEY_A (0xBC) // Sel +#define HID_USAGE_TELEPHONY_PHONE_KEY_B (0xBD) // Sel +#define HID_USAGE_TELEPHONY_PHONE_KEY_C (0xBE) // Sel +#define HID_USAGE_TELEPHONY_PHONE_KEY_D (0xBF) // Sel +#define HID_USAGE_TELEPHONY_PHONE_CALL_HISTORY_KEY (0xC0) // Sel +#define HID_USAGE_TELEPHONY_PHONE_CALLER_ID_KEY (0xC1) // Sel +#define HID_USAGE_TELEPHONY_PHONE_SETTINGS_KEY (0xC2) // Sel +#define HID_USAGE_TELEPHONY_HOST_CONTROL (0xF0) // OOC +#define HID_USAGE_TELEPHONY_HOST_AVAILABLE (0xF1) // OOC +#define HID_USAGE_TELEPHONY_HOST_CALL_ACTIVE (0xF2) // OOC +#define HID_USAGE_TELEPHONY_ACTIVATE_HANDSET_AUDIO (0xF3) // OOC +#define HID_USAGE_TELEPHONY_RING_TYPE (0xF4) // NAry +#define HID_USAGE_TELEPHONY_RE_DIALABLE_PHONE_NUMBER (0xF5) // OOC +#define HID_USAGE_TELEPHONY_STOP_RING_TONE (0xF8) // Sel +#define HID_USAGE_TELEPHONY_PSTN_RING_TONE (0xF9) // Sel +#define HID_USAGE_TELEPHONY_HOST_RING_TONE (0xFA) // Sel +#define HID_USAGE_TELEPHONY_ALERT_SOUND_ERROR (0xFB) // Sel +#define HID_USAGE_TELEPHONY_ALERT_SOUND_CONFIRM (0xFC) // Sel +#define HID_USAGE_TELEPHONY_ALERT_SOUND_NOTIFICATION (0xFD) // Sel +#define HID_USAGE_TELEPHONY_SILENT_RING (0xFE) // Sel +#define HID_USAGE_TELEPHONY_EMAIL_MESSAGE_WAITING (0x108) // OOC +#define HID_USAGE_TELEPHONY_VOICEMAIL_MESSAGE_WAITING (0x109) // OOC +#define HID_USAGE_TELEPHONY_HOST_HOLD (0x10A) // OOC +#define HID_USAGE_TELEPHONY_INCOMING_CALL_HISTORY_COUNT (0x110) // DV +#define HID_USAGE_TELEPHONY_OUTGOING_CALL_HISTORY_COUNT (0x111) // DV +#define HID_USAGE_TELEPHONY_INCOMING_CALL_HISTORY (0x112) // CL +#define HID_USAGE_TELEPHONY_OUTGOING_CALL_HISTORY (0x113) // CL +#define HID_USAGE_TELEPHONY_PHONE_LOCALE (0x114) // DV +#define HID_USAGE_TELEPHONY_PHONE_TIME_SECOND (0x140) // DV +#define HID_USAGE_TELEPHONY_PHONE_TIME_MINUTE (0x141) // DV +#define HID_USAGE_TELEPHONY_PHONE_TIME_HOUR (0x142) // DV +#define HID_USAGE_TELEPHONY_PHONE_DATE_DAY (0x143) // DV +#define HID_USAGE_TELEPHONY_PHONE_DATE_MONTH (0x144) // DV +#define HID_USAGE_TELEPHONY_PHONE_DATE_YEAR (0x145) // DV +#define HID_USAGE_TELEPHONY_HANDSET_NICKNAME (0x146) // DV +#define HID_USAGE_TELEPHONY_ADDRESS_BOOK_ID (0x147) // DV +#define HID_USAGE_TELEPHONY_CALL_DURATION (0x14A) // DV +#define HID_USAGE_TELEPHONY_DUAL_MODE_PHONE (0x14B) // CA + +/* Page 0x0C: Consumer */ +#define HID_USAGE_CONSUMER_UNDEFINED (0x00) +#define HID_USAGE_CONSUMER_CONSUMER_CONTROL (0x01) // CA +#define HID_USAGE_CONSUMER_NUMERIC_KEY_PAD (0x02) // NAry +#define HID_USAGE_CONSUMER_PROGRAMMABLE_BUTTONS (0x03) // NAry +#define HID_USAGE_CONSUMER_MICROPHONE (0x04) // CA +#define HID_USAGE_CONSUMER_HEADPHONE (0x05) // CA +#define HID_USAGE_CONSUMER_GRAPHIC_EQUALIZER (0x06) // CA +#define HID_USAGE_CONSUMER_INCREMENT10 (0x20) // OSC +#define HID_USAGE_CONSUMER_INCREMENT100 (0x21) // OSC +#define HID_USAGE_CONSUMER_AM_PM (0x22) // OSC +#define HID_USAGE_CONSUMER_POWER (0x30) // OOC +#define HID_USAGE_CONSUMER_RESET (0x31) // OSC +#define HID_USAGE_CONSUMER_SLEEP (0x32) // OSC +#define HID_USAGE_CONSUMER_SLEEP_AFTER (0x33) // OSC +#define HID_USAGE_CONSUMER_SLEEP_MODE (0x34) // RTC +#define HID_USAGE_CONSUMER_ILLUMINATION (0x35) // OOC +#define HID_USAGE_CONSUMER_FUNCTION_BUTTONS (0x36) // NAry +#define HID_USAGE_CONSUMER_MENU (0x40) // OOC +#define HID_USAGE_CONSUMER_MENU_PICK (0x41) // OSC +#define HID_USAGE_CONSUMER_MENU_UP (0x42) // OSC +#define HID_USAGE_CONSUMER_MENU_DOWN (0x43) // OSC +#define HID_USAGE_CONSUMER_MENU_LEFT (0x44) // OSC +#define HID_USAGE_CONSUMER_MENU_RIGHT (0x45) // OSC +#define HID_USAGE_CONSUMER_MENU_ESCAPE (0x46) // OSC +#define HID_USAGE_CONSUMER_MENU_VALUE_INCREASE (0x47) // OSC +#define HID_USAGE_CONSUMER_MENU_VALUE_DECREASE (0x48) // OSC +#define HID_USAGE_CONSUMER_DATA_ON_SCREEN (0x60) // OOC +#define HID_USAGE_CONSUMER_CLOSED_CAPTION (0x61) // OOC +#define HID_USAGE_CONSUMER_CLOSED_CAPTION_SELECT (0x62) // OSC +#define HID_USAGE_CONSUMER_VCR_TV (0x63) // OOC +#define HID_USAGE_CONSUMER_BROADCAST_MODE (0x64) // OSC +#define HID_USAGE_CONSUMER_SNAPSHOT (0x65) // OSC +#define HID_USAGE_CONSUMER_STILL (0x66) // OSC +#define HID_USAGE_CONSUMER_PICTURE_IN_PICTURE_TOGGLE (0x67) // OSC +#define HID_USAGE_CONSUMER_PICTURE_IN_PICTURE_SWAP (0x68) // OSC +#define HID_USAGE_CONSUMER_RED_MENU_BUTTON (0x69) // MC +#define HID_USAGE_CONSUMER_GREEN_MENU_BUTTON (0x6A) // MC +#define HID_USAGE_CONSUMER_BLUE_MENU_BUTTON (0x6B) // MC +#define HID_USAGE_CONSUMER_YELLOW_MENU_BUTTON (0x6C) // MC +#define HID_USAGE_CONSUMER_ASPECT (0x6D) // OSC +#define HID_USAGE_CONSUMER_3D_MODE_SELECT (0x6E) // OSC +#define HID_USAGE_CONSUMER_DISPLAY_BRIGHTNESS_INCREMENT (0x6F) // RTC +#define HID_USAGE_CONSUMER_DISPLAY_BRIGHTNESS_DECREMENT (0x70) // RTC +#define HID_USAGE_CONSUMER_DISPLAY_BRIGHTNESS (0x71) // LC +#define HID_USAGE_CONSUMER_DISPLAY_BACKLIGHT_TOGGLE (0x72) // OOC +#define HID_USAGE_CONSUMER_DISPLAY_SET_BRIGHTNESS_TO_MINIMUM (0x73) // OSC +#define HID_USAGE_CONSUMER_DISPLAY_SET_BRIGHTNESS_TO_MAXIMUM (0x74) // OSC +#define HID_USAGE_CONSUMER_DISPLAY_SET_AUTO_BRIGHTNESS (0x75) // OOC +#define HID_USAGE_CONSUMER_CAMERA_ACCESS_ENABLED (0x76) // OOC +#define HID_USAGE_CONSUMER_CAMERA_ACCESS_DISABLED (0x77) // OOC +#define HID_USAGE_CONSUMER_CAMERA_ACCESS_TOGGLE (0x78) // OOC +#define HID_USAGE_CONSUMER_KEYBOARD_BRIGHTNESS_INCREMENT (0x79) // OSC +#define HID_USAGE_CONSUMER_KEYBOARD_BRIGHTNESS_DECREMENT (0x7A) // OSC +#define HID_USAGE_CONSUMER_KEYBOARD_BACKLIGHT_SET_LEVEL (0x7B) // LC +#define HID_USAGE_CONSUMER_KEYBOARD_BACKLIGHT_OOC (0x7C) // OOC +#define HID_USAGE_CONSUMER_KEYBOARD_BACKLIGHT_SET_MINIMUM (0x7D) // OSC +#define HID_USAGE_CONSUMER_KEYBOARD_BACKLIGHT_SET_MAXIMUM (0x7E) // OSC +#define HID_USAGE_CONSUMER_KEYBOARD_BACKLIGHT_AUTO (0x7F) // OOC +#define HID_USAGE_CONSUMER_SELECTION (0x80) // NAry +#define HID_USAGE_CONSUMER_ASSIGN_SELECTION (0x81) // OSC +#define HID_USAGE_CONSUMER_MODE_STEP (0x82) // OSC +#define HID_USAGE_CONSUMER_RECALL_LAST (0x83) // OSC +#define HID_USAGE_CONSUMER_ENTER_CHANNEL (0x84) // OSC +#define HID_USAGE_CONSUMER_ORDER_MOVIE (0x85) // OSC +#define HID_USAGE_CONSUMER_CHANNEL (0x86) // LC +#define HID_USAGE_CONSUMER_MEDIA_SELECTION (0x87) // NAry +#define HID_USAGE_CONSUMER_MEDIA_SELECT_COMPUTER (0x88) // Sel +#define HID_USAGE_CONSUMER_MEDIA_SELECT_TV (0x89) // Sel +#define HID_USAGE_CONSUMER_MEDIA_SELECT_WWW (0x8A) // Sel +#define HID_USAGE_CONSUMER_MEDIA_SELECT_DVD (0x8B) // Sel +#define HID_USAGE_CONSUMER_MEDIA_SELECT_TELEPHONE (0x8C) // Sel +#define HID_USAGE_CONSUMER_MEDIA_SELECT_PROGRAM_GUIDE (0x8D) // Sel +#define HID_USAGE_CONSUMER_MEDIA_SELECT_VIDEO_PHONE (0x8E) // Sel +#define HID_USAGE_CONSUMER_MEDIA_SELECT_GAMES (0x8F) // Sel +#define HID_USAGE_CONSUMER_MEDIA_SELECT_MESSAGES (0x90) // Sel +#define HID_USAGE_CONSUMER_MEDIA_SELECT_CD (0x91) // Sel +#define HID_USAGE_CONSUMER_MEDIA_SELECT_VCR (0x92) // Sel +#define HID_USAGE_CONSUMER_MEDIA_SELECT_TUNER (0x93) // Sel +#define HID_USAGE_CONSUMER_QUIT (0x94) // OSC +#define HID_USAGE_CONSUMER_HELP (0x95) // OOC +#define HID_USAGE_CONSUMER_MEDIA_SELECT_TAPE (0x96) // Sel +#define HID_USAGE_CONSUMER_MEDIA_SELECT_CABLE (0x97) // Sel +#define HID_USAGE_CONSUMER_MEDIA_SELECT_SATELLITE (0x98) // Sel +#define HID_USAGE_CONSUMER_MEDIA_SELECT_SECURITY (0x99) // Sel +#define HID_USAGE_CONSUMER_MEDIA_SELECT_HOME (0x9A) // Sel +#define HID_USAGE_CONSUMER_MEDIA_SELECT_CALL (0x9B) // Sel +#define HID_USAGE_CONSUMER_CHANNEL_INCREMENT (0x9C) // OSC +#define HID_USAGE_CONSUMER_CHANNEL_DECREMENT (0x9D) // OSC +#define HID_USAGE_CONSUMER_MEDIA_SELECT_SAP (0x9E) // Sel +#define HID_USAGE_CONSUMER_VCR_PLUS (0xA0) // OSC +#define HID_USAGE_CONSUMER_ONCE (0xA1) // OSC +#define HID_USAGE_CONSUMER_DAILY (0xA2) // OSC +#define HID_USAGE_CONSUMER_WEEKLY (0xA3) // OSC +#define HID_USAGE_CONSUMER_MONTHLY (0xA4) // OSC +#define HID_USAGE_CONSUMER_PLAY (0xB0) // OOC +#define HID_USAGE_CONSUMER_PAUSE (0xB1) // OOC +#define HID_USAGE_CONSUMER_RECORD (0xB2) // OOC +#define HID_USAGE_CONSUMER_FAST_FORWARD (0xB3) // OOC +#define HID_USAGE_CONSUMER_REWIND (0xB4) // OOC +#define HID_USAGE_CONSUMER_SCAN_NEXT_TRACK (0xB5) // OSC +#define HID_USAGE_CONSUMER_SCAN_PREVIOUS_TRACK (0xB6) // OSC +#define HID_USAGE_CONSUMER_STOP (0xB7) // OSC +#define HID_USAGE_CONSUMER_EJECT (0xB8) // OSC +#define HID_USAGE_CONSUMER_RANDOM_PLAY (0xB9) // OOC +#define HID_USAGE_CONSUMER_SELECT_DISC (0xBA) // NAry +#define HID_USAGE_CONSUMER_ENTER_DISC (0xBB) // MC +#define HID_USAGE_CONSUMER_REPEAT (0xBC) // OSC +#define HID_USAGE_CONSUMER_TRACKING (0xBD) // LC +#define HID_USAGE_CONSUMER_TRACK_NORMAL (0xBE) // OSC +#define HID_USAGE_CONSUMER_SLOW_TRACKING (0xBF) // LC +#define HID_USAGE_CONSUMER_FRAME_FORWARD (0xC0) // RTC +#define HID_USAGE_CONSUMER_FRAME_BACK (0xC1) // RTC +#define HID_USAGE_CONSUMER_MARK (0xC2) // OSC +#define HID_USAGE_CONSUMER_CLEAR_MARK (0xC3) // OSC +#define HID_USAGE_CONSUMER_REPEAT_FROM_MARK (0xC4) // OOC +#define HID_USAGE_CONSUMER_RETURN_TO_MARK (0xC5) // OSC +#define HID_USAGE_CONSUMER_SEARCH_MARK_FORWARD (0xC6) // OSC +#define HID_USAGE_CONSUMER_SEARCH_MARK_BACKWARDS (0xC7) // OSC +#define HID_USAGE_CONSUMER_COUNTER_RESET (0xC8) // OSC +#define HID_USAGE_CONSUMER_SHOW_COUNTER (0xC9) // OSC +#define HID_USAGE_CONSUMER_TRACKING_INCREMENT (0xCA) // RTC +#define HID_USAGE_CONSUMER_TRACKING_DECREMENT (0xCB) // RTC +#define HID_USAGE_CONSUMER_STOP_EJECT (0xCC) // OSC +#define HID_USAGE_CONSUMER_PLAY_PAUSE (0xCD) // OSC +#define HID_USAGE_CONSUMER_PLAY_SKIP (0xCE) // OSC +#define HID_USAGE_CONSUMER_VOICE_COMMAND (0xCF) // OSC +#define HID_USAGE_CONSUMER_INVOKE_CAPTURE_INTERFACE (0xD0) // Sel +#define HID_USAGE_CONSUMER_START_OR_STOP_GAME_RECORDING (0xD1) // Sel +#define HID_USAGE_CONSUMER_HISTORICAL_GAME_CAPTURE (0xD2) // Sel +#define HID_USAGE_CONSUMER_CAPTURE_GAME_SCREENSHOT (0xD3) // Sel +#define HID_USAGE_CONSUMER_SHOW_OR_HIDE_RECORDING_INDICATOR (0xD4) // Sel +#define HID_USAGE_CONSUMER_START_OR_STOP_MICROPHONE_CAPTURE (0xD5) // Sel +#define HID_USAGE_CONSUMER_START_OR_STOP_CAMERA_CAPTURE (0xD6) // Sel +#define HID_USAGE_CONSUMER_START_OR_STOP_GAME_BROADCAST (0xD7) // Sel +#define HID_USAGE_CONSUMER_VOLUME (0xE0) // LC +#define HID_USAGE_CONSUMER_BALANCE (0xE1) // LC +#define HID_USAGE_CONSUMER_MUTE (0xE2) // OOC +#define HID_USAGE_CONSUMER_BASS (0xE3) // LC +#define HID_USAGE_CONSUMER_TREBLE (0xE4) // LC +#define HID_USAGE_CONSUMER_BASS_BOOST (0xE5) // OOC +#define HID_USAGE_CONSUMER_SURROUND_MODE (0xE6) // OSC +#define HID_USAGE_CONSUMER_LOUDNESS (0xE7) // OOC +#define HID_USAGE_CONSUMER_MPX (0xE8) // OOC +#define HID_USAGE_CONSUMER_VOLUME_INCREMENT (0xE9) // RTC +#define HID_USAGE_CONSUMER_VOLUME_DECREMENT (0xEA) // RTC +#define HID_USAGE_CONSUMER_SPEED_SELECT (0xF0) // OSC +#define HID_USAGE_CONSUMER_PLAYBACK_SPEED (0xF1) // NAry +#define HID_USAGE_CONSUMER_STANDARD_PLAY (0xF2) // Sel +#define HID_USAGE_CONSUMER_LONG_PLAY (0xF3) // Sel +#define HID_USAGE_CONSUMER_EXTENDED_PLAY (0xF4) // Sel +#define HID_USAGE_CONSUMER_SLOW (0xF5) // OSC +#define HID_USAGE_CONSUMER_FAN_ENABLE (0x100) // OOC +#define HID_USAGE_CONSUMER_FAN_SPEED (0x101) // LC +#define HID_USAGE_CONSUMER_LIGHT_ENABLE (0x102) // OOC +#define HID_USAGE_CONSUMER_LIGHT_ILLUMINATION_LEVEL (0x103) // LC +#define HID_USAGE_CONSUMER_CLIMATE_CONTROL_ENABLE (0x104) // OOC +#define HID_USAGE_CONSUMER_ROOM_TEMPERATURE (0x105) // LC +#define HID_USAGE_CONSUMER_SECURITY_ENABLE (0x106) // OOC +#define HID_USAGE_CONSUMER_FIRE_ALARM (0x107) // OSC +#define HID_USAGE_CONSUMER_POLICE_ALARM (0x108) // OSC +#define HID_USAGE_CONSUMER_PROXIMITY (0x109) // LC +#define HID_USAGE_CONSUMER_MOTION (0x10A) // OSC +#define HID_USAGE_CONSUMER_DURESS_ALARM (0x10B) // OSC +#define HID_USAGE_CONSUMER_HOLDUP_ALARM (0x10C) // OSC +#define HID_USAGE_CONSUMER_MEDICAL_ALARM (0x10D) // OSC +#define HID_USAGE_CONSUMER_BALANCE_RIGHT (0x150) // RTC +#define HID_USAGE_CONSUMER_BALANCE_LEFT (0x151) // RTC +#define HID_USAGE_CONSUMER_BASS_INCREMENT (0x152) // RTC +#define HID_USAGE_CONSUMER_BASS_DECREMENT (0x153) // RTC +#define HID_USAGE_CONSUMER_TREBLE_INCREMENT (0x154) // RTC +#define HID_USAGE_CONSUMER_TREBLE_DECREMENT (0x155) // RTC +#define HID_USAGE_CONSUMER_SPEAKER_SYSTEM (0x160) // CL +#define HID_USAGE_CONSUMER_CHANNEL_LEFT (0x161) // CL +#define HID_USAGE_CONSUMER_CHANNEL_RIGHT (0x162) // CL +#define HID_USAGE_CONSUMER_CHANNEL_CENTER (0x163) // CL +#define HID_USAGE_CONSUMER_CHANNEL_FRONT (0x164) // CL +#define HID_USAGE_CONSUMER_CHANNEL_CENTER_FRONT (0x165) // CL +#define HID_USAGE_CONSUMER_CHANNEL_SIDE (0x166) // CL +#define HID_USAGE_CONSUMER_CHANNEL_SURROUND (0x167) // CL +#define HID_USAGE_CONSUMER_CHANNEL_LOW_FREQUENCY_ENHANCEMENT (0x168) // CL +#define HID_USAGE_CONSUMER_CHANNEL_TOP (0x169) // CL +#define HID_USAGE_CONSUMER_CHANNEL_UNKNOWN (0x16A) // CL +#define HID_USAGE_CONSUMER_SUB_CHANNEL (0x170) // LC +#define HID_USAGE_CONSUMER_SUB_CHANNEL_INCREMENT (0x171) // OSC +#define HID_USAGE_CONSUMER_SUB_CHANNEL_DECREMENT (0x172) // OSC +#define HID_USAGE_CONSUMER_ALTERNATE_AUDIO_INCREMENT (0x173) // OSC +#define HID_USAGE_CONSUMER_ALTERNATE_AUDIO_DECREMENT (0x174) // OSC +#define HID_USAGE_CONSUMER_APPLICATION_LAUNCH_BUTTONS (0x180) // NAry +#define HID_USAGE_CONSUMER_AL_LAUNCH_BUTTON_CONFIGURATION_TOOL (0x181) // Sel +#define HID_USAGE_CONSUMER_AL_PROGRAMMABLE_BUTTON_CONFIGURATION (0x182) // Sel +#define HID_USAGE_CONSUMER_AL_CONSUMER_CONTROL_CONFIGURATION (0x183) // Sel +#define HID_USAGE_CONSUMER_AL_WORD_PROCESSOR (0x184) // Sel +#define HID_USAGE_CONSUMER_AL_TEXT_EDITOR (0x185) // Sel +#define HID_USAGE_CONSUMER_AL_SPREADSHEET (0x186) // Sel +#define HID_USAGE_CONSUMER_AL_GRAPHICS_EDITOR (0x187) // Sel +#define HID_USAGE_CONSUMER_AL_PRESENTATION_APP (0x188) // Sel +#define HID_USAGE_CONSUMER_AL_DATABASE_APP (0x189) // Sel +#define HID_USAGE_CONSUMER_AL_EMAIL_READER (0x18A) // Sel +#define HID_USAGE_CONSUMER_AL_NEWSREADER (0x18B) // Sel +#define HID_USAGE_CONSUMER_AL_VOICEMAIL (0x18C) // Sel +#define HID_USAGE_CONSUMER_AL_CONTACTS_ADDRESS_BOOK (0x18D) // Sel +#define HID_USAGE_CONSUMER_AL_CALENDAR_SCHEDULE (0x18E) // Sel +#define HID_USAGE_CONSUMER_AL_TASK_PROJECT_MANAGER (0x18F) // Sel +#define HID_USAGE_CONSUMER_AL_LOG_JOURNAL_TIMECARD (0x190) // Sel +#define HID_USAGE_CONSUMER_AL_CHECKBOOK_FINANCE (0x191) // Sel +#define HID_USAGE_CONSUMER_AL_CALCULATOR (0x192) // Sel +#define HID_USAGE_CONSUMER_AL_A_V_CAPTURE_PLAYBACK (0x193) // Sel +#define HID_USAGE_CONSUMER_AL_LOCAL_MACHINE_BROWSER (0x194) // Sel +#define HID_USAGE_CONSUMER_AL_LAN_WAN_BROWSER (0x195) // Sel +#define HID_USAGE_CONSUMER_AL_INTERNET_BROWSER (0x196) // Sel +#define HID_USAGE_CONSUMER_AL_REMOTE_NETWORKING_ISP_CONNECT (0x197) // Sel +#define HID_USAGE_CONSUMER_AL_NETWORK_CONFERENCE (0x198) // Sel +#define HID_USAGE_CONSUMER_AL_NETWORK_CHAT (0x199) // Sel +#define HID_USAGE_CONSUMER_AL_TELEPHONY_DIALER (0x19A) // Sel +#define HID_USAGE_CONSUMER_AL_LOGON (0x19B) // Sel +#define HID_USAGE_CONSUMER_AL_LOGOFF (0x19C) // Sel +#define HID_USAGE_CONSUMER_AL_LOGON_LOGOFF (0x19D) // Sel +#define HID_USAGE_CONSUMER_AL_TERMINAL_LOCK_SCREENSAVER (0x19E) // Sel +#define HID_USAGE_CONSUMER_AL_CONTROL_PANEL (0x19F) // Sel +#define HID_USAGE_CONSUMER_AL_COMMAND_LINE_PROCESSOR_RUN (0x1A0) // Sel +#define HID_USAGE_CONSUMER_AL_PROCESS_TASK_MANAGER (0x1A1) // Sel +#define HID_USAGE_CONSUMER_AL_SELECT_TASK_APPLICATION (0x1A2) // Sel +#define HID_USAGE_CONSUMER_AL_NEXT_TASK_APPLICATION (0x1A3) // Sel +#define HID_USAGE_CONSUMER_AL_PREVIOUS_TASK_APPLICATION (0x1A4) // Sel +#define HID_USAGE_CONSUMER_AL_PREEMPTIVE_HALT_TASK_APPLICATION (0x1A5) // Sel +#define HID_USAGE_CONSUMER_AL_INTEGRATED_HELP_CENTER (0x1A6) // Sel +#define HID_USAGE_CONSUMER_AL_DOCUMENTS (0x1A7) // Sel +#define HID_USAGE_CONSUMER_AL_THESAURUS (0x1A8) // Sel +#define HID_USAGE_CONSUMER_AL_DICTIONARY (0x1A9) // Sel +#define HID_USAGE_CONSUMER_AL_DESKTOP (0x1AA) // Sel +#define HID_USAGE_CONSUMER_AL_SPELL_CHECK (0x1AB) // Sel +#define HID_USAGE_CONSUMER_AL_GRAMMAR_CHECK (0x1AC) // Sel +#define HID_USAGE_CONSUMER_AL_WIRELESS_STATUS (0x1AD) // Sel +#define HID_USAGE_CONSUMER_AL_KEYBOARD_LAYOUT (0x1AE) // Sel +#define HID_USAGE_CONSUMER_AL_VIRUS_PROTECTION (0x1AF) // Sel +#define HID_USAGE_CONSUMER_AL_ENCRYPTION (0x1B0) // Sel +#define HID_USAGE_CONSUMER_AL_SCREEN_SAVER (0x1B1) // Sel +#define HID_USAGE_CONSUMER_AL_ALARMS (0x1B2) // Sel +#define HID_USAGE_CONSUMER_AL_CLOCK (0x1B3) // Sel +#define HID_USAGE_CONSUMER_AL_FILE_BROWSER (0x1B4) // Sel +#define HID_USAGE_CONSUMER_AL_POWER_STATUS (0x1B5) // Sel +#define HID_USAGE_CONSUMER_AL_IMAGE_BROWSER (0x1B6) // Sel +#define HID_USAGE_CONSUMER_AL_AUDIO_BROWSER (0x1B7) // Sel +#define HID_USAGE_CONSUMER_AL_MOVIE_BROWSER (0x1B8) // Sel +#define HID_USAGE_CONSUMER_AL_DIGITAL_RIGHTS_MANAGER (0x1B9) // Sel +#define HID_USAGE_CONSUMER_AL_DIGITAL_WALLET (0x1BA) // Sel +#define HID_USAGE_CONSUMER_AL_INSTANT_MESSAGING (0x1BC) // Sel +#define HID_USAGE_CONSUMER_AL_OEM_FEATURES_TIPS_TUTORIAL_BROWSER (0x1BD) // Sel +#define HID_USAGE_CONSUMER_AL_OEM_HELP (0x1BE) // Sel +#define HID_USAGE_CONSUMER_AL_ONLINE_COMMUNITY (0x1BF) // Sel +#define HID_USAGE_CONSUMER_AL_ENTERTAINMENT_CONTENT_BROWSER (0x1C0) // Sel +#define HID_USAGE_CONSUMER_AL_ONLINE_SHOPPING_BROWSER (0x1C1) // Sel +#define HID_USAGE_CONSUMER_AL_SMARTCARD_INFORMATION_HELP (0x1C2) // Sel +#define HID_USAGE_CONSUMER_AL_MARKET_MONITOR_FINANCE_BROWSER (0x1C3) // Sel +#define HID_USAGE_CONSUMER_AL_CUSTOMIZED_CORPORATE_NEWS_BROWSER (0x1C4) // Sel +#define HID_USAGE_CONSUMER_AL_ONLINE_ACTIVITY_BROWSER (0x1C5) // Sel +#define HID_USAGE_CONSUMER_AL_RESEARCH_SEARCH_BROWSER (0x1C6) // Sel +#define HID_USAGE_CONSUMER_AL_AUDIO_PLAYER (0x1C7) // Sel +#define HID_USAGE_CONSUMER_AL_MESSAGE_STATUS (0x1C8) // Sel +#define HID_USAGE_CONSUMER_AL_CONTACT_SYNC (0x1C9) // Sel +#define HID_USAGE_CONSUMER_AL_NAVIGATION (0x1CA) // Sel +#define HID_USAGE_CONSUMER_AL_CONTEXT_AWARE_DESKTOP_ASSISTANT (0x1CB) // Sel +#define HID_USAGE_CONSUMER_GENERIC_GUI_APPLICATION_CONTROLS (0x200) // NAry +#define HID_USAGE_CONSUMER_AC_NEW (0x201) // Sel +#define HID_USAGE_CONSUMER_AC_OPEN (0x202) // Sel +#define HID_USAGE_CONSUMER_AC_CLOSE (0x203) // Sel +#define HID_USAGE_CONSUMER_AC_EXIT (0x204) // Sel +#define HID_USAGE_CONSUMER_AC_MAXIMIZE (0x205) // Sel +#define HID_USAGE_CONSUMER_AC_MINIMIZE (0x206) // Sel +#define HID_USAGE_CONSUMER_AC_SAVE (0x207) // Sel +#define HID_USAGE_CONSUMER_AC_PRINT (0x208) // Sel +#define HID_USAGE_CONSUMER_AC_PROPERTIES (0x209) // Sel +#define HID_USAGE_CONSUMER_AC_UNDO (0x21A) // Sel +#define HID_USAGE_CONSUMER_AC_COPY (0x21B) // Sel +#define HID_USAGE_CONSUMER_AC_CUT (0x21C) // Sel +#define HID_USAGE_CONSUMER_AC_PASTE (0x21D) // Sel +#define HID_USAGE_CONSUMER_AC_SELECT_ALL (0x21E) // Sel +#define HID_USAGE_CONSUMER_AC_FIND (0x21F) // Sel +#define HID_USAGE_CONSUMER_AC_FIND_AND_REPLACE (0x220) // Sel +#define HID_USAGE_CONSUMER_AC_SEARCH (0x221) // Sel +#define HID_USAGE_CONSUMER_AC_GO_TO (0x222) // Sel +#define HID_USAGE_CONSUMER_AC_HOME (0x223) // Sel +#define HID_USAGE_CONSUMER_AC_BACK (0x224) // Sel +#define HID_USAGE_CONSUMER_AC_FORWARD (0x225) // Sel +#define HID_USAGE_CONSUMER_AC_STOP (0x226) // Sel +#define HID_USAGE_CONSUMER_AC_REFRESH (0x227) // Sel +#define HID_USAGE_CONSUMER_AC_PREVIOUS_LINK (0x228) // Sel +#define HID_USAGE_CONSUMER_AC_NEXT_LINK (0x229) // Sel +#define HID_USAGE_CONSUMER_AC_BOOKMARKS (0x22A) // Sel +#define HID_USAGE_CONSUMER_AC_HISTORY (0x22B) // Sel +#define HID_USAGE_CONSUMER_AC_SUBSCRIPTIONS (0x22C) // Sel +#define HID_USAGE_CONSUMER_AC_ZOOM_IN (0x22D) // Sel +#define HID_USAGE_CONSUMER_AC_ZOOM_OUT (0x22E) // Sel +#define HID_USAGE_CONSUMER_AC_ZOOM (0x22F) // LC +#define HID_USAGE_CONSUMER_AC_FULL_SCREEN_VIEW (0x230) // Sel +#define HID_USAGE_CONSUMER_AC_NORMAL_VIEW (0x231) // Sel +#define HID_USAGE_CONSUMER_AC_VIEW_TOGGLE (0x232) // Sel +#define HID_USAGE_CONSUMER_AC_SCROLL_UP (0x233) // Sel +#define HID_USAGE_CONSUMER_AC_SCROLL_DOWN (0x234) // Sel +#define HID_USAGE_CONSUMER_AC_SCROLL (0x235) // LC +#define HID_USAGE_CONSUMER_AC_PAN_LEFT (0x236) // Sel +#define HID_USAGE_CONSUMER_AC_PAN_RIGHT (0x237) // Sel +#define HID_USAGE_CONSUMER_AC_PAN (0x238) // LC +#define HID_USAGE_CONSUMER_AC_NEW_WINDOW (0x239) // Sel +#define HID_USAGE_CONSUMER_AC_TILE_HORIZONTALLY (0x23A) // Sel +#define HID_USAGE_CONSUMER_AC_TILE_VERTICALLY (0x23B) // Sel +#define HID_USAGE_CONSUMER_AC_FORMAT (0x23C) // Sel +#define HID_USAGE_CONSUMER_AC_EDIT (0x23D) // Sel +#define HID_USAGE_CONSUMER_AC_BOLD (0x23E) // Sel +#define HID_USAGE_CONSUMER_AC_ITALICS (0x23F) // Sel +#define HID_USAGE_CONSUMER_AC_UNDERLINE (0x240) // Sel +#define HID_USAGE_CONSUMER_AC_STRIKETHROUGH (0x241) // Sel +#define HID_USAGE_CONSUMER_AC_SUBSCRIPT (0x242) // Sel +#define HID_USAGE_CONSUMER_AC_SUPERSCRIPT (0x243) // Sel +#define HID_USAGE_CONSUMER_AC_ALL_CAPS (0x244) // Sel +#define HID_USAGE_CONSUMER_AC_ROTATE (0x245) // Sel +#define HID_USAGE_CONSUMER_AC_RESIZE (0x246) // Sel +#define HID_USAGE_CONSUMER_AC_FLIP_HORIZONTAL (0x247) // Sel +#define HID_USAGE_CONSUMER_AC_FLIP_VERTICAL (0x248) // Sel +#define HID_USAGE_CONSUMER_AC_MIRROR_HORIZONTAL (0x249) // Sel +#define HID_USAGE_CONSUMER_AC_MIRROR_VERTICAL (0x24A) // Sel +#define HID_USAGE_CONSUMER_AC_FONT_SELECT (0x24B) // Sel +#define HID_USAGE_CONSUMER_AC_FONT_COLOR (0x24C) // Sel +#define HID_USAGE_CONSUMER_AC_FONT_SIZE (0x24D) // Sel +#define HID_USAGE_CONSUMER_AC_JUSTIFY_LEFT (0x24E) // Sel +#define HID_USAGE_CONSUMER_AC_JUSTIFY_CENTER_H (0x24F) // Sel +#define HID_USAGE_CONSUMER_AC_JUSTIFY_RIGHT (0x250) // Sel +#define HID_USAGE_CONSUMER_AC_JUSTIFY_BLOCK_H (0x251) // Sel +#define HID_USAGE_CONSUMER_AC_JUSTIFY_TOP (0x252) // Sel +#define HID_USAGE_CONSUMER_AC_JUSTIFY_CENTER_V (0x253) // Sel +#define HID_USAGE_CONSUMER_AC_JUSTIFY_BOTTOM (0x254) // Sel +#define HID_USAGE_CONSUMER_AC_JUSTIFY_BLOCK_V (0x255) // Sel +#define HID_USAGE_CONSUMER_AC_INDENT_DECREASE (0x256) // Sel +#define HID_USAGE_CONSUMER_AC_INDENT_INCREASE (0x257) // Sel +#define HID_USAGE_CONSUMER_AC_NUMBERED_LIST (0x258) // Sel +#define HID_USAGE_CONSUMER_AC_RESTART_NUMBERING (0x259) // Sel +#define HID_USAGE_CONSUMER_AC_BULLETED_LIST (0x25A) // Sel +#define HID_USAGE_CONSUMER_AC_PROMOTE (0x25B) // Sel +#define HID_USAGE_CONSUMER_AC_DEMOTE (0x25C) // Sel +#define HID_USAGE_CONSUMER_AC_YES (0x25D) // Sel +#define HID_USAGE_CONSUMER_AC_NO (0x25E) // Sel +#define HID_USAGE_CONSUMER_AC_CANCEL (0x25F) // Sel +#define HID_USAGE_CONSUMER_AC_CATALOG (0x260) // Sel +#define HID_USAGE_CONSUMER_AC_BUY_CHECKOUT (0x261) // Sel +#define HID_USAGE_CONSUMER_AC_ADD_TO_CART (0x262) // Sel +#define HID_USAGE_CONSUMER_AC_EXPAND (0x263) // Sel +#define HID_USAGE_CONSUMER_AC_EXPAND_ALL (0x264) // Sel +#define HID_USAGE_CONSUMER_AC_COLLAPSE (0x265) // Sel +#define HID_USAGE_CONSUMER_AC_COLLAPSE_ALL (0x266) // Sel +#define HID_USAGE_CONSUMER_AC_PRINT_PREVIEW (0x267) // Sel +#define HID_USAGE_CONSUMER_AC_PASTE_SPECIAL (0x268) // Sel +#define HID_USAGE_CONSUMER_AC_INSERT_MODE (0x269) // Sel +#define HID_USAGE_CONSUMER_AC_DELETE (0x26A) // Sel +#define HID_USAGE_CONSUMER_AC_LOCK (0x26B) // Sel +#define HID_USAGE_CONSUMER_AC_UNLOCK (0x26C) // Sel +#define HID_USAGE_CONSUMER_AC_PROTECT (0x26D) // Sel +#define HID_USAGE_CONSUMER_AC_UNPROTECT (0x26E) // Sel +#define HID_USAGE_CONSUMER_AC_ATTACH_COMMENT (0x26F) // Sel +#define HID_USAGE_CONSUMER_AC_DELETE_COMMENT (0x270) // Sel +#define HID_USAGE_CONSUMER_AC_VIEW_COMMENT (0x271) // Sel +#define HID_USAGE_CONSUMER_AC_SELECT_WORD (0x272) // Sel +#define HID_USAGE_CONSUMER_AC_SELECT_SENTENCE (0x273) // Sel +#define HID_USAGE_CONSUMER_AC_SELECT_PARAGRAPH (0x274) // Sel +#define HID_USAGE_CONSUMER_AC_SELECT_COLUMN (0x275) // Sel +#define HID_USAGE_CONSUMER_AC_SELECT_ROW (0x276) // Sel +#define HID_USAGE_CONSUMER_AC_SELECT_TABLE (0x277) // Sel +#define HID_USAGE_CONSUMER_AC_SELECT_OBJECT (0x278) // Sel +#define HID_USAGE_CONSUMER_AC_REDO_REPEAT (0x279) // Sel +#define HID_USAGE_CONSUMER_AC_SORT (0x27A) // Sel +#define HID_USAGE_CONSUMER_AC_SORT_ASCENDING (0x27B) // Sel +#define HID_USAGE_CONSUMER_AC_SORT_DESCENDING (0x27C) // Sel +#define HID_USAGE_CONSUMER_AC_FILTER (0x27D) // Sel +#define HID_USAGE_CONSUMER_AC_SET_CLOCK (0x27E) // Sel +#define HID_USAGE_CONSUMER_AC_VIEW_CLOCK (0x27F) // Sel +#define HID_USAGE_CONSUMER_AC_SELECT_TIME_ZONE (0x280) // Sel +#define HID_USAGE_CONSUMER_AC_EDIT_TIME_ZONES (0x281) // Sel +#define HID_USAGE_CONSUMER_AC_SET_ALARM (0x282) // Sel +#define HID_USAGE_CONSUMER_AC_CLEAR_ALARM (0x283) // Sel +#define HID_USAGE_CONSUMER_AC_SNOOZE_ALARM (0x284) // Sel +#define HID_USAGE_CONSUMER_AC_RESET_ALARM (0x285) // Sel +#define HID_USAGE_CONSUMER_AC_SYNCHRONIZE (0x286) // Sel +#define HID_USAGE_CONSUMER_AC_SEND_RECEIVE (0x287) // Sel +#define HID_USAGE_CONSUMER_AC_SEND_TO (0x288) // Sel +#define HID_USAGE_CONSUMER_AC_REPLY (0x289) // Sel +#define HID_USAGE_CONSUMER_AC_REPLY_ALL (0x28A) // Sel +#define HID_USAGE_CONSUMER_AC_FORWARD_MSG (0x28B) // Sel +#define HID_USAGE_CONSUMER_AC_SEND (0x28C) // Sel +#define HID_USAGE_CONSUMER_AC_ATTACH_FILE (0x28D) // Sel +#define HID_USAGE_CONSUMER_AC_UPLOAD (0x28E) // Sel +#define HID_USAGE_CONSUMER_AC_DOWNLOAD_SAVE_TARGET_AS (0x28F) // Sel +#define HID_USAGE_CONSUMER_AC_SET_BORDERS (0x290) // Sel +#define HID_USAGE_CONSUMER_AC_INSERT_ROW (0x291) // Sel +#define HID_USAGE_CONSUMER_AC_INSERT_COLUMN (0x292) // Sel +#define HID_USAGE_CONSUMER_AC_INSERT_FILE (0x293) // Sel +#define HID_USAGE_CONSUMER_AC_INSERT_PICTURE (0x294) // Sel +#define HID_USAGE_CONSUMER_AC_INSERT_OBJECT (0x295) // Sel +#define HID_USAGE_CONSUMER_AC_INSERT_SYMBOL (0x296) // Sel +#define HID_USAGE_CONSUMER_AC_SAVE_AND_CLOSE (0x297) // Sel +#define HID_USAGE_CONSUMER_AC_RENAME (0x298) // Sel +#define HID_USAGE_CONSUMER_AC_MERGE (0x299) // Sel +#define HID_USAGE_CONSUMER_AC_SPLIT (0x29A) // Sel +#define HID_USAGE_CONSUMER_AC_DISRIBUTE_HORIZONTALLY (0x29B) // Sel +#define HID_USAGE_CONSUMER_AC_DISTRIBUTE_VERTICALLY (0x29C) // Sel +#define HID_USAGE_CONSUMER_AC_NEXT_KEYBOARD_LAYOUT_SELECT (0x29D) // Sel +#define HID_USAGE_CONSUMER_AC_NAVIGATION_GUIDANCE (0x29E) // Sel +#define HID_USAGE_CONSUMER_AC_DESKTOP_SHOW_ALL_WINDOWS (0x29F) // Sel +#define HID_USAGE_CONSUMER_AC_SOFT_KEY_LEFT (0x2A0) // Sel +#define HID_USAGE_CONSUMER_AC_SOFT_KEY_RIGHT (0x2A1) // Sel +#define HID_USAGE_CONSUMER_AC_DESKTOP_SHOW_ALL_APPLICATIONS (0x2A2) // Sel +#define HID_USAGE_CONSUMER_AC_IDLE_KEEP_ALIVE (0x2B0) // Sel +#define HID_USAGE_CONSUMER_EXTENDED_KEYBOARD_ATTRIBUTES_COLLECTION (0x2C0) // CL +#define HID_USAGE_CONSUMER_KEYBOARD_FORM_FACTOR (0x2C1) // SV +#define HID_USAGE_CONSUMER_KEYBOARD_KEY_TYPE (0x2C2) // SV +#define HID_USAGE_CONSUMER_KEYBOARD_PHYSICAL_LAYOUT (0x2C3) // SV +#define HID_USAGE_CONSUMER_VENDOR_SPECIFIC_KEYBOARD_PHYSICAL_LAYOUT (0x2C4) // SV +#define HID_USAGE_CONSUMER_KEYBOARD_IETF_LANGUAGE_TAG_INDEX (0x2C5) // SV +#define HID_USAGE_CONSUMER_IMPLEMENTED_KEYBOARD_INPUT_ASSIST_CONTROLS (0x2C6) // SV +#define HID_USAGE_CONSUMER_KEYBOARD_INPUT_ASSIST_PREVIOUS (0x2C7) // Sel +#define HID_USAGE_CONSUMER_KEYBOARD_INPUT_ASSIST_NEXT (0x2C8) // Sel +#define HID_USAGE_CONSUMER_KEYBOARD_INPUT_ASSIST_PREVIOUS_GROUP (0x2C9) // Sel +#define HID_USAGE_CONSUMER_KEYBOARD_INPUT_ASSIST_NEXT_GROUP (0x2CA) // Sel +#define HID_USAGE_CONSUMER_KEYBOARD_INPUT_ASSIST_ACCEPT (0x2CB) // Sel +#define HID_USAGE_CONSUMER_KEYBOARD_INPUT_ASSIST_CANCEL (0x2CC) // Sel +#define HID_USAGE_CONSUMER_PRIVACY_SCREEN_TOGGLE (0x2D0) // OOC +#define HID_USAGE_CONSUMER_PRIVACY_SCREEN_LEVEL_DECREMENT (0x2D1) // RTC +#define HID_USAGE_CONSUMER_PRIVACY_SCREEN_LEVEL_INCREMENT (0x2D2) // RTC +#define HID_USAGE_CONSUMER_PRIVACY_SCREEN_LEVEL_MINIMUM (0x2D3) // OSC +#define HID_USAGE_CONSUMER_PRIVACY_SCREEN_LEVEL_MAXIMUM (0x2D4) // OSC +#define HID_USAGE_CONSUMER_CONTACT_EDITED (0x500) // OOC +#define HID_USAGE_CONSUMER_CONTACT_ADDED (0x501) // OOC +#define HID_USAGE_CONSUMER_CONTACT_RECORD_ACTIVE (0x502) // OOC +#define HID_USAGE_CONSUMER_CONTACT_INDEX (0x503) // DV +#define HID_USAGE_CONSUMER_CONTACT_NICKNAME (0x504) // DV +#define HID_USAGE_CONSUMER_CONTACT_FIRST_NAME (0x505) // DV +#define HID_USAGE_CONSUMER_CONTACT_LAST_NAME (0x506) // DV +#define HID_USAGE_CONSUMER_CONTACT_FULL_NAME (0x507) // DV +#define HID_USAGE_CONSUMER_CONTACT_PHONE_NUMBER_PERSONAL (0x508) // DV +#define HID_USAGE_CONSUMER_CONTACT_PHONE_NUMBER_BUSINESS (0x509) // DV +#define HID_USAGE_CONSUMER_CONTACT_PHONE_NUMBER_MOBILE (0x50A) // DV +#define HID_USAGE_CONSUMER_CONTACT_PHONE_NUMBER_PAGER (0x50B) // DV +#define HID_USAGE_CONSUMER_CONTACT_PHONE_NUMBER_FAX (0x50C) // DV +#define HID_USAGE_CONSUMER_CONTACT_PHONE_NUMBER_OTHER (0x50D) // DV +#define HID_USAGE_CONSUMER_CONTACT_EMAIL_PERSONAL (0x50E) // DV +#define HID_USAGE_CONSUMER_CONTACT_EMAIL_BUSINESS (0x50F) // DV +#define HID_USAGE_CONSUMER_CONTACT_EMAIL_OTHER (0x510) // DV +#define HID_USAGE_CONSUMER_CONTACT_EMAIL_MAIN (0x511) // DV +#define HID_USAGE_CONSUMER_CONTACT_SPEED_DIAL_NUMBER (0x512) // DV +#define HID_USAGE_CONSUMER_CONTACT_STATUS_FLAG (0x513) // DV +#define HID_USAGE_CONSUMER_CONTACT_MISC (0x514) // DV + +/* Page 0x0D: Digitizers */ +#define HID_USAGE_DIGITIZERS_UNDEFINED (0x00) +#define HID_USAGE_DIGITIZERS_DIGITIZER (0x01) // CA +#define HID_USAGE_DIGITIZERS_PEN (0x02) // CA +#define HID_USAGE_DIGITIZERS_LIGHT_PEN (0x03) // CA +#define HID_USAGE_DIGITIZERS_TOUCH_SCREEN (0x04) // CA +#define HID_USAGE_DIGITIZERS_TOUCH_PAD (0x05) // CA +#define HID_USAGE_DIGITIZERS_WHITEBOARD (0x06) // CA +#define HID_USAGE_DIGITIZERS_COORDINATE_MEASURING_MACHINE (0x07) // CA +#define HID_USAGE_DIGITIZERS_3D_DIGITIZER (0x08) // CA +#define HID_USAGE_DIGITIZERS_STEREO_PLOTTER (0x09) // CA +#define HID_USAGE_DIGITIZERS_ARTICULATED_ARM (0x0A) // CA +#define HID_USAGE_DIGITIZERS_ARMATURE (0x0B) // CA +#define HID_USAGE_DIGITIZERS_MULTIPLE_POINT_DIGITIZER (0x0C) // CA +#define HID_USAGE_DIGITIZERS_FREE_SPACE_WAND (0x0D) // CA +#define HID_USAGE_DIGITIZERS_DEVICE_CONFIGURATION (0x0E) // CA +#define HID_USAGE_DIGITIZERS_CAPACITIVE_HEAT_MAP_DIGITIZER (0x0F) // CA +#define HID_USAGE_DIGITIZERS_STYLUS (0x20) // CA, CL +#define HID_USAGE_DIGITIZERS_PUCK (0x21) // CL +#define HID_USAGE_DIGITIZERS_FINGER (0x22) // CL +#define HID_USAGE_DIGITIZERS_DEVICE_SETTINGS (0x23) // CL +#define HID_USAGE_DIGITIZERS_CHARACTER_GESTURE (0x24) // CL +#define HID_USAGE_DIGITIZERS_TIP_PRESSURE (0x30) // DV +#define HID_USAGE_DIGITIZERS_BARREL_PRESSURE (0x31) // DV +#define HID_USAGE_DIGITIZERS_IN_RANGE (0x32) // MC +#define HID_USAGE_DIGITIZERS_TOUCH (0x33) // MC +#define HID_USAGE_DIGITIZERS_UNTOUCH (0x34) // OSC +#define HID_USAGE_DIGITIZERS_TAP (0x35) // OSC +#define HID_USAGE_DIGITIZERS_QUALITY (0x36) // DV +#define HID_USAGE_DIGITIZERS_DATA_VALID (0x37) // MC +#define HID_USAGE_DIGITIZERS_TRANSDUCER_INDEX (0x38) // DV +#define HID_USAGE_DIGITIZERS_TABLET_FUNCTION_KEYS (0x39) // CL +#define HID_USAGE_DIGITIZERS_PROGRAM_CHANGE_KEYS (0x3A) // CL +#define HID_USAGE_DIGITIZERS_BATTERY_STRENGTH (0x3B) // DV +#define HID_USAGE_DIGITIZERS_INVERT (0x3C) // MC +#define HID_USAGE_DIGITIZERS_X_TILT (0x3D) // DV +#define HID_USAGE_DIGITIZERS_Y_TILT (0x3E) // DV +#define HID_USAGE_DIGITIZERS_AZIMUTH (0x3F) // DV +#define HID_USAGE_DIGITIZERS_ALTITUDE (0x40) // DV +#define HID_USAGE_DIGITIZERS_TWIST (0x41) // DV +#define HID_USAGE_DIGITIZERS_TIP_SWITCH (0x42) // MC +#define HID_USAGE_DIGITIZERS_SECONDARY_TIP_SWITCH (0x43) // MC +#define HID_USAGE_DIGITIZERS_BARREL_SWITCH (0x44) // MC +#define HID_USAGE_DIGITIZERS_ERASER (0x45) // MC +#define HID_USAGE_DIGITIZERS_TABLET_PICK (0x46) // MC +#define HID_USAGE_DIGITIZERS_TOUCH_VALID (0x47) // MC +#define HID_USAGE_DIGITIZERS_WIDTH (0x48) // DV +#define HID_USAGE_DIGITIZERS_HEIGHT (0x49) // DV +#define HID_USAGE_DIGITIZERS_CONTACT_IDENTIFIER (0x51) // DV +#define HID_USAGE_DIGITIZERS_DEVICE_MODE (0x52) // DV +#define HID_USAGE_DIGITIZERS_DEVICE_IDENTIFIER (0x53) // DV, SV +#define HID_USAGE_DIGITIZERS_CONTACT_COUNT (0x54) // DV +#define HID_USAGE_DIGITIZERS_CONTACT_COUNT_MAXIMUM (0x55) // SV +#define HID_USAGE_DIGITIZERS_SCAN_TIME (0x56) // DV +#define HID_USAGE_DIGITIZERS_SURFACE_SWITCH (0x57) // DF +#define HID_USAGE_DIGITIZERS_BUTTON_SWITCH (0x58) // DF +#define HID_USAGE_DIGITIZERS_PAD_TYPE (0x59) // SF +#define HID_USAGE_DIGITIZERS_SECONDARY_BARREL_SWITCH (0x5A) // MC +#define HID_USAGE_DIGITIZERS_TRANSDUCER_SERIAL_NUMBER (0x5B) // SV +#define HID_USAGE_DIGITIZERS_PREFERRED_COLOR (0x5C) // DV +#define HID_USAGE_DIGITIZERS_PREFERRED_COLOR_IS_LOCKED (0x5D) // MC +#define HID_USAGE_DIGITIZERS_PREFERRED_LINE_WIDTH (0x5E) // DV +#define HID_USAGE_DIGITIZERS_PREFERRED_LINE_WIDTH_IS_LOCKED (0x5F) // MC +#define HID_USAGE_DIGITIZERS_LATENCY_MODE (0x60) // DF +#define HID_USAGE_DIGITIZERS_GESTURE_CHARACTER_QUALITY (0x61) // DV +#define HID_USAGE_DIGITIZERS_CHARACTER_GESTURE_DATA_LENGTH (0x62) // DV +#define HID_USAGE_DIGITIZERS_CHARACTER_GESTURE_DATA (0x63) // DV +#define HID_USAGE_DIGITIZERS_GESTURE_CHARACTER_ENCODING (0x64) // NAry +#define HID_USAGE_DIGITIZERS_UTF8_CHARACTER_GESTURE_ENCODING (0x65) // Sel +#define HID_USAGE_DIGITIZERS_UTF16_LITTLE_ENDIAN_CHARACTER_GESTURE_ENCODING (0x66) // Sel +#define HID_USAGE_DIGITIZERS_UTF16_BIG_ENDIAN_CHARACTER_GESTURE_ENCODING (0x67) // Sel +#define HID_USAGE_DIGITIZERS_UTF32_LITTLE_ENDIAN_CHARACTER_GESTURE_ENCODING (0x68) // Sel +#define HID_USAGE_DIGITIZERS_UTF32_BIG_ENDIAN_CHARACTER_GESTURE_ENCODING (0x69) // Sel +#define HID_USAGE_DIGITIZERS_CAPACITIVE_HEAT_MAP_PROTOCOL_VENDOR_ID (0x6A) // SV +#define HID_USAGE_DIGITIZERS_CAPACITIVE_HEAT_MAP_PROTOCOL_VERSION (0x6B) // SV +#define HID_USAGE_DIGITIZERS_CAPACITIVE_HEAT_MAP_FRAME_DATA (0x6C) // DV +#define HID_USAGE_DIGITIZERS_GESTURE_CHARACTER_ENABLE (0x6D) // DF +#define HID_USAGE_DIGITIZERS_PREFERRED_LINE_STYLE (0x70) // NAry +#define HID_USAGE_DIGITIZERS_PREFERRED_LINE_STYLE_IS_LOCKED (0x71) // MC +#define HID_USAGE_DIGITIZERS_INK (0x72) // Sel +#define HID_USAGE_DIGITIZERS_PENCIL (0x73) // Sel +#define HID_USAGE_DIGITIZERS_HIGHLIGHTER (0x74) // Sel +#define HID_USAGE_DIGITIZERS_CHISEL_MARKER (0x75) // Sel +#define HID_USAGE_DIGITIZERS_BRUSH (0x76) // Sel +#define HID_USAGE_DIGITIZERS_NO_PREFERENCE (0x77) // Sel +#define HID_USAGE_DIGITIZERS_DIGITIZER_DIAGNOSTIC (0x80) // CL +#define HID_USAGE_DIGITIZERS_DIGITIZER_ERROR (0x81) // NAry +#define HID_USAGE_DIGITIZERS_ERR_NORMAL_STATUS (0x82) // Sel +#define HID_USAGE_DIGITIZERS_ERR_TRANSDUCERS_EXCEEDED (0x83) // Sel +#define HID_USAGE_DIGITIZERS_ERR_FULL_TRANS_FEATURES_UNAVAILABLE (0x84) // Sel +#define HID_USAGE_DIGITIZERS_ERR_CHARGE_LOW (0x85) // Sel +#define HID_USAGE_DIGITIZERS_TRANSDUCER_SOFTWARE_INFO (0x90) // CL +#define HID_USAGE_DIGITIZERS_TRANSDUCER_VENDOR_ID (0x91) // SV +#define HID_USAGE_DIGITIZERS_TRANSDUCER_PRODUCT_ID (0x92) // SV +#define HID_USAGE_DIGITIZERS_DEVICE_SUPPORTED_PROTOCOLS (0x93) // NAry, CL +#define HID_USAGE_DIGITIZERS_TRANSDUCER_SUPPORTED_PROTOCOLS (0x94) // NAry, CL +#define HID_USAGE_DIGITIZERS_NO_PROTOCOL (0x95) // Sel +#define HID_USAGE_DIGITIZERS_WACOM_AES_PROTOCOL (0x96) // Sel +#define HID_USAGE_DIGITIZERS_USI_PROTOCOL (0x97) // Sel +#define HID_USAGE_DIGITIZERS_MICROSOFT_PEN_PROTOCOL (0x98) // Sel +#define HID_USAGE_DIGITIZERS_SUPPORTED_REPORT_RATES (0xA0) // SV, CL +#define HID_USAGE_DIGITIZERS_REPORT_RATE (0xA1) // DV +#define HID_USAGE_DIGITIZERS_TRANSDUCER_CONNECTED (0xA2) // SF +#define HID_USAGE_DIGITIZERS_SWITCH_DISABLED (0xA3) // Sel +#define HID_USAGE_DIGITIZERS_SWITCH_UNIMPLEMENTED (0xA4) // Sel +#define HID_USAGE_DIGITIZERS_TRANSDUCER_SWITCHES (0xA5) // Sel + +/* Page 0x0E: Haptics */ +#define HID_USAGE_HAPTICS_UNDEFINED (0x00) +#define HID_USAGE_HAPTICS_SIMPLE_HAPTIC_CONTROLLER (0x01) // CA, CL +#define HID_USAGE_HAPTICS_WAVEFORM_LIST (0x10) // NAry +#define HID_USAGE_HAPTICS_DURATION_LIST (0x11) // NAry +#define HID_USAGE_HAPTICS_AUTO_TRIGGER (0x20) // DV +#define HID_USAGE_HAPTICS_MANUAL_TRIGGER (0x21) // DV +#define HID_USAGE_HAPTICS_AUTO_TRIGGER_ASSOCIATED_CONTROL (0x22) // SV +#define HID_USAGE_HAPTICS_INTENSITY (0x23) // DV +#define HID_USAGE_HAPTICS_REPEAT_COUNT (0x24) // DV +#define HID_USAGE_HAPTICS_RETRIGGER_PERIOD (0x25) // DV +#define HID_USAGE_HAPTICS_WAVEFORM_VENDOR_PAGE (0x26) // SV +#define HID_USAGE_HAPTICS_WAVEFORM_VENDOR_ID (0x27) // SV +#define HID_USAGE_HAPTICS_WAVEFORM_CUTOFF_TIME (0x28) // SV +#define HID_USAGE_HAPTICS_WAVEFORM_NONE (0x1001) // SV +#define HID_USAGE_HAPTICS_WAVEFORM_STOP (0x1002) // SV +#define HID_USAGE_HAPTICS_WAVEFORM_CLICK (0x1003) // SV +#define HID_USAGE_HAPTICS_WAVEFORM_BUZZ_CONTINUOUS (0x1004) // SV +#define HID_USAGE_HAPTICS_WAVEFORM_RUMBLE_CONTINUOUS (0x1005) // SV +#define HID_USAGE_HAPTICS_WAVEFORM_PRESS (0x1006) // SV +#define HID_USAGE_HAPTICS_WAVEFORM_RELEASE (0x1007) // SV + +/* Page 0x0F: PID */ +#define HID_USAGE_PID_UNDEFINED (0x00) +#define HID_USAGE_PID_PHYSICAL_INTERFACE_DEVICE (0x01) +#define HID_USAGE_PID_NORMAL (0x20) +#define HID_USAGE_PID_SET_EFFECT_REPORT (0x21) +#define HID_USAGE_PID_EFFECT_BLOCK_INDEX (0x22) +#define HID_USAGE_PID_PARAMETER_BLOCK_OFFSET (0x23) +#define HID_USAGE_PID_ROM_FLAG (0x24) +#define HID_USAGE_PID_EFFECT_TYPE (0x25) +#define HID_USAGE_PID_ET_CONSTANT_FORCE (0x26) +#define HID_USAGE_PID_ET_RAMP (0x27) +#define HID_USAGE_PID_ET_CUSTOM_FORCE_DATA (0x28) +#define HID_USAGE_PID_ET_SQUARE (0x30) +#define HID_USAGE_PID_ET_SINE (0x31) +#define HID_USAGE_PID_ET_TRIANGLE (0x32) +#define HID_USAGE_PID_ET_SAWTOOTH_UP (0x33) +#define HID_USAGE_PID_ET_SAWTOOTH_DOWN (0x34) +#define HID_USAGE_PID_ET_SPRING (0x40) +#define HID_USAGE_PID_ET_DAMPER (0x41) +#define HID_USAGE_PID_ET_INERTIA (0x42) +#define HID_USAGE_PID_ET_FRICTION (0x43) +#define HID_USAGE_PID_DURATION (0x50) +#define HID_USAGE_PID_SAMPLE_PERIOD (0x51) +#define HID_USAGE_PID_GAIN (0x52) +#define HID_USAGE_PID_TRIGGER_BUTTON (0x53) +#define HID_USAGE_PID_TRIGGER_REPEAT_INTERVAL (0x54) +#define HID_USAGE_PID_AXES_ENABLE (0x55) +#define HID_USAGE_PID_DIRECTION_ENABLE (0x56) +#define HID_USAGE_PID_DIRECTION (0x57) +#define HID_USAGE_PID_TYPE_SPECIFIC_BLOCK_OFFSET (0x58) +#define HID_USAGE_PID_BLOCK_TYPE (0x59) +#define HID_USAGE_PID_SET_ENVELOPE_REPORT (0x5A) +#define HID_USAGE_PID_ATTACK_LEVEL (0x5B) +#define HID_USAGE_PID_ATTACK_TIME (0x5C) +#define HID_USAGE_PID_FADE_LEVEL (0x5D) +#define HID_USAGE_PID_FADE_TIME (0x5E) +#define HID_USAGE_PID_SET_CONDITION_REPORT (0x5F) +#define HID_USAGE_PID_CP_OFFSET (0x60) +#define HID_USAGE_PID_POSITIVE_COEFFICIENT (0x61) +#define HID_USAGE_PID_NEGATIVE_COEFFICIENT (0x62) +#define HID_USAGE_PID_POSITIVE_SATURATION (0x63) +#define HID_USAGE_PID_NEGATIVE_SATURATION (0x64) +#define HID_USAGE_PID_DEAD_BAND (0x65) +#define HID_USAGE_PID_DOWNLOAD_FORCE_SAMPLE (0x66) +#define HID_USAGE_PID_ISOCH_CUSTOM_FORCE_ENABLE (0x67) +#define HID_USAGE_PID_CUSTOM_FORCE_DATA_REPORT (0x68) +#define HID_USAGE_PID_CUSTOM_FORCE_DATA (0x69) +#define HID_USAGE_PID_CUSTOM_FORCE_VENDOR_DEFINED_DATA (0x6A) +#define HID_USAGE_PID_SET_CUSTOM_FORCE_REPORT (0x6B) +#define HID_USAGE_PID_CUSTOM_FORCE_DATA_OFFSET (0x6C) +#define HID_USAGE_PID_SAMPLE_COUNT (0x6D) +#define HID_USAGE_PID_SET_PERIODIC_REPORT (0x6E) +#define HID_USAGE_PID_OFFSET (0x6F) +#define HID_USAGE_PID_MAGNITUDE (0x70) +#define HID_USAGE_PID_PHASE (0x71) +#define HID_USAGE_PID_PERIOD (0x72) +#define HID_USAGE_PID_SET_CONSTANT_FORCE_REPORT (0x73) +#define HID_USAGE_PID_SET_RAMP_FORCE_REPORT (0x74) +#define HID_USAGE_PID_RAMP_START (0x75) +#define HID_USAGE_PID_RAMP_END (0x76) +#define HID_USAGE_PID_EFFECT_OPERATION_REPORT (0x77) +#define HID_USAGE_PID_EFFECT_OPERATION (0x78) +#define HID_USAGE_PID_OP_EFFECT_START (0x79) +#define HID_USAGE_PID_OP_EFFECT_START_SOLO (0x7A) +#define HID_USAGE_PID_OP_EFFECT_STOP (0x7B) +#define HID_USAGE_PID_LOOP_COUNT (0x7C) +#define HID_USAGE_PID_DEVICE_GAIN_REPORT (0x7D) +#define HID_USAGE_PID_DEVICE_GAIN (0x7E) +#define HID_USAGE_PID_PID_POOL_REPORT (0x7F) +#define HID_USAGE_PID_RAM_POOL_SIZE (0x80) +#define HID_USAGE_PID_ROM_POOL_SIZE (0x81) +#define HID_USAGE_PID_ROM_EFFECT_BLOCK_COUNT (0x82) +#define HID_USAGE_PID_SIMULTANEOUS_EFFECTS_MAX (0x83) +#define HID_USAGE_PID_POOL_ALIGNMENT (0x84) +#define HID_USAGE_PID_PID_POOL_MOVE_REPORT (0x85) +#define HID_USAGE_PID_MOVE_SOURCE (0x86) +#define HID_USAGE_PID_MOVE_DESTINATION (0x87) +#define HID_USAGE_PID_MOVE_LENGTH (0x88) +#define HID_USAGE_PID_PID_BLOCK_LOAD_REPORT (0x89) +#define HID_USAGE_PID_BLOCK_LOAD_STATUS (0x8B) +#define HID_USAGE_PID_BLOCK_LOAD_SUCCESS (0x8C) +#define HID_USAGE_PID_BLOCK_LOAD_FULL (0x8D) +#define HID_USAGE_PID_BLOCK_LOAD_ERROR (0x8E) +#define HID_USAGE_PID_BLOCK_HANDLE (0x8F) +#define HID_USAGE_PID_PID_BLOCK_FREE_REPORT (0x90) +#define HID_USAGE_PID_TYPE_SPECIFIC_BLOCK_HANDLE (0x91) +#define HID_USAGE_PID_PID_STATE_REPORT (0x92) +#define HID_USAGE_PID_EFFECT_PLAYING (0x94) +#define HID_USAGE_PID_PID_DEVICE_CONTROL_REPORT (0x95) +#define HID_USAGE_PID_PID_DEVICE_CONTROL (0x96) +#define HID_USAGE_PID_DC_ENABLE_ACTUATORS (0x97) +#define HID_USAGE_PID_DC_DISABLE_ACTUATORS (0x98) +#define HID_USAGE_PID_DC_STOP_ALL_EFFECTS (0x99) +#define HID_USAGE_PID_DC_DEVICE_RESET (0x9A) +#define HID_USAGE_PID_DC_DEVICE_PAUSE (0x9B) +#define HID_USAGE_PID_DC_DEVICE_CONTINUE (0x9C) +#define HID_USAGE_PID_DEVICE_PAUSED (0x9F) +#define HID_USAGE_PID_ACTUATORS_ENABLED (0xA0) +#define HID_USAGE_PID_SAFETY_SWITCH (0xA4) +#define HID_USAGE_PID_ACTUATOR_OVERRIDE_SWITCH (0xA5) +#define HID_USAGE_PID_ACTUATOR_POWER (0xA6) +#define HID_USAGE_PID_START_DELAY (0xA7) +#define HID_USAGE_PID_PARAMETER_BLOCK_SIZE (0xA8) +#define HID_USAGE_PID_DEVICE_MANAGED_POOL (0xA9) +#define HID_USAGE_PID_SHARED_PARAMETER_BLOCKS (0xAA) +#define HID_USAGE_PID_CREATE_NEW_EFFECT_REPORT (0xAB) +#define HID_USAGE_PID_RAM_POOL_AVAILABLE (0xAC) + +/* Page 0x12: Eye and Head Trackers */ +#define HID_USAGE_EHT_UNDEFINED (0x00) +#define HID_USAGE_EHT_EYE_TRACKER (0x01) // CA +#define HID_USAGE_EHT_HEAD_TRACKER (0x02) // CA +#define HID_USAGE_EHT_TRACKING_DATA (0x10) // CP +#define HID_USAGE_EHT_CAPABILITIES (0x11) // CL +#define HID_USAGE_EHT_CONFIGURATION (0x12) // CL +#define HID_USAGE_EHT_STATUS (0x13) // CL +#define HID_USAGE_EHT_CONTROL (0x14) // CL +#define HID_USAGE_EHT_SENSOR_TIMESTAMP (0x20) // DV +#define HID_USAGE_EHT_POSITION_X (0x21) // DV +#define HID_USAGE_EHT_POSITION_Y (0x22) // DV +#define HID_USAGE_EHT_POSITION_Z (0x23) // DV +#define HID_USAGE_EHT_GAZE_POINT (0x24) // CP +#define HID_USAGE_EHT_LEFT_EYE_POSITION (0x25) // CP +#define HID_USAGE_EHT_RIGHT_EYE_POSITION (0x26) // CP +#define HID_USAGE_EHT_HEAD_POSITION (0x27) // CP +#define HID_USAGE_EHT_HEAD_DIRECTION_POINT (0x28) // CP +#define HID_USAGE_EHT_ROTATION_ABOUT_X_AXIS (0x29) // DV +#define HID_USAGE_EHT_ROTATION_ABOUT_Y_AXIS (0x2A) // DV +#define HID_USAGE_EHT_ROTATION_ABOUT_Z_AXIS (0x2B) // DV +#define HID_USAGE_EHT_TRACKER_QUALITY (0x100) // SV +#define HID_USAGE_EHT_MINIMUM_TRACKING_DISTANCE (0x101) // SV +#define HID_USAGE_EHT_OPTIMUM_TRACKING_DISTANCE (0x102) // SV +#define HID_USAGE_EHT_MAXIMUM_TRACKING_DISTANCE (0x103) // SV +#define HID_USAGE_EHT_MAXIMUM_SCREEN_PLANE_WIDTH (0x104) // SV +#define HID_USAGE_EHT_MAXIMUM_SCREEN_PLANE_HEIGHT (0x105) // SV +#define HID_USAGE_EHT_DISPLAY_MANUFACTURER_ID (0x200) // SV +#define HID_USAGE_EHT_DISPLAY_PRODUCT_ID (0x201) // SV +#define HID_USAGE_EHT_DISPLAY_SERIAL_NUMBER (0x202) // SV +#define HID_USAGE_EHT_DISPLAY_MANUFACTURER_DATE (0x203) // SV +#define HID_USAGE_EHT_CALIBRATED_SCREEN_WIDTH (0x204) // SV +#define HID_USAGE_EHT_CALIBRATED_SCREEN_HEIGHT (0x205) // SV +#define HID_USAGE_EHT_SAMPLING_FREQUENCY (0x300) // DV +#define HID_USAGE_EHT_CONFIGURATION_STATUS (0x301) // DV +#define HID_USAGE_EHT_DEVICE_MODE_REQUEST (0x400) // DV + +/* Page 0x14: Auxiliary Display */ +#define HID_USAGE_AUXDISP_UNDEFINED (0x00) +#define HID_USAGE_AUXDISP_ALPHANUMERIC_DISPLAY (0x01) // CA +#define HID_USAGE_AUXDISP_AUXILIARY_DISPLAY (0x02) // CA +#define HID_USAGE_AUXDISP_DISPLAY_ATTRIBUTES_REPORT (0x20) // CL +#define HID_USAGE_AUXDISP_ASCII_CHARACTER_SET (0x21) // SF +#define HID_USAGE_AUXDISP_DATA_READ_BACK (0x22) // SF +#define HID_USAGE_AUXDISP_FONT_READ_BACK (0x23) // SF +#define HID_USAGE_AUXDISP_DISPLAY_CONTROL_REPORT (0x24) // CL +#define HID_USAGE_AUXDISP_CLEAR_DISPLAY (0x25) // DF +#define HID_USAGE_AUXDISP_DISPLAY_ENABLE (0x26) // DF +#define HID_USAGE_AUXDISP_SCREEN_SAVER_DELAY (0x27) // SV, DV +#define HID_USAGE_AUXDISP_SCREEN_SAVER_ENABLE (0x28) // DF +#define HID_USAGE_AUXDISP_VERTICAL_SCROLL (0x29) // SF, DF +#define HID_USAGE_AUXDISP_HORIZONTAL_SCROLL (0x2A) // SF, DF +#define HID_USAGE_AUXDISP_CHARACTER_REPORT (0x2B) // CL +#define HID_USAGE_AUXDISP_DISPLAY_DATA (0x2C) // DV +#define HID_USAGE_AUXDISP_DISPLAY_STATUS (0x2D) // CL +#define HID_USAGE_AUXDISP_STAT_NOT_READY (0x2E) // Sel +#define HID_USAGE_AUXDISP_STAT_READY (0x2F) // Sel +#define HID_USAGE_AUXDISP_ERR_NOT_A_LOADABLE_CHARACTER (0x30) // Sel +#define HID_USAGE_AUXDISP_ERR_FONT_DATA_CANNOT_BE_READ (0x31) // Sel +#define HID_USAGE_AUXDISP_CURSOR_POSITION_REPORT (0x32) // Sel +#define HID_USAGE_AUXDISP_ROW (0x33) // DV +#define HID_USAGE_AUXDISP_COLUMN (0x34) // DV +#define HID_USAGE_AUXDISP_ROWS (0x35) // SV +#define HID_USAGE_AUXDISP_COLUMNS (0x36) // SV +#define HID_USAGE_AUXDISP_CURSOR_PIXEL_POSITIONING (0x37) // SF +#define HID_USAGE_AUXDISP_CURSOR_MODE (0x38) // DF +#define HID_USAGE_AUXDISP_CURSOR_ENABLE (0x39) // DF +#define HID_USAGE_AUXDISP_CURSOR_BLINK (0x3A) // DF +#define HID_USAGE_AUXDISP_FONT_REPORT (0x3B) // CL +#define HID_USAGE_AUXDISP_FONT_DATA (0x3C) // Buffered Bytes +#define HID_USAGE_AUXDISP_CHARACTER_WIDTH (0x3D) // SV +#define HID_USAGE_AUXDISP_CHARACTER_HEIGHT (0x3E) // SV +#define HID_USAGE_AUXDISP_CHARACTER_SPACING_HORIZONTAL (0x3F) // SV +#define HID_USAGE_AUXDISP_CHARACTER_SPACING_VERTICAL (0x40) // SV +#define HID_USAGE_AUXDISP_UNICODE_CHARACTER_SET (0x41) // SF +#define HID_USAGE_AUXDISP_FONT_7_SEGMENT (0x42) // SF +#define HID_USAGE_AUXDISP_7_SEGMENT_DIRECT_MAP (0x43) // SF +#define HID_USAGE_AUXDISP_FONT_14_SEGMENT (0x44) // SF +#define HID_USAGE_AUXDISP_14_SEGMENT_DIRECT_MAP (0x45) // SF +#define HID_USAGE_AUXDISP_DISPLAY_BRIGHTNESS (0x46) // DV +#define HID_USAGE_AUXDISP_DISPLAY_CONTRAST (0x47) // DV +#define HID_USAGE_AUXDISP_CHARACTER_ATTRIBUTE (0x48) // CL +#define HID_USAGE_AUXDISP_ATTRIBUTE_READBACK (0x49) // SF +#define HID_USAGE_AUXDISP_ATTRIBUTE_DATA (0x4A) // DV +#define HID_USAGE_AUXDISP_CHAR_ATTR_ENHANCE (0x4B) // OOC +#define HID_USAGE_AUXDISP_CHAR_ATTR_UNDERLINE (0x4C) // OOC +#define HID_USAGE_AUXDISP_CHAR_ATTR_BLINK (0x4D) // OOC +#define HID_USAGE_AUXDISP_BITMAP_SIZE_X (0x80) // SV +#define HID_USAGE_AUXDISP_BITMAP_SIZE_Y (0x81) // SV +#define HID_USAGE_AUXDISP_MAX_BLIT_SIZE (0x82) // SV +#define HID_USAGE_AUXDISP_BIT_DEPTH_FORMAT (0x83) // SV +#define HID_USAGE_AUXDISP_DISPLAY_ORIENTATION (0x84) // DV +#define HID_USAGE_AUXDISP_PALETTE_REPORT (0x85) // CL +#define HID_USAGE_AUXDISP_PALETTE_DATA_SIZE (0x86) // SV +#define HID_USAGE_AUXDISP_PALETTE_DATA_OFFSET (0x87) // SV +#define HID_USAGE_AUXDISP_PALETTE_DATA (0x88) // Buffered Bytes +#define HID_USAGE_AUXDISP_BLIT_REPORT (0x8A) // CL +#define HID_USAGE_AUXDISP_BLIT_RECTANGLE_X1 (0x8B) // SV +#define HID_USAGE_AUXDISP_BLIT_RECTANGLE_Y1 (0x8C) // SV +#define HID_USAGE_AUXDISP_BLIT_RECTANGLE_X2 (0x8D) // SV +#define HID_USAGE_AUXDISP_BLIT_RECTANGLE_Y2 (0x8E) // SV +#define HID_USAGE_AUXDISP_BLIT_DATA (0x8F) // Buffered Bytes +#define HID_USAGE_AUXDISP_SOFT_BUTTON (0x90) // CL +#define HID_USAGE_AUXDISP_SOFT_BUTTON_ID (0x91) // SV +#define HID_USAGE_AUXDISP_SOFT_BUTTON_SIDE (0x92) // SV +#define HID_USAGE_AUXDISP_SOFT_BUTTON_OFFSET_1 (0x93) // SV +#define HID_USAGE_AUXDISP_SOFT_BUTTON_OFFSET_2 (0x94) // SV +#define HID_USAGE_AUXDISP_SOFT_BUTTON_REPORT (0x95) // SV +#define HID_USAGE_AUXDISP_SOFT_KEYS (0xC2) // SV +#define HID_USAGE_AUXDISP_DISPLAY_DATA_EXTENSIONS (0xCC) // SF +#define HID_USAGE_AUXDISP_CHARACTER_MAPPING (0xCF) // SV +#define HID_USAGE_AUXDISP_UNICODE_EQUIVALENT (0xDD) // SV +#define HID_USAGE_AUXDISP_CHARACTER_PAGE_MAPPING (0xDF) // SV +#define HID_USAGE_AUXDISP_REQUEST_REPORT (0xFF) // DV + +/* Page 0x20: Sensors */ +#define HID_USAGE_SENSORS_UNDEFINED (0x00) +#define HID_USAGE_SENSORS_SENSOR (0x01) // CA, CP +#define HID_USAGE_SENSORS_BIOMETRIC (0x10) // CA, CP +#define HID_USAGE_SENSORS_BIOMETRIC_HUMAN_PRESENCE (0x11) // CA, CP +#define HID_USAGE_SENSORS_BIOMETRIC_HUMAN_PROXIMITY (0x12) // CA, CP +#define HID_USAGE_SENSORS_BIOMETRIC_HUMAN_TOUCH (0x13) // CA, CP +#define HID_USAGE_SENSORS_BIOMETRIC_BLOOD_PRESSURE (0x14) // CA, CP +#define HID_USAGE_SENSORS_BIOMETRIC_BODY_TEMPERATURE (0x15) // CA, CP +#define HID_USAGE_SENSORS_BIOMETRIC_HEART_RATE (0x16) // CA, CP +#define HID_USAGE_SENSORS_BIOMETRIC_HEART_RATE_VARIABILITY (0x17) // CA, CP +#define HID_USAGE_SENSORS_BIOMETRIC_PERIPHERAL_OXYGEN_SATURATION (0x18) // CA, CP +#define HID_USAGE_SENSORS_BIOMETRIC_RESPIRATORY_RATE (0x19) // CA, CP +#define HID_USAGE_SENSORS_ELECTRICAL (0x20) // CA, CP +#define HID_USAGE_SENSORS_ELECTRICAL_CAPACITANCE (0x21) // CA, CP +#define HID_USAGE_SENSORS_ELECTRICAL_CURRENT (0x22) // CA, CP +#define HID_USAGE_SENSORS_ELECTRICAL_POWER (0x23) // CA, CP +#define HID_USAGE_SENSORS_ELECTRICAL_INDUCTANCE (0x24) // CA, CP +#define HID_USAGE_SENSORS_ELECTRICAL_RESISTANCE (0x25) // CA, CP +#define HID_USAGE_SENSORS_ELECTRICAL_VOLTAGE (0x26) // CA, CP +#define HID_USAGE_SENSORS_ELECTRICAL_POTENTIOMETER (0x27) // CA, CP +#define HID_USAGE_SENSORS_ELECTRICAL_FREQUENCY (0x28) // CA, CP +#define HID_USAGE_SENSORS_ELECTRICAL_PERIOD (0x29) // CA, CP +#define HID_USAGE_SENSORS_ENVIRONMENTAL (0x30) // CA, CP +#define HID_USAGE_SENSORS_ENVIRONMENTAL_ATMOSPHERIC_PRESSURE (0x31) // CA, CP +#define HID_USAGE_SENSORS_ENVIRONMENTAL_HUMIDITY (0x32) // CA, CP +#define HID_USAGE_SENSORS_ENVIRONMENTAL_TEMPERATURE (0x33) // CA, CP +#define HID_USAGE_SENSORS_ENVIRONMENTAL_WIND_DIRECTION (0x34) // CA, CP +#define HID_USAGE_SENSORS_ENVIRONMENTAL_WIND_SPEED (0x35) // CA, CP +#define HID_USAGE_SENSORS_ENVIRONMENTAL_AIR_QUALITY (0x36) // CA, CP +#define HID_USAGE_SENSORS_ENVIRONMENTAL_HEAT_INDEX (0x37) // CA, CP +#define HID_USAGE_SENSORS_ENVIRONMENTAL_SURFACE_TEMPERATURE (0x38) // CA, CP +#define HID_USAGE_SENSORS_ENVIRONMENTAL_VOLATILE_ORGANIC_COMPOUNDS (0x39) // CA, CP +#define HID_USAGE_SENSORS_ENVIRONMENTAL_OBJECT_PRESENCE (0x3A) // CA, CP +#define HID_USAGE_SENSORS_ENVIRONMENTAL_OBJECT_PROXIMITY (0x3B) // CA, CP +#define HID_USAGE_SENSORS_LIGHT (0x40) // CA, CP +#define HID_USAGE_SENSORS_LIGHT_AMBIENT_LIGHT (0x41) // CA, CP +#define HID_USAGE_SENSORS_LIGHT_CONSUMER_INFRARED (0x42) // CA, CP +#define HID_USAGE_SENSORS_LIGHT_INFRARED_LIGHT (0x43) // CA, CP +#define HID_USAGE_SENSORS_LIGHT_VISIBLE_LIGHT (0x44) // CA, CP +#define HID_USAGE_SENSORS_LIGHT_ULTRAVIOLET_LIGHT (0x45) // CA, CP +#define HID_USAGE_SENSORS_LOCATION (0x50) // CA, CP +#define HID_USAGE_SENSORS_LOCATION_BROADCAST (0x51) // CA, CP +#define HID_USAGE_SENSORS_LOCATION_DEAD_RECKONING (0x52) // CA, CP +#define HID_USAGE_SENSORS_LOCATION_GPS_GLOBAL_POSITIONING_SYSTEM (0x53) // CA, CP +#define HID_USAGE_SENSORS_LOCATION_LOOKUP (0x54) // CA, CP +#define HID_USAGE_SENSORS_LOCATION_OTHER (0x55) // CA, CP +#define HID_USAGE_SENSORS_LOCATION_STATIC (0x56) // CA, CP +#define HID_USAGE_SENSORS_LOCATION_TRIANGULATION (0x57) // CA, CP +#define HID_USAGE_SENSORS_MECHANICAL (0x60) // CA, CP +#define HID_USAGE_SENSORS_MECHANICAL_BOOLEAN_SWITCH (0x61) // CA, CP +#define HID_USAGE_SENSORS_MECHANICAL_BOOLEAN_SWITCH_ARRAY (0x62) // CA, CP +#define HID_USAGE_SENSORS_MECHANICAL_MULTIVALUE_SWITCH (0x63) // CA, CP +#define HID_USAGE_SENSORS_MECHANICAL_FORCE (0x64) // CA, CP +#define HID_USAGE_SENSORS_MECHANICAL_PRESSURE (0x65) // CA, CP +#define HID_USAGE_SENSORS_MECHANICAL_STRAIN (0x66) // CA, CP +#define HID_USAGE_SENSORS_MECHANICAL_WEIGHT (0x67) // CA, CP +#define HID_USAGE_SENSORS_MECHANICAL_HAPTIC_VIBRATOR (0x68) // CA, CP +#define HID_USAGE_SENSORS_MECHANICAL_HALL_EFFECT_SWITCH (0x69) // CA, CP +#define HID_USAGE_SENSORS_MOTION (0x70) // CA, CP +#define HID_USAGE_SENSORS_MOTION_ACCELEROMETER_1D (0x71) // CA, CP +#define HID_USAGE_SENSORS_MOTION_ACCELEROMETER_2D (0x72) // CA, CP +#define HID_USAGE_SENSORS_MOTION_ACCELEROMETER_3D (0x73) // CA, CP +#define HID_USAGE_SENSORS_MOTION_GYROMETER_1D (0x74) // CA, CP +#define HID_USAGE_SENSORS_MOTION_GYROMETER_2D (0x75) // CA, CP +#define HID_USAGE_SENSORS_MOTION_GYROMETER_3D (0x76) // CA, CP +#define HID_USAGE_SENSORS_MOTION_MOTION_DETECTOR (0x77) // CA, CP +#define HID_USAGE_SENSORS_MOTION_SPEEDOMETER (0x78) // CA, CP +#define HID_USAGE_SENSORS_MOTION_ACCELEROMETER (0x79) // CA, CP +#define HID_USAGE_SENSORS_MOTION_GYROMETER (0x7A) // CA, CP +#define HID_USAGE_SENSORS_MOTION_GRAVITY_VECTOR (0x7B) // CA, CP +#define HID_USAGE_SENSORS_MOTION_LINEAR_ACCELEROMETER (0x7C) // CA, CP +#define HID_USAGE_SENSORS_ORIENTATION (0x80) // CA, CP +#define HID_USAGE_SENSORS_ORIENTATION_COMPASS_1D (0x81) // CA, CP +#define HID_USAGE_SENSORS_ORIENTATION_COMPASS_2D (0x82) // CA, CP +#define HID_USAGE_SENSORS_ORIENTATION_COMPASS_3D (0x83) // CA, CP +#define HID_USAGE_SENSORS_ORIENTATION_INCLINOMETER_1D (0x84) // CA, CP +#define HID_USAGE_SENSORS_ORIENTATION_INCLINOMETER_2D (0x85) // CA, CP +#define HID_USAGE_SENSORS_ORIENTATION_INCLINOMETER_3D (0x86) // CA, CP +#define HID_USAGE_SENSORS_ORIENTATION_DISTANCE_1D (0x87) // CA, CP +#define HID_USAGE_SENSORS_ORIENTATION_DISTANCE_2D (0x88) // CA, CP +#define HID_USAGE_SENSORS_ORIENTATION_DISTANCE_3D (0x89) // CA, CP +#define HID_USAGE_SENSORS_ORIENTATION_DEVICE_ORIENTATION (0x8A) // CA, CP +#define HID_USAGE_SENSORS_ORIENTATION_COMPASS (0x8B) // CA, CP +#define HID_USAGE_SENSORS_ORIENTATION_INCLINOMETER (0x8C) // CA, CP +#define HID_USAGE_SENSORS_ORIENTATION_DISTANCE (0x8D) // CA, CP +#define HID_USAGE_SENSORS_ORIENTATION_RELATIVE_ORIENTATION (0x8E) // CA, CP +#define HID_USAGE_SENSORS_ORIENTATION_SIMPLE_ORIENTATION (0x8F) // CA, CP +#define HID_USAGE_SENSORS_SCANNER (0x90) // CA, CP +#define HID_USAGE_SENSORS_SCANNER_BARCODE (0x91) // CA, CP +#define HID_USAGE_SENSORS_SCANNER_RFID (0x92) // CA, CP +#define HID_USAGE_SENSORS_SCANNER_NFC (0x93) // CA, CP +#define HID_USAGE_SENSORS_TIME (0xA0) // CA, CP +#define HID_USAGE_SENSORS_TIME_ALARM_TIMER (0xA1) // CA, CP +#define HID_USAGE_SENSORS_TIME_REAL_TIME_CLOCK (0xA2) // CA, CP +#define HID_USAGE_SENSORS_PERSONAL_ACTIVITY (0xB0) // CA, CP +#define HID_USAGE_SENSORS_PERSONAL_ACTIVITY_ACTIVITY_DETECTION (0xB1) // CA, CP +#define HID_USAGE_SENSORS_PERSONAL_ACTIVITY_DEVICE_POSITION (0xB2) // CA, CP +#define HID_USAGE_SENSORS_PERSONAL_ACTIVITY_PEDOMETER (0xB3) // CA, CP +#define HID_USAGE_SENSORS_PERSONAL_ACTIVITY_STEP_DETECTION (0xB4) // CA, CP +#define HID_USAGE_SENSORS_ORIENTATION_EXTENDED (0xC0) // CA, CP +#define HID_USAGE_SENSORS_ORIENTATION_EXTENDED_GEOMAGNETIC_ORIENTATION (0xC1) // CA, CP +#define HID_USAGE_SENSORS_ORIENTATION_EXTENDED_MAGNETOMETER (0xC2) // CA, CP +#define HID_USAGE_SENSORS_GESTURE (0xD0) // CA, CP +#define HID_USAGE_SENSORS_GESTURE_CHASSIS_FLIP_GESTURE (0xD1) // CA, CP +#define HID_USAGE_SENSORS_GESTURE_HINGE_FOLD_GESTURE (0xD2) // CA, CP +#define HID_USAGE_SENSORS_OTHER (0xE0) // CA, CP +#define HID_USAGE_SENSORS_OTHER_CUSTOM (0xE1) // CA, CP +#define HID_USAGE_SENSORS_OTHER_GENERIC (0xE2) // CA, CP +#define HID_USAGE_SENSORS_OTHER_GENERIC_ENUMERATOR (0xE3) // CA, CP +#define HID_USAGE_SENSORS_OTHER_HINGE_ANGLE (0xE4) // CA, CP +#define HID_USAGE_SENSORS_EVENT (0x200) // DV +#define HID_USAGE_SENSORS_EVENT_SENSOR_STATE (0x201) // NAry +#define HID_USAGE_SENSORS_EVENT_SENSOR_EVENT (0x202) // NAry +#define HID_USAGE_SENSORS_PROPERTY (0x300) // DV +#define HID_USAGE_SENSORS_PROPERTY_FRIENDLY_NAME (0x301) // SV +#define HID_USAGE_SENSORS_PROPERTY_PERSISTENT_UNIQUE_ID (0x302) // DV +#define HID_USAGE_SENSORS_PROPERTY_SENSOR_STATUS (0x303) // DV +#define HID_USAGE_SENSORS_PROPERTY_MINIMUM_REPORT_INTERVAL (0x304) // SV +#define HID_USAGE_SENSORS_PROPERTY_SENSOR_MANUFACTURER (0x305) // SV +#define HID_USAGE_SENSORS_PROPERTY_SENSOR_MODEL (0x306) // SV +#define HID_USAGE_SENSORS_PROPERTY_SENSOR_SERIAL_NUMBER (0x307) // SV +#define HID_USAGE_SENSORS_PROPERTY_SENSOR_DESCRIPTION (0x308) // SV +#define HID_USAGE_SENSORS_PROPERTY_SENSOR_CONNECTION_TYPE (0x309) // NAry +#define HID_USAGE_SENSORS_PROPERTY_SENSOR_DEVICE_PATH (0x30A) // DV +#define HID_USAGE_SENSORS_PROPERTY_HARDWARE_REVISION (0x30B) // SV +#define HID_USAGE_SENSORS_PROPERTY_FIRMWARE_VERSION (0x30C) // SV +#define HID_USAGE_SENSORS_PROPERTY_RELEASE_DATE (0x30D) // SV +#define HID_USAGE_SENSORS_PROPERTY_REPORT_INTERVAL (0x30E) // DV +#define HID_USAGE_SENSORS_PROPERTY_CHANGE_SENSITIVITY_ABSOLUTE (0x30F) // DV +#define HID_USAGE_SENSORS_PROPERTY_CHANGE_SENSITIVITY_PERCENT_OF_RANGE (0x310) // DV +#define HID_USAGE_SENSORS_PROPERTY_CHANGE_SENSITIVITY_PERCENT_RELATIVE (0x311) // DV +#define HID_USAGE_SENSORS_PROPERTY_ACCURACY (0x312) // DV +#define HID_USAGE_SENSORS_PROPERTY_RESOLUTION (0x313) // DV +#define HID_USAGE_SENSORS_PROPERTY_MAXIMUM (0x314) // DV +#define HID_USAGE_SENSORS_PROPERTY_MINIMUM (0x315) // DV +#define HID_USAGE_SENSORS_PROPERTY_REPORTING_STATE (0x316) // NAry +#define HID_USAGE_SENSORS_PROPERTY_SAMPLING_RATE (0x317) // DV +#define HID_USAGE_SENSORS_PROPERTY_RESPONSE_CURVE (0x318) // DV +#define HID_USAGE_SENSORS_PROPERTY_POWER_STATE (0x319) // NAry +#define HID_USAGE_SENSORS_PROPERTY_MAXIMUM_FIFO_EVENTS (0x31A) // SV +#define HID_USAGE_SENSORS_PROPERTY_REPORT_LATENCY (0x31B) // DV +#define HID_USAGE_SENSORS_PROPERTY_FLUSH_FIFO_EVENTS (0x31C) // DF +#define HID_USAGE_SENSORS_PROPERTY_MAXIMUM_POWER_CONSUMPTION (0x31D) // DV +#define HID_USAGE_SENSORS_PROPERTY_IS_PRIMARY (0x31E) // DF +#define HID_USAGE_SENSORS_DATA_FIELD_LOCATION (0x400) // DV +#define HID_USAGE_SENSORS_DATA_FIELD_ALTITUDE_ANTENNA_SEA_LEVEL (0x402) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_DIFFERENTIAL_REFERENCE_STATION_ID (0x403) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ALTITUDE_ELLIPSOID_ERROR (0x404) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ALTITUDE_ELLIPSOID (0x405) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ALTITUDE_SEA_LEVEL_ERROR (0x406) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ALTITUDE_SEA_LEVEL (0x407) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_DIFFERENTIAL_GPS_DATA_AGE (0x408) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ERROR_RADIUS (0x409) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_FIX_QUALITY (0x40A) // NAry +#define HID_USAGE_SENSORS_DATA_FIELD_FIX_TYPE (0x40B) // NAry +#define HID_USAGE_SENSORS_DATA_FIELD_GEOIDAL_SEPARATION (0x40C) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_GPS_OPERATION_MODE (0x40D) // NAry +#define HID_USAGE_SENSORS_DATA_FIELD_GPS_SELECTION_MODE (0x40E) // NAry +#define HID_USAGE_SENSORS_DATA_FIELD_GPS_STATUS (0x40F) // NAry +#define HID_USAGE_SENSORS_DATA_FIELD_POSITION_DILUTION_OF_PRECISION (0x410) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_HORIZONTAL_DILUTION_OF_PRECISION (0x411) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_VERTICAL_DILUTION_OF_PRECISION (0x412) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_LATITUDE (0x413) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_LONGITUDE (0x414) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_TRUE_HEADING (0x415) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_MAGNETIC_HEADING (0x416) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_MAGNETIC_VARIATION (0x417) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_SPEED (0x418) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_SATELLITES_IN_VIEW (0x419) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_SATELLITES_IN_VIEW_AZIMUTH (0x41A) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_SATELLITES_IN_VIEW_ELEVATION (0x41B) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_SATELLITES_IN_VIEW_IDS (0x41C) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_SATELLITES_IN_VIEW_PRNS (0x41D) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_SATELLITES_IN_VIEW_S_N_RATIOS (0x41E) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_SATELLITES_USED_COUNT (0x41F) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_SATELLITES_USED_PRNS (0x420) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_NMEA_SENTENCE (0x421) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ADDRESS_LINE_1 (0x422) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ADDRESS_LINE_2 (0x423) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CITY (0x424) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_STATE_OR_PROVINCE (0x425) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_COUNTRY_OR_REGION (0x426) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_POSTAL_CODE (0x427) // SV +#define HID_USAGE_SENSORS_PROPERTY_LOCATION (0x42A) // DV +#define HID_USAGE_SENSORS_PROPERTY_LOCATION_DESIRED_ACCURACY (0x42B) // NAry +#define HID_USAGE_SENSORS_DATA_FIELD_ENVIRONMENTAL (0x430) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ATMOSPHERIC_PRESSURE (0x431) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_RELATIVE_HUMIDITY (0x433) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_TEMPERATURE (0x434) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_WIND_DIRECTION (0x435) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_WIND_SPEED (0x436) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_AIR_QUALITY_INDEX (0x437) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_EQUIVALENT_CO2 (0x438) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_VOLATILE_ORGANIC_COMPOUND_CONCENTRATION (0x439) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_OBJECT_PRESENCE (0x43A) // SF +#define HID_USAGE_SENSORS_DATA_FIELD_OBJECT_PROXIMITY_RANGE (0x43B) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_OBJECT_PROXIMITY_OUT_OF_RANGE (0x43C) // SF +#define HID_USAGE_SENSORS_PROPERTY_ENVIRONMENTAL (0x440) // SV +#define HID_USAGE_SENSORS_PROPERTY_REFERENCE_PRESSURE (0x441) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_MOTION (0x450) // DV +#define HID_USAGE_SENSORS_DATA_FIELD_MOTION_STATE (0x451) // SF +#define HID_USAGE_SENSORS_DATA_FIELD_ACCELERATION (0x452) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ACCELERATION_AXIS_X (0x453) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ACCELERATION_AXIS_Y (0x454) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ACCELERATION_AXIS_Z (0x455) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ANGULAR_VELOCITY (0x456) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ANGULAR_VELOCITY_ABOUT_X_AXIS (0x457) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ANGULAR_VELOCITY_ABOUT_Y_AXIS (0x458) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ANGULAR_VELOCITY_ABOUT_Z_AXIS (0x459) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ANGULAR_POSITION (0x45A) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ANGULAR_POSITION_ABOUT_X_AXIS (0x45B) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ANGULAR_POSITION_ABOUT_Y_AXIS (0x45C) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ANGULAR_POSITION_ABOUT_Z_AXIS (0x45D) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_MOTION_SPEED (0x45E) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_MOTION_INTENSITY (0x45F) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ORIENTATION (0x470) // DV +#define HID_USAGE_SENSORS_DATA_FIELD_HEADING (0x471) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_HEADING_X_AXIS (0x472) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_HEADING_Y_AXIS (0x473) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_HEADING_Z_AXIS (0x474) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_HEADING_COMPENSATED_MAGNETIC_NORTH (0x475) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_HEADING_COMPENSATED_TRUE_NORTH (0x476) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_HEADING_MAGNETIC_NORTH (0x477) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_HEADING_TRUE_NORTH (0x478) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_DISTANCE (0x479) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_DISTANCE_X_AXIS (0x47A) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_DISTANCE_Y_AXIS (0x47B) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_DISTANCE_Z_AXIS (0x47C) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_DISTANCE_OUT_OF_RANGE (0x47D) // SF +#define HID_USAGE_SENSORS_DATA_FIELD_TILT (0x47E) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_TILT_X_AXIS (0x47F) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_TILT_Y_AXIS (0x480) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_TILT_Z_AXIS (0x481) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ROTATION_MATRIX (0x482) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_QUATERNION (0x483) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_MAGNETIC_FLUX (0x484) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_MAGNETIC_FLUX_X_AXIS (0x485) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_MAGNETIC_FLUX_Y_AXIS (0x486) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_MAGNETIC_FLUX_Z_AXIS (0x487) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_MAGNETOMETER_ACCURACY (0x488) // NAry +#define HID_USAGE_SENSORS_DATA_FIELD_SIMPLE_ORIENTATION_DIRECTION (0x489) // NAry +#define HID_USAGE_SENSORS_DATA_FIELD_MECHANICAL (0x490) // DV +#define HID_USAGE_SENSORS_DATA_FIELD_BOOLEAN_SWITCH_STATE (0x491) // SF +#define HID_USAGE_SENSORS_DATA_FIELD_BOOLEAN_SWITCH_ARRAY_STATES (0x492) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_MULTIVALUE_SWITCH_VALUE (0x493) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_FORCE (0x494) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ABSOLUTE_PRESSURE (0x495) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_GAUGE_PRESSURE (0x496) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_STRAIN (0x497) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_WEIGHT (0x498) // SV +#define HID_USAGE_SENSORS_PROPERTY_MECHANICAL (0x4A0) // DV +#define HID_USAGE_SENSORS_PROPERTY_VIBRATION_STATE (0x4A1) // DF +#define HID_USAGE_SENSORS_PROPERTY_FORWARD_VIBRATION_SPEED (0x4A2) // DV +#define HID_USAGE_SENSORS_PROPERTY_BACKWARD_VIBRATION_SPEED (0x4A3) // DV +#define HID_USAGE_SENSORS_DATA_FIELD_BIOMETRIC (0x4B0) // DV +#define HID_USAGE_SENSORS_DATA_FIELD_HUMAN_PRESENCE (0x4B1) // SF +#define HID_USAGE_SENSORS_DATA_FIELD_HUMAN_PROXIMITY_RANGE (0x4B2) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_HUMAN_PROXIMITY_OUT_OF_RANGE (0x4B3) // SF +#define HID_USAGE_SENSORS_DATA_FIELD_HUMAN_TOUCH_STATE (0x4B4) // SF +#define HID_USAGE_SENSORS_DATA_FIELD_BLOOD_PRESSURE (0x4B5) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_BLOOD_PRESSURE_DIASTOLIC (0x4B6) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_BLOOD_PRESSURE_SYSTOLIC (0x4B7) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_HEART_RATE (0x4B8) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_RESTING_HEART_RATE (0x4B9) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_HEARTBEAT_INTERVAL (0x4BA) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_RESPIRATORY_RATE (0x4BB) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_SPO2 (0x4BC) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_LIGHT (0x4D0) // DV +#define HID_USAGE_SENSORS_DATA_FIELD_ILLUMINANCE (0x4D1) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_COLOR_TEMPERATURE (0x4D2) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CHROMATICITY (0x4D3) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CHROMATICITY_X (0x4D4) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CHROMATICITY_Y (0x4D5) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CONSUMER_IR_SENTENCE_RECEIVE (0x4D6) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_INFRARED_LIGHT (0x4D7) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_RED_LIGHT (0x4D8) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_GREEN_LIGHT (0x4D9) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_BLUE_LIGHT (0x4DA) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ULTRAVIOLET_A_LIGHT (0x4DB) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ULTRAVIOLET_B_LIGHT (0x4DC) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ULTRAVIOLET_INDEX (0x4DD) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_NEAR_INFRARED_LIGHT (0x4DE) // SV +#define HID_USAGE_SENSORS_PROPERTY_LIGHT (0x4DF) // DV +#define HID_USAGE_SENSORS_PROPERTY_CONSUMER_IR_SENTENCE_SEND (0x4E0) // DV +#define HID_USAGE_SENSORS_PROPERTY_AUTO_BRIGHTNESS_PREFERRED (0x4E2) // DF +#define HID_USAGE_SENSORS_PROPERTY_AUTO_COLOR_PREFERRED (0x4E3) // DF +#define HID_USAGE_SENSORS_DATA_FIELD_SCANNER (0x4F0) // DV +#define HID_USAGE_SENSORS_DATA_FIELD_RFID_TAG_40_BIT (0x4F1) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_NFC_SENTENCE_RECEIVE (0x4F2) // SV +#define HID_USAGE_SENSORS_PROPERTY_SCANNER (0x4F8) // DV +#define HID_USAGE_SENSORS_PROPERTY_NFC_SENTENCE_SEND (0x4F9) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ELECTRICAL (0x500) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CAPACITANCE (0x501) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CURRENT (0x502) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ELECTRICAL_POWER (0x503) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_INDUCTANCE (0x504) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_RESISTANCE (0x505) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_VOLTAGE (0x506) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_FREQUENCY (0x507) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_PERIOD (0x508) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_PERCENT_OF_RANGE (0x509) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_TIME (0x520) // DV +#define HID_USAGE_SENSORS_DATA_FIELD_YEAR (0x521) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_MONTH (0x522) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_DAY (0x523) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_DAY_OF_WEEK (0x524) // NAry +#define HID_USAGE_SENSORS_DATA_FIELD_HOUR (0x525) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_MINUTE (0x526) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_SECOND (0x527) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_MILLISECOND (0x528) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_TIMESTAMP (0x529) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_JULIAN_DAY_OF_YEAR (0x52A) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_TIME_SINCE_SYSTEM_BOOT (0x52B) // SV +#define HID_USAGE_SENSORS_PROPERTY_TIME (0x530) // DV +#define HID_USAGE_SENSORS_PROPERTY_TIME_ZONE_OFFSET_FROM_UTC (0x531) // DV +#define HID_USAGE_SENSORS_PROPERTY_TIME_ZONE_NAME (0x532) // DV +#define HID_USAGE_SENSORS_PROPERTY_DAYLIGHT_SAVINGS_TIME_OBSERVED (0x533) // DF +#define HID_USAGE_SENSORS_PROPERTY_TIME_TRIM_ADJUSTMENT (0x534) // DV +#define HID_USAGE_SENSORS_PROPERTY_ARM_ALARM (0x535) // DF +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM (0x540) // DV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_USAGE (0x541) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_BOOLEAN_ARRAY (0x542) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE (0x543) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_1 (0x544) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_2 (0x545) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_3 (0x546) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_4 (0x547) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_5 (0x548) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_6 (0x549) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_7 (0x54A) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_8 (0x54B) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_9 (0x54C) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_10 (0x54D) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_11 (0x54E) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_12 (0x54F) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_13 (0x550) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_14 (0x551) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_15 (0x552) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_16 (0x553) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_17 (0x554) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_18 (0x555) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_19 (0x556) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_20 (0x557) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_21 (0x558) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_22 (0x559) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_23 (0x55A) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_24 (0x55B) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_25 (0x55C) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_26 (0x55D) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_27 (0x55E) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_VALUE_28 (0x55F) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC (0x560) // DV +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC_GUID_OR_PROPERTYKEY (0x561) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC_CATEGORY_GUID (0x562) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC_TYPE_GUID (0x563) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC_EVENT_PROPERTYKEY (0x564) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC_PROPERTY_PROPERTYKEY (0x565) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC_DATA_FIELD_PROPERTYKEY (0x566) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC_EVENT (0x567) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC_PROPERTY (0x568) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC_DATA_FIELD (0x569) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ENUMERATOR_TABLE_ROW_INDEX (0x56A) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_ENUMERATOR_TABLE_ROW_COUNT (0x56B) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC_GUID_OR_PROPERTYKEY_KIND (0x56C) // NAry +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC_GUID (0x56D) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC_PROPERTYKEY (0x56E) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC_TOP_LEVEL_COLLECTION_ID (0x56F) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC_REPORT_ID (0x570) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC_REPORT_ITEM_POSITION_INDEX (0x571) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC_FIRMWARE_VARTYPE (0x572) // NAry +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC_UNIT_OF_MEASURE (0x573) // NAry +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC_UNIT_EXPONENT (0x574) // NAry +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC_REPORT_SIZE (0x575) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_GENERIC_REPORT_COUNT (0x576) // SV +#define HID_USAGE_SENSORS_PROPERTY_GENERIC (0x580) // DV +#define HID_USAGE_SENSORS_PROPERTY_ENUMERATOR_TABLE_ROW_INDEX (0x581) // DV +#define HID_USAGE_SENSORS_PROPERTY_ENUMERATOR_TABLE_ROW_COUNT (0x582) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_PERSONAL_ACTIVITY (0x590) // DV +#define HID_USAGE_SENSORS_DATA_FIELD_ACTIVITY_TYPE (0x591) // NAry +#define HID_USAGE_SENSORS_DATA_FIELD_ACTIVITY_STATE (0x592) // NAry +#define HID_USAGE_SENSORS_DATA_FIELD_DEVICE_POSITION (0x593) // NAry +#define HID_USAGE_SENSORS_DATA_FIELD_STEP_COUNT (0x594) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_STEP_COUNT_RESET (0x595) // DF +#define HID_USAGE_SENSORS_DATA_FIELD_STEP_DURATION (0x596) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_STEP_TYPE (0x597) // NAry +#define HID_USAGE_SENSORS_PROPERTY_MINIMUM_ACTIVITY_DETECTION_INTERVAL (0x5A0) // DV +#define HID_USAGE_SENSORS_PROPERTY_SUPPORTED_ACTIVITY_TYPES (0x5A1) // NAry +#define HID_USAGE_SENSORS_PROPERTY_SUBSCRIBED_ACTIVITY_TYPES (0x5A2) // NAry +#define HID_USAGE_SENSORS_PROPERTY_SUPPORTED_STEP_TYPES (0x5A3) // NAry +#define HID_USAGE_SENSORS_PROPERTY_SUBSCRIBED_STEP_TYPES (0x5A4) // NAry +#define HID_USAGE_SENSORS_PROPERTY_FLOOR_HEIGHT (0x5A5) // DV +#define HID_USAGE_SENSORS_DATA_FIELD_CUSTOM_TYPE_ID (0x5B0) // SV +#define HID_USAGE_SENSORS_PROPERTY_CUSTOM (0x5C0) // DV +#define HID_USAGE_SENSORS_PROPERTY_CUSTOM_VALUE_1 (0x5C1) // DV +#define HID_USAGE_SENSORS_PROPERTY_CUSTOM_VALUE_2 (0x5C2) // DV +#define HID_USAGE_SENSORS_PROPERTY_CUSTOM_VALUE_3 (0x5C3) // DV +#define HID_USAGE_SENSORS_PROPERTY_CUSTOM_VALUE_4 (0x5C4) // DV +#define HID_USAGE_SENSORS_PROPERTY_CUSTOM_VALUE_5 (0x5C5) // DV +#define HID_USAGE_SENSORS_PROPERTY_CUSTOM_VALUE_6 (0x5C6) // DV +#define HID_USAGE_SENSORS_PROPERTY_CUSTOM_VALUE_7 (0x5C7) // DV +#define HID_USAGE_SENSORS_PROPERTY_CUSTOM_VALUE_8 (0x5C8) // DV +#define HID_USAGE_SENSORS_PROPERTY_CUSTOM_VALUE_9 (0x5C9) // DV +#define HID_USAGE_SENSORS_PROPERTY_CUSTOM_VALUE_10 (0x5CA) // DV +#define HID_USAGE_SENSORS_PROPERTY_CUSTOM_VALUE_11 (0x5CB) // DV +#define HID_USAGE_SENSORS_PROPERTY_CUSTOM_VALUE_12 (0x5CC) // DV +#define HID_USAGE_SENSORS_PROPERTY_CUSTOM_VALUE_13 (0x5CD) // DV +#define HID_USAGE_SENSORS_PROPERTY_CUSTOM_VALUE_14 (0x5CE) // DV +#define HID_USAGE_SENSORS_PROPERTY_CUSTOM_VALUE_15 (0x5CF) // DV +#define HID_USAGE_SENSORS_PROPERTY_CUSTOM_VALUE_16 (0x5D0) // DV +#define HID_USAGE_SENSORS_DATA_FIELD_HINGE (0x5E0) // SV, DV +#define HID_USAGE_SENSORS_DATA_FIELD_HINGE_ANGLE (0x5E1) // SV, DV +#define HID_USAGE_SENSORS_DATA_FIELD_GESTURE_SENSOR (0x5F0) // DV +#define HID_USAGE_SENSORS_DATA_FIELD_GESTURE_STATE (0x5F1) // NAry +#define HID_USAGE_SENSORS_DATA_FIELD_HINGE_FOLD_INITIAL_ANGLE (0x5F2) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_HINGE_FOLD_FINAL_ANGLE (0x5F3) // SV +#define HID_USAGE_SENSORS_DATA_FIELD_HINGE_FOLD_CONTRIBUTING_PANEL (0x5F4) // NAry +#define HID_USAGE_SENSORS_DATA_FIELD_HINGE_FOLD_TYPE (0x5F5) // NAry +#define HID_USAGE_SENSORS_SENSOR_STATE_UNDEFINED (0x800) // Sel +#define HID_USAGE_SENSORS_SENSOR_STATE_READY (0x801) // Sel +#define HID_USAGE_SENSORS_SENSOR_STATE_NOT_AVAILABLE (0x802) // Sel +#define HID_USAGE_SENSORS_SENSOR_STATE_NO_DATA (0x803) // Sel +#define HID_USAGE_SENSORS_SENSOR_STATE_INITIALIZING (0x804) // Sel +#define HID_USAGE_SENSORS_SENSOR_STATE_ACCESS_DENIED (0x805) // Sel +#define HID_USAGE_SENSORS_SENSOR_STATE_ERROR (0x806) // Sel +#define HID_USAGE_SENSORS_SENSOR_EVENT_UNKNOWN (0x810) // Sel +#define HID_USAGE_SENSORS_SENSOR_EVENT_STATE_CHANGED (0x811) // Sel +#define HID_USAGE_SENSORS_SENSOR_EVENT_PROPERTY_CHANGED (0x812) // Sel +#define HID_USAGE_SENSORS_SENSOR_EVENT_DATA_UPDATED (0x813) // Sel +#define HID_USAGE_SENSORS_SENSOR_EVENT_POLL_RESPONSE (0x814) // Sel +#define HID_USAGE_SENSORS_SENSOR_EVENT_CHANGE_SENSITIVITY (0x815) // Sel +#define HID_USAGE_SENSORS_SENSOR_EVENT_RANGE_MAXIMUM_REACHED (0x816) // Sel +#define HID_USAGE_SENSORS_SENSOR_EVENT_RANGE_MINIMUM_REACHED (0x817) // Sel +#define HID_USAGE_SENSORS_SENSOR_EVENT_HIGH_THRESHOLD_CROSS_UPWARD (0x818) // Sel +#define HID_USAGE_SENSORS_SENSOR_EVENT_HIGH_THRESHOLD_CROSS_DOWNWARD (0x819) // Sel +#define HID_USAGE_SENSORS_SENSOR_EVENT_LOW_THRESHOLD_CROSS_UPWARD (0x81A) // Sel +#define HID_USAGE_SENSORS_SENSOR_EVENT_LOW_THRESHOLD_CROSS_DOWNWARD (0x81B) // Sel +#define HID_USAGE_SENSORS_SENSOR_EVENT_ZERO_THRESHOLD_CROSS_UPWARD (0x81C) // Sel +#define HID_USAGE_SENSORS_SENSOR_EVENT_ZERO_THRESHOLD_CROSS_DOWNWARD (0x81D) // Sel +#define HID_USAGE_SENSORS_SENSOR_EVENT_PERIOD_EXCEEDED (0x81E) // Sel +#define HID_USAGE_SENSORS_SENSOR_EVENT_FREQUENCY_EXCEEDED (0x81F) // Sel +#define HID_USAGE_SENSORS_SENSOR_EVENT_COMPLEX_TRIGGER (0x820) // Sel +#define HID_USAGE_SENSORS_CONNECTION_TYPE_PC_INTEGRATED (0x830) // Sel +#define HID_USAGE_SENSORS_CONNECTION_TYPE_PC_ATTACHED (0x831) // Sel +#define HID_USAGE_SENSORS_CONNECTION_TYPE_PC_EXTERNAL (0x832) // Sel +#define HID_USAGE_SENSORS_REPORTING_STATE_REPORT_NO_EVENTS (0x840) // Sel +#define HID_USAGE_SENSORS_REPORTING_STATE_REPORT_ALL_EVENTS (0x841) // Sel +#define HID_USAGE_SENSORS_REPORTING_STATE_REPORT_THRESHOLD_EVENTS (0x842) // Sel +#define HID_USAGE_SENSORS_REPORTING_STATE_WAKE_ON_NO_EVENTS (0x843) // Sel +#define HID_USAGE_SENSORS_REPORTING_STATE_WAKE_ON_ALL_EVENTS (0x844) // Sel +#define HID_USAGE_SENSORS_REPORTING_STATE_WAKE_ON_THRESHOLD_EVENTS (0x845) // Sel +#define HID_USAGE_SENSORS_POWER_STATE_UNDEFINED (0x850) // Sel +#define HID_USAGE_SENSORS_POWER_STATE_D0_FULL_POWER (0x851) // Sel +#define HID_USAGE_SENSORS_POWER_STATE_D1_LOW_POWER (0x852) // Sel +#define HID_USAGE_SENSORS_POWER_STATE_D2_STANDBY_POWER_WITH_WAKEUP (0x853) // Sel +#define HID_USAGE_SENSORS_POWER_STATE_D3_SLEEP_WITH_WAKEUP (0x854) // Sel +#define HID_USAGE_SENSORS_POWER_STATE_D4_POWER_OFF (0x855) // Sel +#define HID_USAGE_SENSORS_FIX_QUALITY_NO_FIX (0x870) // Sel +#define HID_USAGE_SENSORS_FIX_QUALITY_GPS (0x871) // Sel +#define HID_USAGE_SENSORS_FIX_QUALITY_DGPS (0x872) // Sel +#define HID_USAGE_SENSORS_FIX_TYPE_NO_FIX (0x880) // Sel +#define HID_USAGE_SENSORS_FIX_TYPE_GPS_SPS_MODE_FIX_VALID (0x881) // Sel +#define HID_USAGE_SENSORS_FIX_TYPE_DGPS_SPS_MODE_FIX_VALID (0x882) // Sel +#define HID_USAGE_SENSORS_FIX_TYPE_GPS_PPS_MODE_FIX_VALID (0x883) // Sel +#define HID_USAGE_SENSORS_FIX_TYPE_REAL_TIME_KINEMATIC (0x884) // Sel +#define HID_USAGE_SENSORS_FIX_TYPE_FLOAT_RTK (0x885) // Sel +#define HID_USAGE_SENSORS_FIX_TYPE_ESTIMATED_DEAD_RECKONED (0x886) // Sel +#define HID_USAGE_SENSORS_FIX_TYPE_MANUAL_INPUT_MODE (0x887) // Sel +#define HID_USAGE_SENSORS_FIX_TYPE_SIMULATOR_MODE (0x888) // Sel +#define HID_USAGE_SENSORS_GPS_OPERATION_MODE_MANUAL (0x890) // Sel +#define HID_USAGE_SENSORS_GPS_OPERATION_MODE_AUTOMATIC (0x891) // Sel +#define HID_USAGE_SENSORS_GPS_SELECTION_MODE_AUTONOMOUS (0x8A0) // Sel +#define HID_USAGE_SENSORS_GPS_SELECTION_MODE_DGPS (0x8A1) // Sel +#define HID_USAGE_SENSORS_GPS_SELECTION_MODE_ESTIMATED_DEAD_RECKONED (0x8A2) // Sel +#define HID_USAGE_SENSORS_GPS_SELECTION_MODE_MANUAL_INPUT (0x8A3) // Sel +#define HID_USAGE_SENSORS_GPS_SELECTION_MODE_SIMULATOR (0x8A4) // Sel +#define HID_USAGE_SENSORS_GPS_SELECTION_MODE_DATA_NOT_VALID (0x8A5) // Sel +#define HID_USAGE_SENSORS_GPS_STATUS_DATA_VALID (0x8B0) // Sel +#define HID_USAGE_SENSORS_GPS_STATUS_DATA_NOT_VALID (0x8B1) // Sel +#define HID_USAGE_SENSORS_ACCURACY_DEFAULT (0x860) // Sel +#define HID_USAGE_SENSORS_ACCURACY_HIGH (0x861) // Sel +#define HID_USAGE_SENSORS_ACCURACY_MEDIUM (0x862) // Sel +#define HID_USAGE_SENSORS_ACCURACY_LOW (0x863) // Sel +#define HID_USAGE_SENSORS_DAY_OF_WEEK_SUNDAY (0x8C0) // Sel +#define HID_USAGE_SENSORS_DAY_OF_WEEK_MONDAY (0x8C1) // Sel +#define HID_USAGE_SENSORS_DAY_OF_WEEK_TUESDAY (0x8C2) // Sel +#define HID_USAGE_SENSORS_DAY_OF_WEEK_WEDNESDAY (0x8C3) // Sel +#define HID_USAGE_SENSORS_DAY_OF_WEEK_THURSDAY (0x8C4) // Sel +#define HID_USAGE_SENSORS_DAY_OF_WEEK_FRIDAY (0x8C5) // Sel +#define HID_USAGE_SENSORS_DAY_OF_WEEK_SATURDAY (0x8C6) // Sel +#define HID_USAGE_SENSORS_KIND_CATEGORY (0x8D0) // Sel +#define HID_USAGE_SENSORS_KIND_TYPE (0x8D1) // Sel +#define HID_USAGE_SENSORS_KIND_EVENT (0x8D2) // Sel +#define HID_USAGE_SENSORS_KIND_PROPERTY (0x8D3) // Sel +#define HID_USAGE_SENSORS_KIND_DATA_FIELD (0x8D4) // Sel +#define HID_USAGE_SENSORS_MAGNETOMETER_ACCURACY_LOW (0x8E0) // Sel +#define HID_USAGE_SENSORS_MAGNETOMETER_ACCURACY_MEDIUM (0x8E1) // Sel +#define HID_USAGE_SENSORS_MAGNETOMETER_ACCURACY_HIGH (0x8E2) // Sel +#define HID_USAGE_SENSORS_SIMPLE_ORIENTATION_DIRECTION_NOT_ROTATED (0x8F0) // Sel +#define HID_USAGE_SENSORS_SIMPLE_ORIENTATION_DIRECTION_ROTATED_90_DEGREES_CCW (0x8F1) // Sel +#define HID_USAGE_SENSORS_SIMPLE_ORIENTATION_DIRECTION_ROTATED_180_DEGREES_CCW (0x8F2) // Sel +#define HID_USAGE_SENSORS_SIMPLE_ORIENTATION_DIRECTION_ROTATED_270_DEGREES_CCW (0x8F3) // Sel +#define HID_USAGE_SENSORS_SIMPLE_ORIENTATION_DIRECTION_FACE_UP (0x8F4) // Sel +#define HID_USAGE_SENSORS_SIMPLE_ORIENTATION_DIRECTION_FACE_DOWN (0x8F5) // Sel +#define HID_USAGE_SENSORS_VT_NULL (0x900) // Sel +#define HID_USAGE_SENSORS_VT_BOOL (0x901) // Sel +#define HID_USAGE_SENSORS_VT_UI1 (0x902) // Sel +#define HID_USAGE_SENSORS_VT_I1 (0x903) // Sel +#define HID_USAGE_SENSORS_VT_UI2 (0x904) // Sel +#define HID_USAGE_SENSORS_VT_I2 (0x905) // Sel +#define HID_USAGE_SENSORS_VT_UI4 (0x906) // Sel +#define HID_USAGE_SENSORS_VT_I4 (0x907) // Sel +#define HID_USAGE_SENSORS_VT_UI8 (0x908) // Sel +#define HID_USAGE_SENSORS_VT_I8 (0x909) // Sel +#define HID_USAGE_SENSORS_VT_R4 (0x90A) // Sel +#define HID_USAGE_SENSORS_VT_R8 (0x90B) // Sel +#define HID_USAGE_SENSORS_VT_WSTR (0x90C) // Sel +#define HID_USAGE_SENSORS_VT_STR (0x90D) // Sel +#define HID_USAGE_SENSORS_VT_CLSID (0x90E) // Sel +#define HID_USAGE_SENSORS_VT_VECTOR_VT_UI1 (0x90F) // Sel +#define HID_USAGE_SENSORS_VT_F16E0 (0x910) // Sel +#define HID_USAGE_SENSORS_VT_F16E1 (0x911) // Sel +#define HID_USAGE_SENSORS_VT_F16E2 (0x912) // Sel +#define HID_USAGE_SENSORS_VT_F16E3 (0x913) // Sel +#define HID_USAGE_SENSORS_VT_F16E4 (0x914) // Sel +#define HID_USAGE_SENSORS_VT_F16E5 (0x915) // Sel +#define HID_USAGE_SENSORS_VT_F16E6 (0x916) // Sel +#define HID_USAGE_SENSORS_VT_F16E7 (0x917) // Sel +#define HID_USAGE_SENSORS_VT_F16E8 (0x918) // Sel +#define HID_USAGE_SENSORS_VT_F16E9 (0x919) // Sel +#define HID_USAGE_SENSORS_VT_F16EA (0x91A) // Sel +#define HID_USAGE_SENSORS_VT_F16EB (0x91B) // Sel +#define HID_USAGE_SENSORS_VT_F16EC (0x91C) // Sel +#define HID_USAGE_SENSORS_VT_F16ED (0x91D) // Sel +#define HID_USAGE_SENSORS_VT_F16EE (0x91E) // Sel +#define HID_USAGE_SENSORS_VT_F16EF (0x91F) // Sel +#define HID_USAGE_SENSORS_VT_F32E0 (0x920) // Sel +#define HID_USAGE_SENSORS_VT_F32E1 (0x921) // Sel +#define HID_USAGE_SENSORS_VT_F32E2 (0x922) // Sel +#define HID_USAGE_SENSORS_VT_F32E3 (0x923) // Sel +#define HID_USAGE_SENSORS_VT_F32E4 (0x924) // Sel +#define HID_USAGE_SENSORS_VT_F32E5 (0x925) // Sel +#define HID_USAGE_SENSORS_VT_F32E6 (0x926) // Sel +#define HID_USAGE_SENSORS_VT_F32E7 (0x927) // Sel +#define HID_USAGE_SENSORS_VT_F32E8 (0x928) // Sel +#define HID_USAGE_SENSORS_VT_F32E9 (0x929) // Sel +#define HID_USAGE_SENSORS_VT_F32EA (0x92A) // Sel +#define HID_USAGE_SENSORS_VT_F32EB (0x92B) // Sel +#define HID_USAGE_SENSORS_VT_F32EC (0x92C) // Sel +#define HID_USAGE_SENSORS_VT_F32ED (0x92D) // Sel +#define HID_USAGE_SENSORS_VT_F32EE (0x92E) // Sel +#define HID_USAGE_SENSORS_VT_F32EF (0x92F) // Sel +#define HID_USAGE_SENSORS_ACTIVITY_TYPE_UNKNOWN (0x930) // Sel +#define HID_USAGE_SENSORS_ACTIVITY_TYPE_STATIONARY (0x931) // Sel +#define HID_USAGE_SENSORS_ACTIVITY_TYPE_FIDGETING (0x932) // Sel +#define HID_USAGE_SENSORS_ACTIVITY_TYPE_WALKING (0x933) // Sel +#define HID_USAGE_SENSORS_ACTIVITY_TYPE_RUNNING (0x934) // Sel +#define HID_USAGE_SENSORS_ACTIVITY_TYPE_IN_VEHICLE (0x935) // Sel +#define HID_USAGE_SENSORS_ACTIVITY_TYPE_BIKING (0x936) // Sel +#define HID_USAGE_SENSORS_ACTIVITY_TYPE_IDLE (0x937) // Sel +#define HID_USAGE_SENSORS_UNIT_NOT_SPECIFIED (0x940) // Sel +#define HID_USAGE_SENSORS_UNIT_LUX (0x941) // Sel +#define HID_USAGE_SENSORS_UNIT_DEGREES_KELVIN (0x942) // Sel +#define HID_USAGE_SENSORS_UNIT_DEGREES_CELSIUS (0x943) // Sel +#define HID_USAGE_SENSORS_UNIT_PASCAL (0x944) // Sel +#define HID_USAGE_SENSORS_UNIT_NEWTON (0x945) // Sel +#define HID_USAGE_SENSORS_UNIT_METERS_SECOND (0x946) // Sel +#define HID_USAGE_SENSORS_UNIT_KILOGRAM (0x947) // Sel +#define HID_USAGE_SENSORS_UNIT_METER (0x948) // Sel +#define HID_USAGE_SENSORS_UNIT_METERS_SECOND_SECOND (0x949) // Sel +#define HID_USAGE_SENSORS_UNIT_FARAD (0x94A) // Sel +#define HID_USAGE_SENSORS_UNIT_AMPERE (0x94B) // Sel +#define HID_USAGE_SENSORS_UNIT_WATT (0x94C) // Sel +#define HID_USAGE_SENSORS_UNIT_HENRY (0x94D) // Sel +#define HID_USAGE_SENSORS_UNIT_OHM (0x94E) // Sel +#define HID_USAGE_SENSORS_UNIT_VOLT (0x94F) // Sel +#define HID_USAGE_SENSORS_UNIT_HERTZ (0x950) // Sel +#define HID_USAGE_SENSORS_UNIT_BAR (0x951) // Sel +#define HID_USAGE_SENSORS_UNIT_DEGREES_ANTI_CLOCKWISE (0x952) // Sel +#define HID_USAGE_SENSORS_UNIT_DEGREES_CLOCKWISE (0x953) // Sel +#define HID_USAGE_SENSORS_UNIT_DEGREES (0x954) // Sel +#define HID_USAGE_SENSORS_UNIT_DEGREES_SECOND (0x955) // Sel +#define HID_USAGE_SENSORS_UNIT_DEGREES_SECOND_SECOND (0x956) // Sel +#define HID_USAGE_SENSORS_UNIT_KNOT (0x957) // Sel +#define HID_USAGE_SENSORS_UNIT_PERCENT (0x958) // Sel +#define HID_USAGE_SENSORS_UNIT_SECOND (0x959) // Sel +#define HID_USAGE_SENSORS_UNIT_MILLISECOND (0x95A) // Sel +#define HID_USAGE_SENSORS_UNIT_G (0x95B) // Sel +#define HID_USAGE_SENSORS_UNIT_BYTES (0x95C) // Sel +#define HID_USAGE_SENSORS_UNIT_MILLIGAUSS (0x95D) // Sel +#define HID_USAGE_SENSORS_UNIT_BITS (0x95E) // Sel +#define HID_USAGE_SENSORS_ACTIVITY_STATE_NO_STATE_CHANGE (0x960) // Sel +#define HID_USAGE_SENSORS_ACTIVITY_STATE_START_ACTIVITY (0x961) // Sel +#define HID_USAGE_SENSORS_ACTIVITY_STATE_END_ACTIVITY (0x962) // Sel +#define HID_USAGE_SENSORS_EXPONENT_0 (0x970) // Sel +#define HID_USAGE_SENSORS_EXPONENT_1 (0x971) // Sel +#define HID_USAGE_SENSORS_EXPONENT_2 (0x972) // Sel +#define HID_USAGE_SENSORS_EXPONENT_3 (0x973) // Sel +#define HID_USAGE_SENSORS_EXPONENT_4 (0x974) // Sel +#define HID_USAGE_SENSORS_EXPONENT_5 (0x975) // Sel +#define HID_USAGE_SENSORS_EXPONENT_6 (0x976) // Sel +#define HID_USAGE_SENSORS_EXPONENT_7 (0x977) // Sel +#define HID_USAGE_SENSORS_EXPONENT_8 (0x978) // Sel +#define HID_USAGE_SENSORS_EXPONENT_9 (0x979) // Sel +#define HID_USAGE_SENSORS_EXPONENT_A (0x97A) // Sel +#define HID_USAGE_SENSORS_EXPONENT_B (0x97B) // Sel +#define HID_USAGE_SENSORS_EXPONENT_C (0x97C) // Sel +#define HID_USAGE_SENSORS_EXPONENT_D (0x97D) // Sel +#define HID_USAGE_SENSORS_EXPONENT_E (0x97E) // Sel +#define HID_USAGE_SENSORS_EXPONENT_F (0x97F) // Sel +#define HID_USAGE_SENSORS_DEVICE_POSITION_UNKNOWN (0x980) // Sel +#define HID_USAGE_SENSORS_DEVICE_POSITION_UNCHANGED (0x981) // Sel +#define HID_USAGE_SENSORS_DEVICE_POSITION_ON_DESK (0x982) // Sel +#define HID_USAGE_SENSORS_DEVICE_POSITION_IN_HAND (0x983) // Sel +#define HID_USAGE_SENSORS_DEVICE_POSITION_MOVING_IN_BAG (0x984) // Sel +#define HID_USAGE_SENSORS_DEVICE_POSITION_STATIONARY_IN_BAG (0x985) // Sel +#define HID_USAGE_SENSORS_STEP_TYPE_UNKNOWN (0x990) // Sel +#define HID_USAGE_SENSORS_STEP_TYPE_RUNNING (0x991) // Sel +#define HID_USAGE_SENSORS_STEP_TYPE_WALKING (0x992) // Sel +#define HID_USAGE_SENSORS_GESTURE_STATE_UNKNOWN (0x9A0) // Sel +#define HID_USAGE_SENSORS_GESTURE_STATE_STARTED (0x9A1) // Sel +#define HID_USAGE_SENSORS_GESTURE_STATE_COMPLETED (0x9A2) // Sel +#define HID_USAGE_SENSORS_GESTURE_STATE_CANCELLED (0x9A3) // Sel +#define HID_USAGE_SENSORS_HINGE_FOLD_CONTRIBUTING_PANEL_UNKNOWN (0x9B0) // Sel +#define HID_USAGE_SENSORS_HINGE_FOLD_CONTRIBUTING_PANEL_PANEL_1 (0x9B1) // Sel +#define HID_USAGE_SENSORS_HINGE_FOLD_CONTRIBUTING_PANEL_PANEL_2 (0x9B2) // Sel +#define HID_USAGE_SENSORS_HINGE_FOLD_CONTRIBUTING_PANEL_BOTH (0x9B3) // Sel +#define HID_USAGE_SENSORS_HINGE_FOLD_TYPE_UNKNOWN (0x9B4) // Sel +#define HID_USAGE_SENSORS_HINGE_FOLD_TYPE_INCREASING (0x9B5) // Sel +#define HID_USAGE_SENSORS_HINGE_FOLD_TYPE_DECREASING (0x9B6) // Sel +#define HID_USAGE_SENSORS_MODIFIER_CHANGE_SENSITIVITY_ABSOLUTE (0x1000) // US +#define HID_USAGE_SENSORS_MODIFIER_MAXIMUM (0x2000) // US +#define HID_USAGE_SENSORS_MODIFIER_MINIMUM (0x3000) // US +#define HID_USAGE_SENSORS_MODIFIER_ACCURACY (0x4000) // US +#define HID_USAGE_SENSORS_MODIFIER_RESOLUTION (0x5000) // US +#define HID_USAGE_SENSORS_MODIFIER_THRESHOLD_HIGH (0x6000) // US +#define HID_USAGE_SENSORS_MODIFIER_THRESHOLD_LOW (0x7000) // US +#define HID_USAGE_SENSORS_MODIFIER_CALIBRATION_OFFSET (0x8000) // US +#define HID_USAGE_SENSORS_MODIFIER_CALIBRATION_MULTIPLIER (0x9000) // US +#define HID_USAGE_SENSORS_MODIFIER_REPORT_INTERVAL (0xA000) // US +#define HID_USAGE_SENSORS_MODIFIER_FREQUENCY_MAX (0xB000) // US +#define HID_USAGE_SENSORS_MODIFIER_PERIOD_MAX (0xC000) // US +#define HID_USAGE_SENSORS_MODIFIER_CHANGE_SENSITIVITY_PERCENT_OF_RANGE (0xD000) // US +#define HID_USAGE_SENSORS_MODIFIER_CHANGE_SENSITIVITY_PERCENT_RELATIVE (0xE000) // US + +/* Page 0x40: Medical Instrument */ +#define HID_USAGE_MEDICAL_UNDEFINED (0x00) +#define HID_USAGE_MEDICAL_MEDICAL_ULTRASOUND (0x01) // CA +#define HID_USAGE_MEDICAL_VCR_ACQUISITION (0x20) // OOC +#define HID_USAGE_MEDICAL_FREEZE_THAW (0x21) // OOC +#define HID_USAGE_MEDICAL_CLIP_STORE (0x22) // OSC +#define HID_USAGE_MEDICAL_UPDATE (0x23) // OSC +#define HID_USAGE_MEDICAL_NEXT (0x24) // OSC +#define HID_USAGE_MEDICAL_SAVE (0x25) // OSC +#define HID_USAGE_MEDICAL_PRINT (0x26) // OSC +#define HID_USAGE_MEDICAL_MICROPHONE_ENABLE (0x27) // OSC +#define HID_USAGE_MEDICAL_CINE (0x40) // LC +#define HID_USAGE_MEDICAL_TRANSMIT_POWER (0x41) // LC +#define HID_USAGE_MEDICAL_VOLUME (0x42) // LC +#define HID_USAGE_MEDICAL_FOCUS (0x43) // LC +#define HID_USAGE_MEDICAL_DEPTH (0x44) // LC +#define HID_USAGE_MEDICAL_SOFT_STEP_MINUS_PRIMARY (0x60) // LC +#define HID_USAGE_MEDICAL_SOFT_STEP_MINUS_SECONDARY (0x61) // LC +#define HID_USAGE_MEDICAL_DEPTH_GAIN_COMPENSATION (0x70) // LC +#define HID_USAGE_MEDICAL_ZOOM_SELECT (0x80) // OSC +#define HID_USAGE_MEDICAL_ZOOM_ADJUST (0x81) // LC +#define HID_USAGE_MEDICAL_SPECTRAL_DOPPLER_MODE_SELECT (0x82) // OSC +#define HID_USAGE_MEDICAL_SPECTRAL_DOPPLER_ADJUST (0x83) // LC +#define HID_USAGE_MEDICAL_COLOR_DOPPLER_MODE_SELECT (0x84) // OSC +#define HID_USAGE_MEDICAL_COLOR_DOPPLER_ADJUST (0x85) // LC +#define HID_USAGE_MEDICAL_MOTION_MODE_SELECT (0x86) // OSC +#define HID_USAGE_MEDICAL_MOTION_MODE_ADJUST (0x87) // LC +#define HID_USAGE_MEDICAL_2_D_MODE_SELECT (0x88) // OSC +#define HID_USAGE_MEDICAL_2_D_MODE_ADJUST (0x89) // LC +#define HID_USAGE_MEDICAL_SOFT_CONTROL_SELECT (0xA0) // OSC +#define HID_USAGE_MEDICAL_SOFT_CONTROL_ADJUST (0xA1) // LC + +/* Page 0x41: Braille Display */ +#define HID_USAGE_BRAILLE_UNDEFINED (0x00) +#define HID_USAGE_BRAILLE_BRAILLE_DISPLAY (0x01) // CA +#define HID_USAGE_BRAILLE_BRAILLE_ROW (0x02) // NAry +#define HID_USAGE_BRAILLE_8_DOT_BRAILLE_CELL (0x03) // DV +#define HID_USAGE_BRAILLE_6_DOT_BRAILLE_CELL (0x04) // DV +#define HID_USAGE_BRAILLE_NUMBER_OF_BRAILLE_CELLS (0x05) // DV +#define HID_USAGE_BRAILLE_SCREEN_READER_CONTROL (0x06) // NAry +#define HID_USAGE_BRAILLE_SCREEN_READER_IDENTIFIER (0x07) // DV +#define HID_USAGE_BRAILLE_ROUTER_SET_1 (0xFA) // NAry +#define HID_USAGE_BRAILLE_ROUTER_SET_2 (0xFB) // NAry +#define HID_USAGE_BRAILLE_ROUTER_SET_3 (0xFC) // Nary +#define HID_USAGE_BRAILLE_ROUTER_KEY (0x100) // Sel +#define HID_USAGE_BRAILLE_ROW_ROUTER_KEY (0x101) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_BUTTONS (0x200) // NAry +#define HID_USAGE_BRAILLE_BRAILLE_KEYBOARD_DOT_1 (0x201) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_KEYBOARD_DOT_2 (0x202) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_KEYBOARD_DOT_3 (0x203) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_KEYBOARD_DOT_4 (0x204) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_KEYBOARD_DOT_5 (0x205) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_KEYBOARD_DOT_6 (0x206) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_KEYBOARD_DOT_7 (0x207) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_KEYBOARD_DOT_8 (0x208) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_KEYBOARD_SPACE (0x209) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_KEYBOARD_LEFT_SPACE (0x20A) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_KEYBOARD_RIGHT_SPACE (0x20B) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_FACE_CONTROLS (0x20C) // NAry +#define HID_USAGE_BRAILLE_BRAILLE_LEFT_CONTROLS (0x20D) // NAry +#define HID_USAGE_BRAILLE_BRAILLE_RIGHT_CONTROLS (0x20E) // NAry +#define HID_USAGE_BRAILLE_BRAILLE_TOP_CONTROLS (0x20F) // NAry +#define HID_USAGE_BRAILLE_BRAILLE_JOYSTICK_CENTER (0x210) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_JOYSTICK_UP (0x211) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_JOYSTICK_DOWN (0x212) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_JOYSTICK_LEFT (0x213) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_JOYSTICK_RIGHT (0x214) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_D_PAD_CENTER (0x215) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_D_PAD_UP (0x216) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_D_PAD_DOWN (0x217) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_D_PAD_LEFT (0x218) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_D_PAD_RIGHT (0x219) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_PAN_LEFT (0x21A) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_PAN_RIGHT (0x21B) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_ROCKER_UP (0x21C) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_ROCKER_DOWN (0x21D) // Sel +#define HID_USAGE_BRAILLE_BRAILLE_ROCKER_PRESS (0x21E) // Sel + +/* Page 0x59: Lighting And Illumination */ +#define HID_USAGE_LIGHT_UNDEFINED (0x00) +#define HID_USAGE_LIGHT_LAMP_ARRAY (0x01) // CA +#define HID_USAGE_LIGHT_LAMP_ARRAY_ATTRIBUTES_REPORT (0x02) // CL +#define HID_USAGE_LIGHT_LAMP_COUNT (0x03) // SV, DV +#define HID_USAGE_LIGHT_BOUNDING_BOX_WIDTH_IN_MICROMETERS (0x04) // SV +#define HID_USAGE_LIGHT_BOUNDING_BOX_HEIGHT_IN_MICROMETERS (0x05) // SV +#define HID_USAGE_LIGHT_BOUNDING_BOX_DEPTH_IN_MICROMETERS (0x06) // SV +#define HID_USAGE_LIGHT_LAMP_ARRAY_KIND (0x07) // SV +#define HID_USAGE_LIGHT_MIN_UPDATE_INTERVAL_IN_MICROSECONDS (0x08) // SV +#define HID_USAGE_LIGHT_LAMP_ATTRIBUTES_REQUEST_REPORT (0x20) // CL +#define HID_USAGE_LIGHT_LAMP_ID (0x21) // SV, DV +#define HID_USAGE_LIGHT_LAMP_ATTRIBUTES_RESPONSE_REPORT (0x22) // CL +#define HID_USAGE_LIGHT_POSITION_X_IN_MICROMETERS (0x23) // DV +#define HID_USAGE_LIGHT_POSITION_Y_IN_MICROMETERS (0x24) // DV +#define HID_USAGE_LIGHT_POSITION_Z_IN_MICROMETERS (0x25) // DV +#define HID_USAGE_LIGHT_LAMP_PURPOSES (0x26) // DV +#define HID_USAGE_LIGHT_UPDATE_LATENCY_IN_MICROSECONDS (0x27) // DV +#define HID_USAGE_LIGHT_RED_LEVEL_COUNT (0x28) // DV +#define HID_USAGE_LIGHT_GREEN_LEVEL_COUNT (0x29) // DV +#define HID_USAGE_LIGHT_BLUE_LEVEL_COUNT (0x2A) // DV +#define HID_USAGE_LIGHT_INTENSITY_LEVEL_COUNT (0x2B) // DV +#define HID_USAGE_LIGHT_IS_PROGRAMMABLE (0x2C) // DV +#define HID_USAGE_LIGHT_INPUT_BINDING (0x2D) // DV +#define HID_USAGE_LIGHT_LAMP_MULTI_UPDATE_REPORT (0x50) // CL +#define HID_USAGE_LIGHT_RED_UPDATE_CHANNEL (0x51) // DV +#define HID_USAGE_LIGHT_GREEN_UPDATE_CHANNEL (0x52) // DV +#define HID_USAGE_LIGHT_BLUE_UPDATE_CHANNEL (0x53) // DV +#define HID_USAGE_LIGHT_INTENSITY_UPDATE_CHANNEL (0x54) // DV +#define HID_USAGE_LIGHT_LAMP_UPDATE_FLAGS (0x55) // DV +#define HID_USAGE_LIGHT_LAMP_RANGE_UPDATE_REPORT (0x60) // CL +#define HID_USAGE_LIGHT_LAMP_ID_START (0x61) // DV +#define HID_USAGE_LIGHT_LAMP_ID_END (0x62) // DV +#define HID_USAGE_LIGHT_LAMP_ARRAY_CONTROL_REPORT (0x70) // CL +#define HID_USAGE_LIGHT_AUTONOMOUS_MODE (0x71) // DV + +/* Page 0x80: USB Monitor */ +#define HID_USAGE_MONITOR_MONITOR_CONTROL (0x01) +#define HID_USAGE_MONITOR_EDID_INFORMATION (0x02) +#define HID_USAGE_MONITOR_VDIF_INFORMATION (0x03) +#define HID_USAGE_MONITOR_VESA_VERSION (0x04) + +/* Page 0x82: VESA Virtual Control */ +#define HID_USAGE_MONITOR_VESA_BRIGHTNESS (0x10) +#define HID_USAGE_MONITOR_VESA_CONTRAST (0x12) +#define HID_USAGE_MONITOR_VESA_RED_VIDEO_GAIN (0x16) +#define HID_USAGE_MONITOR_VESA_GREEN_VIDEO_GAIN (0x18) +#define HID_USAGE_MONITOR_VESA_BLUE_VIDEO_GAIN (0x1A) +#define HID_USAGE_MONITOR_VESA_FOCUS (0x1C) +#define HID_USAGE_MONITOR_VESA_HORIZONTAL_POSITION (0x20) +#define HID_USAGE_MONITOR_VESA_HORIZONTAL_SIZE (0x22) +#define HID_USAGE_MONITOR_VESA_HORIZONTAL_PINCUSHION (0x24) +#define HID_USAGE_MONITOR_VESA_HORIZONTAL_PINCUSHION_BALANCE (0x26) +#define HID_USAGE_MONITOR_VESA_HORIZONTAL_MISCONVERGENCE (0x28) +#define HID_USAGE_MONITOR_VESA_HORIZONTAL_LINEARITY (0x2A) +#define HID_USAGE_MONITOR_VESA_HORIZONTAL_LINEARITY_BALANCE (0x2C) +#define HID_USAGE_MONITOR_VESA_VERTICAL_POSITION (0x30) +#define HID_USAGE_MONITOR_VESA_VERTICAL_SIZE (0x32) +#define HID_USAGE_MONITOR_VESA_VERTICAL_PINCUSHION (0x34) +#define HID_USAGE_MONITOR_VESA_VERTICAL_PINCUSHION_BALANCE (0x36) +#define HID_USAGE_MONITOR_VESA_VERTICAL_MISCONVERGENCE (0x38) +#define HID_USAGE_MONITOR_VESA_VERTICAL_LINEARITY (0x3A) +#define HID_USAGE_MONITOR_VESA_VERTICAL_LINEARITY_BALANCE (0x3C) +#define HID_USAGE_MONITOR_VESA_PARALLELOGRAM_DISTORTION_KEY_BALANCE (0x40) +#define HID_USAGE_MONITOR_VESA_TRAPEZOIDAL_DISTORTION_KEY (0x42) +#define HID_USAGE_MONITOR_VESA_TILT_ROTATION (0x44) +#define HID_USAGE_MONITOR_VESA_TOP_CORNER_DISTORTION_CONTROL (0x46) +#define HID_USAGE_MONITOR_VESA_TOP_CORNER_DISTORTION_BALANCE (0x48) +#define HID_USAGE_MONITOR_VESA_BOTTOM_CORNER_DISTORTION_CONTROL (0x4A) +#define HID_USAGE_MONITOR_VESA_BOTTOM_CORNER_DISTORTION_BALANCE (0x4C) +#define HID_USAGE_MONITOR_VESA_HORIZONTAL_MOIR (0x56) +#define HID_USAGE_MONITOR_VESA_VERTICAL_MOIR (0x58) +#define HID_USAGE_MONITOR_VESA_RED_VIDEO_BLACK_LEVEL (0x6C) +#define HID_USAGE_MONITOR_VESA_GREEN_VIDEO_BLACK_LEVEL (0x6E) +#define HID_USAGE_MONITOR_VESA_BLUE_VIDEO_BLACK_LEVEL (0x70) +#define HID_USAGE_MONITOR_VESA_INPUT_LEVEL_SELECT (0x5E) +#define HID_USAGE_MONITOR_VESA_INPUT_SOURCE_SELECT (0x60) +#define HID_USAGE_MONITOR_VESA_ON_SCREEN_DISPLAY (0xCA) +#define HID_USAGE_MONITOR_VESA_STEREOMODE (0xD4) +#define HID_USAGE_MONITOR_VESA_AUTO_SIZE_CENTER (0xA2) +#define HID_USAGE_MONITOR_VESA_POLARITY_HORIZONTAL_SYNCHRONIZATION (0xA4) +#define HID_USAGE_MONITOR_VESA_POLARITY_VERTICAL_SYNCHRONIZATION (0xA6) +#define HID_USAGE_MONITOR_VESA_SYNCHRONIZATION_TYPE (0xA8) +#define HID_USAGE_MONITOR_VESA_SCREEN_ORIENTATION (0xAA) +#define HID_USAGE_MONITOR_VESA_HORIZONTAL_FREQUENCY (0xAC) +#define HID_USAGE_MONITOR_VESA_VERTICAL_FREQUENCY (0xAE) +#define HID_USAGE_MONITOR_VESA_DEGAUSS (0x01) +#define HID_USAGE_MONITOR_VESA_SETTINGS (0xB0) + +/* Page 0x8C: Bar Code Scanner */ +#define HID_USAGE_POS_BARCODE_UNDEFINED (0x00) +#define HID_USAGE_POS_BARCODE_BAR_CODE_BADGE_READER (0x01) // CA +#define HID_USAGE_POS_BARCODE_BAR_CODE_SCANNER (0x02) // CA +#define HID_USAGE_POS_BARCODE_DUMB_BAR_CODE_SCANNER (0x03) // CA +#define HID_USAGE_POS_BARCODE_CORDLESS_SCANNER_BASE (0x04) // CA +#define HID_USAGE_POS_BARCODE_BAR_CODE_SCANNER_CRADLE (0x05) // CA +#define HID_USAGE_POS_BARCODE_ATTRIBUTE_REPORT (0x10) // CL +#define HID_USAGE_POS_BARCODE_SETTINGS_REPORT (0x11) // CL +#define HID_USAGE_POS_BARCODE_SCANNED_DATA_REPORT (0x12) // CL +#define HID_USAGE_POS_BARCODE_RAW_SCANNED_DATA_REPORT (0x13) // CL +#define HID_USAGE_POS_BARCODE_TRIGGER_REPORT (0x14) // CL +#define HID_USAGE_POS_BARCODE_STATUS_REPORT (0x15) // CL +#define HID_USAGE_POS_BARCODE_UPC_EAN_CONTROL_REPORT (0x16) // CL +#define HID_USAGE_POS_BARCODE_EAN_2_3_LABEL_CONTROL_REPORT (0x17) // CL +#define HID_USAGE_POS_BARCODE_CODE_39_CONTROL_REPORT (0x18) // CL +#define HID_USAGE_POS_BARCODE_INTERLEAVED_2_OF_5_CONTROL_REPORT (0x19) // CL +#define HID_USAGE_POS_BARCODE_STANDARD_2_OF_5_CONTROL_REPORT (0x1A) // CL +#define HID_USAGE_POS_BARCODE_MSI_PLESSEY_CONTROL_REPORT (0x1B) // CL +#define HID_USAGE_POS_BARCODE_CODABAR_CONTROL_REPORT (0x1C) // CL +#define HID_USAGE_POS_BARCODE_CODE_128_CONTROL_REPORT (0x1D) // CL +#define HID_USAGE_POS_BARCODE_MISC_1D_CONTROL_REPORT (0x1E) // CL +#define HID_USAGE_POS_BARCODE_2D_CONTROL_REPORT (0x1F) // CL +#define HID_USAGE_POS_BARCODE_AIMING_POINTER_MODE (0x30) // SF +#define HID_USAGE_POS_BARCODE_BAR_CODE_PRESENT_SENSOR (0x31) // SF +#define HID_USAGE_POS_BARCODE_CLASS_1A_LASER (0x32) // SF +#define HID_USAGE_POS_BARCODE_CLASS_2_LASER (0x33) // SF +#define HID_USAGE_POS_BARCODE_HEATER_PRESENT (0x34) // SF +#define HID_USAGE_POS_BARCODE_CONTACT_SCANNER (0x35) // SF +#define HID_USAGE_POS_BARCODE_ELECTRONIC_ARTICLE_SURVEILLANCE_NOTIFICATION (0x36) // SF +#define HID_USAGE_POS_BARCODE_CONSTANT_ELECTRONIC_ARTICLE_SURVEILLANCE (0x37) // SF +#define HID_USAGE_POS_BARCODE_ERROR_INDICATION (0x38) // SF +#define HID_USAGE_POS_BARCODE_FIXED_BEEPER (0x39) // SF +#define HID_USAGE_POS_BARCODE_GOOD_DECODE_INDICATION (0x3A) // SF +#define HID_USAGE_POS_BARCODE_HANDS_FREE_SCANNING (0x3B) // SF +#define HID_USAGE_POS_BARCODE_INTRINSICALLY_SAFE (0x3C) // SF +#define HID_USAGE_POS_BARCODE_KLASSE_EINS_LASER (0x3D) // SF +#define HID_USAGE_POS_BARCODE_LONG_RANGE_SCANNER (0x3E) // SF +#define HID_USAGE_POS_BARCODE_MIRROR_SPEED_CONTROL (0x3F) // SF +#define HID_USAGE_POS_BARCODE_NOT_ON_FILE_INDICATION (0x40) // SF +#define HID_USAGE_POS_BARCODE_PROGRAMMABLE_BEEPER (0x41) // SF +#define HID_USAGE_POS_BARCODE_TRIGGERLESS (0x42) // SF +#define HID_USAGE_POS_BARCODE_WAND (0x43) // SF +#define HID_USAGE_POS_BARCODE_WATER_RESISTANT (0x44) // SF +#define HID_USAGE_POS_BARCODE_MULTI_RANGE_SCANNER (0x45) // SF +#define HID_USAGE_POS_BARCODE_PROXIMITY_SENSOR (0x46) // SF +#define HID_USAGE_POS_BARCODE_FRAGMENT_DECODING (0x4D) // DF +#define HID_USAGE_POS_BARCODE_SCANNER_READ_CONFIDENCE (0x4E) // DV +#define HID_USAGE_POS_BARCODE_DATA_PREFIX (0x4F) // NAry +#define HID_USAGE_POS_BARCODE_PREFIX_AIMI (0x50) // SEL +#define HID_USAGE_POS_BARCODE_PREFIX_NONE (0x51) // SEL +#define HID_USAGE_POS_BARCODE_PREFIX_PROPRIETARY (0x52) // SEL +#define HID_USAGE_POS_BARCODE_ACTIVE_TIME (0x55) // DV +#define HID_USAGE_POS_BARCODE_AIMING_LASER_PATTERN (0x56) // DF +#define HID_USAGE_POS_BARCODE_BAR_CODE_PRESENT (0x57) // OOC +#define HID_USAGE_POS_BARCODE_BEEPER_STATE (0x58) // OOC +#define HID_USAGE_POS_BARCODE_LASER_ON_TIME (0x59) // DV +#define HID_USAGE_POS_BARCODE_LASER_STATE (0x5A) // OOC +#define HID_USAGE_POS_BARCODE_LOCKOUT_TIME (0x5B) // DV +#define HID_USAGE_POS_BARCODE_MOTOR_STATE (0x5C) // OOC +#define HID_USAGE_POS_BARCODE_MOTOR_TIMEOUT (0x5D) // DV +#define HID_USAGE_POS_BARCODE_POWER_ON_RESET_SCANNER (0x5E) // DF +#define HID_USAGE_POS_BARCODE_PREVENT_READ_OF_BARCODES (0x5F) // DF +#define HID_USAGE_POS_BARCODE_INITIATE_BARCODE_READ (0x60) // DF +#define HID_USAGE_POS_BARCODE_TRIGGER_STATE (0x61) // OOC +#define HID_USAGE_POS_BARCODE_TRIGGER_MODE (0x62) // NAry +#define HID_USAGE_POS_BARCODE_TRIGGER_MODE_BLINKING_LASER_ON (0x63) // SEL +#define HID_USAGE_POS_BARCODE_TRIGGER_MODE_CONTINUOUS_LASER_ON (0x64) // SEL +#define HID_USAGE_POS_BARCODE_TRIGGER_MODE_LASER_ON_WHILE_PULLED (0x65) // SEL +#define HID_USAGE_POS_BARCODE_TRIGGER_MODE_LASER_STAYS_ON_AFTER_TRIGGER_RELEASE (0x66) // SEL +#define HID_USAGE_POS_BARCODE_COMMIT_PARAMETERS_TO_NVM (0x6D) // DF +#define HID_USAGE_POS_BARCODE_PARAMETER_SCANNING (0x6E) // DF +#define HID_USAGE_POS_BARCODE_PARAMETERS_CHANGED (0x6F) // OOC +#define HID_USAGE_POS_BARCODE_SET_PARAMETER_DEFAULT_VALUES (0x70) // DF +#define HID_USAGE_POS_BARCODE_SCANNER_IN_CRADLE (0x75) // OOC +#define HID_USAGE_POS_BARCODE_SCANNER_IN_RANGE (0x76) // OOC +#define HID_USAGE_POS_BARCODE_AIM_DURATION (0x7A) // DV +#define HID_USAGE_POS_BARCODE_GOOD_READ_LAMP_DURATION (0x7B) // DV +#define HID_USAGE_POS_BARCODE_GOOD_READ_LAMP_INTENSITY (0x7C) // DV +#define HID_USAGE_POS_BARCODE_GOOD_READ_LED (0x7D) // DF +#define HID_USAGE_POS_BARCODE_GOOD_READ_TONE_FREQUENCY (0x7E) // DV +#define HID_USAGE_POS_BARCODE_GOOD_READ_TONE_LENGTH (0x7F) // DV +#define HID_USAGE_POS_BARCODE_GOOD_READ_TONE_VOLUME (0x80) // DV +#define HID_USAGE_POS_BARCODE_NO_READ_MESSAGE (0x82) // DF +#define HID_USAGE_POS_BARCODE_NOT_ON_FILE_VOLUME (0x83) // DV +#define HID_USAGE_POS_BARCODE_POWERUP_BEEP (0x84) // DF +#define HID_USAGE_POS_BARCODE_SOUND_ERROR_BEEP (0x85) // DF +#define HID_USAGE_POS_BARCODE_SOUND_GOOD_READ_BEEP (0x86) // DF +#define HID_USAGE_POS_BARCODE_SOUND_NOT_ON_FILE_BEEP (0x87) // DF +#define HID_USAGE_POS_BARCODE_GOOD_READ_WHEN_TO_WRITE (0x88) // NAry +#define HID_USAGE_POS_BARCODE_GRWTI_AFTER_DECODE (0x89) // SEL +#define HID_USAGE_POS_BARCODE_GRWTI_BEEP_LAMP_AFTER_TRANSMIT (0x8A) // SEL +#define HID_USAGE_POS_BARCODE_GRWTI_NO_BEEP_LAMP_USE_AT_ALL (0x8B) // SEL +#define HID_USAGE_POS_BARCODE_BOOKLAND_EAN (0x91) // DF +#define HID_USAGE_POS_BARCODE_CONVERT_EAN_8_TO_13_TYPE (0x92) // DF +#define HID_USAGE_POS_BARCODE_CONVERT_UPC_A_TO_EAN_13 (0x93) // DF +#define HID_USAGE_POS_BARCODE_CONVERT_UPC_E_TO_A (0x94) // DF +#define HID_USAGE_POS_BARCODE_EAN_13 (0x95) // DF +#define HID_USAGE_POS_BARCODE_EAN_8 (0x96) // DF +#define HID_USAGE_POS_BARCODE_EAN_99_128_MANDATORY (0x97) // DF +#define HID_USAGE_POS_BARCODE_EAN_99_P5_128_OPTIONAL (0x98) // DF +#define HID_USAGE_POS_BARCODE_UPC_EAN (0x9A) // DF +#define HID_USAGE_POS_BARCODE_UPC_EAN_COUPON_CODE (0x9B) // DF +#define HID_USAGE_POS_BARCODE_UPC_EAN_PERIODICALS (0x9C) // DV +#define HID_USAGE_POS_BARCODE_UPC_A (0x9D) // DF +#define HID_USAGE_POS_BARCODE_UPC_A_WITH_128_MANDATORY (0x9E) // DF +#define HID_USAGE_POS_BARCODE_UPC_A_WITH_128_OPTIONAL (0x9F) // DF +#define HID_USAGE_POS_BARCODE_UPC_A_WITH_P5_OPTIONAL (0xA0) // DF +#define HID_USAGE_POS_BARCODE_UPC_E (0xA1) // DF +#define HID_USAGE_POS_BARCODE_UPC_E1 (0xA2) // DF +#define HID_USAGE_POS_BARCODE_PERIODICAL (0xA9) // NAry +#define HID_USAGE_POS_BARCODE_PERIODICAL_AUTO_DISCRIMINATE_PLUS_2 (0xAA) // SEL +#define HID_USAGE_POS_BARCODE_PERIODICAL_ONLY_DECODE_WITH_PLUS_2 (0xAB) // SEL +#define HID_USAGE_POS_BARCODE_PERIODICAL_IGNORE_PLUS_2 (0xAC) // SEL +#define HID_USAGE_POS_BARCODE_PERIODICAL_AUTO_DISCRIMINATE_PLUS_5 (0xAD) // SEL +#define HID_USAGE_POS_BARCODE_PERIODICAL_ONLY_DECODE_WITH_PLUS_5 (0xAE) // SEL +#define HID_USAGE_POS_BARCODE_PERIODICAL_IGNORE_PLUS_5 (0xAF) // SEL +#define HID_USAGE_POS_BARCODE_CHECK (0xB0) // NAry +#define HID_USAGE_POS_BARCODE_CHECK_DISABLE_PRICE (0xB1) // SEL +#define HID_USAGE_POS_BARCODE_CHECK_ENABLE_4_DIGIT_PRICE (0xB2) // SEL +#define HID_USAGE_POS_BARCODE_CHECK_ENABLE_5_DIGIT_PRICE (0xB3) // SEL +#define HID_USAGE_POS_BARCODE_CHECK_ENABLE_EUROPEAN_4_DIGIT_PRICE (0xB4) // SEL +#define HID_USAGE_POS_BARCODE_CHECK_ENABLE_EUROPEAN_5_DIGIT_PRICE (0xB5) // SEL +#define HID_USAGE_POS_BARCODE_EAN_TWO_LABEL (0xB7) // DF +#define HID_USAGE_POS_BARCODE_EAN_THREE_LABEL (0xB8) // DF +#define HID_USAGE_POS_BARCODE_EAN_8_FLAG_DIGIT_1 (0xB9) // DV +#define HID_USAGE_POS_BARCODE_EAN_8_FLAG_DIGIT_2 (0xBA) // DV +#define HID_USAGE_POS_BARCODE_EAN_8_FLAG_DIGIT_3 (0xBB) // DV +#define HID_USAGE_POS_BARCODE_EAN_13_FLAG_DIGIT_1 (0xBC) // DV +#define HID_USAGE_POS_BARCODE_EAN_13_FLAG_DIGIT_2 (0xBD) // DV +#define HID_USAGE_POS_BARCODE_TRANSMIT_CHECK_DIGIT (0xF0) // NAry +#define HID_USAGE_POS_BARCODE_DISABLE_CHECK_DIGIT_TRANSMIT (0xF1) // SEL +#define HID_USAGE_POS_BARCODE_ENABLE_CHECK_DIGIT_TRANSMIT (0xF2) // SEL +#define HID_USAGE_POS_BARCODE_SYMBOLOGY_IDENTIFIER_1 (0xFB) // DV +#define HID_USAGE_POS_BARCODE_SYMBOLOGY_IDENTIFIER_2 (0xFC) // DV +#define HID_USAGE_POS_BARCODE_SYMBOLOGY_IDENTIFIER_3 (0xFD) // DV +#define HID_USAGE_POS_BARCODE_DECODED_DATA (0xFE) // DV +#define HID_USAGE_POS_BARCODE_DECODE_DATA_CONTINUED (0xFF) // DF +#define HID_USAGE_POS_BARCODE_BAR_SPACE_DATA (0x100) // DV +#define HID_USAGE_POS_BARCODE_SCANNER_DATA_ACCURACY (0x101) // DV +#define HID_USAGE_POS_BARCODE_RAW_DATA_POLARITY (0x102) // NAry +#define HID_USAGE_POS_BARCODE_POLARITY_INVERTED_BAR_CODE (0x103) // SEL +#define HID_USAGE_POS_BARCODE_POLARITY_NORMAL_BAR_CODE (0x104) // SEL +#define HID_USAGE_POS_BARCODE_MINIMUM_LENGTH_TO_DECODE (0x106) // DV +#define HID_USAGE_POS_BARCODE_MAXIMUM_LENGTH_TO_DECODE (0x107) // DV +#define HID_USAGE_POS_BARCODE_FIRST_DISCRETE_LENGTH_TO_DECODE (0x108) // DV +#define HID_USAGE_POS_BARCODE_SECOND_DISCRETE_LENGTH_TO_DECODE (0x109) // DV +#define HID_USAGE_POS_BARCODE_DATA_LENGTH_METHOD (0x10A) // NAry +#define HID_USAGE_POS_BARCODE_DL_METHOD_READ_ANY (0x10B) // SEL +#define HID_USAGE_POS_BARCODE_DL_METHOD_CHECK_IN_RANGE (0x10C) // SEL +#define HID_USAGE_POS_BARCODE_DL_METHOD_CHECK_FOR_DISCRETE (0x10D) // SEL +#define HID_USAGE_POS_BARCODE_AZTEC_CODE (0x110) // DF +#define HID_USAGE_POS_BARCODE_BC412 (0x111) // DF +#define HID_USAGE_POS_BARCODE_CHANNEL_CODE (0x112) // DF +#define HID_USAGE_POS_BARCODE_CODE_16 (0x113) // DF +#define HID_USAGE_POS_BARCODE_CODE_32 (0x114) // DF +#define HID_USAGE_POS_BARCODE_CODE_49 (0x115) // DF +#define HID_USAGE_POS_BARCODE_CODE_ONE (0x116) // DF +#define HID_USAGE_POS_BARCODE_COLORCODE (0x117) // DF +#define HID_USAGE_POS_BARCODE_DATA_MATRIX (0x118) // DF +#define HID_USAGE_POS_BARCODE_MAXICODE (0x119) // DF +#define HID_USAGE_POS_BARCODE_MICROPDF (0x11A) // DF +#define HID_USAGE_POS_BARCODE_PDF_417 (0x11B) // DF +#define HID_USAGE_POS_BARCODE_POSICODE (0x11C) // DF +#define HID_USAGE_POS_BARCODE_QR_CODE (0x11D) // DF +#define HID_USAGE_POS_BARCODE_SUPERCODE (0x11E) // DF +#define HID_USAGE_POS_BARCODE_ULTRACODE (0x11F) // DF +#define HID_USAGE_POS_BARCODE_USD_5_SLUG_CODE (0x120) // DF +#define HID_USAGE_POS_BARCODE_VERICODE (0x121) // DF + +/* Page 0x8D: Scale */ +#define HID_USAGE_POS_SCALE_UNDEFINED (0x00) +#define HID_USAGE_POS_SCALE_WEIGHING_DEVICE (0x01) // CA +#define HID_USAGE_POS_SCALE_SCALE_DEVICE (0x20) // CL +#define HID_USAGE_POS_SCALE_SCALE_CLASS_I_METRIC (0x21) // CL +#define HID_USAGE_POS_SCALE_SCALE_CLASS_I_METRIC_2 (0x22) // SEL +#define HID_USAGE_POS_SCALE_SCALE_CLASS_II_METRIC (0x23) // SEL +#define HID_USAGE_POS_SCALE_SCALE_CLASS_III_METRIC (0x24) // SEL +#define HID_USAGE_POS_SCALE_SCALE_CLASS_IIIL_METRIC (0x25) // SEL +#define HID_USAGE_POS_SCALE_SCALE_CLASS_IV_METRIC (0x26) // SEL +#define HID_USAGE_POS_SCALE_SCALE_CLASS_III_ENGLISH (0x27) // SEL +#define HID_USAGE_POS_SCALE_SCALE_CLASS_IIIL_ENGLISH (0x28) // SEL +#define HID_USAGE_POS_SCALE_SCALE_CLASS_IV_ENGLISH (0x29) // SEL +#define HID_USAGE_POS_SCALE_SCALE_CLASS_GENERIC (0x2A) // SEL +#define HID_USAGE_POS_SCALE_SCALE_ATTRIBUTE_REPORT (0x30) // CL +#define HID_USAGE_POS_SCALE_SCALE_CONTROL_REPORT (0x31) // CL +#define HID_USAGE_POS_SCALE_SCALE_DATA_REPORT (0x32) // CL +#define HID_USAGE_POS_SCALE_SCALE_STATUS_REPORT (0x33) // CL +#define HID_USAGE_POS_SCALE_SCALE_WEIGHT_LIMIT_REPORT (0x34) // CL +#define HID_USAGE_POS_SCALE_SCALE_STATISTICS_REPORT (0x35) // CL +#define HID_USAGE_POS_SCALE_DATA_WEIGHT (0x40) // DV +#define HID_USAGE_POS_SCALE_DATA_SCALING (0x41) // CV +#define HID_USAGE_POS_SCALE_WEIGHT_UNIT (0x50) // CL +#define HID_USAGE_POS_SCALE_WEIGHT_UNIT_MILLIGRAM (0x51) // SEL +#define HID_USAGE_POS_SCALE_WEIGHT_UNIT_GRAM (0x52) // SEL +#define HID_USAGE_POS_SCALE_WEIGHT_UNIT_KILOGRAM (0x53) // SEL +#define HID_USAGE_POS_SCALE_WEIGHT_UNIT_CARATS (0x54) // SEL +#define HID_USAGE_POS_SCALE_WEIGHT_UNIT_TAELS (0x55) // SEL +#define HID_USAGE_POS_SCALE_WEIGHT_UNIT_GRAINS (0x56) // SEL +#define HID_USAGE_POS_SCALE_WEIGHT_UNIT_PENNYWEIGHTS (0x57) // SEL +#define HID_USAGE_POS_SCALE_WEIGHT_UNIT_METRIC_TON (0x58) // SEL +#define HID_USAGE_POS_SCALE_WEIGHT_UNIT_AVOIR_TON (0x59) // SEL +#define HID_USAGE_POS_SCALE_WEIGHT_UNIT_TROY_OUNCE (0x5A) // SEL +#define HID_USAGE_POS_SCALE_WEIGHT_UNIT_OUNCE (0x5B) // SEL +#define HID_USAGE_POS_SCALE_WEIGHT_UNIT_POUND (0x5C) // SEL +#define HID_USAGE_POS_SCALE_CALIBRATION_COUNT (0x60) // DV +#define HID_USAGE_POS_SCALE_RE_ZERO_COUNT (0x61) // DV +#define HID_USAGE_POS_SCALE_SCALE_STATUS (0x70) // CL +#define HID_USAGE_POS_SCALE_SCALE_STATUS_FAULT (0x71) // SEL +#define HID_USAGE_POS_SCALE_SCALE_STATUS_STABLE_AT_CENTER_OF_ZERO (0x72) // SEL +#define HID_USAGE_POS_SCALE_SCALE_STATUS_IN_MOTION (0x73) // SEL +#define HID_USAGE_POS_SCALE_SCALE_STATUS_WEIGHT_STABLE (0x74) // SEL +#define HID_USAGE_POS_SCALE_SCALE_STATUS_UNDER_ZERO (0x75) // SEL +#define HID_USAGE_POS_SCALE_SCALE_STATUS_OVER_WEIGHT_LIMIT (0x76) // SEL +#define HID_USAGE_POS_SCALE_SCALE_STATUS_REQUIRES_CALIBRATION (0x77) // SEL +#define HID_USAGE_POS_SCALE_SCALE_STATUS_REQUIRES_RE_ZEROING (0x78) // SEL +#define HID_USAGE_POS_SCALE_ZERO_SCALE (0x80) // OOC +#define HID_USAGE_POS_SCALE_ENFORCED_ZERO_RETURN (0x81) // OOC + +/* Page 0x8E: Magnetic Stripe Reading (MSR) Devices */ +#define HID_USAGE_POS_MSR_UNDEFINED (0x00) +#define HID_USAGE_POS_MSR_MSR_DEVICE_READ_ONLY (0x01) // CA +#define HID_USAGE_POS_MSR_TRACK_1_LENGTH (0x11) // SF, DF, SEL +#define HID_USAGE_POS_MSR_TRACK_2_LENGTH (0x12) // SF, DF, SEL +#define HID_USAGE_POS_MSR_TRACK_3_LENGTH (0x13) // SF, DF, SEL +#define HID_USAGE_POS_MSR_TRACK_JIS_LENGTH (0x14) // SF, DF, SEL +#define HID_USAGE_POS_MSR_TRACK_DATA (0x20) // SF, DF, SEL +#define HID_USAGE_POS_MSR_TRACK_1_DATA (0x21) // SF, DF, SEL +#define HID_USAGE_POS_MSR_TRACK_2_DATA (0x22) // SF, DF, SEL +#define HID_USAGE_POS_MSR_TRACK_3_DATA (0x23) // SF, DF, SEL +#define HID_USAGE_POS_MSR_TRACK_JIS_DATA (0x24) // SF, DF, SEL + +/* Page 0x90: Camera Control */ +#define HID_USAGE_CAMERA_UNDEFINED (0x00) +#define HID_USAGE_CAMERA_CAMERA_AUTO_FOCUS (0x20) // OSC +#define HID_USAGE_CAMERA_CAMERA_SHUTTER (0x21) // OSC + +/* Page 0xF1D0: FIDO Alliance */ +#define HID_USAGE_FIDO_UNDEFINED (0x00) +#define HID_USAGE_FIDO_U2F_AUTHENTICATOR_DEVICE (0x01) // CA +#define HID_USAGE_FIDO_INPUT_REPORT_DATA (0x20) // DV +#define HID_USAGE_FIDO_OUTPUT_REPORT_DATA (0x21) // DV \ No newline at end of file diff --git a/app/include/dt-bindings/zmk/hid_usage_pages.h b/app/include/dt-bindings/zmk/hid_usage_pages.h new file mode 100644 index 000000000000..7fa54fd88b90 --- /dev/null +++ b/app/include/dt-bindings/zmk/hid_usage_pages.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + * + * Based on HID Usage Tables 1.21, + * Copyright © 1996-2020, USB Implementers Forum, + * https://www.usb.org/sites/default/files/hut1_21.pdf + */ + +#pragma once + +#define ZMK_HID_USAGE(page, id) ((page << 16) | id) +#define ZMK_HID_USAGE_ID(usage) (usage & 0xFFFF) +#define ZMK_HID_USAGE_PAGE(usage) ((usage >> 16) & 0xFF) + +/* WARNING: DEPRECATED from dt-bindings/zmk/keys.h */ +#define USAGE_KEYPAD (0x07) // WARNING: DEPRECATED (DO NOT USE) +#define USAGE_CONSUMER (0x0C) // WARNING: DEPRECATED (DO NOT USE) + +#define HID_USAGE_GD (0x01) // Generic Desktop +#define HID_USAGE_SIM (0x02) // Simulation Controls +#define HID_USAGE_VR (0x03) // VR Controls +#define HID_USAGE_SPORT (0x04) // Sport Controls +#define HID_USAGE_GAME (0x05) // Game Controls +#define HID_USAGE_GDV (0x06) // Generic Device Controls +#define HID_USAGE_KEY (0x07) // Keyboard/Keypad +#define HID_USAGE_LED (0x08) // LED +#define HID_USAGE_BUTTON (0x09) // Button +#define HID_USAGE_TELEPHONY (0x0B) // Telephony Device +#define HID_USAGE_CONSUMER (0x0C) // Consumer +#define HID_USAGE_DIGITIZERS (0x0D) // Digitizers +#define HID_USAGE_HAPTICS (0x0E) // Haptics +#define HID_USAGE_PID (0x0F) // PID +#define HID_USAGE_EHT (0x12) // Eye and Head Trackers +#define HID_USAGE_AUXDISP (0x14) // Auxiliary Display +#define HID_USAGE_SENSORS (0x20) // Sensors +#define HID_USAGE_MEDICAL (0x40) // Medical Instrument +#define HID_USAGE_BRAILLE (0x41) // Braille Display +#define HID_USAGE_LIGHT (0x59) // Lighting And Illumination +#define HID_USAGE_MONITOR (0x80) // USB Monitor +#define HID_USAGE_MONITOR_VALUES (0x81) // Monitor Enumerated Values +#define HID_USAGE_MONITOR_VESA (0x82) // VESA Virtual Control +#define HID_USAGE_POWER (0x84) // Power +#define HID_USAGE_POS_BARCODE (0x8C) // Bar Code Scanner +#define HID_USAGE_POS_SCALE (0x8D) // Scale +#define HID_USAGE_POS_MSR (0x8E) // Magnetic Stripe Reading (MSR) Devices +#define HID_USAGE_POS_RESV (0x8F) // Reserved Point of Sale +#define HID_USAGE_CAMERA (0x90) // Camera Control +#define HID_USAGE_ARCADE (0x91) // Arcade +#define HID_USAGE_GAMING (0x92) // Gaming Device +#define HID_USAGE_FIDO (0xF1D0) // FIDO Alliance \ No newline at end of file diff --git a/app/include/dt-bindings/zmk/keys.h b/app/include/dt-bindings/zmk/keys.h new file mode 100644 index 000000000000..364ffa8647ad --- /dev/null +++ b/app/include/dt-bindings/zmk/keys.h @@ -0,0 +1,1445 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ +#pragma once + +#include +#include +#include + +/* System Power Down */ +#define SYSTEM_POWER (ZMK_HID_USAGE(HID_USAGE_GD, HID_USAGE_GD_SYSTEM_POWER_DOWN)) +#define SYS_PWR (SYSTEM_POWER) + +/* System Sleep */ +#define SYSTEM_SLEEP (ZMK_HID_USAGE(HID_USAGE_GD, HID_USAGE_GD_SYSTEM_SLEEP)) +#define SYS_SLEEP (SYSTEM_SLEEP) + +/* System Wake Up */ +#define SYSTEM_WAKE_UP (ZMK_HID_USAGE(HID_USAGE_GD, HID_USAGE_GD_SYSTEM_WAKE_UP)) +#define SYS_WAKE (SYSTEM_WAKE_UP) + +/* Keyboard a and A */ +#define A (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_A)) + +/* Keyboard b and B */ +#define B (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_B)) + +/* Keyboard c and C */ +#define C (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_C)) + +/* Keyboard d and D */ +#define D (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_D)) + +/* Keyboard e and E */ +#define E (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_E)) + +/* Keyboard f and F */ +#define F (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F)) + +/* Keyboard g and G */ +#define G (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_G)) + +/* Keyboard h and H */ +#define H (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_H)) + +/* Keyboard i and I */ +#define I (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_I)) + +/* Keyboard j and J */ +#define J (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_J)) + +/* Keyboard k and K */ +#define K (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_K)) + +/* Keyboard l and L */ +#define L (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_L)) + +/* Keyboard m and M */ +#define M (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_M)) + +/* Keyboard n and N */ +#define N (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_N)) + +/* Keyboard o and O */ +#define O (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_O)) + +/* Keyboard p and P */ +#define P (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_P)) + +/* Keyboard q and Q */ +#define Q (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_Q)) + +/* Keyboard r and R */ +#define R (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_R)) + +/* Keyboard s and S */ +#define S (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_S)) + +/* Keyboard t and T */ +#define T (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_T)) + +/* Keyboard u and U */ +#define U (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_U)) + +/* Keyboard v and V */ +#define V (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_V)) + +/* Keyboard w and W */ +#define W (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_W)) + +/* Keyboard x and X */ +#define X (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_X)) + +/* Keyboard y and Y */ +#define Y (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_Y)) + +/* Keyboard z and Z */ +#define Z (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_Z)) + +/* Keyboard 1 and ! (Exclamation) */ +#define NUMBER_1 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_1_AND_EXCLAMATION)) +#define N1 (NUMBER_1) +#define NUM_1 (NUMBER_1) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard ! (Exclamation) */ +#define EXCLAMATION (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_1_AND_EXCLAMATION))) +#define EXCL (EXCLAMATION) +#define BANG (EXCLAMATION) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard 2 and @ (At sign) */ +#define NUMBER_2 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_2_AND_AT)) +#define N2 (NUMBER_2) +#define NUM_2 (NUMBER_2) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard @ (At sign) */ +#define AT_SIGN (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_2_AND_AT))) +#define AT (AT_SIGN) +#define ATSN (AT_SIGN) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard 3 and # (Hash/Number) */ +#define NUMBER_3 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_3_AND_HASH)) +#define N3 (NUMBER_3) +#define NUM_3 (NUMBER_3) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard # (Hash/Number) */ +#define HASH (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_3_AND_HASH))) +#define POUND (HASH) + +/* Keyboard 4 and $ (Dollar) */ +#define NUMBER_4 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_4_AND_DOLLAR)) +#define N4 (NUMBER_4) +#define NUM_4 (NUMBER_4) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard $ (Dollar) */ +#define DOLLAR (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_4_AND_DOLLAR))) +#define DLLR (DOLLAR) + +/* Keyboard 5 and % (Percent) */ +#define NUMBER_5 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_5_AND_PERCENT)) +#define N5 (NUMBER_5) +#define NUM_5 (NUMBER_5) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard % (Percent) */ +#define PERCENT (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_5_AND_PERCENT))) +#define PRCNT (PERCENT) +#define PRCT (PERCENT) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard 6 and ^ (Caret) */ +#define NUMBER_6 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_6_AND_CARET)) +#define N6 (NUMBER_6) +#define NUM_6 (NUMBER_6) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard ^ (Caret) */ +#define CARET (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_6_AND_CARET))) +#define CRRT (CARET) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard 7 and & (Ampersand) */ +#define NUMBER_7 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_7_AND_AMPERSAND)) +#define N7 (NUMBER_7) +#define NUM_7 (NUMBER_7) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard & (Ampersand) */ +#define AMPERSAND (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_7_AND_AMPERSAND))) +#define AMPS (AMPERSAND) + +/* Keyboard 8 and * (Asterisk) */ +#define NUMBER_8 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_8_AND_ASTERISK)) +#define N8 (NUMBER_8) +#define NUM_8 (NUMBER_8) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard * (Asterisk) */ +#define ASTERISK (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_8_AND_ASTERISK))) +#define ASTRK (ASTERISK) +#define STAR (ASTERISK) + +/* Keyboard 9 and ( (Left Parenthesis) */ +#define NUMBER_9 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_9_AND_LEFT_PARENTHESIS)) +#define N9 (NUMBER_9) +#define NUM_9 (NUMBER_9) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard ( (Left Parenthesis) */ +#define LEFT_PARENTHESIS \ + (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_9_AND_LEFT_PARENTHESIS))) +#define LPAR (LEFT_PARENTHESIS) +#define LPRN (LEFT_PARENTHESIS) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard 0 and ) (Right Parenthesis) */ +#define NUMBER_0 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_0_AND_RIGHT_PARENTHESIS)) +#define N0 (NUMBER_0) +#define NUM_0 (NUMBER_0) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard ) (Right Parenthesis) */ +#define RIGHT_PARENTHESIS \ + (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_0_AND_RIGHT_PARENTHESIS))) +#define RPAR (RIGHT_PARENTHESIS) +#define RPRN (RIGHT_PARENTHESIS) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Return (Enter) */ +#define RETURN (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_RETURN_ENTER)) +#define ENTER (RETURN) +#define RET (RETURN) + +/* Keyboard Escape */ +#define ESCAPE (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_ESCAPE)) +#define ESC (ESCAPE) + +/* Keyboard Backspace */ +#define BACKSPACE (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_DELETE_BACKSPACE)) +#define BSPC (BACKSPACE) +#define BKSP (BACKSPACE) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Tab */ +#define TAB (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_TAB)) + +/* Keyboard Space */ +#define SPACE (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_SPACEBAR)) +#define SPC (SPACE) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard - and _ (Minus and Underscore) */ +#define MINUS (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_MINUS_AND_UNDERSCORE)) + +/* Keyboard _ (Underscore) */ +#define UNDERSCORE (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_MINUS_AND_UNDERSCORE))) +#define UNDER (UNDERSCORE) + +/* Keyboard = and + (Equal and Plus) */ +#define EQUAL (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_EQUAL_AND_PLUS)) +#define EQL (EQUAL) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard + (Plus) */ +#define PLUS (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_EQUAL_AND_PLUS))) + +/* Keyboard [ and { (Left Bracket and Left Brace) */ +#define LEFT_BRACKET \ + (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_LEFT_BRACKET_AND_LEFT_BRACE)) +#define LBKT (LEFT_BRACKET) + +/* Keyboard { (Left Brace) */ +#define LEFT_BRACE \ + (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_LEFT_BRACKET_AND_LEFT_BRACE))) +#define LBRC (LEFT_BRACE) +#define LCUR (LEFT_BRACE) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard ] and } (Right Bracket and Right Brace) */ +#define RIGHT_BRACKET \ + (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_RIGHT_BRACKET_AND_RIGHT_BRACE)) +#define RBKT (RIGHT_BRACKET) + +/* Keyboard } (Right Brace) */ +#define RIGHT_BRACE \ + (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_RIGHT_BRACKET_AND_RIGHT_BRACE))) +#define RBRC (RIGHT_BRACE) +#define RCUR (RIGHT_BRACE) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard \ and | (Backslash and Pipe) */ +#define BACKSLASH (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_BACKSLASH_AND_PIPE)) +#define BSLH (BACKSLASH) + +/* Keyboard | (Pipe) */ +#define PIPE (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_BACKSLASH_AND_PIPE))) + +/* Keyboard Non-US # and ~ (Non-US Hash/Number and Tilde) */ +#define NON_US_HASH (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_NON_US_HASH_AND_TILDE)) +#define NUHS (NON_US_HASH) + +/* Keyboard ~ (Tilde) */ +#define TILDE2 (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_NON_US_HASH_AND_TILDE))) + +/* Keyboard ; and : (Semicolon and Colon) */ +#define SEMICOLON (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_SEMICOLON_AND_COLON)) +#define SEMI (SEMICOLON) +#define SCLN (SEMICOLON) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard : (Colon) */ +#define COLON (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_SEMICOLON_AND_COLON))) +#define COLN (COLON) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard ' and " (Apostrophe and Quote) */ +#define SINGLE_QUOTE (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_APOSTROPHE_AND_QUOTE)) +#define SQT (SINGLE_QUOTE) +#define APOSTROPHE (SINGLE_QUOTE) +#define APOS (SINGLE_QUOTE) +#define QUOT (SINGLE_QUOTE) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard " (Quote) */ +#define DOUBLE_QUOTES \ + (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_APOSTROPHE_AND_QUOTE))) +#define DQT (DOUBLE_QUOTES) + +/* Keyboard ` and ~ (Grave Accent and Tilde) */ +#define GRAVE (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_GRAVE_ACCENT_AND_TILDE)) +#define GRAV (GRAVE) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard ~ (Tilde) */ +#define TILDE (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_GRAVE_ACCENT_AND_TILDE))) +#define TILD (TILDE) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard , and < (Comma and Less Than) */ +#define COMMA (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_COMMA_AND_LESS_THAN)) +#define CMMA (COMMA) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard < (Less Than) */ +#define LESS_THAN (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_COMMA_AND_LESS_THAN))) +#define LT (LESS_THAN) +#define LABT (LESS_THAN) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard . and > (Period and Greater Than) */ +#define PERIOD (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_PERIOD_AND_GREATER_THAN)) +#define DOT (PERIOD) + +/* Keyboard > (Greater Than) */ +#define GREATER_THAN \ + (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_PERIOD_AND_GREATER_THAN))) +#define GT (GREATER_THAN) +#define RABT (GREATER_THAN) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard / and ? (Forward Slash and Question) */ +#define SLASH (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_SLASH_AND_QUESTION_MARK)) +#define FSLH (SLASH) + +/* Keyboard ? (Question) */ +#define QUESTION (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_SLASH_AND_QUESTION_MARK))) +#define QMARK (QUESTION) + +/* Keyboard Caps Lock */ +#define CAPSLOCK (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_CAPS_LOCK)) +#define CAPS (CAPSLOCK) +#define CLCK (CAPSLOCK) + +/* Keyboard F1 */ +#define F1 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F1)) + +/* Keyboard F2 */ +#define F2 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F2)) + +/* Keyboard F3 */ +#define F3 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F3)) + +/* Keyboard F4 */ +#define F4 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F4)) + +/* Keyboard F5 */ +#define F5 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F5)) + +/* Keyboard F6 */ +#define F6 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F6)) + +/* Keyboard F7 */ +#define F7 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F7)) + +/* Keyboard F8 */ +#define F8 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F8)) + +/* Keyboard F9 */ +#define F9 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F9)) + +/* Keyboard F10 */ +#define F10 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F10)) + +/* Keyboard F11 */ +#define F11 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F11)) + +/* Keyboard F12 */ +#define F12 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F12)) + +/* Keyboard Print Screen */ +#define PRINTSCREEN (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_PRINTSCREEN)) +#define PSCRN (PRINTSCREEN) +#define PRSC (PRINTSCREEN) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Scroll Lock */ +#define SCROLLLOCK (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_SCROLL_LOCK)) +#define SLCK (SCROLLLOCK) +#define SCLK (SCROLLLOCK) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Pause/Break */ +#define PAUSE_BREAK (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_PAUSE)) +#define PAUS (PAUSE_BREAK) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Insert */ +#define INSERT (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_INSERT)) +#define INS (INSERT) + +/* Keyboard Home */ +#define HOME (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_HOME)) + +/* Keyboard Page Up */ +#define PAGE_UP (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_PAGEUP)) +#define PG_UP (PAGE_UP) +#define PGUP (PAGE_UP) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Delete */ +#define DELETE (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_DELETE_FORWARD)) +#define DEL (DELETE) + +/* Keyboard End */ +#define END (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_END)) + +/* Keyboard Page Down */ +#define PAGE_DOWN (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_PAGEDOWN)) +#define PG_DN (PAGE_DOWN) +#define PGDN (PAGE_DOWN) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Right Arrow */ +#define RIGHT_ARROW (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_RIGHTARROW)) +#define RIGHT (RIGHT_ARROW) +#define RARW (RIGHT_ARROW) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Left Arrow */ +#define LEFT_ARROW (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_LEFTARROW)) +#define LEFT (LEFT_ARROW) +#define LARW (LEFT_ARROW) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Down Arrow */ +#define DOWN_ARROW (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_DOWNARROW)) +#define DOWN (DOWN_ARROW) +#define DARW (DOWN_ARROW) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Up Arrow */ +#define UP_ARROW (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_UPARROW)) +#define UP (UP_ARROW) +#define UARW (UP_ARROW) // WARNING: DEPRECATED (DO NOT USE) + +/* Keypad Numlock and Clear */ +#define KP_NUMLOCK (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_NUM_LOCK_AND_CLEAR)) +#define KP_NUM (KP_NUMLOCK) +#define KP_NLCK (KP_NUMLOCK) + +/* Keypad Clear */ +#define CLEAR2 (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_NUM_LOCK_AND_CLEAR))) + +/* Keypad / (Slash/Divide) */ +#define KP_DIVIDE (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_SLASH)) +#define KP_SLASH (KP_DIVIDE) +#define KDIV (KP_DIVIDE) // WARNING: DEPRECATED (DO NOT USE) + +/* Keypad * (Multiply) */ +#define KP_MULTIPLY (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_ASTERISK)) +#define KP_ASTERISK (KP_MULTIPLY) +#define KMLT (KP_MULTIPLY) // WARNING: DEPRECATED (DO NOT USE) + +/* Keypad - (Minus) */ +#define KP_MINUS (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_MINUS)) +#define KP_SUBTRACT (KP_MINUS) +#define KMIN (KP_MINUS) // WARNING: DEPRECATED (DO NOT USE) + +/* Keypad + (Plus) */ +#define KP_PLUS (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_PLUS)) +#define KPLS (KP_PLUS) // WARNING: DEPRECATED (DO NOT USE) + +/* Keypad Enter */ +#define KP_ENTER (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_ENTER)) + +/* Keypad 1 */ +#define KP_NUMBER_1 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_1_AND_END)) +#define KP_N1 (KP_NUMBER_1) + +/* Keypad 2 */ +#define KP_NUMBER_2 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_2_AND_DOWN_ARROW)) +#define KP_N2 (KP_NUMBER_2) + +/* Keypad 3 */ +#define KP_NUMBER_3 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_3_AND_PAGEDN)) +#define KP_N3 (KP_NUMBER_3) + +/* Keypad 4 */ +#define KP_NUMBER_4 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_4_AND_LEFT_ARROW)) +#define KP_N4 (KP_NUMBER_4) + +/* Keypad 5 */ +#define KP_NUMBER_5 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_5)) +#define KP_N5 (KP_NUMBER_5) + +/* Keypad 6 */ +#define KP_NUMBER_6 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_6_AND_RIGHT_ARROW)) +#define KP_N6 (KP_NUMBER_6) + +/* Keypad 7 */ +#define KP_NUMBER_7 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_7_AND_HOME)) +#define KP_N7 (KP_NUMBER_7) + +/* Keypad 8 */ +#define KP_NUMBER_8 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_8_AND_UP_ARROW)) +#define KP_N8 (KP_NUMBER_8) + +/* Keypad 9 */ +#define KP_NUMBER_9 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_9_AND_PAGEUP)) +#define KP_N9 (KP_NUMBER_9) + +/* Keypad 0 */ +#define KP_NUMBER_0 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_0_AND_INSERT)) +#define KP_N0 (KP_NUMBER_0) + +/* Keypad . (Dot) */ +#define KP_DOT (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_PERIOD_AND_DELETE)) + +/* Keyboard Non-US \ and | (Non-us Backslash and Pipe) */ +#define NON_US_BACKSLASH \ + (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_NON_US_BACKSLASH_AND_PIPE)) +#define NON_US_BSLH (NON_US_BACKSLASH) +#define NUBS (NON_US_BACKSLASH) + +/* Keyboard Pipe */ +#define PIPE2 (LS(ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_NON_US_BACKSLASH_AND_PIPE))) + +/* Keyboard Application (Context Menu) */ +#define K_APPLICATION (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_APPLICATION)) +#define K_APP (K_APPLICATION) +#define K_CONTEXT_MENU (K_APPLICATION) +#define K_CMENU (K_APPLICATION) +#define GUI (K_APPLICATION) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Power */ +#define K_POWER (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_POWER)) +#define K_PWR (K_POWER) + +/* Keypad = (Equal) */ +#define KP_EQUAL (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_EQUAL)) + +/* Keyboard F13 */ +#define F13 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F13)) + +/* Keyboard F14 */ +#define F14 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F14)) + +/* Keyboard F15 */ +#define F15 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F15)) + +/* Keyboard F16 */ +#define F16 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F16)) + +/* Keyboard F17 */ +#define F17 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F17)) + +/* Keyboard F18 */ +#define F18 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F18)) + +/* Keyboard F19 */ +#define F19 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F19)) + +/* Keyboard F20 */ +#define F20 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F20)) + +/* Keyboard F21 */ +#define F21 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F21)) + +/* Keyboard F22 */ +#define F22 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F22)) + +/* Keyboard F23 */ +#define F23 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F23)) + +/* Keyboard F24 */ +#define F24 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_F24)) + +/* Keyboard Execute */ +#define K_EXECUTE (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_EXECUTE)) +#define K_EXEC (K_EXECUTE) + +/* Keyboard Help */ +#define K_HELP (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_HELP)) + +/* Keyboard Menu */ +#define K_MENU (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_MENU)) + +/* Keyboard Select */ +#define K_SELECT (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_SELECT)) + +/* Keyboard Stop */ +#define K_STOP (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_STOP)) + +/* Keyboard Again */ +#define K_AGAIN (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_AGAIN)) +#define K_REDO (K_AGAIN) + +/* Keyboard Undo */ +#define K_UNDO (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_UNDO)) +#define UNDO (K_UNDO) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Cut */ +#define K_CUT (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_CUT)) +#define CUT (K_CUT) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Copy */ +#define K_COPY (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_COPY)) +#define COPY (K_COPY) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Paste */ +#define K_PASTE (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_PASTE)) +#define PSTE (K_PASTE) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Find */ +#define K_FIND (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_FIND)) + +/* Keyboard Mute */ +#define K_MUTE (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_MUTE)) + +/* Keyboard Volume Up */ +#define K_VOLUME_UP (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_VOLUME_UP)) +#define K_VOL_UP (K_VOLUME_UP) +#define VOLU (K_VOLUME_UP) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Volume Down */ +#define K_VOLUME_DOWN (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_VOLUME_DOWN)) +#define K_VOL_DN (K_VOLUME_DOWN) +#define VOLD (K_VOLUME_DOWN) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Locking Caps Lock */ +#define LOCKING_CAPS (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_LOCKING_CAPS_LOCK)) +#define LCAPS (LOCKING_CAPS) + +/* Keyboard Locking Num Lock */ +#define LOCKING_NUM (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_LOCKING_NUM_LOCK)) +#define LNLCK (LOCKING_NUM) + +/* Keyboard Locking Scroll Lock */ +#define LOCKING_SCROLL (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_LOCKING_SCROLL_LOCK)) +#define LSLCK (LOCKING_SCROLL) + +/* Keypad , (Comma) */ +#define KP_COMMA (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_COMMA)) + +/* Keypad = (Equal) AS/400 */ +#define KP_EQUAL_AS400 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_EQUAL_SIGN)) + +/* Keyboard International 1 */ +#define INTERNATIONAL_1 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_INTERNATIONAL1)) +#define INT1 (INTERNATIONAL_1) +#define INT_RO (INTERNATIONAL_1) + +/* Keyboard International 2 */ +#define INTERNATIONAL_2 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_INTERNATIONAL2)) +#define INT2 (INTERNATIONAL_2) +#define INT_KATAKANAHIRAGANA (INTERNATIONAL_2) +#define INT_KANA (INTERNATIONAL_2) + +/* Keyboard International 3 */ +#define INTERNATIONAL_3 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_INTERNATIONAL3)) +#define INT3 (INTERNATIONAL_3) +#define INT_YEN (INTERNATIONAL_3) + +/* Keyboard International 4 */ +#define INTERNATIONAL_4 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_INTERNATIONAL4)) +#define INT4 (INTERNATIONAL_4) +#define INT_HENKAN (INTERNATIONAL_4) + +/* Keyboard International 5 */ +#define INTERNATIONAL_5 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_INTERNATIONAL5)) +#define INT5 (INTERNATIONAL_5) +#define INT_MUHENKAN (INTERNATIONAL_5) + +/* Keyboard International 6 */ +#define INTERNATIONAL_6 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_INTERNATIONAL6)) +#define INT6 (INTERNATIONAL_6) +#define INT_KPJPCOMMA (INTERNATIONAL_6) + +/* Keyboard International 7 */ +#define INTERNATIONAL_7 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_INTERNATIONAL7)) +#define INT7 (INTERNATIONAL_7) + +/* Keyboard International 8 */ +#define INTERNATIONAL_8 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_INTERNATIONAL8)) +#define INT8 (INTERNATIONAL_8) + +/* Keyboard International 9 */ +#define INTERNATIONAL_9 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_INTERNATIONAL9)) +#define INT9 (INTERNATIONAL_9) + +/* Keyboard Language 1 */ +#define LANGUAGE_1 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_LANG1)) +#define LANG1 (LANGUAGE_1) +#define LANG_HANGEUL (LANGUAGE_1) + +/* Keyboard Language 2 */ +#define LANGUAGE_2 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_LANG2)) +#define LANG2 (LANGUAGE_2) +#define LANG_HANJA (LANGUAGE_2) + +/* Keyboard Language 3 */ +#define LANGUAGE_3 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_LANG3)) +#define LANG3 (LANGUAGE_3) +#define LANG_KATAKANA (LANGUAGE_3) + +/* Keyboard Language 4 */ +#define LANGUAGE_4 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_LANG4)) +#define LANG4 (LANGUAGE_4) +#define LANG_HIRAGANA (LANGUAGE_4) + +/* Keyboard Language 5 */ +#define LANGUAGE_5 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_LANG5)) +#define LANG5 (LANGUAGE_5) +#define LANG_ZENKAKUHANKAKU (LANGUAGE_5) + +/* Keyboard Language 6 */ +#define LANGUAGE_6 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_LANG6)) +#define LANG6 (LANGUAGE_6) + +/* Keyboard Language 7 */ +#define LANGUAGE_7 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_LANG7)) +#define LANG7 (LANGUAGE_7) + +/* Keyboard Language 8 */ +#define LANGUAGE_8 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_LANG8)) +#define LANG8 (LANGUAGE_8) + +/* Keyboard Language 9 */ +#define LANGUAGE_9 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_LANG9)) +#define LANG9 (LANGUAGE_9) + +/* Keyboard Alternate Erase */ +#define ALT_ERASE (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_ALTERNATE_ERASE)) + +/* Keyboard SysReq/Attention */ +#define SYSREQ (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_SYSREQ_ATTENTION)) +#define ATTENTION (SYSREQ) + +/* Keyboard Cancel */ +#define K_CANCEL (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_CANCEL)) + +/* Keyboard Clear */ +#define CLEAR (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_CLEAR)) + +/* Keyboard Prior */ +#define PRIOR (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_PRIOR)) + +/* Keyboard Return */ +#define RETURN2 (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_RETURN)) +#define RET2 (RETURN2) + +/* Keyboard Separator */ +#define SEPARATOR (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_SEPARATOR)) + +/* Keyboard Out */ +#define OUT (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_OUT)) + +/* Keyboard Oper */ +#define OPER (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_OPER)) + +/* Keyboard Clear/Again */ +#define CLEAR_AGAIN (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_CLEAR_AGAIN)) + +/* Keyboard CrSel/Props */ +#define CRSEL (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_CRSEL_PROPS)) + +/* Keyboard ExSel */ +#define EXSEL (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_EXSEL)) + +/* Keyboard Currency Unit */ +#define CURU \ + (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_CURRENCY_UNIT)) // WARNING: DEPRECATED (DO NOT USE) + +/* Keypad ( (Left Parenthesis) */ +#define KP_LEFT_PARENTHESIS (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_LEFT_PARENTHESIS)) +#define KP_LPAR (KP_LEFT_PARENTHESIS) + +/* Keypad ) (Right Parenthesis) */ +#define KP_RIGHT_PARENTHESIS (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_RIGHT_PARENTHESIS)) +#define KP_RPAR (KP_RIGHT_PARENTHESIS) + +/* Keypad Space */ +#define KSPC \ + (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_SPACE)) // WARNING: DEPRECATED (DO NOT USE) + +/* Keypad Clear */ +#define KP_CLEAR (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYPAD_CLEAR)) + +/* Keyboard Left Control */ +#define LEFT_CONTROL (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_LEFTCONTROL)) +#define LCTRL (LEFT_CONTROL) +#define LCTL (LEFT_CONTROL) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Left Shift */ +#define LEFT_SHIFT (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_LEFTSHIFT)) +#define LSHIFT (LEFT_SHIFT) +#define LSHFT (LEFT_SHIFT) +#define LSFT (LEFT_SHIFT) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Left Alt */ +#define LEFT_ALT (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_LEFTALT)) +#define LALT (LEFT_ALT) + +/* Keyboard Left GUI (Windows / Command / Meta) */ +#define LEFT_GUI (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_LEFT_GUI)) +#define LGUI (LEFT_GUI) +#define LEFT_WIN (LEFT_GUI) +#define LWIN (LEFT_GUI) +#define LEFT_COMMAND (LEFT_GUI) +#define LCMD (LEFT_GUI) +#define LEFT_META (LEFT_GUI) +#define LMETA (LEFT_GUI) + +/* Keyboard Right Control */ +#define RIGHT_CONTROL (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_RIGHTCONTROL)) +#define RCTRL (RIGHT_CONTROL) +#define RCTL (RIGHT_CONTROL) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Right Shift */ +#define RIGHT_SHIFT (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_RIGHTSHIFT)) +#define RSHIFT (RIGHT_SHIFT) +#define RSHFT (RIGHT_SHIFT) +#define RSFT (RIGHT_SHIFT) // WARNING: DEPRECATED (DO NOT USE) + +/* Keyboard Right Alt */ +#define RIGHT_ALT (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_RIGHTALT)) +#define RALT (RIGHT_ALT) + +/* Keyboard Right GUI (Windows / Command / Meta) */ +#define RIGHT_GUI (ZMK_HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_RIGHT_GUI)) +#define RGUI (RIGHT_GUI) +#define RIGHT_WIN (RIGHT_GUI) +#define RWIN (RIGHT_GUI) +#define RIGHT_COMMAND (RIGHT_GUI) +#define RCMD (RIGHT_GUI) +#define RIGHT_META (RIGHT_GUI) +#define RMETA (RIGHT_GUI) + +/* Keyboard Play/Pause */ +#define K_PLAY_PAUSE (ZMK_HID_USAGE(HID_USAGE_KEY, 0xE8)) +#define K_PP (K_PLAY_PAUSE) + +/* Keyboard Stop */ +#define K_STOP2 (ZMK_HID_USAGE(HID_USAGE_KEY, 0xE9)) + +/* Keyboard Previous */ +#define K_PREVIOUS (ZMK_HID_USAGE(HID_USAGE_KEY, 0xEA)) +#define K_PREV (K_PREVIOUS) + +/* Keyboard Next */ +#define K_NEXT (ZMK_HID_USAGE(HID_USAGE_KEY, 0xEB)) + +/* Keyboard Eject */ +#define K_EJECT (ZMK_HID_USAGE(HID_USAGE_KEY, 0xEC)) + +/* Keyboard Volume Up */ +#define K_VOLUME_UP2 (ZMK_HID_USAGE(HID_USAGE_KEY, 0xED)) +#define K_VOL_UP2 (K_VOLUME_UP2) + +/* Keyboard Volume Down */ +#define K_VOLUME_DOWN2 (ZMK_HID_USAGE(HID_USAGE_KEY, 0xEE)) +#define K_VOL_DN2 (K_VOLUME_DOWN2) + +/* Keyboard Mute */ +#define K_MUTE2 (ZMK_HID_USAGE(HID_USAGE_KEY, 0xEF)) + +/* Keyboard WWW */ +#define K_WWW (ZMK_HID_USAGE(HID_USAGE_KEY, 0xF0)) + +/* Keyboard Back */ +#define K_BACK (ZMK_HID_USAGE(HID_USAGE_KEY, 0xF1)) + +/* Keyboard Forward */ +#define K_FORWARD (ZMK_HID_USAGE(HID_USAGE_KEY, 0xF2)) + +/* Keyboard Stop */ +#define K_STOP3 (ZMK_HID_USAGE(HID_USAGE_KEY, 0xF3)) + +/* Keyboard Find */ +#define K_FIND2 (ZMK_HID_USAGE(HID_USAGE_KEY, 0xF4)) + +/* Keyboard Scroll Up */ +#define K_SCROLL_UP (ZMK_HID_USAGE(HID_USAGE_KEY, 0xF5)) + +/* Keyboard Scroll Down */ +#define K_SCROLL_DOWN (ZMK_HID_USAGE(HID_USAGE_KEY, 0xF6)) + +/* Keyboard Edit */ +#define K_EDIT (ZMK_HID_USAGE(HID_USAGE_KEY, 0xF7)) + +/* Keyboard Sleep */ +#define K_SLEEP (ZMK_HID_USAGE(HID_USAGE_KEY, 0xF8)) + +/* Keyboard Lock */ +#define K_LOCK (ZMK_HID_USAGE(HID_USAGE_KEY, 0xF9)) +#define K_SCREENSAVER (K_LOCK) +#define K_COFFEE (K_LOCK) + +/* Keyboard Refresh */ +#define K_REFRESH (ZMK_HID_USAGE(HID_USAGE_KEY, 0xFA)) + +/* Keyboard Calculator */ +#define K_CALCULATOR (ZMK_HID_USAGE(HID_USAGE_KEY, 0xFB)) +#define K_CALC (K_CALCULATOR) + +/* Consumer Power */ +#define C_POWER (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_POWER)) +#define C_PWR (C_POWER) + +/* Consumer Reset */ +#define C_RESET (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_RESET)) + +/* Consumer Sleep */ +#define C_SLEEP (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_SLEEP)) + +/* Consumer Sleep Mode */ +#define C_SLEEP_MODE (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_SLEEP_MODE)) + +/* Consumer Menu */ +#define C_MENU (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MENU)) + +/* Consumer Menu Pick */ +#define C_MENU_PICK (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MENU_PICK)) +#define C_MENU_SELECT (C_MENU_PICK) + +/* Consumer Menu Up */ +#define C_MENU_UP (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MENU_UP)) + +/* Consumer Menu Down */ +#define C_MENU_DOWN (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MENU_DOWN)) + +/* Consumer Menu Left */ +#define C_MENU_LEFT (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MENU_LEFT)) + +/* Consumer Menu Right */ +#define C_MENU_RIGHT (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MENU_RIGHT)) + +/* Consumer Menu Escape */ +#define C_MENU_ESCAPE (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MENU_ESCAPE)) +#define C_MENU_ESC (C_MENU_ESCAPE) + +/* Consumer Menu Value Increase */ +#define C_MENU_INCREASE (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MENU_VALUE_INCREASE)) +#define C_MENU_INC (C_MENU_INCREASE) + +/* Consumer Menu Value Decrease */ +#define C_MENU_DECREASE (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MENU_VALUE_DECREASE)) +#define C_MENU_DEC (C_MENU_DECREASE) + +/* Consumer Data On Screen */ +#define C_DATA_ON_SCREEN (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_DATA_ON_SCREEN)) + +/* Consumer Closed Caption */ +#define C_CAPTIONS (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_CLOSED_CAPTION)) +#define C_SUBTITLES (C_CAPTIONS) + +/* Consumer Snapshot */ +#define C_SNAPSHOT (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_SNAPSHOT)) + +/* Consumer Picture-in-Picture Toggle */ +#define C_PIP (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_PICTURE_IN_PICTURE_TOGGLE)) + +/* Consumer Red Menu Button */ +#define C_RED_BUTTON (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_RED_MENU_BUTTON)) +#define C_RED (C_RED_BUTTON) + +/* Consumer Green Menu Button */ +#define C_GREEN_BUTTON (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_GREEN_MENU_BUTTON)) +#define C_GREEN (C_GREEN_BUTTON) + +/* Consumer Blue Menu Button */ +#define C_BLUE_BUTTON (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_BLUE_MENU_BUTTON)) +#define C_BLUE (C_BLUE_BUTTON) + +/* Consumer Yellow Menu Button */ +#define C_YELLOW_BUTTON (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_YELLOW_MENU_BUTTON)) +#define C_YELLOW (C_YELLOW_BUTTON) + +/* Consumer Aspect */ +#define C_ASPECT (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_ASPECT)) + +/* Consumer Display Brightness Increment */ +#define C_BRIGHTNESS_INC \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_DISPLAY_BRIGHTNESS_INCREMENT)) +#define C_BRI_INC (C_BRIGHTNESS_INC) +#define C_BRI_UP (C_BRIGHTNESS_INC) + +/* Consumer Display Brightness Decrement */ +#define C_BRIGHTNESS_DEC \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_DISPLAY_BRIGHTNESS_DECREMENT)) +#define C_BRI_DEC (C_BRIGHTNESS_DEC) +#define C_BRI_DN (C_BRIGHTNESS_DEC) + +/* Consumer Display Backlight Toggle */ +#define C_BACKLIGHT_TOGGLE \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_DISPLAY_BACKLIGHT_TOGGLE)) +#define C_BKLT_TOG (C_BACKLIGHT_TOGGLE) + +/* Consumer Display Set Brightness to Minimum */ +#define C_BRIGHTNESS_MINIMUM \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_DISPLAY_SET_BRIGHTNESS_TO_MINIMUM)) +#define C_BRI_MIN (C_BRIGHTNESS_MINIMUM) + +/* Consumer Display Set Brightness to Maximum */ +#define C_BRIGHTNESS_MAXIMUM \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_DISPLAY_SET_BRIGHTNESS_TO_MAXIMUM)) +#define C_BRI_MAX (C_BRIGHTNESS_MAXIMUM) + +/* Consumer Display Set Auto Brightness */ +#define C_BRIGHTNESS_AUTO \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_DISPLAY_SET_AUTO_BRIGHTNESS)) +#define C_BRI_AUTO (C_BRIGHTNESS_AUTO) + +/* Consumer Mode Step */ +#define C_MEDIA_STEP (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MODE_STEP)) +#define C_MODE_STEP (C_MEDIA_STEP) + +/* Consumer Recall Last */ +#define C_RECALL_LAST (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_RECALL_LAST)) +#define C_CHAN_LAST (C_RECALL_LAST) + +/* Consumer Media Select Computer */ +#define C_MEDIA_COMPUTER \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MEDIA_SELECT_COMPUTER)) + +/* Consumer Media Select TV */ +#define C_MEDIA_TV (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MEDIA_SELECT_TV)) + +/* Consumer Media Select WWW */ +#define C_MEDIA_WWW (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MEDIA_SELECT_WWW)) + +/* Consumer Media Select DVD */ +#define C_MEDIA_DVD (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MEDIA_SELECT_DVD)) + +/* Consumer Media Select Telephone */ +#define C_MEDIA_PHONE (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MEDIA_SELECT_TELEPHONE)) + +/* Consumer Media Select Program Guide */ +#define C_MEDIA_GUIDE \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MEDIA_SELECT_PROGRAM_GUIDE)) + +/* Consumer Media Select Video Phone */ +#define C_MEDIA_VIDEOPHONE \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MEDIA_SELECT_VIDEO_PHONE)) + +/* Consumer Media Select Games */ +#define C_MEDIA_GAMES (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MEDIA_SELECT_GAMES)) + +/* Consumer Media Select Messages */ +#define C_MEDIA_MESSAGES \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MEDIA_SELECT_MESSAGES)) + +/* Consumer Media Select CD */ +#define C_MEDIA_CD (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MEDIA_SELECT_CD)) + +/* Consumer Media Select VCR */ +#define C_MEDIA_VCR (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MEDIA_SELECT_VCR)) + +/* Consumer Media Select Tuner */ +#define C_MEDIA_TUNER (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MEDIA_SELECT_TUNER)) + +/* Consumer Quit */ +#define C_QUIT (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_QUIT)) + +/* Consumer Help */ +#define C_HELP (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_HELP)) + +/* Consumer Media Select Tape */ +#define C_MEDIA_TAPE (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MEDIA_SELECT_TAPE)) + +/* Consumer Media Select Cable */ +#define C_MEDIA_CABLE (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MEDIA_SELECT_CABLE)) + +/* Consumer Media Select Satellite */ +#define C_MEDIA_SATELLITE \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MEDIA_SELECT_SATELLITE)) + +/* Consumer Media Select Home */ +#define C_MEDIA_HOME (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MEDIA_SELECT_HOME)) + +/* Consumer Channel Increment */ +#define C_CHANNEL_INC (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_CHANNEL_INCREMENT)) +#define C_CHAN_INC (C_CHANNEL_INC) + +/* Consumer Channel Decrement */ +#define C_CHANNEL_DEC (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_CHANNEL_DECREMENT)) +#define C_CHAN_DEC (C_CHANNEL_DEC) + +/* Consumer VCR Plus */ +#define C_MEDIA_VCR_PLUS (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_VCR_PLUS)) + +/* Consumer Play */ +#define C_PLAY (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_PLAY)) + +/* Consumer Pause */ +#define C_PAUSE (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_PAUSE)) + +/* Consumer Record */ +#define C_RECORD (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_RECORD)) +#define C_REC (C_RECORD) + +/* Consumer Fast Forward */ +#define C_FAST_FORWARD (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_FAST_FORWARD)) +#define C_FF (C_FAST_FORWARD) + +/* Consumer Rewind */ +#define C_REWIND (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_REWIND)) +#define C_RW (C_REWIND) + +/* Consumer Scan Next Track */ +#define C_NEXT (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_SCAN_NEXT_TRACK)) +#define M_NEXT (C_NEXT) // WARNING: DEPRECATED (DO NOT USE) + +/* Consumer Scan Previous Track */ +#define C_PREVIOUS (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_SCAN_PREVIOUS_TRACK)) +#define C_PREV (C_PREVIOUS) +#define M_PREV (C_PREVIOUS) // WARNING: DEPRECATED (DO NOT USE) + +/* Consumer Stop */ +#define C_STOP (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_STOP)) +#define M_STOP (C_STOP) // WARNING: DEPRECATED (DO NOT USE) + +/* Consumer Eject */ +#define C_EJECT (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_EJECT)) +#define M_EJCT (C_EJECT) // WARNING: DEPRECATED (DO NOT USE) + +/* Consumer Random Play */ +#define C_RANDOM_PLAY (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_RANDOM_PLAY)) +#define C_SHUFFLE (C_RANDOM_PLAY) + +/* Consumer Repeat */ +#define C_REPEAT (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_REPEAT)) + +/* Consumer Slow Tracking */ +#define C_SLOW_TRACKING (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_SLOW_TRACKING)) +#define C_SLOW2 (C_SLOW_TRACKING) + +/* Consumer Stop/Eject */ +#define C_STOP_EJECT (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_STOP_EJECT)) + +/* Consumer Play/Pause */ +#define C_PLAY_PAUSE (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_PLAY_PAUSE)) +#define C_PP (C_PLAY_PAUSE) +#define M_PLAY (C_PLAY_PAUSE) // WARNING: DEPRECATED (DO NOT USE) + +/* Consumer Voice Command */ +#define C_VOICE_COMMAND (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_VOICE_COMMAND)) + +/* Consumer Mute */ +#define C_MUTE (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_MUTE)) +#define M_MUTE (C_MUTE) // WARNING: DEPRECATED (DO NOT USE) + +/* Consumer Bass Boost */ +#define C_BASS_BOOST (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_BASS_BOOST)) + +/* Consumer Volume Increment */ +#define C_VOLUME_UP (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_VOLUME_INCREMENT)) +#define C_VOL_UP (C_VOLUME_UP) +#define M_VOLU (C_VOLUME_UP) // WARNING: DEPRECATED (DO NOT USE) + +/* Consumer Volume Decrement */ +#define C_VOLUME_DOWN (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_VOLUME_DECREMENT)) +#define C_VOL_DN (C_VOLUME_DOWN) +#define M_VOLD (C_VOLUME_DOWN) // WARNING: DEPRECATED (DO NOT USE) + +/* Consumer Slow */ +#define C_SLOW (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_SLOW)) + +/* Consumer Alternate Audio Increment */ +#define C_ALTERNATE_AUDIO_INCREMENT \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_ALTERNATE_AUDIO_INCREMENT)) +#define C_ALT_AUDIO_INC (C_ALTERNATE_AUDIO_INCREMENT) + +/* Consumer AL Consumer Control Configuration */ +#define C_AL_CCC \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_CONSUMER_CONTROL_CONFIGURATION)) + +/* Consumer AL Word Processor */ +#define C_AL_WORD (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_WORD_PROCESSOR)) + +/* Consumer AL Text Editor */ +#define C_AL_TEXT_EDITOR (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_TEXT_EDITOR)) + +/* Consumer AL Spreadsheet */ +#define C_AL_SPREADSHEET (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_SPREADSHEET)) +#define C_AL_SHEET (C_AL_SPREADSHEET) + +/* Consumer AL Graphics Editor */ +#define C_AL_GRAPHICS_EDITOR \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_GRAPHICS_EDITOR)) + +/* Consumer AL Presentation App */ +#define C_AL_PRESENTATION \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_PRESENTATION_APP)) + +/* Consumer AL Database App */ +#define C_AL_DATABASE (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_DATABASE_APP)) +#define C_AL_DB (C_AL_DATABASE) + +/* Consumer AL Email Reader */ +#define C_AL_EMAIL (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_EMAIL_READER)) +#define C_AL_MAIL (C_AL_EMAIL) + +/* Consumer AL Newsreader */ +#define C_AL_NEWS (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_NEWSREADER)) + +/* Consumer AL Voicemail */ +#define C_AL_VOICEMAIL (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_VOICEMAIL)) + +/* Consumer AL Contacts/Address Book */ +#define C_AL_CONTACTS \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_CONTACTS_ADDRESS_BOOK)) +#define C_AL_ADDRESS_BOOK (C_AL_CONTACTS) + +/* Consumer AL Calendar/Schedule */ +#define C_AL_CALENDAR (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_CALENDAR_SCHEDULE)) +#define C_AL_CAL (C_AL_CALENDAR) + +/* Consumer AL Task/Project Manager */ +#define C_AL_TASK_MANAGER \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_TASK_PROJECT_MANAGER)) + +/* Consumer AL Log/Journal/Timecard */ +#define C_AL_JOURNAL (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_LOG_JOURNAL_TIMECARD)) + +/* Consumer AL Checkbook/Finance */ +#define C_AL_FINANCE (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_CHECKBOOK_FINANCE)) + +/* Consumer AL Calculator */ +#define C_AL_CALCULATOR (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_CALCULATOR)) +#define C_AL_CALC (C_AL_CALCULATOR) + +/* Consumer AL A/V Capture/Playback */ +#define C_AL_AV_CAPTURE_PLAYBACK \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_A_V_CAPTURE_PLAYBACK)) + +/* Consumer AL Local Machine Browser */ +#define C_AL_MY_COMPUTER \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_LOCAL_MACHINE_BROWSER)) + +/* Consumer AL Internet Browser */ +#define C_AL_WWW (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_INTERNET_BROWSER)) + +/* Consumer AL Network Chat */ +#define C_AL_NETWORK_CHAT (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_NETWORK_CHAT)) +#define C_AL_CHAT (C_AL_NETWORK_CHAT) + +/* Consumer AL Logoff */ +#define C_AL_LOGOFF (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_LOGOFF)) + +/* Consumer AL Terminal Lock/Screensaver */ +#define C_AL_LOCK \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_TERMINAL_LOCK_SCREENSAVER)) +#define C_AL_SCREENSAVER (C_AL_LOCK) +#define C_AL_COFFEE (C_AL_LOCK) + +/* Consumer AL Control Panel */ +#define C_AL_CONTROL_PANEL (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_CONTROL_PANEL)) + +/* Consumer AL Select Task/Application */ +#define C_AL_SELECT_TASK \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_SELECT_TASK_APPLICATION)) + +/* Consumer AL Next Task/Application */ +#define C_AL_NEXT_TASK \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_NEXT_TASK_APPLICATION)) + +/* Consumer AL Previous Task/Application */ +#define C_AL_PREVIOUS_TASK \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_PREVIOUS_TASK_APPLICATION)) +#define C_AL_PREV_TASK (C_AL_PREVIOUS_TASK) + +/* Consumer AL Integrated Help Center */ +#define C_AL_HELP (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_INTEGRATED_HELP_CENTER)) + +/* Consumer AL Documents */ +#define C_AL_DOCUMENTS (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_DOCUMENTS)) +#define C_AL_DOCS (C_AL_DOCUMENTS) + +/* Consumer AL Spell Check */ +#define C_AL_SPELLCHECK (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_SPELL_CHECK)) +#define C_AL_SPELL (C_AL_SPELLCHECK) + +/* Consumer AL Keyboard Layout */ +#define C_AL_KEYBOARD_LAYOUT \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_KEYBOARD_LAYOUT)) + +/* Consumer AL Screen Saver */ +#define C_AL_SCREEN_SAVER (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_SCREEN_SAVER)) + +/* Consumer AL File Browser */ +#define C_AL_FILE_BROWSER (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_FILE_BROWSER)) +#define C_AL_FILES (C_AL_FILE_BROWSER) + +/* Consumer AL Image Browser */ +#define C_AL_IMAGE_BROWSER (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_IMAGE_BROWSER)) +#define C_AL_IMAGES (C_AL_IMAGE_BROWSER) + +/* Consumer AL Audio Browser */ +#define C_AL_AUDIO_BROWSER (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_AUDIO_BROWSER)) +#define C_AL_AUDIO (C_AL_AUDIO_BROWSER) +#define C_AL_MUSIC (C_AL_AUDIO_BROWSER) + +/* Consumer AL Movie Browser */ +#define C_AL_MOVIE_BROWSER (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_MOVIE_BROWSER)) +#define C_AL_MOVIES (C_AL_MOVIE_BROWSER) + +/* Consumer AL Instant Messaging */ +#define C_AL_INSTANT_MESSAGING \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_INSTANT_MESSAGING)) +#define C_AL_IM (C_AL_INSTANT_MESSAGING) + +/* Consumer AL OEM Features/Tips/Tutorial Browser */ +#define C_AL_OEM_FEATURES \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AL_OEM_FEATURES_TIPS_TUTORIAL_BROWSER)) +#define C_AL_TIPS (C_AL_OEM_FEATURES) +#define C_AL_TUTORIAL (C_AL_OEM_FEATURES) + +/* Consumer AC New */ +#define C_AC_NEW (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_NEW)) + +/* Consumer AC Open */ +#define C_AC_OPEN (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_OPEN)) + +/* Consumer AC Close */ +#define C_AC_CLOSE (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_CLOSE)) + +/* Consumer AC Exit */ +#define C_AC_EXIT (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_EXIT)) + +/* Consumer AC Save */ +#define C_AC_SAVE (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_SAVE)) + +/* Consumer AC Print */ +#define C_AC_PRINT (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_PRINT)) + +/* Consumer AC Properties */ +#define C_AC_PROPERTIES (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_PROPERTIES)) +#define C_AC_PROPS (C_AC_PROPERTIES) + +/* Consumer AC Undo */ +#define C_AC_UNDO (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_UNDO)) + +/* Consumer AC Copy */ +#define C_AC_COPY (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_COPY)) + +/* Consumer AC Cut */ +#define C_AC_CUT (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_CUT)) + +/* Consumer AC Paste */ +#define C_AC_PASTE (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_PASTE)) + +/* Consumer AC Find */ +#define C_AC_FIND (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_FIND)) + +/* Consumer AC Search */ +#define C_AC_SEARCH (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_SEARCH)) + +/* Consumer AC Go To */ +#define C_AC_GOTO (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_GO_TO)) + +/* Consumer AC Home */ +#define C_AC_HOME (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_HOME)) + +/* Consumer AC Back */ +#define C_AC_BACK (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_BACK)) + +/* Consumer AC Forward */ +#define C_AC_FORWARD (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_FORWARD)) + +/* Consumer AC Stop */ +#define C_AC_STOP (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_STOP)) + +/* Consumer AC Refresh */ +#define C_AC_REFRESH (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_REFRESH)) + +/* Consumer AC Bookmarks */ +#define C_AC_BOOKMARKS (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_BOOKMARKS)) +#define C_AC_FAVORITES (C_AC_BOOKMARKS) +#define C_AC_FAVOURITES (C_AC_BOOKMARKS) + +/* Consumer AC Zoom In */ +#define C_AC_ZOOM_IN (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_ZOOM_IN)) + +/* Consumer AC Zoom Out */ +#define C_AC_ZOOM_OUT (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_ZOOM_OUT)) + +/* Consumer AC Zoom */ +#define C_AC_ZOOM (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_ZOOM)) + +/* Consumer AC View Toggle */ +#define C_AC_VIEW_TOGGLE (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_VIEW_TOGGLE)) + +/* Consumer AC Scroll Up */ +#define C_AC_SCROLL_UP (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_SCROLL_UP)) + +/* Consumer AC Scroll Down */ +#define C_AC_SCROLL_DOWN (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_SCROLL_DOWN)) + +/* Consumer AC Edit */ +#define C_AC_EDIT (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_EDIT)) + +/* Consumer AC Cancel */ +#define C_AC_CANCEL (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_CANCEL)) + +/* Consumer AC Insert Mode */ +#define C_AC_INSERT (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_INSERT_MODE)) +#define C_AC_INS (C_AC_INSERT) + +/* Consumer AC Delete */ +#define C_AC_DEL (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_DELETE)) + +/* Consumer AC Redo/Repeat */ +#define C_AC_REDO (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_REDO_REPEAT)) + +/* Consumer AC Reply */ +#define C_AC_REPLY (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_REPLY)) + +/* Consumer AC Forward Msg */ +#define C_AC_FORWARD_MAIL (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_FORWARD_MSG)) + +/* Consumer AC Send */ +#define C_AC_SEND (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_SEND)) + +/* Consumer AC Desktop Show All Windows */ +#define C_AC_DESKTOP_SHOW_ALL_WINDOWS \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_DESKTOP_SHOW_ALL_WINDOWS)) + +/* Consumer AC Desktop Show All Applications */ +#define C_AC_DESKTOP_SHOW_ALL_APPLICATIONS \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_AC_DESKTOP_SHOW_ALL_APPLICATIONS)) + +/* Consumer Keyboard Input Assist Previous */ +#define C_KEYBOARD_INPUT_ASSIST_PREVIOUS \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_KEYBOARD_INPUT_ASSIST_PREVIOUS)) +#define C_KBIA_PREV (C_KEYBOARD_INPUT_ASSIST_PREVIOUS) + +/* Consumer Keyboard Input Assist Next */ +#define C_KEYBOARD_INPUT_ASSIST_NEXT \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_KEYBOARD_INPUT_ASSIST_NEXT)) +#define C_KBIA_NEXT (C_KEYBOARD_INPUT_ASSIST_NEXT) + +/* Consumer Keyboard Input Assist Previous Group */ +#define C_KEYBOARD_INPUT_ASSIST_PREVIOUS_GROUP \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_KEYBOARD_INPUT_ASSIST_PREVIOUS_GROUP)) +#define C_KBIA_PREV_GRP (C_KEYBOARD_INPUT_ASSIST_PREVIOUS_GROUP) + +/* Consumer Keyboard Input Assist Next Group */ +#define C_KEYBOARD_INPUT_ASSIST_NEXT_GROUP \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_KEYBOARD_INPUT_ASSIST_NEXT_GROUP)) +#define C_KBIA_NEXT_GRP (C_KEYBOARD_INPUT_ASSIST_NEXT_GROUP) + +/* Consumer Keyboard Input Assist Accept */ +#define C_KEYBOARD_INPUT_ASSIST_ACCEPT \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_KEYBOARD_INPUT_ASSIST_ACCEPT)) +#define C_KBIA_ACCEPT (C_KEYBOARD_INPUT_ASSIST_ACCEPT) + +/* Consumer Keyboard Input Assist Cancel */ +#define C_KEYBOARD_INPUT_ASSIST_CANCEL \ + (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_KEYBOARD_INPUT_ASSIST_CANCEL)) +#define C_KBIA_CANCEL (C_KEYBOARD_INPUT_ASSIST_CANCEL) + +/* Apple Globe key */ +#define C_AC_NEXT_KEYBOARD_LAYOUT_SELECT (ZMK_HID_USAGE(HID_USAGE_CONSUMER, 0x029D)) +#define GLOBE (C_AC_NEXT_KEYBOARD_LAYOUT_SELECT) diff --git a/app/include/dt-bindings/zmk/matrix-transform.h b/app/include/dt-bindings/zmk/matrix-transform.h new file mode 100644 index 000000000000..223b1429cf33 --- /dev/null +++ b/app/include/dt-bindings/zmk/matrix-transform.h @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#warning "matrix-transform.h has been deprecated and superseded by matrix_transform.h" + +#include "matrix_transform.h" \ No newline at end of file diff --git a/app/include/dt-bindings/zmk/matrix_transform.h b/app/include/dt-bindings/zmk/matrix_transform.h new file mode 100644 index 000000000000..2989cb60794f --- /dev/null +++ b/app/include/dt-bindings/zmk/matrix_transform.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define KT_ROW(item) (item >> 8) +#define KT_COL(item) (item & 0xFF) + +#define RC(row, col) (((row) << 8) + (col)) \ No newline at end of file diff --git a/app/include/dt-bindings/zmk/modifiers.h b/app/include/dt-bindings/zmk/modifiers.h new file mode 100644 index 000000000000..b49849d0379f --- /dev/null +++ b/app/include/dt-bindings/zmk/modifiers.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ +#pragma once + +#define MOD_LCTL 0x01 +#define MOD_LSFT 0x02 +#define MOD_LALT 0x04 +#define MOD_LGUI 0x08 +#define MOD_RCTL 0x10 +#define MOD_RSFT 0x20 +#define MOD_RALT 0x40 +#define MOD_RGUI 0x80 + +#define SELECT_MODS(keycode) (keycode >> 24) +#define STRIP_MODS(keycode) (keycode & ~(0xFF << 24)) +#define APPLY_MODS(mods, keycode) (mods << 24 | keycode) + +#define LC(keycode) APPLY_MODS(MOD_LCTL, keycode) +#define LS(keycode) APPLY_MODS(MOD_LSFT, keycode) +#define LA(keycode) APPLY_MODS(MOD_LALT, keycode) +#define LG(keycode) APPLY_MODS(MOD_LGUI, keycode) +#define RC(keycode) APPLY_MODS(MOD_RCTL, keycode) +#define RS(keycode) APPLY_MODS(MOD_RSFT, keycode) +#define RA(keycode) APPLY_MODS(MOD_RALT, keycode) +#define RG(keycode) APPLY_MODS(MOD_RGUI, keycode) \ No newline at end of file diff --git a/app/include/dt-bindings/zmk/mouse.h b/app/include/dt-bindings/zmk/mouse.h new file mode 100644 index 000000000000..582518aff7e6 --- /dev/null +++ b/app/include/dt-bindings/zmk/mouse.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ +#pragma once + +#include + +/* Mouse press behavior */ +/* Left click */ +#define MB1 BIT(0) +#define LCLK (MB1) + +/* Right click */ +#define MB2 BIT(1) +#define RCLK (MB2) + +/* Middle click */ +#define MB3 BIT(2) +#define MCLK (MB3) + +#define MB4 BIT(3) +#define MB5 BIT(4) diff --git a/app/include/dt-bindings/zmk/outputs.h b/app/include/dt-bindings/zmk/outputs.h new file mode 100644 index 000000000000..f24380f7e1f1 --- /dev/null +++ b/app/include/dt-bindings/zmk/outputs.h @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define OUT_TOG 0 +#define OUT_USB 1 +#define OUT_BLE 2 \ No newline at end of file diff --git a/app/include/dt-bindings/zmk/reset.h b/app/include/dt-bindings/zmk/reset.h new file mode 100644 index 000000000000..2b3d8760d5c2 --- /dev/null +++ b/app/include/dt-bindings/zmk/reset.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define RST_WARM 0x00 +#define RST_COLD 0x01 + +// AdaFruit nrf52 Bootloader Specific. See +// https://github.com/adafruit/Adafruit_nRF52_Bootloader/blob/d6b28e66053eea467166f44875e3c7ec741cb471/src/main.c#L107 + +#define RST_UF2 0x57 \ No newline at end of file diff --git a/app/include/dt-bindings/zmk/rgb.h b/app/include/dt-bindings/zmk/rgb.h new file mode 100644 index 000000000000..c1a8008273c3 --- /dev/null +++ b/app/include/dt-bindings/zmk/rgb.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define RGB_TOG_CMD 0 +#define RGB_ON_CMD 1 +#define RGB_OFF_CMD 2 +#define RGB_HUI_CMD 3 +#define RGB_HUD_CMD 4 +#define RGB_SAI_CMD 5 +#define RGB_SAD_CMD 6 +#define RGB_BRI_CMD 7 +#define RGB_BRD_CMD 8 +#define RGB_SPI_CMD 9 +#define RGB_SPD_CMD 10 +#define RGB_EFF_CMD 11 +#define RGB_EFR_CMD 12 +#define RGB_EFS_CMD 13 +#define RGB_COLOR_HSB_CMD 14 + +#define RGB_TOG RGB_TOG_CMD 0 +#define RGB_ON RGB_ON_CMD 0 +#define RGB_OFF RGB_OFF_CMD 0 +#define RGB_HUI RGB_HUI_CMD 0 +#define RGB_HUD RGB_HUD_CMD 0 +#define RGB_SAI RGB_SAI_CMD 0 +#define RGB_SAD RGB_SAD_CMD 0 +#define RGB_BRI RGB_BRI_CMD 0 +#define RGB_BRD RGB_BRD_CMD 0 +#define RGB_SPI RGB_SPI_CMD 0 +#define RGB_SPD RGB_SPD_CMD 0 +#define RGB_EFF RGB_EFF_CMD 0 +#define RGB_EFR RGB_EFR_CMD 0 +#define RGB_COLOR_HSB_VAL(h, s, v) (((h) << 16) + ((s) << 8) + (v)) +#define RGB_COLOR_HSB(h, s, v) RGB_COLOR_HSB_CMD##(RGB_COLOR_HSB_VAL(h, s, v)) +#define RGB_COLOR_HSV RGB_COLOR_HSB \ No newline at end of file diff --git a/app/include/linker/zmk-behaviors.ld b/app/include/linker/zmk-behaviors.ld new file mode 100644 index 000000000000..14ecee63c563 --- /dev/null +++ b/app/include/linker/zmk-behaviors.ld @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +ITERABLE_SECTION_ROM(zmk_behavior_ref, 4) diff --git a/app/include/linker/zmk-events.ld b/app/include/linker/zmk-events.ld new file mode 100644 index 000000000000..0c4bb6e48565 --- /dev/null +++ b/app/include/linker/zmk-events.ld @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + + __event_type_start = .; \ + KEEP(*(".event_type")); \ + __event_type_end = .; \ + + __event_subscriptions_start = .; \ + KEEP(*(".event_subscription")); \ + __event_subscriptions_end = .; \ + diff --git a/app/include/zmk/activity.h b/app/include/zmk/activity.h new file mode 100644 index 000000000000..9c858b15d42f --- /dev/null +++ b/app/include/zmk/activity.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +enum zmk_activity_state { ZMK_ACTIVITY_ACTIVE, ZMK_ACTIVITY_IDLE, ZMK_ACTIVITY_SLEEP }; + +enum zmk_activity_state zmk_activity_get_state(); \ No newline at end of file diff --git a/app/include/zmk/backlight.h b/app/include/zmk/backlight.h new file mode 100644 index 000000000000..a0f524311756 --- /dev/null +++ b/app/include/zmk/backlight.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +int zmk_backlight_on(); +int zmk_backlight_off(); +int zmk_backlight_toggle(); +bool zmk_backlight_is_on(); + +int zmk_backlight_set_brt(uint8_t brightness); +uint8_t zmk_backlight_get_brt(); +uint8_t zmk_backlight_calc_brt(int direction); +uint8_t zmk_backlight_calc_brt_cycle(); diff --git a/app/include/zmk/battery.h b/app/include/zmk/battery.h new file mode 100644 index 000000000000..f62219c18147 --- /dev/null +++ b/app/include/zmk/battery.h @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +uint8_t zmk_battery_state_of_charge(); diff --git a/app/include/zmk/behavior.h b/app/include/zmk/behavior.h new file mode 100644 index 000000000000..ab95fd8e7285 --- /dev/null +++ b/app/include/zmk/behavior.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +#define ZMK_BEHAVIOR_OPAQUE 0 +#define ZMK_BEHAVIOR_TRANSPARENT 1 + +struct zmk_behavior_binding { + char *behavior_dev; + uint32_t param1; + uint32_t param2; +}; + +struct zmk_behavior_binding_event { + int layer; + uint32_t position; + int64_t timestamp; +}; + +/** + * @brief Get a const struct device* for a behavior from its @p name field. + * + * @param name Behavior name to search for. + * + * @retval Pointer to the device structure for the behavior with the given name. + * @retval NULL if the behavior is not found or its initialization function failed. + * + * @note This is equivalent to device_get_binding(), except it only searches + * behavior devices, so it is faster and there is no chance of it returning an + * unrelated node which shares the same name as a behavior. + */ +const struct device *zmk_behavior_get_binding(const char *name); diff --git a/app/include/zmk/behavior_queue.h b/app/include/zmk/behavior_queue.h new file mode 100644 index 000000000000..307482e7cd42 --- /dev/null +++ b/app/include/zmk/behavior_queue.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include + +int zmk_behavior_queue_add(uint32_t position, const struct zmk_behavior_binding behavior, + bool press, uint32_t wait); diff --git a/app/include/zmk/ble.h b/app/include/zmk/ble.h new file mode 100644 index 000000000000..4323d0980e4c --- /dev/null +++ b/app/include/zmk/ble.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +#define ZMK_BLE_IS_CENTRAL \ + (IS_ENABLED(CONFIG_ZMK_SPLIT) && IS_ENABLED(CONFIG_ZMK_BLE) && \ + IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)) + +#if ZMK_BLE_IS_CENTRAL +#define ZMK_BLE_PROFILE_COUNT (CONFIG_BT_MAX_PAIRED - CONFIG_ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS) +#define ZMK_SPLIT_BLE_PERIPHERAL_COUNT CONFIG_ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS +#else +#define ZMK_BLE_PROFILE_COUNT CONFIG_BT_MAX_PAIRED +#endif + +int zmk_ble_clear_bonds(); +int zmk_ble_prof_next(); +int zmk_ble_prof_prev(); +int zmk_ble_prof_select(uint8_t index); +int zmk_ble_prof_disconnect(uint8_t index); + +int zmk_ble_active_profile_index(); +int zmk_ble_profile_index(const bt_addr_le_t *addr); +bt_addr_le_t *zmk_ble_active_profile_addr(); +bool zmk_ble_active_profile_is_open(); +bool zmk_ble_active_profile_is_connected(); +char *zmk_ble_active_profile_name(); + +int zmk_ble_unpair_all(); + +#if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) +int zmk_ble_put_peripheral_addr(const bt_addr_le_t *addr); +#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */ diff --git a/app/include/zmk/ble/profile.h b/app/include/zmk/ble/profile.h new file mode 100644 index 000000000000..0a57f16fa4b5 --- /dev/null +++ b/app/include/zmk/ble/profile.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +#define ZMK_BLE_PROFILE_NAME_MAX 15 + +struct zmk_ble_profile { + char name[ZMK_BLE_PROFILE_NAME_MAX]; + bt_addr_le_t peer; +}; diff --git a/app/include/zmk/display.h b/app/include/zmk/display.h new file mode 100644 index 000000000000..45a4bee03505 --- /dev/null +++ b/app/include/zmk/display.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/** @file display.h + * @brief Display functions and macros. + */ + +#pragma once + +struct k_work_q *zmk_display_work_q(); + +bool zmk_display_is_initialized(); +int zmk_display_init(); + +/** + * @brief Macro to define a ZMK event listener that handles the thread safety of fetching + * the necessary state from the system work queue context, invoking a work callback + * in the display queue context, and properly accessing that state safely when performing + * display/LVGL updates. + * + * @param listener THe ZMK Event manager listener name. + * @param state_type The struct/enum type used to store/transfer state. + * @param cb The callback to invoke in the dispaly queue context to update the UI. Should be `void + * func(state_type)` signature. + * @param state_func The callback function to invoke to fetch the updated state from ZMK core. + * Should be `state type func(const zmk_event_t *eh)` signature. + * @retval listner##_init Generates a function `listener##_init` that should be called by the widget + * once ready to be updated. + **/ +#define ZMK_DISPLAY_WIDGET_LISTENER(listener, state_type, cb, state_func) \ + K_MUTEX_DEFINE(listener##_mutex); \ + static state_type __##listener##_state; \ + static state_type listener##_get_local_state() { \ + k_mutex_lock(&listener##_mutex, K_FOREVER); \ + state_type copy = __##listener##_state; \ + k_mutex_unlock(&listener##_mutex); \ + return copy; \ + }; \ + static void listener##_work_cb(struct k_work *work) { cb(listener##_get_local_state()); }; \ + K_WORK_DEFINE(listener##_work, listener##_work_cb); \ + static void listener##_refresh_state(const zmk_event_t *eh) { \ + k_mutex_lock(&listener##_mutex, K_FOREVER); \ + __##listener##_state = state_func(eh); \ + k_mutex_unlock(&listener##_mutex); \ + }; \ + static void listener##_init() { \ + listener##_refresh_state(NULL); \ + listener##_work_cb(NULL); \ + } \ + static int listener##_cb(const zmk_event_t *eh) { \ + if (zmk_display_is_initialized()) { \ + listener##_refresh_state(eh); \ + k_work_submit_to_queue(zmk_display_work_q(), &listener##_work); \ + } \ + return ZMK_EV_EVENT_BUBBLE; \ + } \ + ZMK_LISTENER(listener, listener##_cb); diff --git a/app/include/zmk/display/status_screen.h b/app/include/zmk/display/status_screen.h new file mode 100644 index 000000000000..c15bfe9f3061 --- /dev/null +++ b/app/include/zmk/display/status_screen.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +lv_obj_t *zmk_display_status_screen(); \ No newline at end of file diff --git a/app/include/zmk/display/widgets/battery_status.h b/app/include/zmk/display/widgets/battery_status.h new file mode 100644 index 000000000000..ce22da4d71bf --- /dev/null +++ b/app/include/zmk/display/widgets/battery_status.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +struct zmk_widget_battery_status { + sys_snode_t node; + lv_obj_t *obj; +}; + +int zmk_widget_battery_status_init(struct zmk_widget_battery_status *widget, lv_obj_t *parent); +lv_obj_t *zmk_widget_battery_status_obj(struct zmk_widget_battery_status *widget); \ No newline at end of file diff --git a/app/include/zmk/display/widgets/layer_status.h b/app/include/zmk/display/widgets/layer_status.h new file mode 100644 index 000000000000..a11c40398669 --- /dev/null +++ b/app/include/zmk/display/widgets/layer_status.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +struct zmk_widget_layer_status { + sys_snode_t node; + lv_obj_t *obj; +}; + +int zmk_widget_layer_status_init(struct zmk_widget_layer_status *widget, lv_obj_t *parent); +lv_obj_t *zmk_widget_layer_status_obj(struct zmk_widget_layer_status *widget); \ No newline at end of file diff --git a/app/include/zmk/display/widgets/output_status.h b/app/include/zmk/display/widgets/output_status.h new file mode 100644 index 000000000000..ed8ee813c58d --- /dev/null +++ b/app/include/zmk/display/widgets/output_status.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +struct zmk_widget_output_status { + sys_snode_t node; + lv_obj_t *obj; +}; + +int zmk_widget_output_status_init(struct zmk_widget_output_status *widget, lv_obj_t *parent); +lv_obj_t *zmk_widget_output_status_obj(struct zmk_widget_output_status *widget); \ No newline at end of file diff --git a/app/include/zmk/display/widgets/peripheral_status.h b/app/include/zmk/display/widgets/peripheral_status.h new file mode 100644 index 000000000000..07caeaa76d5e --- /dev/null +++ b/app/include/zmk/display/widgets/peripheral_status.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +struct zmk_widget_peripheral_status { + sys_snode_t node; + lv_obj_t *obj; +}; + +int zmk_widget_peripheral_status_init(struct zmk_widget_peripheral_status *widget, + lv_obj_t *parent); +lv_obj_t *zmk_widget_peripheral_status_obj(struct zmk_widget_peripheral_status *widget); \ No newline at end of file diff --git a/app/include/zmk/display/widgets/wpm_status.h b/app/include/zmk/display/widgets/wpm_status.h new file mode 100644 index 000000000000..fbe96cc237a3 --- /dev/null +++ b/app/include/zmk/display/widgets/wpm_status.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +struct zmk_widget_wpm_status { + sys_snode_t node; + lv_obj_t *obj; +}; + +int zmk_widget_wpm_status_init(struct zmk_widget_wpm_status *widget, lv_obj_t *parent); +lv_obj_t *zmk_widget_wpm_status_obj(struct zmk_widget_wpm_status *widget); \ No newline at end of file diff --git a/app/include/zmk/endpoints.h b/app/include/zmk/endpoints.h new file mode 100644 index 000000000000..70240183e366 --- /dev/null +++ b/app/include/zmk/endpoints.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +/** + * Recommended length of string buffer for printing endpoint identifiers. + */ +#define ZMK_ENDPOINT_STR_LEN 10 + +#ifdef CONFIG_ZMK_USB +#define ZMK_ENDPOINT_USB_COUNT 1 +#else +#define ZMK_ENDPOINT_USB_COUNT 0 +#endif + +#ifdef CONFIG_ZMK_BLE +#define ZMK_ENDPOINT_BLE_COUNT ZMK_BLE_PROFILE_COUNT +#else +#define ZMK_ENDPOINT_BLE_COUNT 0 +#endif + +/** + * The total number of different (struct zmk_endpoint_instance) values that can + * be selected. + * + * Note that this value may change between firmware versions, so it should not + * be used in any persistent storage. + */ +#define ZMK_ENDPOINT_COUNT (ZMK_ENDPOINT_USB_COUNT + ZMK_ENDPOINT_BLE_COUNT) + +bool zmk_endpoint_instance_eq(struct zmk_endpoint_instance a, struct zmk_endpoint_instance b); + +/** + * Writes a string identifying an endpoint instance. + * + * @param str Address of output string buffer + * @param len Length of string buffer. See ZMK_ENDPOINT_STR_LEN for recommended length. + * + * @returns Number of characters written. + */ +int zmk_endpoint_instance_to_str(struct zmk_endpoint_instance endpoint, char *str, size_t len); + +/** + * Gets a unique index for an endpoint instance. This can be used together with + * ZMK_ENDPOINT_COUNT to manage separate state for each endpoint instance. + * + * Note that the index for a specific instance may change between firmware versions, + * so it should not be used in any persistent storage. + */ +int zmk_endpoint_instance_to_index(struct zmk_endpoint_instance endpoint); + +/** + * Sets the preferred endpoint transport to use. (If the preferred endpoint is + * not available, a different one may automatically be selected.) + */ +int zmk_endpoints_select_transport(enum zmk_transport transport); +int zmk_endpoints_toggle_transport(void); + +/** + * Gets the currently-selected endpoint. + */ +struct zmk_endpoint_instance zmk_endpoints_selected(void); + +int zmk_endpoints_send_report(uint16_t usage_page); + +#if IS_ENABLED(CONFIG_ZMK_MOUSE) +int zmk_endpoints_send_mouse_report(); +#endif // IS_ENABLE(CONFIG_ZMK_MOUSE) diff --git a/app/include/zmk/endpoints_types.h b/app/include/zmk/endpoints_types.h new file mode 100644 index 000000000000..ea51c8aa93dd --- /dev/null +++ b/app/include/zmk/endpoints_types.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +/** + * The method by which data is sent. + */ +enum zmk_transport { + ZMK_TRANSPORT_USB, + ZMK_TRANSPORT_BLE, +}; + +/** + * Configuration to select an endpoint on ZMK_TRANSPORT_USB. + */ +struct zmk_transport_usb_data {}; + +/** + * Configuration to select an endpoint on ZMK_TRANSPORT_BLE. + */ +struct zmk_transport_ble_data { + int profile_index; +}; + +/** + * A specific endpoint to which data may be sent. + */ +struct zmk_endpoint_instance { + enum zmk_transport transport; + union { + struct zmk_transport_usb_data usb; // ZMK_TRANSPORT_USB + struct zmk_transport_ble_data ble; // ZMK_TRANSPORT_BLE + }; +}; diff --git a/app/include/zmk/event_manager.h b/app/include/zmk/event_manager.h new file mode 100644 index 000000000000..aa9942ea366a --- /dev/null +++ b/app/include/zmk/event_manager.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include + +struct zmk_event_type { + const char *name; +}; + +typedef struct { + const struct zmk_event_type *event; + uint8_t last_listener_index; +} zmk_event_t; + +#define ZMK_EV_EVENT_BUBBLE 0 +#define ZMK_EV_EVENT_HANDLED 1 +#define ZMK_EV_EVENT_CAPTURED 2 + +typedef int (*zmk_listener_callback_t)(const zmk_event_t *eh); +struct zmk_listener { + zmk_listener_callback_t callback; +}; + +struct zmk_event_subscription { + const struct zmk_event_type *event_type; + const struct zmk_listener *listener; +}; + +#define ZMK_EVENT_DECLARE(event_type) \ + struct event_type##_event { \ + zmk_event_t header; \ + struct event_type data; \ + }; \ + struct event_type##_event *new_##event_type(struct event_type); \ + struct event_type *as_##event_type(const zmk_event_t *eh); \ + extern const struct zmk_event_type zmk_event_##event_type; + +#define ZMK_EVENT_IMPL(event_type) \ + const struct zmk_event_type zmk_event_##event_type = {.name = STRINGIFY(event_type)}; \ + const struct zmk_event_type *zmk_event_ref_##event_type __used \ + __attribute__((__section__(".event_type"))) = &zmk_event_##event_type; \ + struct event_type##_event *new_##event_type(struct event_type data) { \ + struct event_type##_event *ev = \ + (struct event_type##_event *)k_malloc(sizeof(struct event_type##_event)); \ + ev->header.event = &zmk_event_##event_type; \ + ev->data = data; \ + return ev; \ + }; \ + struct event_type *as_##event_type(const zmk_event_t *eh) { \ + return (eh->event == &zmk_event_##event_type) ? &((struct event_type##_event *)eh)->data \ + : NULL; \ + }; + +#define ZMK_LISTENER(mod, cb) const struct zmk_listener zmk_listener_##mod = {.callback = cb}; + +#define ZMK_SUBSCRIPTION(mod, ev_type) \ + const Z_DECL_ALIGN(struct zmk_event_subscription) \ + _CONCAT(_CONCAT(zmk_event_sub_, mod), ev_type) __used \ + __attribute__((__section__(".event_subscription"))) = { \ + .event_type = &zmk_event_##ev_type, \ + .listener = &zmk_listener_##mod, \ + }; + +#define ZMK_EVENT_RAISE(ev) zmk_event_manager_raise((zmk_event_t *)ev); + +#define ZMK_EVENT_RAISE_AFTER(ev, mod) \ + zmk_event_manager_raise_after((zmk_event_t *)ev, &zmk_listener_##mod); + +#define ZMK_EVENT_RAISE_AT(ev, mod) \ + zmk_event_manager_raise_at((zmk_event_t *)ev, &zmk_listener_##mod); + +#define ZMK_EVENT_RELEASE(ev) zmk_event_manager_release((zmk_event_t *)ev); + +#define ZMK_EVENT_FREE(ev) k_free((void *)ev); + +int zmk_event_manager_raise(zmk_event_t *event); +int zmk_event_manager_raise_after(zmk_event_t *event, const struct zmk_listener *listener); +int zmk_event_manager_raise_at(zmk_event_t *event, const struct zmk_listener *listener); +int zmk_event_manager_release(zmk_event_t *event); \ No newline at end of file diff --git a/app/include/zmk/events/activity_state_changed.h b/app/include/zmk/events/activity_state_changed.h new file mode 100644 index 000000000000..6a3481f3e0ea --- /dev/null +++ b/app/include/zmk/events/activity_state_changed.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include + +struct zmk_activity_state_changed { + enum zmk_activity_state state; +}; + +ZMK_EVENT_DECLARE(zmk_activity_state_changed); \ No newline at end of file diff --git a/app/include/zmk/events/battery_state_changed.h b/app/include/zmk/events/battery_state_changed.h new file mode 100644 index 000000000000..5a8c625e0790 --- /dev/null +++ b/app/include/zmk/events/battery_state_changed.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +struct zmk_battery_state_changed { + // TODO: Other battery channels + uint8_t state_of_charge; +}; + +ZMK_EVENT_DECLARE(zmk_battery_state_changed); \ No newline at end of file diff --git a/app/include/zmk/events/ble_active_profile_changed.h b/app/include/zmk/events/ble_active_profile_changed.h new file mode 100644 index 000000000000..620e19b4b882 --- /dev/null +++ b/app/include/zmk/events/ble_active_profile_changed.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include + +#include + +struct zmk_ble_active_profile_changed { + uint8_t index; + struct zmk_ble_profile *profile; +}; + +ZMK_EVENT_DECLARE(zmk_ble_active_profile_changed); diff --git a/app/include/zmk/events/endpoint_changed.h b/app/include/zmk/events/endpoint_changed.h new file mode 100644 index 000000000000..2147009b84ba --- /dev/null +++ b/app/include/zmk/events/endpoint_changed.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +#include +#include + +struct zmk_endpoint_changed { + struct zmk_endpoint_instance endpoint; +}; + +ZMK_EVENT_DECLARE(zmk_endpoint_changed); diff --git a/app/include/zmk/events/hid_indicators_changed.h b/app/include/zmk/events/hid_indicators_changed.h new file mode 100644 index 000000000000..b1fba7975599 --- /dev/null +++ b/app/include/zmk/events/hid_indicators_changed.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +struct zmk_hid_indicators_changed { + zmk_hid_indicators_t indicators; +}; + +ZMK_EVENT_DECLARE(zmk_hid_indicators_changed); diff --git a/app/include/zmk/events/keycode_state_changed.h b/app/include/zmk/events/keycode_state_changed.h new file mode 100644 index 000000000000..c3a3ed30d034 --- /dev/null +++ b/app/include/zmk/events/keycode_state_changed.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include + +struct zmk_keycode_state_changed { + uint16_t usage_page; + uint32_t keycode; + uint8_t implicit_modifiers; + uint8_t explicit_modifiers; + bool state; + int64_t timestamp; +}; + +ZMK_EVENT_DECLARE(zmk_keycode_state_changed); + +static inline struct zmk_keycode_state_changed_event * +zmk_keycode_state_changed_from_encoded(uint32_t encoded, bool pressed, int64_t timestamp) { + uint16_t page = ZMK_HID_USAGE_PAGE(encoded); + uint16_t id = ZMK_HID_USAGE_ID(encoded); + uint8_t implicit_modifiers = 0x00; + uint8_t explicit_modifiers = 0x00; + + if (!page) { + page = HID_USAGE_KEY; + } + + if (is_mod(page, id)) { + explicit_modifiers = SELECT_MODS(encoded); + } else { + implicit_modifiers = SELECT_MODS(encoded); + } + + return new_zmk_keycode_state_changed( + (struct zmk_keycode_state_changed){.usage_page = page, + .keycode = id, + .implicit_modifiers = implicit_modifiers, + .explicit_modifiers = explicit_modifiers, + .state = pressed, + .timestamp = timestamp}); +} diff --git a/app/include/zmk/events/layer_state_changed.h b/app/include/zmk/events/layer_state_changed.h new file mode 100644 index 000000000000..405d1365b7a9 --- /dev/null +++ b/app/include/zmk/events/layer_state_changed.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +struct zmk_layer_state_changed { + uint8_t layer; + bool state; + int64_t timestamp; +}; + +ZMK_EVENT_DECLARE(zmk_layer_state_changed); + +static inline struct zmk_layer_state_changed_event *create_layer_state_changed(uint8_t layer, + bool state) { + return new_zmk_layer_state_changed((struct zmk_layer_state_changed){ + .layer = layer, .state = state, .timestamp = k_uptime_get()}); +} diff --git a/app/include/zmk/events/modifiers_state_changed.h b/app/include/zmk/events/modifiers_state_changed.h new file mode 100644 index 000000000000..3f772cdb1d9f --- /dev/null +++ b/app/include/zmk/events/modifiers_state_changed.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include + +struct zmk_modifiers_state_changed { + zmk_mod_flags_t modifiers; + bool state; +}; + +ZMK_EVENT_DECLARE(zmk_modifiers_state_changed); \ No newline at end of file diff --git a/app/include/zmk/events/mouse_button_state_changed.h b/app/include/zmk/events/mouse_button_state_changed.h new file mode 100644 index 000000000000..9382789e56f6 --- /dev/null +++ b/app/include/zmk/events/mouse_button_state_changed.h @@ -0,0 +1,26 @@ + +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include + +struct zmk_mouse_button_state_changed { + zmk_mouse_button_t buttons; + bool state; + int64_t timestamp; +}; + +ZMK_EVENT_DECLARE(zmk_mouse_button_state_changed); + +static inline struct zmk_mouse_button_state_changed_event * +zmk_mouse_button_state_changed_from_encoded(uint32_t encoded, bool pressed, int64_t timestamp) { + return new_zmk_mouse_button_state_changed((struct zmk_mouse_button_state_changed){ + .buttons = ZMK_HID_USAGE_ID(encoded), .state = pressed, .timestamp = timestamp}); +} diff --git a/app/include/zmk/events/position_state_changed.h b/app/include/zmk/events/position_state_changed.h new file mode 100644 index 000000000000..3e4e9238cfef --- /dev/null +++ b/app/include/zmk/events/position_state_changed.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +#define ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL UINT8_MAX + +struct zmk_position_state_changed { + uint8_t source; + uint32_t position; + bool state; + int64_t timestamp; +}; + +ZMK_EVENT_DECLARE(zmk_position_state_changed); diff --git a/app/include/zmk/events/sensor_event.h b/app/include/zmk/events/sensor_event.h new file mode 100644 index 000000000000..f6d23ac71d96 --- /dev/null +++ b/app/include/zmk/events/sensor_event.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +#include +#include + +// TODO: Move to Kconfig when we need more than one channel +#define ZMK_SENSOR_EVENT_MAX_CHANNELS 1 + +struct zmk_sensor_event { + size_t channel_data_size; + struct zmk_sensor_channel_data channel_data[ZMK_SENSOR_EVENT_MAX_CHANNELS]; + + int64_t timestamp; + + uint8_t sensor_index; +}; + +ZMK_EVENT_DECLARE(zmk_sensor_event); \ No newline at end of file diff --git a/app/include/zmk/events/split_peripheral_status_changed.h b/app/include/zmk/events/split_peripheral_status_changed.h new file mode 100644 index 000000000000..6ea59f606499 --- /dev/null +++ b/app/include/zmk/events/split_peripheral_status_changed.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +struct zmk_split_peripheral_status_changed { + bool connected; +}; + +ZMK_EVENT_DECLARE(zmk_split_peripheral_status_changed); diff --git a/app/include/zmk/events/usb_conn_state_changed.h b/app/include/zmk/events/usb_conn_state_changed.h new file mode 100644 index 000000000000..5f4ac5d235b0 --- /dev/null +++ b/app/include/zmk/events/usb_conn_state_changed.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +#include +#include + +struct zmk_usb_conn_state_changed { + enum zmk_usb_conn_state conn_state; +}; + +ZMK_EVENT_DECLARE(zmk_usb_conn_state_changed); \ No newline at end of file diff --git a/app/include/zmk/events/wpm_state_changed.h b/app/include/zmk/events/wpm_state_changed.h new file mode 100644 index 000000000000..76253e208d65 --- /dev/null +++ b/app/include/zmk/events/wpm_state_changed.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include + +struct zmk_wpm_state_changed { + int state; +}; + +ZMK_EVENT_DECLARE(zmk_wpm_state_changed); diff --git a/app/include/zmk/hid.h b/app/include/zmk/hid.h new file mode 100644 index 000000000000..30534b02d21b --- /dev/null +++ b/app/include/zmk/hid.h @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +#include +#if IS_ENABLED(CONFIG_ZMK_MOUSE) +#include +#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) + +#include +#include + +#if IS_ENABLED(CONFIG_ZMK_HID_KEYBOARD_NKRO_EXTENDED_REPORT) +#define ZMK_HID_KEYBOARD_NKRO_MAX_USAGE HID_USAGE_KEY_KEYBOARD_LANG8 +#else +#define ZMK_HID_KEYBOARD_NKRO_MAX_USAGE HID_USAGE_KEY_KEYPAD_EQUAL +#endif + +#define ZMK_HID_MOUSE_NUM_BUTTONS 0x05 + +// See https://www.usb.org/sites/default/files/hid1_11.pdf section 6.2.2.4 Main Items + +#define ZMK_HID_MAIN_VAL_DATA (0x00 << 0) +#define ZMK_HID_MAIN_VAL_CONST (0x01 << 0) + +#define ZMK_HID_MAIN_VAL_ARRAY (0x00 << 1) +#define ZMK_HID_MAIN_VAL_VAR (0x01 << 1) + +#define ZMK_HID_MAIN_VAL_ABS (0x00 << 2) +#define ZMK_HID_MAIN_VAL_REL (0x01 << 2) + +#define ZMK_HID_MAIN_VAL_NO_WRAP (0x00 << 3) +#define ZMK_HID_MAIN_VAL_WRAP (0x01 << 3) + +#define ZMK_HID_MAIN_VAL_LIN (0x00 << 4) +#define ZMK_HID_MAIN_VAL_NON_LIN (0x01 << 4) + +#define ZMK_HID_MAIN_VAL_PREFERRED (0x00 << 5) +#define ZMK_HID_MAIN_VAL_NO_PREFERRED (0x01 << 5) + +#define ZMK_HID_MAIN_VAL_NO_NULL (0x00 << 6) +#define ZMK_HID_MAIN_VAL_NULL (0x01 << 6) + +#define ZMK_HID_MAIN_VAL_NON_VOL (0x00 << 7) +#define ZMK_HID_MAIN_VAL_VOL (0x01 << 7) + +#define ZMK_HID_MAIN_VAL_BIT_FIELD (0x00 << 8) +#define ZMK_HID_MAIN_VAL_BUFFERED_BYTES (0x01 << 8) + +#define ZMK_HID_REPORT_ID_KEYBOARD 0x01 +#define ZMK_HID_REPORT_ID_LEDS 0x01 +#define ZMK_HID_REPORT_ID_CONSUMER 0x02 +#define ZMK_HID_REPORT_ID_MOUSE 0x03 + +static const uint8_t zmk_hid_report_desc[] = { + HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP), + HID_USAGE(HID_USAGE_GD_KEYBOARD), + HID_COLLECTION(HID_COLLECTION_APPLICATION), + HID_REPORT_ID(ZMK_HID_REPORT_ID_KEYBOARD), + HID_USAGE_PAGE(HID_USAGE_KEY), + HID_USAGE_MIN8(HID_USAGE_KEY_KEYBOARD_LEFTCONTROL), + HID_USAGE_MAX8(HID_USAGE_KEY_KEYBOARD_RIGHT_GUI), + HID_LOGICAL_MIN8(0x00), + HID_LOGICAL_MAX8(0x01), + + HID_REPORT_SIZE(0x01), + HID_REPORT_COUNT(0x08), + HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS), + + HID_USAGE_PAGE(HID_USAGE_KEY), + HID_REPORT_SIZE(0x08), + HID_REPORT_COUNT(0x01), + HID_INPUT(ZMK_HID_MAIN_VAL_CONST | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS), + +#if IS_ENABLED(CONFIG_ZMK_HID_INDICATORS) + + HID_USAGE_PAGE(HID_USAGE_LED), + HID_USAGE_MIN8(HID_USAGE_LED_NUM_LOCK), + HID_USAGE_MAX8(HID_USAGE_LED_KANA), + HID_REPORT_SIZE(0x01), + HID_REPORT_COUNT(0x05), + HID_OUTPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS), + + HID_USAGE_PAGE(HID_USAGE_LED), + HID_REPORT_SIZE(0x03), + HID_REPORT_COUNT(0x01), + HID_OUTPUT(ZMK_HID_MAIN_VAL_CONST | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS), + +#endif // IS_ENABLED(CONFIG_ZMK_HID_INDICATORS) + + HID_USAGE_PAGE(HID_USAGE_KEY), + +#if IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_NKRO) + HID_LOGICAL_MIN8(0x00), + HID_LOGICAL_MAX8(0x01), + HID_USAGE_MIN8(0x00), + HID_USAGE_MAX8(ZMK_HID_KEYBOARD_NKRO_MAX_USAGE), + HID_REPORT_SIZE(0x01), + HID_REPORT_COUNT(ZMK_HID_KEYBOARD_NKRO_MAX_USAGE + 1), + HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS), +#elif IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_HKRO) + HID_LOGICAL_MIN8(0x00), + HID_LOGICAL_MAX16(0xFF, 0x00), + HID_USAGE_MIN8(0x00), + HID_USAGE_MAX8(0xFF), + HID_REPORT_SIZE(0x08), + HID_REPORT_COUNT(CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE), + HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_ARRAY | ZMK_HID_MAIN_VAL_ABS), +#else +#error "A proper HID report type must be selected" +#endif + + HID_END_COLLECTION, + HID_USAGE_PAGE(HID_USAGE_CONSUMER), + HID_USAGE(HID_USAGE_CONSUMER_CONSUMER_CONTROL), + HID_COLLECTION(HID_COLLECTION_APPLICATION), + HID_REPORT_ID(ZMK_HID_REPORT_ID_CONSUMER), + HID_USAGE_PAGE(HID_USAGE_CONSUMER), + +#if IS_ENABLED(CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_BASIC) + HID_LOGICAL_MIN8(0x00), + HID_LOGICAL_MAX16(0xFF, 0x00), + HID_USAGE_MIN8(0x00), + HID_USAGE_MAX8(0xFF), + HID_REPORT_SIZE(0x08), +#elif IS_ENABLED(CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_FULL) + HID_LOGICAL_MIN8(0x00), + HID_LOGICAL_MAX16(0xFF, 0x0F), + HID_USAGE_MIN8(0x00), + HID_USAGE_MAX16(0xFF, 0x0F), + HID_REPORT_SIZE(0x10), +#else +#error "A proper consumer HID report usage range must be selected" +#endif + HID_REPORT_COUNT(CONFIG_ZMK_HID_CONSUMER_REPORT_SIZE), + HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_ARRAY | ZMK_HID_MAIN_VAL_ABS), + HID_END_COLLECTION, + +#if IS_ENABLED(CONFIG_ZMK_MOUSE) + HID_USAGE_PAGE(HID_USAGE_GD), + HID_USAGE(HID_USAGE_GD_MOUSE), + HID_COLLECTION(HID_COLLECTION_APPLICATION), + HID_REPORT_ID(ZMK_HID_REPORT_ID_MOUSE), + HID_USAGE(HID_USAGE_GD_POINTER), + HID_COLLECTION(HID_COLLECTION_PHYSICAL), + HID_USAGE_PAGE(HID_USAGE_BUTTON), + HID_USAGE_MIN8(0x1), + HID_USAGE_MAX8(ZMK_HID_MOUSE_NUM_BUTTONS), + HID_LOGICAL_MIN8(0x00), + HID_LOGICAL_MAX8(0x01), + HID_REPORT_SIZE(0x01), + HID_REPORT_COUNT(0x5), + HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS), + // Constant padding for the last 3 bits. + HID_REPORT_SIZE(0x03), + HID_REPORT_COUNT(0x01), + HID_INPUT(ZMK_HID_MAIN_VAL_CONST | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS), + // Some OSes ignore pointer devices without X/Y data. + HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP), + HID_USAGE(HID_USAGE_GD_X), + HID_USAGE(HID_USAGE_GD_Y), + HID_USAGE(HID_USAGE_GD_WHEEL), + HID_LOGICAL_MIN8(-0x7F), + HID_LOGICAL_MAX8(0x7F), + HID_REPORT_SIZE(0x08), + HID_REPORT_COUNT(0x03), + HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_REL), + HID_END_COLLECTION, + HID_END_COLLECTION, +#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) +}; + +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + +#define HID_ERROR_ROLLOVER 0x1 +#define HID_BOOT_KEY_LEN 6 + +#if IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_HKRO) && \ + CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE == HID_BOOT_KEY_LEN +typedef struct zmk_hid_keyboard_report_body zmk_hid_boot_report_t; +#else +struct zmk_hid_boot_report { + zmk_mod_flags_t modifiers; + uint8_t _reserved; + uint8_t keys[HID_BOOT_KEY_LEN]; +} __packed; + +typedef struct zmk_hid_boot_report zmk_hid_boot_report_t; +#endif +#endif + +struct zmk_hid_keyboard_report_body { + zmk_mod_flags_t modifiers; + uint8_t _reserved; +#if IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_NKRO) + uint8_t keys[(ZMK_HID_KEYBOARD_NKRO_MAX_USAGE + 1) / 8]; +#elif IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_HKRO) + uint8_t keys[CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE]; +#endif +} __packed; + +struct zmk_hid_keyboard_report { + uint8_t report_id; + struct zmk_hid_keyboard_report_body body; +} __packed; + +#if IS_ENABLED(CONFIG_ZMK_HID_INDICATORS) + +struct zmk_hid_led_report_body { + uint8_t leds; +} __packed; + +struct zmk_hid_led_report { + uint8_t report_id; + struct zmk_hid_led_report_body body; +} __packed; + +#endif // IS_ENABLED(CONFIG_ZMK_HID_INDICATORS) + +struct zmk_hid_consumer_report_body { +#if IS_ENABLED(CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_BASIC) + uint8_t keys[CONFIG_ZMK_HID_CONSUMER_REPORT_SIZE]; +#elif IS_ENABLED(CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_FULL) + uint16_t keys[CONFIG_ZMK_HID_CONSUMER_REPORT_SIZE]; +#endif +} __packed; + +struct zmk_hid_consumer_report { + uint8_t report_id; + struct zmk_hid_consumer_report_body body; +} __packed; + +#if IS_ENABLED(CONFIG_ZMK_MOUSE) +struct zmk_hid_mouse_report_body { + zmk_mouse_button_flags_t buttons; + int8_t d_x; + int8_t d_y; + int8_t d_wheel; +} __packed; + +struct zmk_hid_mouse_report { + uint8_t report_id; + struct zmk_hid_mouse_report_body body; +} __packed; + +#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) + +zmk_mod_flags_t zmk_hid_get_explicit_mods(); +int zmk_hid_register_mod(zmk_mod_t modifier); +int zmk_hid_unregister_mod(zmk_mod_t modifier); +bool zmk_hid_mod_is_pressed(zmk_mod_t modifier); + +int zmk_hid_register_mods(zmk_mod_flags_t explicit_modifiers); +int zmk_hid_unregister_mods(zmk_mod_flags_t explicit_modifiers); +int zmk_hid_implicit_modifiers_press(zmk_mod_flags_t implicit_modifiers); +int zmk_hid_implicit_modifiers_release(); +int zmk_hid_masked_modifiers_set(zmk_mod_flags_t masked_modifiers); +int zmk_hid_masked_modifiers_clear(); + +int zmk_hid_keyboard_press(zmk_key_t key); +int zmk_hid_keyboard_release(zmk_key_t key); +void zmk_hid_keyboard_clear(); +bool zmk_hid_keyboard_is_pressed(zmk_key_t key); + +int zmk_hid_consumer_press(zmk_key_t key); +int zmk_hid_consumer_release(zmk_key_t key); +void zmk_hid_consumer_clear(); +bool zmk_hid_consumer_is_pressed(zmk_key_t key); + +int zmk_hid_press(uint32_t usage); +int zmk_hid_release(uint32_t usage); +bool zmk_hid_is_pressed(uint32_t usage); + +#if IS_ENABLED(CONFIG_ZMK_MOUSE) +int zmk_hid_mouse_button_press(zmk_mouse_button_t button); +int zmk_hid_mouse_button_release(zmk_mouse_button_t button); +int zmk_hid_mouse_buttons_press(zmk_mouse_button_flags_t buttons); +int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons); +void zmk_hid_mouse_clear(); +#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) + +struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report(); +struct zmk_hid_consumer_report *zmk_hid_get_consumer_report(); + +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) +zmk_hid_boot_report_t *zmk_hid_get_boot_report(); +#endif + +#if IS_ENABLED(CONFIG_ZMK_MOUSE) +struct zmk_hid_mouse_report *zmk_hid_get_mouse_report(); +#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) diff --git a/app/include/zmk/hid_indicators.h b/app/include/zmk/hid_indicators.h new file mode 100644 index 000000000000..7c7b89f53ce5 --- /dev/null +++ b/app/include/zmk/hid_indicators.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include + +zmk_hid_indicators_t zmk_hid_indicators_get_current_profile(void); +zmk_hid_indicators_t zmk_hid_indicators_get_profile(struct zmk_endpoint_instance endpoint); +void zmk_hid_indicators_set_profile(zmk_hid_indicators_t indicators, + struct zmk_endpoint_instance endpoint); + +void zmk_hid_indicators_process_report(struct zmk_hid_led_report_body *report, + struct zmk_endpoint_instance endpoint); diff --git a/app/include/zmk/hid_indicators_types.h b/app/include/zmk/hid_indicators_types.h new file mode 100644 index 000000000000..43bcf3c5bb20 --- /dev/null +++ b/app/include/zmk/hid_indicators_types.h @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +typedef uint8_t zmk_hid_indicators_t; diff --git a/app/include/zmk/hog.h b/app/include/zmk/hog.h new file mode 100644 index 000000000000..b4e45d9186d6 --- /dev/null +++ b/app/include/zmk/hog.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +int zmk_hog_init(); + +int zmk_hog_send_keyboard_report(struct zmk_hid_keyboard_report_body *body); +int zmk_hog_send_consumer_report(struct zmk_hid_consumer_report_body *body); + +#if IS_ENABLED(CONFIG_ZMK_MOUSE) +int zmk_hog_send_mouse_report(struct zmk_hid_mouse_report_body *body); +#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) diff --git a/app/include/zmk/keymap.h b/app/include/zmk/keymap.h new file mode 100644 index 000000000000..9bf81e1e60ff --- /dev/null +++ b/app/include/zmk/keymap.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +#define ZMK_LAYER_CHILD_LEN_PLUS_ONE(node) 1 + +#define ZMK_KEYMAP_LAYERS_LEN \ + (DT_FOREACH_CHILD(DT_INST(0, zmk_keymap), ZMK_LAYER_CHILD_LEN_PLUS_ONE) 0) + +typedef uint32_t zmk_keymap_layers_state_t; + +uint8_t zmk_keymap_layer_default(); +zmk_keymap_layers_state_t zmk_keymap_layer_state(); +bool zmk_keymap_layer_active(uint8_t layer); +uint8_t zmk_keymap_highest_layer_active(); +int zmk_keymap_layer_activate(uint8_t layer); +int zmk_keymap_layer_deactivate(uint8_t layer); +int zmk_keymap_layer_toggle(uint8_t layer); +int zmk_keymap_layer_to(uint8_t layer); +const char *zmk_keymap_layer_name(uint8_t layer); + +int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pressed, + int64_t timestamp); + +#define ZMK_KEYMAP_EXTRACT_BINDING(idx, drv_inst) \ + { \ + .behavior_dev = DEVICE_DT_NAME(DT_PHANDLE_BY_IDX(drv_inst, bindings, idx)), \ + .param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(drv_inst, bindings, idx, param1), (0), \ + (DT_PHA_BY_IDX(drv_inst, bindings, idx, param1))), \ + .param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(drv_inst, bindings, idx, param2), (0), \ + (DT_PHA_BY_IDX(drv_inst, bindings, idx, param2))), \ + } diff --git a/app/include/zmk/keys.h b/app/include/zmk/keys.h new file mode 100644 index 000000000000..fa6e7cfe6931 --- /dev/null +++ b/app/include/zmk/keys.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +typedef uint32_t zmk_key_t; +typedef uint8_t zmk_mod_t; +typedef uint8_t zmk_mod_flags_t; + +struct zmk_key_event { + uint32_t column; + uint32_t row; + zmk_key_t key; + bool pressed; +}; + +static inline bool is_mod(uint8_t usage_page, uint32_t keycode) { + return (keycode >= HID_USAGE_KEY_KEYBOARD_LEFTCONTROL && + keycode <= HID_USAGE_KEY_KEYBOARD_RIGHT_GUI && usage_page == HID_USAGE_KEY); +} \ No newline at end of file diff --git a/app/include/zmk/kscan.h b/app/include/zmk/kscan.h new file mode 100644 index 000000000000..eebe41e743b7 --- /dev/null +++ b/app/include/zmk/kscan.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +int zmk_kscan_init(const struct device *dev); diff --git a/app/include/zmk/matrix.h b/app/include/zmk/matrix.h new file mode 100644 index 000000000000..5f8cd7d76972 --- /dev/null +++ b/app/include/zmk/matrix.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +#define ZMK_MATRIX_NODE_ID DT_CHOSEN(zmk_kscan) + +#if DT_HAS_CHOSEN(zmk_matrix_transform) + +#define ZMK_KEYMAP_TRANSFORM_NODE DT_CHOSEN(zmk_matrix_transform) +#define ZMK_KEYMAP_LEN DT_PROP_LEN(ZMK_KEYMAP_TRANSFORM_NODE, map) + +#define ZMK_MATRIX_ROWS DT_PROP(ZMK_KEYMAP_TRANSFORM_NODE, rows) +#define ZMK_MATRIX_COLS DT_PROP(ZMK_KEYMAP_TRANSFORM_NODE, columns) + +#else /* DT_HAS_CHOSEN(zmk_matrix_transform) */ + +#if DT_NODE_HAS_PROP(ZMK_MATRIX_NODE_ID, row_gpios) +#define ZMK_MATRIX_ROWS DT_PROP_LEN(ZMK_MATRIX_NODE_ID, row_gpios) +#define ZMK_MATRIX_COLS DT_PROP_LEN(ZMK_MATRIX_NODE_ID, col_gpios) +#elif DT_NODE_HAS_PROP(ZMK_MATRIX_NODE_ID, input_gpios) +#define ZMK_MATRIX_ROWS 1 +#define ZMK_MATRIX_COLS DT_PROP_LEN(ZMK_MATRIX_NODE_ID, input_gpios) +#else +#define ZMK_MATRIX_ROWS DT_PROP(ZMK_MATRIX_NODE_ID, rows) +#define ZMK_MATRIX_COLS DT_PROP(ZMK_MATRIX_NODE_ID, columns) +#endif + +#define ZMK_KEYMAP_LEN (ZMK_MATRIX_COLS * ZMK_MATRIX_ROWS) + +#endif /* !DT_HAS_CHOSEN(zmk_matrix_transform) */ \ No newline at end of file diff --git a/app/include/zmk/matrix_transform.h b/app/include/zmk/matrix_transform.h new file mode 100644 index 000000000000..ffd3e3f1d291 --- /dev/null +++ b/app/include/zmk/matrix_transform.h @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +int32_t zmk_matrix_transform_row_column_to_position(uint32_t row, uint32_t column); \ No newline at end of file diff --git a/app/include/zmk/mouse.h b/app/include/zmk/mouse.h new file mode 100644 index 000000000000..d873f15689a7 --- /dev/null +++ b/app/include/zmk/mouse.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +typedef uint8_t zmk_mouse_button_flags_t; +typedef uint16_t zmk_mouse_button_t; diff --git a/app/include/zmk/rgb_underglow.h b/app/include/zmk/rgb_underglow.h new file mode 100644 index 000000000000..797f0b19f1d4 --- /dev/null +++ b/app/include/zmk/rgb_underglow.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +struct zmk_led_hsb { + uint16_t h; + uint8_t s; + uint8_t b; +}; + +int zmk_rgb_underglow_toggle(); +int zmk_rgb_underglow_get_state(bool *state); +int zmk_rgb_underglow_on(); +int zmk_rgb_underglow_off(); +int zmk_rgb_underglow_cycle_effect(int direction); +int zmk_rgb_underglow_calc_effect(int direction); +int zmk_rgb_underglow_select_effect(int effect); +struct zmk_led_hsb zmk_rgb_underglow_calc_hue(int direction); +struct zmk_led_hsb zmk_rgb_underglow_calc_sat(int direction); +struct zmk_led_hsb zmk_rgb_underglow_calc_brt(int direction); +int zmk_rgb_underglow_change_hue(int direction); +int zmk_rgb_underglow_change_sat(int direction); +int zmk_rgb_underglow_change_brt(int direction); +int zmk_rgb_underglow_change_spd(int direction); +int zmk_rgb_underglow_set_hsb(struct zmk_led_hsb color); \ No newline at end of file diff --git a/app/include/zmk/sensors.h b/app/include/zmk/sensors.h new file mode 100644 index 000000000000..1919d4ce6477 --- /dev/null +++ b/app/include/zmk/sensors.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +#define ZMK_KEYMAP_SENSORS_NODE DT_INST(0, zmk_keymap_sensors) +#define ZMK_KEYMAP_HAS_SENSORS DT_NODE_HAS_STATUS(ZMK_KEYMAP_SENSORS_NODE, okay) +#define ZMK_KEYMAP_SENSORS_BY_IDX(idx) DT_PHANDLE_BY_IDX(ZMK_KEYMAP_SENSORS_NODE, sensors, idx) + +#if ZMK_KEYMAP_HAS_SENSORS +#define ZMK_KEYMAP_SENSORS_LEN DT_PROP_LEN(ZMK_KEYMAP_SENSORS_NODE, sensors) +#else +#define ZMK_KEYMAP_SENSORS_LEN 0 +#endif + +const struct zmk_sensor_config *zmk_sensors_get_config_at_index(uint8_t sensor_index); + +struct zmk_sensor_config { + uint16_t triggers_per_rotation; +}; + +// This struct is also used for data transfer for splits, so any changes to the size, layout, etc +// is a breaking change for the split GATT service protocol. +struct zmk_sensor_channel_data { + struct sensor_value value; + enum sensor_channel channel; +} __packed; diff --git a/app/include/zmk/split/bluetooth/central.h b/app/include/zmk/split/bluetooth/central.h new file mode 100644 index 000000000000..4706b3aa831c --- /dev/null +++ b/app/include/zmk/split/bluetooth/central.h @@ -0,0 +1,18 @@ + +#pragma once + +#include +#include + +#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) +#include +#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) + +int zmk_split_bt_invoke_behavior(uint8_t source, struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event, bool state); + +#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) + +int zmk_split_bt_update_hid_indicator(zmk_hid_indicators_t indicators); + +#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) diff --git a/app/include/zmk/split/bluetooth/peripheral.h b/app/include/zmk/split/bluetooth/peripheral.h new file mode 100644 index 000000000000..44ac8062a516 --- /dev/null +++ b/app/include/zmk/split/bluetooth/peripheral.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +bool zmk_split_bt_peripheral_is_connected(void); + +bool zmk_split_bt_peripheral_is_bonded(void); \ No newline at end of file diff --git a/app/include/zmk/split/bluetooth/service.h b/app/include/zmk/split/bluetooth/service.h new file mode 100644 index 000000000000..112cd5529424 --- /dev/null +++ b/app/include/zmk/split/bluetooth/service.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +#define ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN 9 + +struct sensor_event { + uint8_t sensor_index; + + uint8_t channel_data_size; + struct zmk_sensor_channel_data channel_data[ZMK_SENSOR_EVENT_MAX_CHANNELS]; +} __packed; + +struct zmk_split_run_behavior_data { + uint8_t position; + uint8_t state; + uint32_t param1; + uint32_t param2; +} __packed; + +struct zmk_split_run_behavior_payload { + struct zmk_split_run_behavior_data data; + char behavior_dev[ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN]; +} __packed; + +int zmk_split_bt_position_pressed(uint8_t position); +int zmk_split_bt_position_released(uint8_t position); +int zmk_split_bt_sensor_triggered(uint8_t sensor_index, + const struct zmk_sensor_channel_data channel_data[], + size_t channel_data_size); diff --git a/app/include/zmk/split/bluetooth/uuid.h b/app/include/zmk/split/bluetooth/uuid.h new file mode 100644 index 000000000000..dccdfc804c56 --- /dev/null +++ b/app/include/zmk/split/bluetooth/uuid.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +#ifndef BT_UUID_NUM_OF_DIGITALS +#define BT_UUID_NUM_OF_DIGITALS BT_UUID_DECLARE_16(0x2909) +#endif + +#define ZMK_BT_SPLIT_UUID(num) BT_UUID_128_ENCODE(num, 0x0096, 0x7107, 0xc967, 0xc5cfb1c2482a) +#define ZMK_SPLIT_BT_SERVICE_UUID ZMK_BT_SPLIT_UUID(0x00000000) +#define ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID ZMK_BT_SPLIT_UUID(0x00000001) +#define ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID ZMK_BT_SPLIT_UUID(0x00000002) +#define ZMK_SPLIT_BT_CHAR_SENSOR_STATE_UUID ZMK_BT_SPLIT_UUID(0x00000003) +#define ZMK_SPLIT_BT_UPDATE_HID_INDICATORS_UUID ZMK_BT_SPLIT_UUID(0x00000004) diff --git a/app/include/zmk/stdlib.h b/app/include/zmk/stdlib.h new file mode 100644 index 000000000000..fa8fe6737a1b --- /dev/null +++ b/app/include/zmk/stdlib.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include /* for size_t */ + +/* + * ANSI C version of strlcpy + * Based on the NetBSD strlcpy man page. + * + * Nathan Myers , 2003/06/03 + * Placed in the public domain. + */ + +size_t strlcpy(char *dst, const char *src, size_t size); \ No newline at end of file diff --git a/app/include/zmk/usb.h b/app/include/zmk/usb.h new file mode 100644 index 000000000000..9e92a83664cb --- /dev/null +++ b/app/include/zmk/usb.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +#include +#include + +enum zmk_usb_conn_state { + ZMK_USB_CONN_NONE, + ZMK_USB_CONN_POWERED, + ZMK_USB_CONN_HID, +}; + +enum usb_dc_status_code zmk_usb_get_status(); +enum zmk_usb_conn_state zmk_usb_get_conn_state(); + +static inline bool zmk_usb_is_powered() { return zmk_usb_get_conn_state() != ZMK_USB_CONN_NONE; } +static inline bool zmk_usb_is_hid_ready() { return zmk_usb_get_conn_state() == ZMK_USB_CONN_HID; } diff --git a/app/include/zmk/usb_hid.h b/app/include/zmk/usb_hid.h new file mode 100644 index 000000000000..f90917785013 --- /dev/null +++ b/app/include/zmk/usb_hid.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +int zmk_usb_hid_send_keyboard_report(); +int zmk_usb_hid_send_consumer_report(); +#if IS_ENABLED(CONFIG_ZMK_MOUSE) +int zmk_usb_hid_send_mouse_report(); +#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) +void zmk_usb_hid_set_protocol(uint8_t protocol); diff --git a/app/include/zmk/virtual_key_position.h b/app/include/zmk/virtual_key_position.h new file mode 100644 index 000000000000..b8f20683d7b9 --- /dev/null +++ b/app/include/zmk/virtual_key_position.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +/** + * Gets the virtual key position to use for the sensor with the given index. + */ +#define ZMK_VIRTUAL_KEY_POSITION_SENSOR(index) (ZMK_KEYMAP_LEN + (index)) + +/** + * Gets the sensor number from the virtual key position. + */ +#define ZMK_SENSOR_POSITION_FROM_VIRTUAL_KEY_POSITION(vkp) ((vkp)-ZMK_KEYMAP_LEN) + +/** + * Gets the virtual key position to use for the combo with the given index. + */ +#define ZMK_VIRTUAL_KEY_POSITION_COMBO(index) (ZMK_KEYMAP_LEN + ZMK_KEYMAP_SENSORS_LEN + (index)) diff --git a/app/include/zmk/workqueue.h b/app/include/zmk/workqueue.h new file mode 100644 index 000000000000..41e94580846d --- /dev/null +++ b/app/include/zmk/workqueue.h @@ -0,0 +1 @@ +struct k_work_q *zmk_workqueue_lowprio_work_q(); diff --git a/app/include/zmk/wpm.h b/app/include/zmk/wpm.h new file mode 100644 index 000000000000..6db100a0693d --- /dev/null +++ b/app/include/zmk/wpm.h @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +int zmk_wpm_get_state(); \ No newline at end of file diff --git a/app/keymap-module/modules/modules.cmake b/app/keymap-module/modules/modules.cmake new file mode 100644 index 000000000000..e260da8fc370 --- /dev/null +++ b/app/keymap-module/modules/modules.cmake @@ -0,0 +1,198 @@ +# TODO: Check for env or command line "ZMK_CONFIG" setting. +# * That directory should load +# * defconfigs, +# * .conf file, +# * single overlay, +# * or per board/shield. + +list(APPEND BOARD_ROOT ${APPLICATION_SOURCE_DIR}) +list(APPEND DTS_ROOT ${APPLICATION_SOURCE_DIR}) + +get_property(cached_user_config_value CACHE ZMK_CONFIG PROPERTY VALUE) + +set(user_config_cli_argument ${cached_user_config_value}) # Either new or old +if(user_config_cli_argument STREQUAL CACHED_ZMK_CONFIG) + # We already have a CACHED_ZMK_CONFIG so there is no new input on the CLI + unset(user_config_cli_argument) +endif() + +set(user_config_app_cmake_lists ${ZMK_CONFIG}) +if(cached_user_config_value STREQUAL ZMK_CONFIG) + # The app build scripts did not set a default, The ZMK_CONFIG we are + # reading is the cached value from the CLI + unset(user_config_app_cmake_lists) +endif() + +if(CACHED_ZMK_CONFIG) + # Warn the user if it looks like he is trying to change the user_config + # without cleaning first + if(user_config_cli_argument) + if(NOT (CACHED_ZMK_CONFIG STREQUAL user_config_cli_argument)) + message(WARNING "The build directory must be cleaned pristinely when changing user ZMK config") + endif() + endif() + + set(ZMK_CONFIG ${CACHED_ZMK_CONFIG}) +elseif(user_config_cli_argument) + set(ZMK_CONFIG ${user_config_cli_argument}) + +elseif(DEFINED ENV{ZMK_CONFIG}) + set(ZMK_CONFIG $ENV{ZMK_CONFIG}) + +elseif(user_config_app_cmake_lists) + set(ZMK_CONFIG ${user_config_app_cmake_lists}) +endif() + +# Store the selected user_config in the cache +set(CACHED_ZMK_CONFIG ${ZMK_CONFIG} CACHE STRING "Selected user ZMK config") + +if (ZMK_CONFIG) + set(ENV{ZMK_CONFIG} "${ZMK_CONFIG}") + if(EXISTS ${ZMK_CONFIG}/boards) + message(STATUS "Adding ZMK config directory as board root: ${ZMK_CONFIG}") + list(APPEND BOARD_ROOT ${ZMK_CONFIG}) + endif() + if(EXISTS ${ZMK_CONFIG}/dts) + message(STATUS "Adding ZMK config directory as DTS root: ${ZMK_CONFIG}") + list(APPEND DTS_ROOT ${ZMK_CONFIG}) + endif() +endif() + + +if(DEFINED SHIELD) + string(REPLACE " " ";" SHIELD_AS_LIST "${SHIELD}") +endif() + +foreach(root ${BOARD_ROOT}) + set(shield_dir ${root}/boards/shields) + # Match the Kconfig.shield files in the shield directories to make sure we are + # finding shields, e.g. x_nucleo_iks01a1/Kconfig.shield + file(GLOB_RECURSE shields_refs_list ${shield_dir}/*/Kconfig.shield) + unset(SHIELD_LIST) + foreach(shields_refs ${shields_refs_list}) + get_filename_component(shield_path ${shields_refs} DIRECTORY) + file(GLOB shield_overlays RELATIVE ${shield_path} ${shield_path}/*.overlay) + foreach(overlay ${shield_overlays}) + get_filename_component(shield ${overlay} NAME_WE) + list(APPEND SHIELD_LIST ${shield}) + set(SHIELD_DIR_${shield} ${shield_path}) + endforeach() + endforeach() + + if (EXISTS "${root}/boards/${BOARD}.overlay") + list(APPEND shield_dts_files "${root}/boards/${BOARD}.overlay") + endif() + if (NOT DEFINED BOARD_DIR_NAME) + find_path(BOARD_DIR + NAMES ${BOARD}_defconfig + PATHS ${root}/boards/*/* + NO_DEFAULT_PATH + ) + if(BOARD_DIR) + get_filename_component(BOARD_DIR_NAME ${BOARD_DIR} NAME) + list(APPEND KEYMAP_DIRS ${BOARD_DIR}) + endif() + endif() + + if(DEFINED SHIELD) + foreach(s ${SHIELD_AS_LIST}) + if(NOT ${s} IN_LIST SHIELD_LIST) + message(WARNING "Didn't find ${s}") + continue() + endif() + message(STATUS "Adding ${SHIELD_DIR_${s}}") + list(APPEND KEYMAP_DIRS ${SHIELD_DIR_${s}}) + get_filename_component(shield_dir_name ${SHIELD_DIR_${s}} NAME) + list(APPEND SHIELD_DIR ${shield_dir_name}) + endforeach() + endif() +endforeach() + +# Give a shield like `kyria_rev2_left` we want to use `kyria_rev2` and `kyria` as candidate names for +# overlay/conf/keymap files. +if(DEFINED SHIELD) + foreach(s ${SHIELD_AS_LIST}) + if (DEFINED $SHIELD_DIR_${s}) + get_filename_component(shield_dir_name ${SHIELD_DIR_${s}} NAME) + endif() + string(REPLACE "_" ";" S_PIECES ${s}) + list(LENGTH S_PIECES S_PIECES_LEN) + while(NOT S_PIECES STREQUAL "") + list(POP_BACK S_PIECES) + list(JOIN S_PIECES "_" s_substr) + if ("${s_substr}" STREQUAL "" OR "${s_substr}" STREQUAL "${shield_dir_name}") + break() + endif() + list(APPEND shield_candidate_names ${s_substr}) + endwhile() + endforeach() +endif() + +if (ZMK_CONFIG) + if (EXISTS ${ZMK_CONFIG}) + message(STATUS "ZMK Config directory: ${ZMK_CONFIG}") + list(PREPEND KEYMAP_DIRS "${ZMK_CONFIG}") + + if (DEFINED SHIELD) + foreach (s ${shield_candidate_names} ${SHIELD_AS_LIST}) + if (DEFINED ${SHIELD_DIR_${s}}) + get_filename_component(shield_dir_name ${SHIELD_DIR_${s}} NAME) + endif() + list(APPEND overlay_candidates "${ZMK_CONFIG}/${s}_${BOARD}.overlay") + list(APPEND overlay_candidates "${ZMK_CONFIG}/${s}.overlay") + if (NOT "${shield_dir_name}" STREQUAL "${s}") + list(APPEND config_candidates "${ZMK_CONFIG}/${shield_dir_name}_${BOARD}.conf") + list(APPEND config_candidates "${ZMK_CONFIG}/${shield_dir_name}.conf") + endif() + list(APPEND config_candidates "${ZMK_CONFIG}/${s}_${BOARD}.conf") + list(APPEND config_candidates "${ZMK_CONFIG}/${s}.conf") + endforeach() + endif() + + # TODO: Board revisions? + list(APPEND overlay_candidates "${ZMK_CONFIG}/${BOARD_DIR_NAME}.overlay") + list(APPEND overlay_candidates "${ZMK_CONFIG}/${BOARD}.overlay") + list(APPEND overlay_candidates "${ZMK_CONFIG}/default.overlay") + list(APPEND config_candidates "${ZMK_CONFIG}/${BOARD_DIR_NAME}.conf") + list(APPEND config_candidates "${ZMK_CONFIG}/${BOARD}.conf") + list(APPEND config_candidates "${ZMK_CONFIG}/default.conf") + + foreach(overlay ${overlay_candidates}) + if (EXISTS "${overlay}") + message(STATUS "ZMK Config devicetree overlay: ${overlay}") + list(APPEND shield_dts_files "${overlay}") + break() + endif() + endforeach() + + foreach(conf ${config_candidates}) + if (EXISTS "${conf}") + message(STATUS "ZMK Config Kconfig: ${conf}") + list(APPEND shield_conf_files "${conf}") + endif() + endforeach() + else() + message(WARNING "Unable to locate ZMK config at: ${ZMK_CONFIG}") + endif() +endif() + + +if(NOT KEYMAP_FILE) + foreach(keymap_dir ${KEYMAP_DIRS}) + foreach(keymap_prefix ${shield_candidate_names} ${SHIELD_AS_LIST} ${SHIELD_DIR} ${BOARD} ${BOARD_DIR_NAME}) + if (EXISTS ${keymap_dir}/${keymap_prefix}.keymap) + set(KEYMAP_FILE "${keymap_dir}/${keymap_prefix}.keymap" CACHE STRING "Selected keymap file") + message(STATUS "Using keymap file: ${KEYMAP_FILE}") + set(DTC_OVERLAY_FILE ${KEYMAP_FILE}) + break() + endif() + endforeach() + endforeach() +else() + message(STATUS "Using keymap file: ${KEYMAP_FILE}") + set(DTC_OVERLAY_FILE ${KEYMAP_FILE}) +endif() + +if (NOT KEYMAP_FILE) + message(WARNING "Failed to locate keymap file!") +endif() diff --git a/app/keymap-module/zephyr/module.yml b/app/keymap-module/zephyr/module.yml new file mode 100644 index 000000000000..9daa3a18e442 --- /dev/null +++ b/app/keymap-module/zephyr/module.yml @@ -0,0 +1,5 @@ +# This ensures our modules/modules.cmake file is loaded *after* all the other modules, +# To set up the various keymap DTS and overridden .conf files are located and chosen. +build: + settings: + module_ext_root: "." diff --git a/app/module/CMakeLists.txt b/app/module/CMakeLists.txt new file mode 100644 index 000000000000..db886ac69878 --- /dev/null +++ b/app/module/CMakeLists.txt @@ -0,0 +1,4 @@ +zephyr_include_directories(include) + +add_subdirectory(drivers) +add_subdirectory(lib) \ No newline at end of file diff --git a/app/module/Kconfig b/app/module/Kconfig new file mode 100644 index 000000000000..52c013151a99 --- /dev/null +++ b/app/module/Kconfig @@ -0,0 +1,3 @@ + +rsource "drivers/Kconfig" +rsource "lib/Kconfig" \ No newline at end of file diff --git a/app/module/drivers/CMakeLists.txt b/app/module/drivers/CMakeLists.txt new file mode 100644 index 000000000000..5281c3dcb21e --- /dev/null +++ b/app/module/drivers/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +add_subdirectory_ifdef(CONFIG_GPIO gpio) +add_subdirectory_ifdef(CONFIG_KSCAN kscan) +add_subdirectory_ifdef(CONFIG_SENSOR sensor) +add_subdirectory_ifdef(CONFIG_DISPLAY display) diff --git a/app/module/drivers/Kconfig b/app/module/drivers/Kconfig new file mode 100644 index 000000000000..c57ed3347c99 --- /dev/null +++ b/app/module/drivers/Kconfig @@ -0,0 +1,7 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +rsource "gpio/Kconfig" +rsource "kscan/Kconfig" +rsource "sensor/Kconfig" +rsource "display/Kconfig" diff --git a/app/module/drivers/display/CMakeLists.txt b/app/module/drivers/display/CMakeLists.txt new file mode 100644 index 000000000000..6fc98c95a9da --- /dev/null +++ b/app/module/drivers/display/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +zephyr_library_amend() + +zephyr_library_sources_ifdef(CONFIG_IL0323 il0323.c) \ No newline at end of file diff --git a/app/module/drivers/display/Kconfig b/app/module/drivers/display/Kconfig new file mode 100644 index 000000000000..d70aff7c40aa --- /dev/null +++ b/app/module/drivers/display/Kconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if DISPLAY + +rsource "Kconfig.il0323" + +endif # DISPLAY \ No newline at end of file diff --git a/app/module/drivers/display/Kconfig.il0323 b/app/module/drivers/display/Kconfig.il0323 new file mode 100644 index 000000000000..f3308c1650d4 --- /dev/null +++ b/app/module/drivers/display/Kconfig.il0323 @@ -0,0 +1,11 @@ +# Copyright (c) 2020 Phytec Messtechnik GmbH, Peter Johanson +# SPDX-License-Identifier: Apache-2.0 + +# IL0323 display controller configuration options + +config IL0323 + bool "IL0323 compatible display controller driver" + depends on SPI + depends on HEAP_MEM_POOL_SIZE != 0 + help + Enable driver for IL0323 compatible controller. \ No newline at end of file diff --git a/app/module/drivers/display/il0323.c b/app/module/drivers/display/il0323.c new file mode 100644 index 000000000000..6555e5c1d9bf --- /dev/null +++ b/app/module/drivers/display/il0323.c @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2020 PHYTEC Messtechnik GmbHH, Peter Johanson + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT gooddisplay_il0323 + +#include +#include +#include +#include +#include +#include +#include + +#include "il0323_regs.h" + +#include +LOG_MODULE_REGISTER(il0323, CONFIG_DISPLAY_LOG_LEVEL); + +/** + * IL0323 compatible EPD controller driver. + * + */ + +#define EPD_PANEL_WIDTH DT_INST_PROP(0, width) +#define EPD_PANEL_HEIGHT DT_INST_PROP(0, height) +#define IL0323_PIXELS_PER_BYTE 8U + +/* Horizontally aligned page! */ +#define IL0323_NUMOF_PAGES (EPD_PANEL_WIDTH / IL0323_PIXELS_PER_BYTE) +#define IL0323_PANEL_FIRST_GATE 0U +#define IL0323_PANEL_LAST_GATE (EPD_PANEL_HEIGHT - 1) +#define IL0323_PANEL_FIRST_PAGE 0U +#define IL0323_PANEL_LAST_PAGE (IL0323_NUMOF_PAGES - 1) +#define IL0323_BUFFER_SIZE 1280 + +struct il0323_cfg { + struct gpio_dt_spec reset; + struct gpio_dt_spec dc; + struct gpio_dt_spec busy; + struct spi_dt_spec spi; +}; + +static uint8_t il0323_pwr[] = DT_INST_PROP(0, pwr); + +static uint8_t last_buffer[IL0323_BUFFER_SIZE]; +static bool blanking_on = true; +static bool init_clear_done = false; + +static inline int il0323_write_cmd(const struct il0323_cfg *cfg, uint8_t cmd, uint8_t *data, + size_t len) { + struct spi_buf buf = {.buf = &cmd, .len = sizeof(cmd)}; + struct spi_buf_set buf_set = {.buffers = &buf, .count = 1}; + + gpio_pin_set_dt(&cfg->dc, 1); + if (spi_write_dt(&cfg->spi, &buf_set)) { + return -EIO; + } + + if (data != NULL) { + buf.buf = data; + buf.len = len; + gpio_pin_set_dt(&cfg->dc, 0); + if (spi_write_dt(&cfg->spi, &buf_set)) { + return -EIO; + } + } + + return 0; +} + +static inline void il0323_busy_wait(const struct il0323_cfg *cfg) { + int pin = gpio_pin_get_dt(&cfg->busy); + + while (pin > 0) { + __ASSERT(pin >= 0, "Failed to get pin level"); + // LOG_DBG("wait %u", pin); + k_msleep(IL0323_BUSY_DELAY); + pin = gpio_pin_get_dt(&cfg->busy); + } +} + +static int il0323_update_display(const struct device *dev) { + const struct il0323_cfg *cfg = dev->config; + + LOG_DBG("Trigger update sequence"); + if (il0323_write_cmd(cfg, IL0323_CMD_DRF, NULL, 0)) { + return -EIO; + } + + k_msleep(IL0323_BUSY_DELAY); + + return 0; +} + +static int il0323_write(const struct device *dev, const uint16_t x, const uint16_t y, + const struct display_buffer_descriptor *desc, const void *buf) { + const struct il0323_cfg *cfg = dev->config; + uint16_t x_end_idx = x + desc->width - 1; + uint16_t y_end_idx = y + desc->height - 1; + uint8_t ptl[IL0323_PTL_REG_LENGTH] = {0}; + size_t buf_len; + + LOG_DBG("x %u, y %u, height %u, width %u, pitch %u", x, y, desc->height, desc->width, + desc->pitch); + + buf_len = MIN(desc->buf_size, desc->height * desc->width / IL0323_PIXELS_PER_BYTE); + __ASSERT(desc->width <= desc->pitch, "Pitch is smaller then width"); + __ASSERT(buf != NULL, "Buffer is not available"); + __ASSERT(buf_len != 0U, "Buffer of length zero"); + __ASSERT(!(desc->width % IL0323_PIXELS_PER_BYTE), "Buffer width not multiple of %d", + IL0323_PIXELS_PER_BYTE); + + LOG_DBG("buf_len %d", buf_len); + if ((y_end_idx > (EPD_PANEL_HEIGHT - 1)) || (x_end_idx > (EPD_PANEL_WIDTH - 1))) { + LOG_ERR("Position out of bounds"); + return -EINVAL; + } + + /* Setup Partial Window and enable Partial Mode */ + ptl[IL0323_PTL_HRST_IDX] = x; + ptl[IL0323_PTL_HRED_IDX] = x_end_idx; + ptl[IL0323_PTL_VRST_IDX] = y; + ptl[IL0323_PTL_VRED_IDX] = y_end_idx; + ptl[sizeof(ptl) - 1] = IL0323_PTL_PT_SCAN; + LOG_HEXDUMP_DBG(ptl, sizeof(ptl), "ptl"); + + il0323_busy_wait(cfg); + if (il0323_write_cmd(cfg, IL0323_CMD_PIN, NULL, 0)) { + return -EIO; + } + + if (il0323_write_cmd(cfg, IL0323_CMD_PTL, ptl, sizeof(ptl))) { + return -EIO; + } + + if (il0323_write_cmd(cfg, IL0323_CMD_DTM1, last_buffer, IL0323_BUFFER_SIZE)) { + return -EIO; + } + + if (il0323_write_cmd(cfg, IL0323_CMD_DTM2, (uint8_t *)buf, buf_len)) { + return -EIO; + } + + memcpy(last_buffer, (uint8_t *)buf, IL0323_BUFFER_SIZE); + + /* Update partial window and disable Partial Mode */ + if (blanking_on == false) { + if (il0323_update_display(dev)) { + return -EIO; + } + } + + if (il0323_write_cmd(cfg, IL0323_CMD_POUT, NULL, 0)) { + return -EIO; + } + + return 0; +} + +static int il0323_read(const struct device *dev, const uint16_t x, const uint16_t y, + const struct display_buffer_descriptor *desc, void *buf) { + LOG_ERR("not supported"); + return -ENOTSUP; +} + +static int il0323_clear_and_write_buffer(const struct device *dev, uint8_t pattern, bool update) { + struct display_buffer_descriptor desc = { + .buf_size = IL0323_NUMOF_PAGES, + .width = EPD_PANEL_WIDTH, + .height = 1, + .pitch = EPD_PANEL_WIDTH, + }; + uint8_t *line; + + line = k_malloc(IL0323_NUMOF_PAGES); + if (line == NULL) { + return -ENOMEM; + } + + memset(line, pattern, IL0323_NUMOF_PAGES); + for (int i = 0; i < EPD_PANEL_HEIGHT; i++) { + il0323_write(dev, 0, i, &desc, line); + } + + k_free(line); + + if (update == true) { + if (il0323_update_display(dev)) { + return -EIO; + } + } + + return 0; +} + +static int il0323_blanking_off(const struct device *dev) { + const struct il0323_cfg *cfg = dev->config; + + if (!init_clear_done) { + /* Update EPD panel in normal mode */ + il0323_busy_wait(cfg); + if (il0323_clear_and_write_buffer(dev, 0xff, true)) { + return -EIO; + } + init_clear_done = true; + } + + blanking_on = false; + + if (il0323_update_display(dev)) { + return -EIO; + } + + return 0; +} + +static int il0323_blanking_on(const struct device *dev) { + blanking_on = true; + + return 0; +} + +static void *il0323_get_framebuffer(const struct device *dev) { + LOG_ERR("not supported"); + return NULL; +} + +static int il0323_set_brightness(const struct device *dev, const uint8_t brightness) { + LOG_WRN("not supported"); + return -ENOTSUP; +} + +static int il0323_set_contrast(const struct device *dev, uint8_t contrast) { + LOG_WRN("not supported"); + return -ENOTSUP; +} + +static void il0323_get_capabilities(const struct device *dev, struct display_capabilities *caps) { + memset(caps, 0, sizeof(struct display_capabilities)); + caps->x_resolution = EPD_PANEL_WIDTH; + caps->y_resolution = EPD_PANEL_HEIGHT; + caps->supported_pixel_formats = PIXEL_FORMAT_MONO10; + caps->current_pixel_format = PIXEL_FORMAT_MONO10; + caps->screen_info = SCREEN_INFO_MONO_MSB_FIRST | SCREEN_INFO_EPD; +} + +static int il0323_set_orientation(const struct device *dev, + const enum display_orientation orientation) { + LOG_ERR("Unsupported"); + return -ENOTSUP; +} + +static int il0323_set_pixel_format(const struct device *dev, const enum display_pixel_format pf) { + if (pf == PIXEL_FORMAT_MONO10) { + return 0; + } + + LOG_ERR("not supported"); + return -ENOTSUP; +} + +static int il0323_controller_init(const struct device *dev) { + const struct il0323_cfg *cfg = dev->config; + uint8_t tmp[IL0323_TRES_REG_LENGTH]; + + LOG_DBG(""); + + gpio_pin_set_dt(&cfg->reset, 1); + k_msleep(IL0323_RESET_DELAY); + gpio_pin_set_dt(&cfg->reset, 0); + k_msleep(IL0323_RESET_DELAY); + il0323_busy_wait(cfg); + + LOG_DBG("Initialize IL0323 controller"); + + if (il0323_write_cmd(cfg, IL0323_CMD_PWR, il0323_pwr, sizeof(il0323_pwr))) { + return -EIO; + } + + /* Turn on: booster, controller, regulators, and sensor. */ + if (il0323_write_cmd(cfg, IL0323_CMD_PON, NULL, 0)) { + return -EIO; + } + + k_msleep(IL0323_PON_DELAY); + il0323_busy_wait(cfg); + + /* Pannel settings, KW mode */ + tmp[0] = IL0323_PSR_UD | IL0323_PSR_SHL | IL0323_PSR_SHD | IL0323_PSR_RST; +#if EPD_PANEL_WIDTH == 80 + +#if EPD_PANEL_HEIGHT == 128 + tmp[0] |= IL0323_PSR_RES_HEIGHT; +#endif /* panel height */ + +#else + tmp[0] |= IL0323_PSR_RES_WIDTH; +#if EPD_PANEL_HEIGHT == 96 + tmp[0] |= IL0323_PSR_RES_HEIGHT; +#else +#endif /* panel height */ + +#endif /* panel width */ + + LOG_HEXDUMP_DBG(tmp, 1, "PSR"); + if (il0323_write_cmd(cfg, IL0323_CMD_PSR, tmp, 1)) { + return -EIO; + } + + /* Set panel resolution */ + tmp[IL0323_TRES_HRES_IDX] = EPD_PANEL_WIDTH; + tmp[IL0323_TRES_VRES_IDX] = EPD_PANEL_HEIGHT; + LOG_HEXDUMP_DBG(tmp, IL0323_TRES_REG_LENGTH, "TRES"); + if (il0323_write_cmd(cfg, IL0323_CMD_TRES, tmp, IL0323_TRES_REG_LENGTH)) { + return -EIO; + } + + tmp[IL0323_CDI_CDI_IDX] = DT_INST_PROP(0, cdi); + LOG_HEXDUMP_DBG(tmp, IL0323_CDI_REG_LENGTH, "CDI"); + if (il0323_write_cmd(cfg, IL0323_CMD_CDI, tmp, IL0323_CDI_REG_LENGTH)) { + return -EIO; + } + + tmp[0] = DT_INST_PROP(0, tcon); + if (il0323_write_cmd(cfg, IL0323_CMD_TCON, tmp, 1)) { + return -EIO; + } + + /* Enable Auto Sequence */ + tmp[0] = IL0323_AUTO_PON_DRF_POF; + if (il0323_write_cmd(cfg, IL0323_CMD_AUTO, tmp, 1)) { + return -EIO; + } + + return 0; +} + +static int il0323_init(const struct device *dev) { + const struct il0323_cfg *cfg = dev->config; + + if (!spi_is_ready(&cfg->spi)) { + LOG_ERR("SPI device not ready for IL0323"); + return -EIO; + } + + if (!device_is_ready(cfg->reset.port)) { + LOG_ERR("Could not get GPIO port for IL0323 reset"); + return -EIO; + } + + gpio_pin_configure_dt(&cfg->reset, GPIO_OUTPUT_INACTIVE); + + if (!device_is_ready(cfg->dc.port)) { + LOG_ERR("Could not get GPIO port for IL0323 DC signal"); + return -EIO; + } + + gpio_pin_configure_dt(&cfg->dc, GPIO_OUTPUT_INACTIVE); + + if (!device_is_ready(cfg->busy.port)) { + LOG_ERR("Could not get GPIO port for IL0323 busy signal"); + return -EIO; + } + + gpio_pin_configure_dt(&cfg->busy, GPIO_INPUT); + + return il0323_controller_init(dev); +} + +static struct il0323_cfg il0323_config = { + .spi = SPI_DT_SPEC_INST_GET(0, SPI_OP_MODE_MASTER | SPI_WORD_SET(8), 0), + .reset = GPIO_DT_SPEC_INST_GET(0, reset_gpios), + .busy = GPIO_DT_SPEC_INST_GET(0, busy_gpios), + .dc = GPIO_DT_SPEC_INST_GET(0, dc_gpios), +}; + +static struct display_driver_api il0323_driver_api = { + .blanking_on = il0323_blanking_on, + .blanking_off = il0323_blanking_off, + .write = il0323_write, + .read = il0323_read, + .get_framebuffer = il0323_get_framebuffer, + .set_brightness = il0323_set_brightness, + .set_contrast = il0323_set_contrast, + .get_capabilities = il0323_get_capabilities, + .set_pixel_format = il0323_set_pixel_format, + .set_orientation = il0323_set_orientation, +}; + +DEVICE_DT_INST_DEFINE(0, il0323_init, NULL, NULL, &il0323_config, POST_KERNEL, + CONFIG_APPLICATION_INIT_PRIORITY, &il0323_driver_api); diff --git a/app/module/drivers/display/il0323_regs.h b/app/module/drivers/display/il0323_regs.h new file mode 100644 index 000000000000..3eb19755fdbb --- /dev/null +++ b/app/module/drivers/display/il0323_regs.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 PHYTEC Messtechnik GmbH, Peter Johanson + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_DISPLAY_IL0323_REGS_H_ +#define ZEPHYR_DRIVERS_DISPLAY_IL0323_REGS_H_ + +#define IL0323_CMD_PSR 0x00 +#define IL0323_CMD_PWR 0x01 +#define IL0323_CMD_POF 0x02 +#define IL0323_CMD_PFS 0x03 +#define IL0323_CMD_PON 0x04 +#define IL0323_CMD_PMES 0x05 +#define IL0323_CMD_CPSET 0x06 +#define IL0323_CMD_DSLP 0x07 +#define IL0323_CMD_DTM1 0x10 +#define IL0323_CMD_DSP 0x11 +#define IL0323_CMD_DRF 0x12 +#define IL0323_CMD_DTM2 0x13 +#define IL0323_CMD_AUTO 0x17 +#define IL0323_CMD_LUTOPT 0x2A +#define IL0323_CMD_PLL 0x30 +#define IL0323_CMD_TSC 0x40 +#define IL0323_CMD_TSE 0x41 +#define IL0323_CMD_PBC 0x44 +#define IL0323_CMD_CDI 0x50 +#define IL0323_CMD_LPD 0x51 +#define IL0323_CMD_TCON 0x60 +#define IL0323_CMD_TRES 0x61 +#define IL0323_CMD_GSST 0x65 +#define IL0323_CMD_REV 0x70 +#define IL0323_CMD_FLG 0x71 +#define IL0323_CMD_CRC 0x72 +#define IL0323_CMD_AMV 0x80 +#define IL0323_CMD_VV 0x81 +#define IL0323_CMD_VDCS 0x82 +#define IL0323_CMD_PTL 0x90 +#define IL0323_CMD_PIN 0x91 +#define IL0323_CMD_POUT 0x92 +#define IL0323_CMD_PGM 0xA0 +#define IL0323_CMD_APG 0xA1 +#define IL0323_CMD_ROTP 0xA2 +#define IL0323_CMD_CCSET 0xE0 +#define IL0323_CMD_PWS 0xE3 +#define IL0323_CMD_LVSEL 0xE4 +#define IL0323_CMD_TSSET 0xE5 + +#define IL0323_PSR_RES_WIDTH BIT(7) +#define IL0323_PSR_RES_HEIGHT BIT(6) +#define IL0323_PSR_LUT_REG BIT(5) +#define IL0323_PSR_LUT_OTP BIT(4) +#define IL0323_PSR_UD BIT(3) +#define IL0323_PSR_SHL BIT(2) +#define IL0323_PSR_SHD BIT(1) +#define IL0323_PSR_RST BIT(0) + +#define IL0323_AUTO_PON_DRF_POF 0xA5 +#define IL0323_AUTO_PON_DRF_POF_DSLP 0xA7 + +#define IL0323_CDI_REG_LENGTH 1U +#define IL0323_CDI_CDI_IDX 0 + +#define IL0323_TRES_REG_LENGTH 2U +#define IL0323_TRES_HRES_IDX 0 +#define IL0323_TRES_VRES_IDX 1 + +#define IL0323_PTL_REG_LENGTH 5U +#define IL0323_PTL_HRST_IDX 0 +#define IL0323_PTL_HRED_IDX 1 +#define IL0323_PTL_VRST_IDX 2 +#define IL0323_PTL_VRED_IDX 3 +#define IL0323_PTL_PT_SCAN BIT(0) + +/* Time constants in ms */ +#define IL0323_RESET_DELAY 10U +#define IL0323_PON_DELAY 100U +#define IL0323_BUSY_DELAY 1U + +#endif /* ZEPHYR_DRIVERS_DISPLAY_IL0323_REGS_H_ */ \ No newline at end of file diff --git a/app/module/drivers/gpio/CMakeLists.txt b/app/module/drivers/gpio/CMakeLists.txt new file mode 100644 index 000000000000..b5647e87bd74 --- /dev/null +++ b/app/module/drivers/gpio/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +zephyr_library_amend() + +zephyr_library_sources_ifdef(CONFIG_GPIO_595 gpio_595.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_MAX7318 gpio_max7318.c) diff --git a/app/module/drivers/gpio/Kconfig b/app/module/drivers/gpio/Kconfig new file mode 100644 index 000000000000..a6c7b4a19ef0 --- /dev/null +++ b/app/module/drivers/gpio/Kconfig @@ -0,0 +1,7 @@ + +if GPIO + +rsource "Kconfig.max7318" +rsource "Kconfig.595" + +endif # GPIO \ No newline at end of file diff --git a/app/module/drivers/gpio/Kconfig.595 b/app/module/drivers/gpio/Kconfig.595 new file mode 100644 index 000000000000..7ebdc0cc54ca --- /dev/null +++ b/app/module/drivers/gpio/Kconfig.595 @@ -0,0 +1,24 @@ +# 595 GPIO configuration options + +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +DT_COMPAT_ZMK_GPIO_595 := zmk,gpio-595 + +menuconfig GPIO_595 + bool "595 Shift Register SPI driver" + default $(dt_compat_enabled,$(DT_COMPAT_ZMK_GPIO_595)) + depends on SPI + select HAS_DTS_GPIO + help + Enable driver for 595 shift register chip using SPI. + +if GPIO_595 + +config GPIO_595_INIT_PRIORITY + int "Init priority" + default 75 + help + Device driver initialization priority. + +endif #GPIO_595 diff --git a/app/module/drivers/gpio/Kconfig.max7318 b/app/module/drivers/gpio/Kconfig.max7318 new file mode 100644 index 000000000000..b54e1dba4654 --- /dev/null +++ b/app/module/drivers/gpio/Kconfig.max7318 @@ -0,0 +1,24 @@ +# MAX7318 GPIO configuration options + +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +DT_COMPAT_MAXIM_MAX7318 := maxim,max7318 + +menuconfig GPIO_MAX7318 + bool "MAX7318 I2C-based GPIO chip" + default $(dt_compat_enabled,$(DT_COMPAT_MAXIM_MAX7318)) + depends on I2C + select HAS_DTS_GPIO + help + Enable driver for MAX7318 I2C-based GPIO chip. + +if GPIO_MAX7318 + +config GPIO_MAX7318_INIT_PRIORITY + int "Init priority" + default 75 + help + Device driver initialization priority. + +endif #GPIO_MAX7318 diff --git a/app/module/drivers/gpio/gpio_595.c b/app/module/drivers/gpio/gpio_595.c new file mode 100644 index 000000000000..3d3858449c5f --- /dev/null +++ b/app/module/drivers/gpio/gpio_595.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_gpio_595 + +/** + * @file Driver for 595 SPI-based GPIO driver. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_GPIO_LOG_LEVEL +#include +LOG_MODULE_REGISTER(gpio_595); + +/** Configuration data */ +struct reg_595_config { + /* gpio_driver_data needs to be first */ + struct gpio_driver_config common; + + struct spi_dt_spec bus; + + uint8_t ngpios; +}; + +/** Runtime driver data */ +struct reg_595_drv_data { + /* gpio_driver_data needs to be first */ + struct gpio_driver_config data; + + struct k_sem lock; + + uint32_t gpio_cache; +}; + +static int reg_595_write_registers(const struct device *dev, uint32_t value) { + const struct reg_595_config *config = dev->config; + struct reg_595_drv_data *const drv_data = (struct reg_595_drv_data *const)dev->data; + int ret = 0; + + uint8_t nwrite = config->ngpios / 8; + uint32_t reg_data = sys_cpu_to_be32(value); + + /* Allow a sequence of 1-4 registers in sequence, lowest byte is for the first in the chain */ + const struct spi_buf tx_buf[1] = {{ + .buf = ((uint8_t *)®_data) + (4 - nwrite), + .len = nwrite, + }}; + + const struct spi_buf_set tx = { + .buffers = tx_buf, + .count = ARRAY_SIZE(tx_buf), + }; + + ret = spi_write_dt(&config->bus, &tx); + if (ret < 0) { + LOG_ERR("spi_write FAIL %d\n", ret); + return ret; + } + + drv_data->gpio_cache = value; + return 0; +} + +/** + * @brief Setup the pin direction (input or output) + * + * @param dev Device struct of the 595 + * @param pin The pin number + * @param flags Flags of pin or port + * + * @return 0 if successful, failed otherwise + */ +static int setup_pin_dir(const struct device *dev, uint32_t pin, int flags) { + if ((flags & GPIO_OUTPUT) == 0U) { + return -ENOTSUP; + } + + return 0; +} + +static int reg_595_pin_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) { + int ret; + + /* Can't do SPI bus operations from an ISR */ + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + if ((flags & GPIO_OPEN_DRAIN) != 0U) { + return -ENOTSUP; + }; + + ret = setup_pin_dir(dev, pin, flags); + if (ret) { + LOG_ERR("595: error setting pin direction (%d)", ret); + } + + return ret; +} + +static int reg_595_port_get_raw(const struct device *dev, uint32_t *value) { return -ENOTSUP; } + +static int reg_595_port_set_masked_raw(const struct device *dev, uint32_t mask, uint32_t value) { + struct reg_595_drv_data *const drv_data = (struct reg_595_drv_data *const)dev->data; + uint32_t buf; + int ret; + + /* Can't do SPI bus operations from an ISR */ + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + k_sem_take(&drv_data->lock, K_FOREVER); + + buf = drv_data->gpio_cache; + buf = (buf & ~mask) | (mask & value); + + ret = reg_595_write_registers(dev, buf); + + k_sem_give(&drv_data->lock); + return ret; +} + +static int reg_595_port_set_bits_raw(const struct device *dev, uint32_t mask) { + return reg_595_port_set_masked_raw(dev, mask, mask); +} + +static int reg_595_port_clear_bits_raw(const struct device *dev, uint32_t mask) { + return reg_595_port_set_masked_raw(dev, mask, 0); +} + +static int reg_595_port_toggle_bits(const struct device *dev, uint32_t mask) { + struct reg_595_drv_data *const drv_data = (struct reg_595_drv_data *const)dev->data; + uint32_t buf; + int ret; + + /* Can't do SPI bus operations from an ISR */ + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + k_sem_take(&drv_data->lock, K_FOREVER); + + buf = drv_data->gpio_cache; + buf ^= mask; + + ret = reg_595_write_registers(dev, buf); + + k_sem_give(&drv_data->lock); + return ret; +} + +static const struct gpio_driver_api api_table = { + .pin_configure = reg_595_pin_config, + .port_get_raw = reg_595_port_get_raw, + .port_set_masked_raw = reg_595_port_set_masked_raw, + .port_set_bits_raw = reg_595_port_set_bits_raw, + .port_clear_bits_raw = reg_595_port_clear_bits_raw, + .port_toggle_bits = reg_595_port_toggle_bits, +}; + +/** + * @brief Initialization function of 595 + * + * @param dev Device struct + * @return 0 if successful, failed otherwise. + */ +static int reg_595_init(const struct device *dev) { + const struct reg_595_config *const config = dev->config; + struct reg_595_drv_data *const drv_data = (struct reg_595_drv_data *const)dev->data; + + if (!device_is_ready(config->bus.bus)) { + LOG_ERR("Unable to get SPI bus device"); + return -ENODEV; + } + + k_sem_init(&drv_data->lock, 1, 1); + + return 0; +} + +#define GPIO_PORT_PIN_MASK_FROM_NGPIOS(ngpios) ((gpio_port_pins_t)(((uint64_t)1 << (ngpios)) - 1U)) + +#define GPIO_PORT_PIN_MASK_FROM_DT_INST(inst) \ + GPIO_PORT_PIN_MASK_FROM_NGPIOS(DT_INST_PROP(inst, ngpios)) + +#define REG_595_INIT(n) \ + static struct reg_595_config reg_595_##n##_config = { \ + .common = \ + { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ + }, \ + .bus = \ + SPI_DT_SPEC_INST_GET(n, SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8), 0), \ + .ngpios = DT_INST_PROP(n, ngpios), \ + }; \ + \ + static struct reg_595_drv_data reg_595_##n##_drvdata = {}; \ + \ + /* This has to init after SPI master */ \ + DEVICE_DT_INST_DEFINE(n, reg_595_init, NULL, ®_595_##n##_drvdata, ®_595_##n##_config, \ + POST_KERNEL, CONFIG_GPIO_595_INIT_PRIORITY, &api_table); + +DT_INST_FOREACH_STATUS_OKAY(REG_595_INIT) diff --git a/app/module/drivers/gpio/gpio_max7318.c b/app/module/drivers/gpio/gpio_max7318.c new file mode 100644 index 000000000000..1842ce7b2d60 --- /dev/null +++ b/app/module/drivers/gpio/gpio_max7318.c @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT maxim_max7318 + +/** + * @file Driver for MAX7318 I2C-based GPIO driver. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_GPIO_LOG_LEVEL +#include + +LOG_MODULE_REGISTER(gpio_max7318); + +// Register definitions +#define REG_INPUT_PORTA 0x00 +#define REG_INPUT_PORTB 0x01 +#define REG_OUTPUT_PORTA 0x02 +#define REG_OUTPUT_PORTB 0x03 +#define REG_IPOL_PORTA 0x04 +#define REG_IPOL_PORTB 0x05 +#define REG_CONFIG_PORTA 0x06 +#define REG_CONFIG_PORTB 0x07 + +// Configuration data +struct max7318_config { + struct gpio_driver_config common; + + struct i2c_dt_spec i2c_bus; + uint8_t ngpios; +}; + +// Runtime driver data +struct max7318_drv_data { + // gpio_driver_data needs to be first + struct gpio_driver_config data; + + struct k_sem lock; + + struct { + uint16_t ipol; + uint16_t config; + uint16_t output; + } reg_cache; +}; + +/** + * @brief Read the value of two consecutive registers + * + * Read two consecutive bytes from the register at address `reg` and `reg + 1`, + * typically reading from registers for port 0 and 1 simultaneously. + * + * @param dev The max7318 device. + * @param reg Register to read (the PORT0 of the pair of registers). + * @param buf Buffer to read data into. + * + * @return 0 if successful, failed otherwise. + */ +static int read_registers(const struct device *dev, uint8_t reg, uint16_t *buf) { + const struct max7318_config *config = dev->config; + + uint8_t data[2] = {0}; + int ret = i2c_burst_read_dt(&config->i2c_bus, reg, &data[0], sizeof(data)); + if (ret) { + LOG_DBG("i2c_burst_read FAIL %d\n", ret); + return ret; + } + + // the first register is data[0], the second one is data[1] + // since we only ever read the PORTA registers here, it's effectively little endian. + *buf = sys_get_le16(data); + + LOG_DBG("max7318: read: reg[0x%X] = 0x%X, reg[0x%X] = 0x%X", reg, data[0], (reg + 1), data[1]); + + return 0; +} + +/** + * @brief Write the value of two consecutive registers + * + * Write two consecutive bytes from the register at address `reg` and `reg + 1`, + * typically to registers for port 0 and 1 simultaneously. + * + * @param dev The max7318 device. + * @param reg Register to write (usually the register for PORT0). + * @param value The value to write + * + * @return 0 if successful, failed otherwise. + */ +static int write_registers(const struct device *dev, uint8_t reg, uint16_t value) { + const struct max7318_config *config = dev->config; + + LOG_DBG("max7318: write: reg[0x%X] = 0x%X, reg[0x%X] = 0x%X", reg, (value & 0xFF), (reg + 1), + (value >> 8)); + + uint8_t data[2] = {0}; + + // bits 0..7 are port A, 8..15 are port B, so we should write bits 0..7 first + // -- ie. this is little endian also. + sys_put_le16(value, &data[0]); + + return i2c_burst_write_dt(&config->i2c_bus, reg, &data[0], sizeof(data)); +} + +/** + * @brief Setup the pin direction (input or output) + * + * @param dev The max7318 device. + * @param pin The pin number. + * @param flags Flags of pin or port. + * + * @return 0 if successful, failed otherwise + */ +static int set_pin_direction(const struct device *dev, uint32_t pin, int flags) { + struct max7318_drv_data *const drv_data = (struct max7318_drv_data *const)dev->data; + uint16_t *dir = &drv_data->reg_cache.config; + uint16_t *output = &drv_data->reg_cache.output; + + /* + The output register is 1=high, 0=low; the direction (config) register + is 1=input, 0=output. + */ + if ((flags & GPIO_OUTPUT) != 0U) { + if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0U) { + *output |= BIT(pin); + } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0U) { + *output &= ~BIT(pin); + } + *dir &= ~BIT(pin); + } else { + *dir |= BIT(pin); + } + + int ret = write_registers(dev, REG_OUTPUT_PORTA, *output); + if (ret != 0) { + return ret; + } + + return write_registers(dev, REG_CONFIG_PORTA, *dir); +} + +/** + * @brief Setup the pin pull up/pull down status. This function doesn't actually set any + * registers, since the max7318 only supports a pullup, and it can't be controlled. + * + * @param dev The max7318 device. + * @param pin The pin number + * @param flags Flags of pin or port + * + * @return 0 if successful, failed otherwise + */ +static int set_pin_pull_direction(const struct device *dev, uint32_t pin, int flags) { + // actually, this chip only supports pull-up, and it can't be disabled. + // so, if we try to set anything else, return enotsup; we don't actually + // need to set any registers. + if ((flags & GPIO_PULL_DOWN) != 0U) { + return -ENOTSUP; + } + + return 0; +} + +static int max7318_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) { + struct max7318_drv_data *const drv_data = (struct max7318_drv_data *const)dev->data; + + /* Can't do I2C bus operations from an ISR */ + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + k_sem_take(&drv_data->lock, K_FOREVER); + + int ret = 0; + if ((flags & GPIO_OPEN_DRAIN) != 0U) { + ret = -ENOTSUP; + goto done; + }; + + ret = set_pin_direction(dev, pin, flags); + if (ret != 0) { + LOG_ERR("error setting pin direction (%d)", ret); + goto done; + } + + ret = set_pin_pull_direction(dev, pin, flags); + if (ret != 0) { + LOG_ERR("error setting pin pull up/down (%d)", ret); + goto done; + } + +done: + k_sem_give(&drv_data->lock); + return ret; +} + +static int max7318_port_get_raw(const struct device *dev, uint32_t *value) { + struct max7318_drv_data *const drv_data = (struct max7318_drv_data *const)dev->data; + + /* Can't do I2C bus operations from an ISR */ + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + k_sem_take(&drv_data->lock, K_FOREVER); + + uint16_t buf = 0; + int ret = read_registers(dev, REG_INPUT_PORTA, &buf); + if (ret != 0) { + goto done; + } + + *value = buf; + +done: + k_sem_give(&drv_data->lock); + return ret; +} + +static int max7318_port_set_masked_raw(const struct device *dev, uint32_t mask, uint32_t value) { + struct max7318_drv_data *const drv_data = (struct max7318_drv_data *const)dev->data; + + /* Can't do I2C bus operations from an ISR */ + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + k_sem_take(&drv_data->lock, K_FOREVER); + + uint16_t buf = drv_data->reg_cache.output; + buf = (buf & ~mask) | (mask & value); + + int ret = write_registers(dev, REG_OUTPUT_PORTA, buf); + if (ret == 0) { + drv_data->reg_cache.output = buf; + } + + k_sem_give(&drv_data->lock); + return ret; +} + +static int max7318_port_set_bits_raw(const struct device *dev, uint32_t mask) { + return max7318_port_set_masked_raw(dev, mask, mask); +} + +static int max7318_port_clear_bits_raw(const struct device *dev, uint32_t mask) { + return max7318_port_set_masked_raw(dev, mask, 0); +} + +static int max7318_port_toggle_bits(const struct device *dev, uint32_t mask) { + struct max7318_drv_data *const drv_data = (struct max7318_drv_data *const)dev->data; + + /* Can't do I2C bus operations from an ISR */ + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + k_sem_take(&drv_data->lock, K_FOREVER); + + uint16_t buf = drv_data->reg_cache.output; + buf ^= mask; + + int ret = write_registers(dev, REG_OUTPUT_PORTA, buf); + if (ret == 0) { + drv_data->reg_cache.output = buf; + } + + k_sem_give(&drv_data->lock); + return ret; +} + +static int max7318_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, + enum gpio_int_mode mode, enum gpio_int_trig trig) { + return -ENOTSUP; +} + +static const struct gpio_driver_api api_table = { + .pin_configure = max7318_config, + .port_get_raw = max7318_port_get_raw, + .port_set_masked_raw = max7318_port_set_masked_raw, + .port_set_bits_raw = max7318_port_set_bits_raw, + .port_clear_bits_raw = max7318_port_clear_bits_raw, + .port_toggle_bits = max7318_port_toggle_bits, + .pin_interrupt_configure = max7318_pin_interrupt_configure, +}; + +/** + * @brief Initialisation function of MAX7318 + * + * @param dev Device struct + * @return 0 if successful, failed otherwise. + */ +static int max7318_init(const struct device *dev) { + const struct max7318_config *const config = dev->config; + struct max7318_drv_data *const drv_data = (struct max7318_drv_data *const)dev->data; + + if (!device_is_ready(config->i2c_bus.bus)) { + LOG_WRN("i2c bus not ready!"); + return -EINVAL; + } + + LOG_INF("device initialised at 0x%x", config->i2c_bus.addr); + + k_sem_init(&drv_data->lock, 1, 1); + return 0; +} + +#define GPIO_PORT_PIN_MASK_FROM_NGPIOS(ngpios) ((gpio_port_pins_t)(((uint64_t)1 << (ngpios)) - 1U)) + +#define GPIO_PORT_PIN_MASK_FROM_DT_INST(inst) \ + GPIO_PORT_PIN_MASK_FROM_NGPIOS(DT_INST_PROP(inst, ngpios)) + +#define MAX7318_INIT(inst) \ + static struct max7318_config max7318_##inst##_config = { \ + .common = {.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(inst)}, \ + .i2c_bus = I2C_DT_SPEC_INST_GET(inst)}; \ + \ + static struct max7318_drv_data max7318_##inst##_drvdata = { \ + /* Default for registers according to datasheet */ \ + .reg_cache.ipol = 0x0, \ + .reg_cache.config = 0xFFFF, \ + .reg_cache.output = 0xFFFF, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, max7318_init, NULL, &max7318_##inst##_drvdata, \ + &max7318_##inst##_config, POST_KERNEL, \ + CONFIG_GPIO_MAX7318_INIT_PRIORITY, &api_table); + +DT_INST_FOREACH_STATUS_OKAY(MAX7318_INIT) diff --git a/app/module/drivers/kscan/CMakeLists.txt b/app/module/drivers/kscan/CMakeLists.txt new file mode 100644 index 000000000000..5b05af767e25 --- /dev/null +++ b/app/module/drivers/kscan/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright (c) 2020-2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +zephyr_library_amend() + +zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DRIVER kscan_gpio.c) +zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_MATRIX kscan_gpio_matrix.c) +zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_CHARLIEPLEX kscan_gpio_charlieplex.c) +zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DIRECT kscan_gpio_direct.c) +zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DEMUX kscan_gpio_demux.c) +zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_MOCK_DRIVER kscan_mock.c) +zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_COMPOSITE_DRIVER kscan_composite.c) diff --git a/app/module/drivers/kscan/Kconfig b/app/module/drivers/kscan/Kconfig new file mode 100644 index 000000000000..6b701936d4f6 --- /dev/null +++ b/app/module/drivers/kscan/Kconfig @@ -0,0 +1,123 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +DT_COMPAT_ZMK_KSCAN_COMPOSITE := zmk,kscan-composite +DT_COMPAT_ZMK_KSCAN_GPIO_DEMUX := zmk,kscan-gpio-demux +DT_COMPAT_ZMK_KSCAN_GPIO_DIRECT := zmk,kscan-gpio-direct +DT_COMPAT_ZMK_KSCAN_GPIO_MATRIX := zmk,kscan-gpio-matrix +DT_COMPAT_ZMK_KSCAN_GPIO_CHARLIEPLEX := zmk,kscan-gpio-charlieplex +DT_COMPAT_ZMK_KSCAN_MOCK := zmk,kscan-mock + +if KSCAN + +config ZMK_KSCAN_COMPOSITE_DRIVER + bool + default $(dt_compat_enabled,$(DT_COMPAT_ZMK_KSCAN_COMPOSITE)) + +config ZMK_KSCAN_GPIO_DRIVER + bool + select GPIO + select ZMK_DEBOUNCE + +config ZMK_KSCAN_GPIO_DEMUX + bool + default $(dt_compat_enabled,$(DT_COMPAT_ZMK_KSCAN_GPIO_DEMUX)) + select ZMK_KSCAN_GPIO_DRIVER + +config ZMK_KSCAN_GPIO_DIRECT + bool + default $(dt_compat_enabled,$(DT_COMPAT_ZMK_KSCAN_GPIO_DIRECT)) + select ZMK_KSCAN_GPIO_DRIVER + +config ZMK_KSCAN_GPIO_MATRIX + bool + default $(dt_compat_enabled,$(DT_COMPAT_ZMK_KSCAN_GPIO_MATRIX)) + select ZMK_KSCAN_GPIO_DRIVER + +config ZMK_KSCAN_GPIO_CHARLIEPLEX + bool + default $(dt_compat_enabled,$(DT_COMPAT_ZMK_KSCAN_GPIO_CHARLIEPLEX)) + select ZMK_KSCAN_GPIO_DRIVER + +if ZMK_KSCAN_GPIO_MATRIX + +config ZMK_KSCAN_MATRIX_WAIT_BEFORE_INPUTS + int "Ticks to wait before reading inputs after an output set active" + default 0 + help + When iterating over each output to drive it active, read inputs, then set + inactive again, some boards may take time for output to propagate to the + inputs. In that scenario, set this value to a positive value to configure + the number of ticks to wait after setting an output active before reading + the inputs for their active state. + +config ZMK_KSCAN_MATRIX_WAIT_BETWEEN_OUTPUTS + int "Ticks to wait between each output when scanning" + default 1 if SOC_RP2040 + default 0 + help + When iterating over each output to drive it active, read inputs, then set + inactive again, some boards may take time for the previous output to + "settle" before reading inputs for the next active output column. In that + scenario, set this value to a positive value to configure the number of + ticks to wait after reading each column of keys. + +endif # ZMK_KSCAN_GPIO_MATRIX + +if ZMK_KSCAN_GPIO_CHARLIEPLEX + +config ZMK_KSCAN_CHARLIEPLEX_WAIT_BEFORE_INPUTS + int "Ticks to wait before reading inputs after an output set active" + default 0 + help + When iterating over each output to drive it active, read inputs, then set + inactive again, some boards may take time for output to propagate to the + inputs. In that scenario, set this value to a positive value to configure + the number of ticks to wait after setting an output active before reading + the inputs for their active state. + +config ZMK_KSCAN_CHARLIEPLEX_WAIT_BETWEEN_OUTPUTS + int "Ticks to wait between each output when scanning charlieplex matrix" + default 0 + help + When iterating over each output to drive it active, read inputs, then set + inactive again, some boards may take time for the previous output to + "settle" before reading inputs for the next active output column. In that + scenario, set this value to a positive value to configure the number of + usecs to wait after reading each column of keys. + +endif # ZMK_KSCAN_GPIO_CHARLIEPLEX + +config ZMK_KSCAN_MOCK_DRIVER + bool + default $(dt_compat_enabled,$(DT_COMPAT_ZMK_KSCAN_MOCK)) + +if ZMK_KSCAN_GPIO_DRIVER + +config ZMK_KSCAN_MATRIX_POLLING + bool "Poll for key event triggers instead of using interrupts on matrix boards." + +config ZMK_KSCAN_DIRECT_POLLING + bool "Poll for key event triggers instead of using interrupts on direct wired boards." + +config ZMK_KSCAN_DEBOUNCE_PRESS_MS + int "Debounce time for key press in milliseconds." + default -1 + help + Global debounce time for key press in milliseconds. + If this is -1, the debounce time is controlled by the debounce-press-ms + Devicetree property, which defaults to 5 ms. Otherwise this overrides the + debounce time for all key scan drivers to the chosen value. + +config ZMK_KSCAN_DEBOUNCE_RELEASE_MS + int "Debounce time for key release in milliseconds." + default -1 + help + Global debounce time for key release in milliseconds. + If this is -1, the debounce time is controlled by the debounce-release-ms + Devicetree property, which defaults to 5 ms. Otherwise this overrides the + debounce time for all key scan drivers to the chosen value. + +endif + +endif # KSCAN diff --git a/app/module/drivers/kscan/kscan_composite.c b/app/module/drivers/kscan/kscan_composite.c new file mode 100644 index 000000000000..97311ef8e52a --- /dev/null +++ b/app/module/drivers/kscan/kscan_composite.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_kscan_composite + +#include +#include +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#define MATRIX_NODE_ID DT_DRV_INST(0) +#define MATRIX_ROWS DT_PROP(MATRIX_NODE_ID, rows) +#define MATRIX_COLS DT_PROP(MATRIX_NODE_ID, columns) + +struct kscan_composite_child_config { + const struct device *child; + uint8_t row_offset; + uint8_t column_offset; +}; + +#define CHILD_CONFIG(inst) \ + {.child = DEVICE_DT_GET(DT_PHANDLE(inst, kscan)), \ + .row_offset = DT_PROP(inst, row_offset), \ + .column_offset = DT_PROP(inst, column_offset)}, + +const struct kscan_composite_child_config kscan_composite_children[] = { + DT_FOREACH_CHILD(MATRIX_NODE_ID, CHILD_CONFIG)}; + +struct kscan_composite_config {}; + +struct kscan_composite_data { + kscan_callback_t callback; + + const struct device *dev; +}; + +static int kscan_composite_enable_callback(const struct device *dev) { + for (int i = 0; i < ARRAY_SIZE(kscan_composite_children); i++) { + const struct kscan_composite_child_config *cfg = &kscan_composite_children[i]; + + kscan_enable_callback(cfg->child); + } + return 0; +} + +static int kscan_composite_disable_callback(const struct device *dev) { + for (int i = 0; i < ARRAY_SIZE(kscan_composite_children); i++) { + const struct kscan_composite_child_config *cfg = &kscan_composite_children[i]; + + kscan_disable_callback(cfg->child); + } + return 0; +} + +static void kscan_composite_child_callback(const struct device *child_dev, uint32_t row, + uint32_t column, bool pressed) { + // TODO: Ideally we can get this passed into our callback! + const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0)); + struct kscan_composite_data *data = dev->data; + + for (int i = 0; i < ARRAY_SIZE(kscan_composite_children); i++) { + const struct kscan_composite_child_config *cfg = &kscan_composite_children[i]; + + if (cfg->child != child_dev) { + continue; + } + + data->callback(dev, row + cfg->row_offset, column + cfg->column_offset, pressed); + } +} + +static int kscan_composite_configure(const struct device *dev, kscan_callback_t callback) { + struct kscan_composite_data *data = dev->data; + + if (!callback) { + return -EINVAL; + } + + for (int i = 0; i < ARRAY_SIZE(kscan_composite_children); i++) { + const struct kscan_composite_child_config *cfg = &kscan_composite_children[i]; + + kscan_config(cfg->child, &kscan_composite_child_callback); + } + + data->callback = callback; + + return 0; +} + +static int kscan_composite_init(const struct device *dev) { + struct kscan_composite_data *data = dev->data; + + data->dev = dev; + + return 0; +} + +static const struct kscan_driver_api mock_driver_api = { + .config = kscan_composite_configure, + .enable_callback = kscan_composite_enable_callback, + .disable_callback = kscan_composite_disable_callback, +}; + +static const struct kscan_composite_config kscan_composite_config = {}; + +static struct kscan_composite_data kscan_composite_data; + +DEVICE_DT_INST_DEFINE(0, kscan_composite_init, NULL, &kscan_composite_data, &kscan_composite_config, + POST_KERNEL, CONFIG_KSCAN_INIT_PRIORITY, &mock_driver_api); diff --git a/app/module/drivers/kscan/kscan_gpio.c b/app/module/drivers/kscan/kscan_gpio.c new file mode 100644 index 000000000000..4963f6784f22 --- /dev/null +++ b/app/module/drivers/kscan/kscan_gpio.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "kscan_gpio.h" + +#include + +static int compare_ports(const void *a, const void *b) { + const struct kscan_gpio *gpio_a = a; + const struct kscan_gpio *gpio_b = b; + + return gpio_a->spec.port - gpio_b->spec.port; +} + +void kscan_gpio_list_sort_by_port(struct kscan_gpio_list *list) { + qsort(list->gpios, list->len, sizeof(list->gpios[0]), compare_ports); +} + +int kscan_gpio_pin_get(const struct kscan_gpio *gpio, struct kscan_gpio_port_state *state) { + if (gpio->spec.port != state->port) { + state->port = gpio->spec.port; + + const int err = gpio_port_get(state->port, &state->value); + if (err) { + return err; + } + } + + return (state->value & BIT(gpio->spec.pin)) != 0; +} diff --git a/app/module/drivers/kscan/kscan_gpio.h b/app/module/drivers/kscan/kscan_gpio.h new file mode 100644 index 000000000000..39343136d22e --- /dev/null +++ b/app/module/drivers/kscan/kscan_gpio.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +struct kscan_gpio { + struct gpio_dt_spec spec; + /** The index of the GPIO in the devicetree *-gpios array. */ + size_t index; +}; + +/** GPIO_DT_SPEC_GET_BY_IDX(), but for a struct kscan_gpio. */ +#define KSCAN_GPIO_GET_BY_IDX(node_id, prop, idx) \ + ((struct kscan_gpio){.spec = GPIO_DT_SPEC_GET_BY_IDX(node_id, prop, idx), .index = idx}) + +struct kscan_gpio_list { + struct kscan_gpio *gpios; + size_t len; +}; + +/** Define a kscan_gpio_list from a compile-time GPIO array. */ +#define KSCAN_GPIO_LIST(gpio_array) \ + ((struct kscan_gpio_list){.gpios = gpio_array, .len = ARRAY_SIZE(gpio_array)}) + +struct kscan_gpio_port_state { + const struct device *port; + gpio_port_value_t value; +}; + +/** + * Sorts a GPIO list by port so it can be used with kscan_gpio_pin_get(). + */ +void kscan_gpio_list_sort_by_port(struct kscan_gpio_list *list); + +/** + * Get logical level of an input pin. + * + * This is equivalent to gpio_pin_get() except that, when iterating through the + * pins in a list which is sorted by kscan_gpio_list_sort_by_port(), it only + * performs one read per port instead of one read per pin. + * + * @param gpio The input pin to read. + * @param state An object to track state between reads. Must be zero-initialized before the first + * use. + * + * @retval 1 If pin logical value is 1 / active. + * @retval 0 If pin logical value is 0 / inactive. + * @retval -EIO I/O error when accessing an external GPIO chip. + * @retval -EWOULDBLOCK if operation would block. + */ +int kscan_gpio_pin_get(const struct kscan_gpio *gpio, struct kscan_gpio_port_state *state); diff --git a/app/module/drivers/kscan/kscan_gpio_charlieplex.c b/app/module/drivers/kscan/kscan_gpio_charlieplex.c new file mode 100644 index 000000000000..f450af2b59cf --- /dev/null +++ b/app/module/drivers/kscan/kscan_gpio_charlieplex.c @@ -0,0 +1,420 @@ +/* + * Copyright (c) 2020-2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#define DT_DRV_COMPAT zmk_kscan_gpio_charlieplex + +#define INST_LEN(n) DT_INST_PROP_LEN(n, gpios) +#define INST_CHARLIEPLEX_LEN(n) (INST_LEN(n) * INST_LEN(n)) + +#if CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS >= 0 +#define INST_DEBOUNCE_PRESS_MS(n) CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS +#else +#define INST_DEBOUNCE_PRESS_MS(n) \ + DT_INST_PROP_OR(n, debounce_period, DT_INST_PROP(n, debounce_press_ms)) +#endif + +#if CONFIG_ZMK_KSCAN_DEBOUNCE_RELEASE_MS >= 0 +#define INST_DEBOUNCE_RELEASE_MS(n) CONFIG_ZMK_KSCAN_DEBOUNCE_RELEASE_MS +#else +#define INST_DEBOUNCE_RELEASE_MS(n) \ + DT_INST_PROP_OR(n, debounce_period, DT_INST_PROP(n, debounce_release_ms)) +#endif + +#define KSCAN_GPIO_CFG_INIT(idx, inst_idx) \ + GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst_idx), gpios, idx) + +#define INST_INTR_DEFINED(n) DT_INST_NODE_HAS_PROP(n, interrupt_gpios) + +#define WITH_INTR(n) COND_CODE_1(INST_INTR_DEFINED(n), (+1), (+0)) +#define WITHOUT_INTR(n) COND_CODE_0(INST_INTR_DEFINED(n), (+1), (+0)) + +#define USES_POLLING DT_INST_FOREACH_STATUS_OKAY(WITHOUT_INTR) > 0 +#define USES_INTERRUPT DT_INST_FOREACH_STATUS_OKAY(WITH_INTR) > 0 + +#if USES_POLLING && USES_INTERRUPT +#define USES_POLL_AND_INTR 1 +#else +#define USES_POLL_AND_INTR 0 +#endif + +#define COND_ANY_POLLING(code) COND_CODE_1(USES_POLLING, code, ()) +#define COND_POLL_AND_INTR(code) COND_CODE_1(USES_POLL_AND_INTR, code, ()) +#define COND_THIS_INTERRUPT(n, code) COND_CODE_1(INST_INTR_DEFINED(n), code, ()) + +#define KSCAN_INTR_CFG_INIT(inst_idx) GPIO_DT_SPEC_GET(DT_DRV_INST(inst_idx), interrupt_gpios) + +struct kscan_charlieplex_data { + const struct device *dev; + kscan_callback_t callback; + struct k_work_delayable work; + int64_t scan_time; /* Timestamp of the current or scheduled scan. */ + struct gpio_callback irq_callback; + /** + * Current state of the matrix as a flattened 2D array of length + * (config->cells.length ^2) + */ + struct zmk_debounce_state *charlieplex_state; +}; + +struct kscan_gpio_list { + const struct gpio_dt_spec *gpios; + size_t len; +}; + +/** Define a kscan_gpio_list from a compile-time GPIO array. */ +#define KSCAN_GPIO_LIST(gpio_array) \ + ((struct kscan_gpio_list){.gpios = gpio_array, .len = ARRAY_SIZE(gpio_array)}) + +struct kscan_charlieplex_config { + struct kscan_gpio_list cells; + struct zmk_debounce_config debounce_config; + int32_t debounce_scan_period_ms; + int32_t poll_period_ms; + bool use_interrupt; + const struct gpio_dt_spec interrupt; +}; + +/** + * Get the index into a matrix state array from a row and column. + * There are effectively (n) cols and (n-1) rows, but we use the full col x row space + * as a safety measure against someone accidentally defining a transform RC at (p,p) + */ +static int state_index(const struct kscan_charlieplex_config *config, const int row, + const int col) { + __ASSERT(row < config->cells.len, "Invalid row %i", row); + __ASSERT(col < config->cells.len, "Invalid column %i", col); + __ASSERT(col != row, "Invalid column row pair %i, %i", col, row); + + return (col * config->cells.len) + row; +} + +static int kscan_charlieplex_set_as_input(const struct gpio_dt_spec *gpio) { + if (!device_is_ready(gpio->port)) { + LOG_ERR("GPIO is not ready: %s", gpio->port->name); + return -ENODEV; + } + + gpio_flags_t pull_flag = + ((gpio->dt_flags & GPIO_ACTIVE_LOW) == GPIO_ACTIVE_LOW) ? GPIO_PULL_UP : GPIO_PULL_DOWN; + + int err = gpio_pin_configure_dt(gpio, GPIO_INPUT | pull_flag); + if (err) { + LOG_ERR("Unable to configure pin %u on %s for input", gpio->pin, gpio->port->name); + return err; + } + return 0; +} + +static int kscan_charlieplex_set_as_output(const struct gpio_dt_spec *gpio) { + if (!device_is_ready(gpio->port)) { + LOG_ERR("GPIO is not ready: %s", gpio->port->name); + return -ENODEV; + } + + int err = gpio_pin_configure_dt(gpio, GPIO_OUTPUT); + if (err) { + LOG_ERR("Unable to configure pin %u on %s for output", gpio->pin, gpio->port->name); + return err; + } + + err = gpio_pin_set_dt(gpio, 1); + if (err) { + LOG_ERR("Failed to set output pin %u active: %i", gpio->pin, err); + } + return err; +} + +static int kscan_charlieplex_set_all_as_input(const struct device *dev) { + const struct kscan_charlieplex_config *config = dev->config; + int err = 0; + for (int i = 0; i < config->cells.len; i++) { + err = kscan_charlieplex_set_as_input(&config->cells.gpios[i]); + if (err) { + return err; + } + } + + return 0; +} + +static int kscan_charlieplex_set_all_outputs(const struct device *dev, const int value) { + const struct kscan_charlieplex_config *config = dev->config; + + for (int i = 0; i < config->cells.len; i++) { + const struct gpio_dt_spec *gpio = &config->cells.gpios[i]; + int err = gpio_pin_configure_dt(gpio, GPIO_OUTPUT); + if (err) { + LOG_ERR("Unable to configure pin %u on %s for input", gpio->pin, gpio->port->name); + return err; + } + + err = gpio_pin_set_dt(gpio, value); + if (err) { + LOG_ERR("Failed to set output %i to %i: %i", i, value, err); + return err; + } + } + + return 0; +} + +static int kscan_charlieplex_interrupt_configure(const struct device *dev, + const gpio_flags_t flags) { + const struct kscan_charlieplex_config *config = dev->config; + const struct gpio_dt_spec *gpio = &config->interrupt; + + int err = gpio_pin_interrupt_configure_dt(gpio, flags); + if (err) { + LOG_ERR("Unable to configure interrupt for pin %u on %s", gpio->pin, gpio->port->name); + return err; + } + + return 0; +} + +static int kscan_charlieplex_interrupt_enable(const struct device *dev) { + int err = kscan_charlieplex_interrupt_configure(dev, GPIO_INT_LEVEL_ACTIVE); + if (err) { + return err; + } + + // While interrupts are enabled, set all outputs active so an pressed key will trigger + return kscan_charlieplex_set_all_outputs(dev, 1); +} + +static void kscan_charlieplex_irq_callback(const struct device *port, struct gpio_callback *cb, + const gpio_port_pins_t _pin) { + struct kscan_charlieplex_data *data = + CONTAINER_OF(cb, struct kscan_charlieplex_data, irq_callback); + + // Disable our interrupt to avoid re-entry while we scan. + kscan_charlieplex_interrupt_configure(data->dev, GPIO_INT_DISABLE); + data->scan_time = k_uptime_get(); + k_work_reschedule(&data->work, K_NO_WAIT); +} + +static void kscan_charlieplex_read_continue(const struct device *dev) { + const struct kscan_charlieplex_config *config = dev->config; + struct kscan_charlieplex_data *data = dev->data; + + data->scan_time += config->debounce_scan_period_ms; + + k_work_reschedule(&data->work, K_TIMEOUT_ABS_MS(data->scan_time)); +} + +static void kscan_charlieplex_read_end(const struct device *dev) { + struct kscan_charlieplex_data *data = dev->data; + const struct kscan_charlieplex_config *config = dev->config; + + if (config->use_interrupt) { + // Return to waiting for an interrupt. + kscan_charlieplex_interrupt_enable(dev); + } else { + data->scan_time += config->poll_period_ms; + + // Return to polling slowly. + k_work_reschedule(&data->work, K_TIMEOUT_ABS_MS(data->scan_time)); + } +} + +static int kscan_charlieplex_read(const struct device *dev) { + struct kscan_charlieplex_data *data = dev->data; + const struct kscan_charlieplex_config *config = dev->config; + bool continue_scan = false; + + // NOTE: RR vs MATRIX: set all pins as input, in case there was a failure on a + // previous scan, and one of the pins is still set as output + int err = kscan_charlieplex_set_all_as_input(dev); + if (err) { + return err; + } + + // Scan the matrix. + for (int row = 0; row < config->cells.len; row++) { + const struct gpio_dt_spec *out_gpio = &config->cells.gpios[row]; + err = kscan_charlieplex_set_as_output(out_gpio); + if (err) { + return err; + } + +#if CONFIG_ZMK_KSCAN_CHARLIEPLEX_WAIT_BEFORE_INPUTS > 0 + k_busy_wait(CONFIG_ZMK_KSCAN_CHARLIEPLEX_WAIT_BEFORE_INPUTS); +#endif + + for (int col = 0; col < config->cells.len; col++) { + if (col == row) { + continue; // pin can't drive itself + } + const struct gpio_dt_spec *in_gpio = &config->cells.gpios[col]; + const int index = state_index(config, row, col); + + struct zmk_debounce_state *state = &data->charlieplex_state[index]; + zmk_debounce_update(state, gpio_pin_get_dt(in_gpio), config->debounce_scan_period_ms, + &config->debounce_config); + + // NOTE: RR vs MATRIX: because we don't need an input/output => row/column + // setup, we can update in the same loop. + if (zmk_debounce_get_changed(state)) { + const bool pressed = zmk_debounce_is_pressed(state); + + LOG_DBG("Sending event at %i,%i state %s", row, col, pressed ? "on" : "off"); + data->callback(dev, row, col, pressed); + } + continue_scan = continue_scan || zmk_debounce_is_active(state); + } + + err = kscan_charlieplex_set_as_input(out_gpio); + if (err) { + return err; + } +#if CONFIG_ZMK_KSCAN_CHARLIEPLEX_WAIT_BETWEEN_OUTPUTS > 0 + k_busy_wait(CONFIG_ZMK_KSCAN_CHARLIEPLEX_WAIT_BETWEEN_OUTPUTS); +#endif + } + + if (continue_scan) { + // At least one key is pressed or the debouncer has not yet decided if + // it is pressed. Poll quickly until everything is released. + kscan_charlieplex_read_continue(dev); + } else { + // All keys are released. Return to normal. + kscan_charlieplex_read_end(dev); + } + + return 0; +} + +static void kscan_charlieplex_work_handler(struct k_work *work) { + struct k_work_delayable *dwork = CONTAINER_OF(work, struct k_work_delayable, work); + struct kscan_charlieplex_data *data = CONTAINER_OF(dwork, struct kscan_charlieplex_data, work); + kscan_charlieplex_read(data->dev); +} + +static int kscan_charlieplex_configure(const struct device *dev, const kscan_callback_t callback) { + if (!callback) { + return -EINVAL; + } + + struct kscan_charlieplex_data *data = dev->data; + data->callback = callback; + return 0; +} + +static int kscan_charlieplex_enable(const struct device *dev) { + struct kscan_charlieplex_data *data = dev->data; + data->scan_time = k_uptime_get(); + + // Read will automatically start interrupts/polling once done. + return kscan_charlieplex_read(dev); +} + +static int kscan_charlieplex_disable(const struct device *dev) { + struct kscan_charlieplex_data *data = dev->data; + k_work_cancel_delayable(&data->work); + + const struct kscan_charlieplex_config *config = dev->config; + if (config->use_interrupt) { + return kscan_charlieplex_interrupt_configure(dev, GPIO_INT_DISABLE); + } + return 0; +} + +static int kscan_charlieplex_init_inputs(const struct device *dev) { + const struct kscan_charlieplex_config *config = dev->config; + + for (int i = 0; i < config->cells.len; i++) { + int err = kscan_charlieplex_set_as_input(&config->cells.gpios[i]); + if (err) { + return err; + } + } + + return 0; +} + +static int kscan_charlieplex_init_interrupt(const struct device *dev) { + struct kscan_charlieplex_data *data = dev->data; + + const struct kscan_charlieplex_config *config = dev->config; + const struct gpio_dt_spec *gpio = &config->interrupt; + int err = kscan_charlieplex_set_as_input(gpio); + if (err) { + return err; + } + + gpio_init_callback(&data->irq_callback, kscan_charlieplex_irq_callback, BIT(gpio->pin)); + err = gpio_add_callback(gpio->port, &data->irq_callback); + if (err) { + LOG_ERR("Error adding the callback to the input device: %i", err); + } + return err; +} + +static int kscan_charlieplex_init(const struct device *dev) { + struct kscan_charlieplex_data *data = dev->data; + + data->dev = dev; + + kscan_charlieplex_init_inputs(dev); + kscan_charlieplex_set_all_outputs(dev, 0); + + const struct kscan_charlieplex_config *config = dev->config; + if (config->use_interrupt) { + kscan_charlieplex_init_interrupt(dev); + } + k_work_init_delayable(&data->work, kscan_charlieplex_work_handler); + return 0; +} + +static const struct kscan_driver_api kscan_charlieplex_api = { + .config = kscan_charlieplex_configure, + .enable_callback = kscan_charlieplex_enable, + .disable_callback = kscan_charlieplex_disable, +}; + +#define KSCAN_CHARLIEPLEX_INIT(n) \ + BUILD_ASSERT(INST_DEBOUNCE_PRESS_MS(n) <= DEBOUNCE_COUNTER_MAX, \ + "ZMK_KSCAN_DEBOUNCE_PRESS_MS or debounce-press-ms is too large"); \ + BUILD_ASSERT(INST_DEBOUNCE_RELEASE_MS(n) <= DEBOUNCE_COUNTER_MAX, \ + "ZMK_KSCAN_DEBOUNCE_RELEASE_MS or debounce-release-ms is too large"); \ + \ + static struct zmk_debounce_state kscan_charlieplex_state_##n[INST_CHARLIEPLEX_LEN(n)]; \ + static const struct gpio_dt_spec kscan_charlieplex_cells_##n[] = { \ + LISTIFY(INST_LEN(n), KSCAN_GPIO_CFG_INIT, (, ), n)}; \ + static struct kscan_charlieplex_data kscan_charlieplex_data_##n = { \ + .charlieplex_state = kscan_charlieplex_state_##n, \ + }; \ + \ + static struct kscan_charlieplex_config kscan_charlieplex_config_##n = { \ + .cells = KSCAN_GPIO_LIST(kscan_charlieplex_cells_##n), \ + .debounce_config = \ + { \ + .debounce_press_ms = INST_DEBOUNCE_PRESS_MS(n), \ + .debounce_release_ms = INST_DEBOUNCE_RELEASE_MS(n), \ + }, \ + .debounce_scan_period_ms = DT_INST_PROP(n, debounce_scan_period_ms), \ + COND_ANY_POLLING((.poll_period_ms = DT_INST_PROP(n, poll_period_ms), )) \ + COND_POLL_AND_INTR((.use_interrupt = INST_INTR_DEFINED(n), )) \ + COND_THIS_INTERRUPT(n, (.interrupt = KSCAN_INTR_CFG_INIT(n), ))}; \ + \ + DEVICE_DT_INST_DEFINE(n, &kscan_charlieplex_init, NULL, &kscan_charlieplex_data_##n, \ + &kscan_charlieplex_config_##n, APPLICATION, \ + CONFIG_APPLICATION_INIT_PRIORITY, &kscan_charlieplex_api); + +DT_INST_FOREACH_STATUS_OKAY(KSCAN_CHARLIEPLEX_INIT); diff --git a/app/module/drivers/kscan/kscan_gpio_demux.c b/app/module/drivers/kscan/kscan_gpio_demux.c new file mode 100644 index 000000000000..2cbe116d9f24 --- /dev/null +++ b/app/module/drivers/kscan/kscan_gpio_demux.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_kscan_gpio_demux + +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +// Helper macro +#define PWR_TWO(x) (1 << (x)) + +// Define row and col cfg +#define _KSCAN_GPIO_CFG_INIT(n, prop, idx) GPIO_DT_SPEC_GET_BY_IDX(n, prop, idx), + +// Check debounce config +#define CHECK_DEBOUNCE_CFG(n, a, b) COND_CODE_0(DT_INST_PROP(n, debounce_period), a, b) + +// Define the row and column lengths +#define INST_MATRIX_INPUTS(n) DT_INST_PROP_LEN(n, input_gpios) +#define INST_DEMUX_GPIOS(n) DT_INST_PROP_LEN(n, output_gpios) +#define INST_MATRIX_OUTPUTS(n) PWR_TWO(INST_DEMUX_GPIOS(n)) +#define POLL_INTERVAL(n) DT_INST_PROP(n, polling_interval_msec) + +#define GPIO_INST_INIT(n) \ + struct kscan_gpio_irq_callback_##n { \ + struct CHECK_DEBOUNCE_CFG(n, (k_work), (k_work_delayable)) * work; \ + struct gpio_callback callback; \ + const struct device *dev; \ + }; \ + \ + struct kscan_gpio_config_##n { \ + const struct gpio_dt_spec rows[INST_MATRIX_INPUTS(n)]; \ + const struct gpio_dt_spec cols[INST_DEMUX_GPIOS(n)]; \ + }; \ + \ + struct kscan_gpio_data_##n { \ + kscan_callback_t callback; \ + struct k_timer poll_timer; \ + struct CHECK_DEBOUNCE_CFG(n, (k_work), (k_work_delayable)) work; \ + bool matrix_state[INST_MATRIX_INPUTS(n)][INST_MATRIX_OUTPUTS(n)]; \ + const struct device *dev; \ + }; \ + /* IO/GPIO SETUP */ \ + static const struct gpio_dt_spec *kscan_gpio_input_specs_##n(const struct device *dev) { \ + const struct kscan_gpio_config_##n *cfg = dev->config; \ + return cfg->rows; \ + } \ + \ + static const struct gpio_dt_spec *kscan_gpio_output_specs_##n(const struct device *dev) { \ + const struct kscan_gpio_config_##n *cfg = dev->config; \ + return cfg->cols; \ + } \ + /* POLLING SETUP */ \ + static void kscan_gpio_timer_handler(struct k_timer *timer) { \ + struct kscan_gpio_data_##n *data = \ + CONTAINER_OF(timer, struct kscan_gpio_data_##n, poll_timer); \ + k_work_submit(&data->work.work); \ + } \ + \ + /* Read the state of the input GPIOs */ \ + /* This is the core matrix_scan func */ \ + static int kscan_gpio_read_##n(const struct device *dev) { \ + bool submit_follow_up_read = false; \ + struct kscan_gpio_data_##n *data = dev->data; \ + static bool read_state[INST_MATRIX_INPUTS(n)][INST_MATRIX_OUTPUTS(n)]; \ + for (int o = 0; o < INST_MATRIX_OUTPUTS(n); o++) { \ + /* Iterate over bits and set GPIOs accordingly */ \ + for (uint8_t bit = 0; bit < INST_DEMUX_GPIOS(n); bit++) { \ + uint8_t state = (o & (0b1 << bit)) >> bit; \ + const struct gpio_dt_spec *out_spec = &kscan_gpio_output_specs_##n(dev)[bit]; \ + gpio_pin_set_dt(out_spec, state); \ + } \ + /* Let the col settle before reading the rows */ \ + k_usleep(1); \ + \ + for (int i = 0; i < INST_MATRIX_INPUTS(n); i++) { \ + /* Get the input spec */ \ + const struct gpio_dt_spec *in_spec = &kscan_gpio_input_specs_##n(dev)[i]; \ + read_state[i][o] = gpio_pin_get_dt(in_spec) > 0; \ + } \ + } \ + for (int r = 0; r < INST_MATRIX_INPUTS(n); r++) { \ + for (int c = 0; c < INST_MATRIX_OUTPUTS(n); c++) { \ + bool pressed = read_state[r][c]; \ + submit_follow_up_read = (submit_follow_up_read || pressed); \ + if (pressed != data->matrix_state[r][c]) { \ + LOG_DBG("Sending event at %d,%d state %s", r, c, (pressed ? "on" : "off")); \ + data->matrix_state[r][c] = pressed; \ + data->callback(dev, r, c, pressed); \ + } \ + } \ + } \ + if (submit_follow_up_read) { \ + CHECK_DEBOUNCE_CFG(n, ({ k_work_submit(&data->work); }), \ + ({ k_work_reschedule(&data->work, K_MSEC(5)); })) \ + } \ + return 0; \ + } \ + \ + static void kscan_gpio_work_handler_##n(struct k_work *work) { \ + struct kscan_gpio_data_##n *data = CONTAINER_OF(work, struct kscan_gpio_data_##n, work); \ + kscan_gpio_read_##n(data->dev); \ + } \ + \ + static struct kscan_gpio_data_##n kscan_gpio_data_##n = {}; \ + \ + /* KSCAN API configure function */ \ + static int kscan_gpio_configure_##n(const struct device *dev, kscan_callback_t callback) { \ + LOG_DBG("KSCAN API configure"); \ + struct kscan_gpio_data_##n *data = dev->data; \ + if (!callback) { \ + return -EINVAL; \ + } \ + data->callback = callback; \ + LOG_DBG("Configured GPIO %d", n); \ + return 0; \ + }; \ + \ + /* KSCAN API enable function */ \ + static int kscan_gpio_enable_##n(const struct device *dev) { \ + LOG_DBG("KSCAN API enable"); \ + struct kscan_gpio_data_##n *data = dev->data; \ + /* TODO: we might want a follow up to hook into the sleep state hooks in Zephyr, */ \ + /* and disable this timer when we enter a sleep state */ \ + k_timer_start(&data->poll_timer, K_MSEC(POLL_INTERVAL(n)), K_MSEC(POLL_INTERVAL(n))); \ + return 0; \ + }; \ + \ + /* KSCAN API disable function */ \ + static int kscan_gpio_disable_##n(const struct device *dev) { \ + LOG_DBG("KSCAN API disable"); \ + struct kscan_gpio_data_##n *data = dev->data; \ + k_timer_stop(&data->poll_timer); \ + return 0; \ + }; \ + \ + /* GPIO init function*/ \ + static int kscan_gpio_init_##n(const struct device *dev) { \ + LOG_DBG("KSCAN GPIO init"); \ + struct kscan_gpio_data_##n *data = dev->data; \ + int err; \ + /* configure input devices*/ \ + for (int i = 0; i < INST_MATRIX_INPUTS(n); i++) { \ + const struct gpio_dt_spec *in_spec = &kscan_gpio_input_specs_##n(dev)[i]; \ + if (!device_is_ready(in_spec->port)) { \ + LOG_ERR("Unable to find input GPIO device"); \ + return -EINVAL; \ + } \ + err = gpio_pin_configure_dt(in_spec, GPIO_INPUT); \ + if (err) { \ + LOG_ERR("Unable to configure pin %d for input", in_spec->pin); \ + return err; \ + } else { \ + LOG_DBG("Configured pin %d for input", in_spec->pin); \ + } \ + if (err) { \ + LOG_ERR("Error adding the callback to the column device"); \ + return err; \ + } \ + } \ + /* configure output devices*/ \ + for (int o = 0; o < INST_DEMUX_GPIOS(n); o++) { \ + const struct gpio_dt_spec *out_spec = &kscan_gpio_output_specs_##n(dev)[o]; \ + if (!device_is_ready(out_spec->port)) { \ + LOG_ERR("Unable to find output GPIO device"); \ + return -EINVAL; \ + } \ + err = gpio_pin_configure_dt(out_spec, GPIO_OUTPUT_ACTIVE); \ + if (err) { \ + LOG_ERR("Unable to configure pin %d for output", out_spec->pin); \ + return err; \ + } else { \ + LOG_DBG("Configured pin %d for output", out_spec->pin); \ + } \ + } \ + data->dev = dev; \ + \ + k_timer_init(&data->poll_timer, kscan_gpio_timer_handler, NULL); \ + \ + (CHECK_DEBOUNCE_CFG(n, (k_work_init), (k_work_init_delayable)))( \ + &data->work, kscan_gpio_work_handler_##n); \ + return 0; \ + } \ + \ + static const struct kscan_driver_api gpio_driver_api_##n = { \ + .config = kscan_gpio_configure_##n, \ + .enable_callback = kscan_gpio_enable_##n, \ + .disable_callback = kscan_gpio_disable_##n, \ + }; \ + \ + static const struct kscan_gpio_config_##n kscan_gpio_config_##n = { \ + .rows = {DT_FOREACH_PROP_ELEM(DT_DRV_INST(n), input_gpios, _KSCAN_GPIO_CFG_INIT)}, \ + .cols = {DT_FOREACH_PROP_ELEM(DT_DRV_INST(n), output_gpios, _KSCAN_GPIO_CFG_INIT)}, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, kscan_gpio_init_##n, NULL, &kscan_gpio_data_##n, \ + &kscan_gpio_config_##n, POST_KERNEL, CONFIG_KSCAN_INIT_PRIORITY, \ + &gpio_driver_api_##n); + +DT_INST_FOREACH_STATUS_OKAY(GPIO_INST_INIT) diff --git a/app/module/drivers/kscan/kscan_gpio_direct.c b/app/module/drivers/kscan/kscan_gpio_direct.c new file mode 100644 index 000000000000..5b227784dadc --- /dev/null +++ b/app/module/drivers/kscan/kscan_gpio_direct.c @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "kscan_gpio.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#define DT_DRV_COMPAT zmk_kscan_gpio_direct + +#if CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS >= 0 +#define INST_DEBOUNCE_PRESS_MS(n) CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS +#else +#define INST_DEBOUNCE_PRESS_MS(n) \ + DT_INST_PROP_OR(n, debounce_period, DT_INST_PROP(n, debounce_press_ms)) +#endif + +#if CONFIG_ZMK_KSCAN_DEBOUNCE_RELEASE_MS >= 0 +#define INST_DEBOUNCE_RELEASE_MS(n) CONFIG_ZMK_KSCAN_DEBOUNCE_RELEASE_MS +#else +#define INST_DEBOUNCE_RELEASE_MS(n) \ + DT_INST_PROP_OR(n, debounce_period, DT_INST_PROP(n, debounce_release_ms)) +#endif + +#define USE_POLLING IS_ENABLED(CONFIG_ZMK_KSCAN_DIRECT_POLLING) +#define USE_INTERRUPTS (!USE_POLLING) + +#define COND_INTERRUPTS(code) COND_CODE_1(CONFIG_ZMK_KSCAN_DIRECT_POLLING, (), code) +#define COND_POLL_OR_INTERRUPTS(pollcode, intcode) \ + COND_CODE_1(CONFIG_ZMK_KSCAN_DIRECT_POLLING, pollcode, intcode) + +#define INST_INPUTS_LEN(n) DT_INST_PROP_LEN(n, input_gpios) +#define KSCAN_DIRECT_INPUT_CFG_INIT(idx, inst_idx) \ + KSCAN_GPIO_GET_BY_IDX(DT_DRV_INST(inst_idx), input_gpios, idx) + +struct kscan_direct_irq_callback { + const struct device *dev; + struct gpio_callback callback; +}; + +struct kscan_direct_data { + const struct device *dev; + struct kscan_gpio_list inputs; + kscan_callback_t callback; + struct k_work_delayable work; +#if USE_INTERRUPTS + /** Array of length config->inputs.len */ + struct kscan_direct_irq_callback *irqs; +#endif + /** Timestamp of the current or scheduled scan. */ + int64_t scan_time; + /** Current state of the inputs as an array of length config->inputs.len */ + struct zmk_debounce_state *pin_state; +}; + +struct kscan_direct_config { + struct zmk_debounce_config debounce_config; + int32_t debounce_scan_period_ms; + int32_t poll_period_ms; + bool toggle_mode; +}; + +#if USE_INTERRUPTS +static int kscan_direct_interrupt_configure(const struct device *dev, const gpio_flags_t flags) { + const struct kscan_direct_data *data = dev->data; + + for (int i = 0; i < data->inputs.len; i++) { + const struct gpio_dt_spec *gpio = &data->inputs.gpios[i].spec; + + int err = gpio_pin_interrupt_configure_dt(gpio, flags); + if (err) { + LOG_ERR("Unable to configure interrupt for pin %u on %s", gpio->pin, gpio->port->name); + return err; + } + } + + return 0; +} +#endif + +#if USE_INTERRUPTS +static int kscan_direct_interrupt_enable(const struct device *dev) { + return kscan_direct_interrupt_configure(dev, GPIO_INT_LEVEL_ACTIVE); +} +#endif + +#if USE_INTERRUPTS +static int kscan_direct_interrupt_disable(const struct device *dev) { + return kscan_direct_interrupt_configure(dev, GPIO_INT_DISABLE); +} +#endif + +#if USE_INTERRUPTS +static void kscan_direct_irq_callback_handler(const struct device *port, struct gpio_callback *cb, + const gpio_port_pins_t pin) { + struct kscan_direct_irq_callback *irq_data = + CONTAINER_OF(cb, struct kscan_direct_irq_callback, callback); + struct kscan_direct_data *data = irq_data->dev->data; + + // Disable our interrupts temporarily to avoid re-entry while we scan. + kscan_direct_interrupt_disable(data->dev); + + data->scan_time = k_uptime_get(); + + k_work_reschedule(&data->work, K_NO_WAIT); +} +#endif + +static gpio_flags_t kscan_gpio_get_extra_flags(const struct gpio_dt_spec *gpio, bool active) { + if (!active) { + return ((BIT(0) & gpio->dt_flags) ? GPIO_PULL_UP : GPIO_PULL_DOWN); + } + return 0; +} + +static int kscan_inputs_set_flags(const struct kscan_gpio_list *inputs, + const struct gpio_dt_spec *active_gpio) { + for (int i = 0; i < inputs->len; i++) { + const bool active = &inputs->gpios[i].spec == active_gpio; + const gpio_flags_t extra_flags = + GPIO_INPUT | kscan_gpio_get_extra_flags(&inputs->gpios[i].spec, active); + LOG_DBG("Extra flags equal to: %d", extra_flags); + + int err = gpio_pin_configure_dt(&inputs->gpios[i].spec, extra_flags); + if (err) { + LOG_ERR("Unable to configure flags on pin %d on %s", inputs->gpios[i].spec.pin, + inputs->gpios[i].spec.port->name); + return err; + } + } + return 0; +} + +static void kscan_direct_read_continue(const struct device *dev) { + const struct kscan_direct_config *config = dev->config; + struct kscan_direct_data *data = dev->data; + + data->scan_time += config->debounce_scan_period_ms; + + k_work_reschedule(&data->work, K_TIMEOUT_ABS_MS(data->scan_time)); +} + +static void kscan_direct_read_end(const struct device *dev) { +#if USE_INTERRUPTS + // Return to waiting for an interrupt. + kscan_direct_interrupt_enable(dev); +#else + struct kscan_direct_data *data = dev->data; + const struct kscan_direct_config *config = dev->config; + + data->scan_time += config->poll_period_ms; + + // Return to polling slowly. + k_work_reschedule(&data->work, K_TIMEOUT_ABS_MS(data->scan_time)); +#endif +} + +static int kscan_direct_read(const struct device *dev) { + struct kscan_direct_data *data = dev->data; + const struct kscan_direct_config *config = dev->config; + + // Read the inputs. + struct kscan_gpio_port_state state = {0}; + + for (int i = 0; i < data->inputs.len; i++) { + const struct kscan_gpio *gpio = &data->inputs.gpios[i]; + + const int active = kscan_gpio_pin_get(gpio, &state); + if (active < 0) { + LOG_ERR("Failed to read port %s: %i", gpio->spec.port->name, active); + return active; + } + + zmk_debounce_update(&data->pin_state[gpio->index], active, config->debounce_scan_period_ms, + &config->debounce_config); + } + + // Process the new state. + bool continue_scan = false; + + for (int i = 0; i < data->inputs.len; i++) { + const struct kscan_gpio *gpio = &data->inputs.gpios[i]; + struct zmk_debounce_state *state = &data->pin_state[gpio->index]; + + if (zmk_debounce_get_changed(state)) { + const bool pressed = zmk_debounce_is_pressed(state); + + LOG_DBG("Sending event at 0,%i state %s", gpio->index, pressed ? "on" : "off"); + data->callback(dev, 0, gpio->index, pressed); + if (config->toggle_mode && pressed) { + kscan_inputs_set_flags(&data->inputs, &gpio->spec); + } + } + + continue_scan = continue_scan || zmk_debounce_is_active(state); + } + + if (continue_scan) { + // At least one key is pressed or the debouncer has not yet decided if + // it is pressed. Poll quickly until everything is released. + kscan_direct_read_continue(dev); + } else { + // All keys are released. Return to normal. + kscan_direct_read_end(dev); + } + + return 0; +} + +static void kscan_direct_work_handler(struct k_work *work) { + struct k_work_delayable *dwork = CONTAINER_OF(work, struct k_work_delayable, work); + struct kscan_direct_data *data = CONTAINER_OF(dwork, struct kscan_direct_data, work); + kscan_direct_read(data->dev); +} + +static int kscan_direct_configure(const struct device *dev, kscan_callback_t callback) { + struct kscan_direct_data *data = dev->data; + + if (!callback) { + return -EINVAL; + } + + data->callback = callback; + return 0; +} + +static int kscan_direct_enable(const struct device *dev) { + struct kscan_direct_data *data = dev->data; + + data->scan_time = k_uptime_get(); + + // Read will automatically start interrupts/polling once done. + return kscan_direct_read(dev); +} + +static int kscan_direct_disable(const struct device *dev) { + struct kscan_direct_data *data = dev->data; + + k_work_cancel_delayable(&data->work); + +#if USE_INTERRUPTS + return kscan_direct_interrupt_disable(dev); +#else + return 0; +#endif +} + +static int kscan_direct_init_input_inst(const struct device *dev, const struct gpio_dt_spec *gpio, + const int index, bool toggle_mode) { + if (!device_is_ready(gpio->port)) { + LOG_ERR("GPIO is not ready: %s", gpio->port->name); + return -ENODEV; + } + int err = gpio_pin_configure_dt( + gpio, GPIO_INPUT | (toggle_mode ? kscan_gpio_get_extra_flags(gpio, false) : 0)); + if (err) { + LOG_ERR("Unable to configure pin %u on %s for input", gpio->pin, gpio->port->name); + return err; + } + + LOG_DBG("Configured pin %u on %s for input", gpio->pin, gpio->port->name); + +#if USE_INTERRUPTS + struct kscan_direct_data *data = dev->data; + struct kscan_direct_irq_callback *irq = &data->irqs[index]; + + irq->dev = dev; + gpio_init_callback(&irq->callback, kscan_direct_irq_callback_handler, BIT(gpio->pin)); + err = gpio_add_callback(gpio->port, &irq->callback); + if (err) { + LOG_ERR("Error adding the callback to the input device: %i", err); + return err; + } +#endif + + return 0; +} + +static int kscan_direct_init_inputs(const struct device *dev) { + const struct kscan_direct_data *data = dev->data; + const struct kscan_direct_config *config = dev->config; + + for (int i = 0; i < data->inputs.len; i++) { + const struct gpio_dt_spec *gpio = &data->inputs.gpios[i].spec; + int err = kscan_direct_init_input_inst(dev, gpio, i, config->toggle_mode); + if (err) { + return err; + } + } + + return 0; +} + +static int kscan_direct_init(const struct device *dev) { + struct kscan_direct_data *data = dev->data; + + data->dev = dev; + + // Sort inputs by port so we can read each port just once per scan. + kscan_gpio_list_sort_by_port(&data->inputs); + + kscan_direct_init_inputs(dev); + + k_work_init_delayable(&data->work, kscan_direct_work_handler); + + return 0; +} + +static const struct kscan_driver_api kscan_direct_api = { + .config = kscan_direct_configure, + .enable_callback = kscan_direct_enable, + .disable_callback = kscan_direct_disable, +}; + +#define KSCAN_DIRECT_INIT(n) \ + BUILD_ASSERT(INST_DEBOUNCE_PRESS_MS(n) <= DEBOUNCE_COUNTER_MAX, \ + "ZMK_KSCAN_DEBOUNCE_PRESS_MS or debounce-press-ms is too large"); \ + BUILD_ASSERT(INST_DEBOUNCE_RELEASE_MS(n) <= DEBOUNCE_COUNTER_MAX, \ + "ZMK_KSCAN_DEBOUNCE_RELEASE_MS or debounce-release-ms is too large"); \ + \ + static struct kscan_gpio kscan_direct_inputs_##n[] = { \ + LISTIFY(INST_INPUTS_LEN(n), KSCAN_DIRECT_INPUT_CFG_INIT, (, ), n)}; \ + \ + static struct zmk_debounce_state kscan_direct_state_##n[INST_INPUTS_LEN(n)]; \ + \ + COND_INTERRUPTS( \ + (static struct kscan_direct_irq_callback kscan_direct_irqs_##n[INST_INPUTS_LEN(n)];)) \ + \ + static struct kscan_direct_data kscan_direct_data_##n = { \ + .inputs = KSCAN_GPIO_LIST(kscan_direct_inputs_##n), \ + .pin_state = kscan_direct_state_##n, \ + COND_INTERRUPTS((.irqs = kscan_direct_irqs_##n, ))}; \ + \ + static struct kscan_direct_config kscan_direct_config_##n = { \ + .debounce_config = \ + { \ + .debounce_press_ms = INST_DEBOUNCE_PRESS_MS(n), \ + .debounce_release_ms = INST_DEBOUNCE_RELEASE_MS(n), \ + }, \ + .debounce_scan_period_ms = DT_INST_PROP(n, debounce_scan_period_ms), \ + .poll_period_ms = DT_INST_PROP(n, poll_period_ms), \ + .toggle_mode = DT_INST_PROP(n, toggle_mode), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, &kscan_direct_init, NULL, &kscan_direct_data_##n, \ + &kscan_direct_config_##n, POST_KERNEL, CONFIG_KSCAN_INIT_PRIORITY, \ + &kscan_direct_api); + +DT_INST_FOREACH_STATUS_OKAY(KSCAN_DIRECT_INIT); diff --git a/app/module/drivers/kscan/kscan_gpio_matrix.c b/app/module/drivers/kscan/kscan_gpio_matrix.c new file mode 100644 index 000000000000..0d8a3190659a --- /dev/null +++ b/app/module/drivers/kscan/kscan_gpio_matrix.c @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2020-2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "kscan_gpio.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#define DT_DRV_COMPAT zmk_kscan_gpio_matrix + +#define INST_DIODE_DIR(n) DT_ENUM_IDX(DT_DRV_INST(n), diode_direction) +#define COND_DIODE_DIR(n, row2col_code, col2row_code) \ + COND_CODE_0(INST_DIODE_DIR(n), row2col_code, col2row_code) + +#define INST_ROWS_LEN(n) DT_INST_PROP_LEN(n, row_gpios) +#define INST_COLS_LEN(n) DT_INST_PROP_LEN(n, col_gpios) +#define INST_MATRIX_LEN(n) (INST_ROWS_LEN(n) * INST_COLS_LEN(n)) +#define INST_INPUTS_LEN(n) COND_DIODE_DIR(n, (INST_COLS_LEN(n)), (INST_ROWS_LEN(n))) + +#if CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS >= 0 +#define INST_DEBOUNCE_PRESS_MS(n) CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS +#else +#define INST_DEBOUNCE_PRESS_MS(n) \ + DT_INST_PROP_OR(n, debounce_period, DT_INST_PROP(n, debounce_press_ms)) +#endif + +#if CONFIG_ZMK_KSCAN_DEBOUNCE_RELEASE_MS >= 0 +#define INST_DEBOUNCE_RELEASE_MS(n) CONFIG_ZMK_KSCAN_DEBOUNCE_RELEASE_MS +#else +#define INST_DEBOUNCE_RELEASE_MS(n) \ + DT_INST_PROP_OR(n, debounce_period, DT_INST_PROP(n, debounce_release_ms)) +#endif + +#define USE_POLLING IS_ENABLED(CONFIG_ZMK_KSCAN_MATRIX_POLLING) +#define USE_INTERRUPTS (!USE_POLLING) + +#define COND_INTERRUPTS(code) COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), code) +#define COND_POLL_OR_INTERRUPTS(pollcode, intcode) \ + COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, pollcode, intcode) + +#define KSCAN_GPIO_ROW_CFG_INIT(idx, inst_idx) \ + KSCAN_GPIO_GET_BY_IDX(DT_DRV_INST(inst_idx), row_gpios, idx) +#define KSCAN_GPIO_COL_CFG_INIT(idx, inst_idx) \ + KSCAN_GPIO_GET_BY_IDX(DT_DRV_INST(inst_idx), col_gpios, idx) + +enum kscan_diode_direction { + KSCAN_ROW2COL, + KSCAN_COL2ROW, +}; + +struct kscan_matrix_irq_callback { + const struct device *dev; + struct gpio_callback callback; +}; + +struct kscan_matrix_data { + const struct device *dev; + struct kscan_gpio_list inputs; + kscan_callback_t callback; + struct k_work_delayable work; +#if USE_INTERRUPTS + /** Array of length config->inputs.len */ + struct kscan_matrix_irq_callback *irqs; +#endif + /** Timestamp of the current or scheduled scan. */ + int64_t scan_time; + /** + * Current state of the matrix as a flattened 2D array of length + * (config->rows * config->cols) + */ + struct zmk_debounce_state *matrix_state; +}; + +struct kscan_matrix_config { + struct kscan_gpio_list outputs; + struct zmk_debounce_config debounce_config; + size_t rows; + size_t cols; + int32_t debounce_scan_period_ms; + int32_t poll_period_ms; + enum kscan_diode_direction diode_direction; +}; + +/** + * Get the index into a matrix state array from a row and column. + */ +static int state_index_rc(const struct kscan_matrix_config *config, const int row, const int col) { + __ASSERT(row < config->rows, "Invalid row %i", row); + __ASSERT(col < config->cols, "Invalid column %i", col); + + return (col * config->rows) + row; +} + +/** + * Get the index into a matrix state array from input/output pin indices. + */ +static int state_index_io(const struct kscan_matrix_config *config, const int input_idx, + const int output_idx) { + return (config->diode_direction == KSCAN_ROW2COL) + ? state_index_rc(config, output_idx, input_idx) + : state_index_rc(config, input_idx, output_idx); +} + +static int kscan_matrix_set_all_outputs(const struct device *dev, const int value) { + const struct kscan_matrix_config *config = dev->config; + + for (int i = 0; i < config->outputs.len; i++) { + const struct gpio_dt_spec *gpio = &config->outputs.gpios[i].spec; + + int err = gpio_pin_set_dt(gpio, value); + if (err) { + LOG_ERR("Failed to set output %i to %i: %i", i, value, err); + return err; + } + } + + return 0; +} + +#if USE_INTERRUPTS +static int kscan_matrix_interrupt_configure(const struct device *dev, const gpio_flags_t flags) { + const struct kscan_matrix_data *data = dev->data; + + for (int i = 0; i < data->inputs.len; i++) { + const struct gpio_dt_spec *gpio = &data->inputs.gpios[i].spec; + + int err = gpio_pin_interrupt_configure_dt(gpio, flags); + if (err) { + LOG_ERR("Unable to configure interrupt for pin %u on %s", gpio->pin, gpio->port->name); + return err; + } + } + + return 0; +} +#endif + +#if USE_INTERRUPTS +static int kscan_matrix_interrupt_enable(const struct device *dev) { + int err = kscan_matrix_interrupt_configure(dev, GPIO_INT_LEVEL_ACTIVE); + if (err) { + return err; + } + + // While interrupts are enabled, set all outputs active so a pressed key + // will trigger an interrupt. + return kscan_matrix_set_all_outputs(dev, 1); +} +#endif + +#if USE_INTERRUPTS +static int kscan_matrix_interrupt_disable(const struct device *dev) { + int err = kscan_matrix_interrupt_configure(dev, GPIO_INT_DISABLE); + if (err) { + return err; + } + + // While interrupts are disabled, set all outputs inactive so + // kscan_matrix_read() can scan them one by one. + return kscan_matrix_set_all_outputs(dev, 0); +} +#endif + +#if USE_INTERRUPTS +static void kscan_matrix_irq_callback_handler(const struct device *port, struct gpio_callback *cb, + const gpio_port_pins_t pin) { + struct kscan_matrix_irq_callback *irq_data = + CONTAINER_OF(cb, struct kscan_matrix_irq_callback, callback); + struct kscan_matrix_data *data = irq_data->dev->data; + + // Disable our interrupts temporarily to avoid re-entry while we scan. + kscan_matrix_interrupt_disable(data->dev); + + data->scan_time = k_uptime_get(); + + k_work_reschedule(&data->work, K_NO_WAIT); +} +#endif + +static void kscan_matrix_read_continue(const struct device *dev) { + const struct kscan_matrix_config *config = dev->config; + struct kscan_matrix_data *data = dev->data; + + data->scan_time += config->debounce_scan_period_ms; + + k_work_reschedule(&data->work, K_TIMEOUT_ABS_MS(data->scan_time)); +} + +static void kscan_matrix_read_end(const struct device *dev) { +#if USE_INTERRUPTS + // Return to waiting for an interrupt. + kscan_matrix_interrupt_enable(dev); +#else + struct kscan_matrix_data *data = dev->data; + const struct kscan_matrix_config *config = dev->config; + + data->scan_time += config->poll_period_ms; + + // Return to polling slowly. + k_work_reschedule(&data->work, K_TIMEOUT_ABS_MS(data->scan_time)); +#endif +} + +static int kscan_matrix_read(const struct device *dev) { + struct kscan_matrix_data *data = dev->data; + const struct kscan_matrix_config *config = dev->config; + + // Scan the matrix. + for (int i = 0; i < config->outputs.len; i++) { + const struct kscan_gpio *out_gpio = &config->outputs.gpios[i]; + + int err = gpio_pin_set_dt(&out_gpio->spec, 1); + if (err) { + LOG_ERR("Failed to set output %i active: %i", out_gpio->index, err); + return err; + } + +#if CONFIG_ZMK_KSCAN_MATRIX_WAIT_BEFORE_INPUTS > 0 + k_busy_wait(CONFIG_ZMK_KSCAN_MATRIX_WAIT_BEFORE_INPUTS); +#endif + struct kscan_gpio_port_state state = {0}; + + for (int j = 0; j < data->inputs.len; j++) { + const struct kscan_gpio *in_gpio = &data->inputs.gpios[j]; + + const int index = state_index_io(config, in_gpio->index, out_gpio->index); + const int active = kscan_gpio_pin_get(in_gpio, &state); + if (active < 0) { + LOG_ERR("Failed to read port %s: %i", in_gpio->spec.port->name, active); + return active; + } + + zmk_debounce_update(&data->matrix_state[index], active, config->debounce_scan_period_ms, + &config->debounce_config); + } + + err = gpio_pin_set_dt(&out_gpio->spec, 0); + if (err) { + LOG_ERR("Failed to set output %i inactive: %i", out_gpio->index, err); + return err; + } + +#if CONFIG_ZMK_KSCAN_MATRIX_WAIT_BETWEEN_OUTPUTS > 0 + k_busy_wait(CONFIG_ZMK_KSCAN_MATRIX_WAIT_BETWEEN_OUTPUTS); +#endif + } + + // Process the new state. + bool continue_scan = false; + + for (int r = 0; r < config->rows; r++) { + for (int c = 0; c < config->cols; c++) { + const int index = state_index_rc(config, r, c); + struct zmk_debounce_state *state = &data->matrix_state[index]; + + if (zmk_debounce_get_changed(state)) { + const bool pressed = zmk_debounce_is_pressed(state); + + LOG_DBG("Sending event at %i,%i state %s", r, c, pressed ? "on" : "off"); + data->callback(dev, r, c, pressed); + } + + continue_scan = continue_scan || zmk_debounce_is_active(state); + } + } + + if (continue_scan) { + // At least one key is pressed or the debouncer has not yet decided if + // it is pressed. Poll quickly until everything is released. + kscan_matrix_read_continue(dev); + } else { + // All keys are released. Return to normal. + kscan_matrix_read_end(dev); + } + + return 0; +} + +static void kscan_matrix_work_handler(struct k_work *work) { + struct k_work_delayable *dwork = CONTAINER_OF(work, struct k_work_delayable, work); + struct kscan_matrix_data *data = CONTAINER_OF(dwork, struct kscan_matrix_data, work); + kscan_matrix_read(data->dev); +} + +static int kscan_matrix_configure(const struct device *dev, const kscan_callback_t callback) { + struct kscan_matrix_data *data = dev->data; + + if (!callback) { + return -EINVAL; + } + + data->callback = callback; + return 0; +} + +static int kscan_matrix_enable(const struct device *dev) { + struct kscan_matrix_data *data = dev->data; + + data->scan_time = k_uptime_get(); + + // Read will automatically start interrupts/polling once done. + return kscan_matrix_read(dev); +} + +static int kscan_matrix_disable(const struct device *dev) { + struct kscan_matrix_data *data = dev->data; + + k_work_cancel_delayable(&data->work); + +#if USE_INTERRUPTS + return kscan_matrix_interrupt_disable(dev); +#else + return 0; +#endif +} + +static int kscan_matrix_init_input_inst(const struct device *dev, const struct kscan_gpio *gpio) { + if (!device_is_ready(gpio->spec.port)) { + LOG_ERR("GPIO is not ready: %s", gpio->spec.port->name); + return -ENODEV; + } + + int err = gpio_pin_configure_dt(&gpio->spec, GPIO_INPUT); + if (err) { + LOG_ERR("Unable to configure pin %u on %s for input", gpio->spec.pin, + gpio->spec.port->name); + return err; + } + + LOG_DBG("Configured pin %u on %s for input", gpio->spec.pin, gpio->spec.port->name); + +#if USE_INTERRUPTS + struct kscan_matrix_data *data = dev->data; + struct kscan_matrix_irq_callback *irq = &data->irqs[gpio->index]; + + irq->dev = dev; + gpio_init_callback(&irq->callback, kscan_matrix_irq_callback_handler, BIT(gpio->spec.pin)); + err = gpio_add_callback(gpio->spec.port, &irq->callback); + if (err) { + LOG_ERR("Error adding the callback to the input device: %i", err); + return err; + } +#endif + + return 0; +} + +static int kscan_matrix_init_inputs(const struct device *dev) { + const struct kscan_matrix_data *data = dev->data; + + for (int i = 0; i < data->inputs.len; i++) { + const struct kscan_gpio *gpio = &data->inputs.gpios[i]; + int err = kscan_matrix_init_input_inst(dev, gpio); + if (err) { + return err; + } + } + + return 0; +} + +static int kscan_matrix_init_output_inst(const struct device *dev, + const struct gpio_dt_spec *gpio) { + if (!device_is_ready(gpio->port)) { + LOG_ERR("GPIO is not ready: %s", gpio->port->name); + return -ENODEV; + } + + int err = gpio_pin_configure_dt(gpio, GPIO_OUTPUT); + if (err) { + LOG_ERR("Unable to configure pin %u on %s for output", gpio->pin, gpio->port->name); + return err; + } + + LOG_DBG("Configured pin %u on %s for output", gpio->pin, gpio->port->name); + + return 0; +} + +static int kscan_matrix_init_outputs(const struct device *dev) { + const struct kscan_matrix_config *config = dev->config; + + for (int i = 0; i < config->outputs.len; i++) { + const struct gpio_dt_spec *gpio = &config->outputs.gpios[i].spec; + int err = kscan_matrix_init_output_inst(dev, gpio); + if (err) { + return err; + } + } + + return 0; +} + +static int kscan_matrix_init(const struct device *dev) { + struct kscan_matrix_data *data = dev->data; + + data->dev = dev; + + // Sort inputs by port so we can read each port just once per scan. + kscan_gpio_list_sort_by_port(&data->inputs); + + kscan_matrix_init_inputs(dev); + kscan_matrix_init_outputs(dev); + kscan_matrix_set_all_outputs(dev, 0); + + k_work_init_delayable(&data->work, kscan_matrix_work_handler); + + return 0; +} + +static const struct kscan_driver_api kscan_matrix_api = { + .config = kscan_matrix_configure, + .enable_callback = kscan_matrix_enable, + .disable_callback = kscan_matrix_disable, +}; + +#define KSCAN_MATRIX_INIT(n) \ + BUILD_ASSERT(INST_DEBOUNCE_PRESS_MS(n) <= DEBOUNCE_COUNTER_MAX, \ + "ZMK_KSCAN_DEBOUNCE_PRESS_MS or debounce-press-ms is too large"); \ + BUILD_ASSERT(INST_DEBOUNCE_RELEASE_MS(n) <= DEBOUNCE_COUNTER_MAX, \ + "ZMK_KSCAN_DEBOUNCE_RELEASE_MS or debounce-release-ms is too large"); \ + \ + static struct kscan_gpio kscan_matrix_rows_##n[] = { \ + LISTIFY(INST_ROWS_LEN(n), KSCAN_GPIO_ROW_CFG_INIT, (, ), n)}; \ + \ + static struct kscan_gpio kscan_matrix_cols_##n[] = { \ + LISTIFY(INST_COLS_LEN(n), KSCAN_GPIO_COL_CFG_INIT, (, ), n)}; \ + \ + static struct zmk_debounce_state kscan_matrix_state_##n[INST_MATRIX_LEN(n)]; \ + \ + COND_INTERRUPTS( \ + (static struct kscan_matrix_irq_callback kscan_matrix_irqs_##n[INST_INPUTS_LEN(n)];)) \ + \ + static struct kscan_matrix_data kscan_matrix_data_##n = { \ + .inputs = \ + KSCAN_GPIO_LIST(COND_DIODE_DIR(n, (kscan_matrix_cols_##n), (kscan_matrix_rows_##n))), \ + .matrix_state = kscan_matrix_state_##n, \ + COND_INTERRUPTS((.irqs = kscan_matrix_irqs_##n, ))}; \ + \ + static struct kscan_matrix_config kscan_matrix_config_##n = { \ + .rows = ARRAY_SIZE(kscan_matrix_rows_##n), \ + .cols = ARRAY_SIZE(kscan_matrix_cols_##n), \ + .outputs = \ + KSCAN_GPIO_LIST(COND_DIODE_DIR(n, (kscan_matrix_rows_##n), (kscan_matrix_cols_##n))), \ + .debounce_config = \ + { \ + .debounce_press_ms = INST_DEBOUNCE_PRESS_MS(n), \ + .debounce_release_ms = INST_DEBOUNCE_RELEASE_MS(n), \ + }, \ + .debounce_scan_period_ms = DT_INST_PROP(n, debounce_scan_period_ms), \ + .poll_period_ms = DT_INST_PROP(n, poll_period_ms), \ + .diode_direction = INST_DIODE_DIR(n), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, &kscan_matrix_init, NULL, &kscan_matrix_data_##n, \ + &kscan_matrix_config_##n, POST_KERNEL, CONFIG_KSCAN_INIT_PRIORITY, \ + &kscan_matrix_api); + +DT_INST_FOREACH_STATUS_OKAY(KSCAN_MATRIX_INIT); diff --git a/app/module/drivers/kscan/kscan_mock.c b/app/module/drivers/kscan/kscan_mock.c new file mode 100644 index 000000000000..604e164cbc52 --- /dev/null +++ b/app/module/drivers/kscan/kscan_mock.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_kscan_mock + +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include + +struct kscan_mock_data { + kscan_callback_t callback; + + uint32_t event_index; + struct k_work_delayable work; + const struct device *dev; +}; + +static int kscan_mock_disable_callback(const struct device *dev) { + struct kscan_mock_data *data = dev->data; + + k_work_cancel_delayable(&data->work); + return 0; +} + +static int kscan_mock_configure(const struct device *dev, kscan_callback_t callback) { + struct kscan_mock_data *data = dev->data; + + if (!callback) { + return -EINVAL; + } + + data->event_index = 0; + data->callback = callback; + + return 0; +} + +#define MOCK_INST_INIT(n) \ + struct kscan_mock_config_##n { \ + uint32_t events[DT_INST_PROP_LEN(n, events)]; \ + bool exit_after; \ + }; \ + static void kscan_mock_schedule_next_event_##n(const struct device *dev) { \ + struct kscan_mock_data *data = dev->data; \ + const struct kscan_mock_config_##n *cfg = dev->config; \ + if (data->event_index < DT_INST_PROP_LEN(n, events)) { \ + uint32_t ev = cfg->events[data->event_index]; \ + LOG_DBG("delaying next keypress: %d", ZMK_MOCK_MSEC(ev)); \ + k_work_schedule(&data->work, K_MSEC(ZMK_MOCK_MSEC(ev))); \ + } else if (cfg->exit_after) { \ + LOG_DBG("Exiting"); \ + exit(0); \ + } \ + } \ + static void kscan_mock_work_handler_##n(struct k_work *work) { \ + struct kscan_mock_data *data = CONTAINER_OF(work, struct kscan_mock_data, work); \ + const struct kscan_mock_config_##n *cfg = data->dev->config; \ + uint32_t ev = cfg->events[data->event_index]; \ + LOG_DBG("ev %u row %d column %d state %d\n", ev, ZMK_MOCK_ROW(ev), ZMK_MOCK_COL(ev), \ + ZMK_MOCK_IS_PRESS(ev)); \ + data->callback(data->dev, ZMK_MOCK_ROW(ev), ZMK_MOCK_COL(ev), ZMK_MOCK_IS_PRESS(ev)); \ + kscan_mock_schedule_next_event_##n(data->dev); \ + data->event_index++; \ + } \ + static int kscan_mock_init_##n(const struct device *dev) { \ + struct kscan_mock_data *data = dev->data; \ + data->dev = dev; \ + k_work_init_delayable(&data->work, kscan_mock_work_handler_##n); \ + return 0; \ + } \ + static int kscan_mock_enable_callback_##n(const struct device *dev) { \ + kscan_mock_schedule_next_event_##n(dev); \ + return 0; \ + } \ + static const struct kscan_driver_api mock_driver_api_##n = { \ + .config = kscan_mock_configure, \ + .enable_callback = kscan_mock_enable_callback_##n, \ + .disable_callback = kscan_mock_disable_callback, \ + }; \ + static struct kscan_mock_data kscan_mock_data_##n; \ + static const struct kscan_mock_config_##n kscan_mock_config_##n = { \ + .events = DT_INST_PROP(n, events), .exit_after = DT_INST_PROP(n, exit_after)}; \ + DEVICE_DT_INST_DEFINE(n, kscan_mock_init_##n, NULL, &kscan_mock_data_##n, \ + &kscan_mock_config_##n, POST_KERNEL, CONFIG_KSCAN_INIT_PRIORITY, \ + &mock_driver_api_##n); + +DT_INST_FOREACH_STATUS_OKAY(MOCK_INST_INIT) diff --git a/app/module/drivers/sensor/CMakeLists.txt b/app/module/drivers/sensor/CMakeLists.txt new file mode 100644 index 000000000000..9654600a756a --- /dev/null +++ b/app/module/drivers/sensor/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2020-2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +add_subdirectory_ifdef(CONFIG_ZMK_BATTERY battery) +add_subdirectory_ifdef(CONFIG_EC11 ec11) +add_subdirectory_ifdef(CONFIG_MAX17048 max17048) diff --git a/app/module/drivers/sensor/Kconfig b/app/module/drivers/sensor/Kconfig new file mode 100644 index 000000000000..ad570c58c941 --- /dev/null +++ b/app/module/drivers/sensor/Kconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SENSOR + +rsource "battery/Kconfig" +rsource "ec11/Kconfig" +rsource "max17048/Kconfig" + +endif # SENSOR diff --git a/app/module/drivers/sensor/battery/CMakeLists.txt b/app/module/drivers/sensor/battery/CMakeLists.txt new file mode 100644 index 000000000000..1203e53a6be5 --- /dev/null +++ b/app/module/drivers/sensor/battery/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2020-2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +zephyr_include_directories(.) + +zephyr_library() + +zephyr_library_sources(battery_common.c) +zephyr_library_sources_ifdef(CONFIG_ZMK_BATTERY_NRF_VDDH battery_nrf_vddh.c) +zephyr_library_sources_ifdef(CONFIG_ZMK_BATTERY_VOLTAGE_DIVIDER battery_voltage_divider.c) \ No newline at end of file diff --git a/app/module/drivers/sensor/battery/Kconfig b/app/module/drivers/sensor/battery/Kconfig new file mode 100644 index 000000000000..703adebd44ed --- /dev/null +++ b/app/module/drivers/sensor/battery/Kconfig @@ -0,0 +1,28 @@ +# Copyright (c) 2020-2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +DT_COMPAT_ZMK_BATTERY_NRF_VDDH := zmk,battery-nrf-vddh +DT_COMPAT_ZMK_BATTERY_VOLTAGE_DIVIDER := zmk,battery-voltage-divider + +config ZMK_BATTERY + bool "ZMK battery monitoring" + help + Enable battery monitoring + +config ZMK_BATTERY_NRF_VDDH + bool + default $(dt_compat_enabled,$(DT_COMPAT_ZMK_BATTERY_NRF_VDDH)) + select ADC + select ZMK_BATTERY + depends on SENSOR + help + Enable ZMK nRF VDDH voltage driver for battery monitoring. + +config ZMK_BATTERY_VOLTAGE_DIVIDER + bool + default $(dt_compat_enabled,$(DT_COMPAT_ZMK_BATTERY_VOLTAGE_DIVIDER)) + select ADC + select ZMK_BATTERY + depends on SENSOR + help + Enable ZMK battery voltage divider driver for battery monitoring. diff --git a/app/module/drivers/sensor/battery/battery_common.c b/app/module/drivers/sensor/battery/battery_common.c new file mode 100644 index 000000000000..9afe2d5b4cac --- /dev/null +++ b/app/module/drivers/sensor/battery/battery_common.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#include "battery_common.h" + +int battery_channel_get(const struct battery_value *value, enum sensor_channel chan, + struct sensor_value *val_out) { + switch (chan) { + case SENSOR_CHAN_GAUGE_VOLTAGE: + val_out->val1 = value->millivolts / 1000; + val_out->val2 = (value->millivolts % 1000) * 1000U; + break; + + case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE: + val_out->val1 = value->state_of_charge; + val_out->val2 = 0; + break; + + default: + return -ENOTSUP; + } + + return 0; +} + +uint8_t lithium_ion_mv_to_pct(int16_t bat_mv) { + // Simple linear approximation of a battery based off adafruit's discharge graph: + // https://learn.adafruit.com/li-ion-and-lipoly-batteries/voltages + + if (bat_mv >= 4200) { + return 100; + } else if (bat_mv <= 3450) { + return 0; + } + + return bat_mv * 2 / 15 - 459; +} \ No newline at end of file diff --git a/app/module/drivers/sensor/battery/battery_common.h b/app/module/drivers/sensor/battery/battery_common.h new file mode 100644 index 000000000000..3e16ceed145f --- /dev/null +++ b/app/module/drivers/sensor/battery/battery_common.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +struct battery_value { + uint16_t adc_raw; + uint16_t millivolts; + uint8_t state_of_charge; +}; + +int battery_channel_get(const struct battery_value *value, enum sensor_channel chan, + struct sensor_value *val_out); + +uint8_t lithium_ion_mv_to_pct(int16_t bat_mv); diff --git a/app/module/drivers/sensor/battery/battery_nrf_vddh.c b/app/module/drivers/sensor/battery/battery_nrf_vddh.c new file mode 100644 index 000000000000..32c7c61eb825 --- /dev/null +++ b/app/module/drivers/sensor/battery/battery_nrf_vddh.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + * + * This is a simplified version of battery_voltage_divider.c which always reads + * the VDDHDIV5 channel of the &adc node and multiplies it by 5. + */ + +#define DT_DRV_COMPAT zmk_battery_nrf_vddh + +#include +#include +#include +#include +#include + +#include "battery_common.h" + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#define VDDHDIV (5) + +static const struct device *adc = DEVICE_DT_GET(DT_NODELABEL(adc)); + +struct vddh_data { + struct adc_channel_cfg acc; + struct adc_sequence as; + struct battery_value value; +}; + +static int vddh_sample_fetch(const struct device *dev, enum sensor_channel chan) { + // Make sure selected channel is supported + if (chan != SENSOR_CHAN_GAUGE_VOLTAGE && chan != SENSOR_CHAN_GAUGE_STATE_OF_CHARGE && + chan != SENSOR_CHAN_ALL) { + LOG_DBG("Selected channel is not supported: %d.", chan); + return -ENOTSUP; + } + + struct vddh_data *drv_data = dev->data; + struct adc_sequence *as = &drv_data->as; + + int rc = adc_read(adc, as); + as->calibrate = false; + + if (rc != 0) { + LOG_ERR("Failed to read ADC: %d", rc); + return rc; + } + + int32_t val = drv_data->value.adc_raw; + rc = adc_raw_to_millivolts(adc_ref_internal(adc), drv_data->acc.gain, as->resolution, &val); + if (rc != 0) { + LOG_ERR("Failed to convert raw ADC to mV: %d", rc); + return rc; + } + + drv_data->value.millivolts = val * VDDHDIV; + drv_data->value.state_of_charge = lithium_ion_mv_to_pct(drv_data->value.millivolts); + + LOG_DBG("ADC raw %d ~ %d mV => %d%%", drv_data->value.adc_raw, drv_data->value.millivolts, + drv_data->value.state_of_charge); + + return rc; +} + +static int vddh_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) { + struct vddh_data const *drv_data = dev->data; + return battery_channel_get(&drv_data->value, chan, val); +} + +static const struct sensor_driver_api vddh_api = { + .sample_fetch = vddh_sample_fetch, + .channel_get = vddh_channel_get, +}; + +static int vddh_init(const struct device *dev) { + struct vddh_data *drv_data = dev->data; + + if (!device_is_ready(adc)) { + LOG_ERR("ADC device is not ready %s", adc->name); + return -ENODEV; + } + + drv_data->as = (struct adc_sequence){ + .channels = BIT(0), + .buffer = &drv_data->value.adc_raw, + .buffer_size = sizeof(drv_data->value.adc_raw), + .oversampling = 4, + .calibrate = true, + }; + +#ifdef CONFIG_ADC_NRFX_SAADC + drv_data->acc = (struct adc_channel_cfg){ + .gain = ADC_GAIN_1_2, + .reference = ADC_REF_INTERNAL, + .acquisition_time = ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 40), + .input_positive = SAADC_CH_PSELN_PSELN_VDDHDIV5, + }; + + drv_data->as.resolution = 12; +#else +#error Unsupported ADC +#endif + + const int rc = adc_channel_setup(adc, &drv_data->acc); + LOG_DBG("VDDHDIV5 setup returned %d", rc); + + return rc; +} + +static struct vddh_data vddh_data; + +DEVICE_DT_INST_DEFINE(0, &vddh_init, NULL, &vddh_data, NULL, POST_KERNEL, + CONFIG_SENSOR_INIT_PRIORITY, &vddh_api); diff --git a/app/module/drivers/sensor/battery/battery_voltage_divider.c b/app/module/drivers/sensor/battery/battery_voltage_divider.c new file mode 100644 index 000000000000..62a02e9c3df3 --- /dev/null +++ b/app/module/drivers/sensor/battery/battery_voltage_divider.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_battery_voltage_divider + +#include +#include +#include +#include +#include +#include + +#include "battery_common.h" + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +struct io_channel_config { + uint8_t channel; +}; + +struct bvd_config { + struct io_channel_config io_channel; + struct gpio_dt_spec power; + uint32_t output_ohm; + uint32_t full_ohm; +}; + +struct bvd_data { + const struct device *adc; + struct adc_channel_cfg acc; + struct adc_sequence as; + struct battery_value value; +}; + +static int bvd_sample_fetch(const struct device *dev, enum sensor_channel chan) { + struct bvd_data *drv_data = dev->data; + const struct bvd_config *drv_cfg = dev->config; + struct adc_sequence *as = &drv_data->as; + + // Make sure selected channel is supported + if (chan != SENSOR_CHAN_GAUGE_VOLTAGE && chan != SENSOR_CHAN_GAUGE_STATE_OF_CHARGE && + chan != SENSOR_CHAN_ALL) { + LOG_DBG("Selected channel is not supported: %d.", chan); + return -ENOTSUP; + } + + int rc = 0; + +#if DT_INST_NODE_HAS_PROP(0, power_gpios) + // Enable power before sampling + rc = gpio_pin_set_dt(&drv_cfg->power, 1); + + if (rc != 0) { + LOG_DBG("Failed to enable ADC power GPIO: %d", rc); + return rc; + } + + // wait for any capacitance to charge up + k_sleep(K_MSEC(10)); +#endif // DT_INST_NODE_HAS_PROP(0, power_gpios) + + // Read ADC + rc = adc_read(drv_data->adc, as); + as->calibrate = false; + + if (rc == 0) { + int32_t val = drv_data->value.adc_raw; + + adc_raw_to_millivolts(adc_ref_internal(drv_data->adc), drv_data->acc.gain, as->resolution, + &val); + + uint16_t millivolts = val * (uint64_t)drv_cfg->full_ohm / drv_cfg->output_ohm; + LOG_DBG("ADC raw %d ~ %d mV => %d mV", drv_data->value.adc_raw, val, millivolts); + uint8_t percent = lithium_ion_mv_to_pct(millivolts); + LOG_DBG("Percent: %d", percent); + + drv_data->value.millivolts = millivolts; + drv_data->value.state_of_charge = percent; + } else { + LOG_DBG("Failed to read ADC: %d", rc); + } + +#if DT_INST_NODE_HAS_PROP(0, power_gpios) + // Disable power GPIO if present + int rc2 = gpio_pin_set_dt(&drv_cfg->power, 0); + + if (rc2 != 0) { + LOG_DBG("Failed to disable ADC power GPIO: %d", rc2); + return rc2; + } +#endif // DT_INST_NODE_HAS_PROP(0, power_gpios) + + return rc; +} + +static int bvd_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) { + struct bvd_data *drv_data = dev->data; + return battery_channel_get(&drv_data->value, chan, val); +} + +static const struct sensor_driver_api bvd_api = { + .sample_fetch = bvd_sample_fetch, + .channel_get = bvd_channel_get, +}; + +static int bvd_init(const struct device *dev) { + struct bvd_data *drv_data = dev->data; + const struct bvd_config *drv_cfg = dev->config; + + if (drv_data->adc == NULL) { + LOG_ERR("ADC failed to retrieve ADC driver"); + return -ENODEV; + } + + int rc = 0; + +#if DT_INST_NODE_HAS_PROP(0, power_gpios) + if (!device_is_ready(drv_cfg->power.port)) { + LOG_ERR("GPIO port for power control is not ready"); + return -ENODEV; + } + rc = gpio_pin_configure_dt(&drv_cfg->power, GPIO_OUTPUT_INACTIVE); + if (rc != 0) { + LOG_ERR("Failed to control feed %u: %d", drv_cfg->power.pin, rc); + return rc; + } +#endif // DT_INST_NODE_HAS_PROP(0, power_gpios) + + drv_data->as = (struct adc_sequence){ + .channels = BIT(0), + .buffer = &drv_data->value.adc_raw, + .buffer_size = sizeof(drv_data->value.adc_raw), + .oversampling = 4, + .calibrate = true, + }; + +#ifdef CONFIG_ADC_NRFX_SAADC + drv_data->acc = (struct adc_channel_cfg){ + .gain = ADC_GAIN_1_6, + .reference = ADC_REF_INTERNAL, + .acquisition_time = ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 40), + .input_positive = SAADC_CH_PSELP_PSELP_AnalogInput0 + drv_cfg->io_channel.channel, + }; + + drv_data->as.resolution = 12; +#else +#error Unsupported ADC +#endif + + rc = adc_channel_setup(drv_data->adc, &drv_data->acc); + LOG_DBG("AIN%u setup returned %d", drv_cfg->io_channel.channel, rc); + + return rc; +} + +static struct bvd_data bvd_data = {.adc = DEVICE_DT_GET(DT_IO_CHANNELS_CTLR(DT_DRV_INST(0)))}; + +static const struct bvd_config bvd_cfg = { + .io_channel = + { + DT_IO_CHANNELS_INPUT(DT_DRV_INST(0)), + }, +#if DT_INST_NODE_HAS_PROP(0, power_gpios) + .power = GPIO_DT_SPEC_INST_GET(0, power_gpios), +#endif + .output_ohm = DT_INST_PROP(0, output_ohms), + .full_ohm = DT_INST_PROP(0, full_ohms), +}; + +DEVICE_DT_INST_DEFINE(0, &bvd_init, NULL, &bvd_data, &bvd_cfg, POST_KERNEL, + CONFIG_SENSOR_INIT_PRIORITY, &bvd_api); diff --git a/app/module/drivers/sensor/ec11/CMakeLists.txt b/app/module/drivers/sensor/ec11/CMakeLists.txt new file mode 100644 index 000000000000..de291fefea50 --- /dev/null +++ b/app/module/drivers/sensor/ec11/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +zephyr_include_directories(.) + +zephyr_library() + +zephyr_library_sources(ec11.c) +zephyr_library_sources_ifdef(CONFIG_EC11_TRIGGER ec11_trigger.c) \ No newline at end of file diff --git a/app/module/drivers/sensor/ec11/Kconfig b/app/module/drivers/sensor/ec11/Kconfig new file mode 100644 index 000000000000..5da327280a87 --- /dev/null +++ b/app/module/drivers/sensor/ec11/Kconfig @@ -0,0 +1,52 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +menuconfig EC11 + bool "EC11 Incremental Encoder Sensor" + default y + depends on DT_HAS_ALPS_EC11_ENABLED + depends on GPIO + help + Enable driver for EC11 incremental encoder sensors. + +if EC11 + +choice + prompt "Trigger mode" + default EC11_TRIGGER_NONE + help + Specify the type of triggering to be used by the driver. + +config EC11_TRIGGER_NONE + bool "No trigger" + +config EC11_TRIGGER_GLOBAL_THREAD + bool "Use global thread" + depends on GPIO + select EC11_TRIGGER + +config EC11_TRIGGER_OWN_THREAD + bool "Use own thread" + depends on GPIO + select EC11_TRIGGER + +endchoice + +config EC11_TRIGGER + bool + +config EC11_THREAD_PRIORITY + int "Thread priority" + depends on EC11_TRIGGER_OWN_THREAD + default 10 + help + Priority of thread used by the driver to handle interrupts. + +config EC11_THREAD_STACK_SIZE + int "Thread stack size" + depends on EC11_TRIGGER_OWN_THREAD + default 1024 + help + Stack size of thread used by the driver to handle interrupts. + +endif # EC11 \ No newline at end of file diff --git a/app/module/drivers/sensor/ec11/ec11.c b/app/module/drivers/sensor/ec11/ec11.c new file mode 100644 index 000000000000..ee8b41e74c81 --- /dev/null +++ b/app/module/drivers/sensor/ec11/ec11.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT alps_ec11 + +#include +#include +#include +#include +#include +#include +#include + +#include "ec11.h" + +#define FULL_ROTATION 360 + +LOG_MODULE_REGISTER(EC11, CONFIG_SENSOR_LOG_LEVEL); + +static int ec11_get_ab_state(const struct device *dev) { + const struct ec11_config *drv_cfg = dev->config; + + return (gpio_pin_get_dt(&drv_cfg->a) << 1) | gpio_pin_get_dt(&drv_cfg->b); +} + +static int ec11_sample_fetch(const struct device *dev, enum sensor_channel chan) { + struct ec11_data *drv_data = dev->data; + const struct ec11_config *drv_cfg = dev->config; + uint8_t val; + int8_t delta; + + __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_ROTATION); + + val = ec11_get_ab_state(dev); + + LOG_DBG("prev: %d, new: %d", drv_data->ab_state, val); + + switch (val | (drv_data->ab_state << 2)) { + case 0b0010: + case 0b0100: + case 0b1101: + case 0b1011: + delta = -1; + break; + case 0b0001: + case 0b0111: + case 0b1110: + case 0b1000: + delta = 1; + break; + default: + delta = 0; + break; + } + + LOG_DBG("Delta: %d", delta); + + drv_data->pulses += delta; + drv_data->ab_state = val; + + // TODO: Temporary code for backwards compatibility to support + // the sensor channel rotation reporting *ticks* instead of delta of degrees. + // REMOVE ME + if (drv_cfg->steps == 0) { + drv_data->ticks = drv_data->pulses / drv_cfg->resolution; + drv_data->delta = delta; + drv_data->pulses %= drv_cfg->resolution; + } + + return 0; +} + +static int ec11_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) { + struct ec11_data *drv_data = dev->data; + const struct ec11_config *drv_cfg = dev->config; + int32_t pulses = drv_data->pulses; + + if (chan != SENSOR_CHAN_ROTATION) { + return -ENOTSUP; + } + + drv_data->pulses = 0; + + if (drv_cfg->steps > 0) { + val->val1 = (pulses * FULL_ROTATION) / drv_cfg->steps; + val->val2 = (pulses * FULL_ROTATION) % drv_cfg->steps; + if (val->val2 != 0) { + val->val2 *= 1000000; + val->val2 /= drv_cfg->steps; + } + } else { + val->val1 = drv_data->ticks; + val->val2 = drv_data->delta; + } + + return 0; +} + +static const struct sensor_driver_api ec11_driver_api = { +#ifdef CONFIG_EC11_TRIGGER + .trigger_set = ec11_trigger_set, +#endif + .sample_fetch = ec11_sample_fetch, + .channel_get = ec11_channel_get, +}; + +int ec11_init(const struct device *dev) { + struct ec11_data *drv_data = dev->data; + const struct ec11_config *drv_cfg = dev->config; + + LOG_DBG("A: %s %d B: %s %d resolution %d", drv_cfg->a.port->name, drv_cfg->a.pin, + drv_cfg->b.port->name, drv_cfg->b.pin, drv_cfg->resolution); + + if (!device_is_ready(drv_cfg->a.port)) { + LOG_ERR("A GPIO device is not ready"); + return -EINVAL; + } + + if (!device_is_ready(drv_cfg->b.port)) { + LOG_ERR("B GPIO device is not ready"); + return -EINVAL; + } + + if (gpio_pin_configure_dt(&drv_cfg->a, GPIO_INPUT)) { + LOG_DBG("Failed to configure A pin"); + return -EIO; + } + + if (gpio_pin_configure_dt(&drv_cfg->b, GPIO_INPUT)) { + LOG_DBG("Failed to configure B pin"); + return -EIO; + } + +#ifdef CONFIG_EC11_TRIGGER + if (ec11_init_interrupt(dev) < 0) { + LOG_DBG("Failed to initialize interrupt!"); + return -EIO; + } +#endif + + drv_data->ab_state = ec11_get_ab_state(dev); + + return 0; +} + +#define EC11_INST(n) \ + struct ec11_data ec11_data_##n; \ + const struct ec11_config ec11_cfg_##n = { \ + .a = GPIO_DT_SPEC_INST_GET(n, a_gpios), \ + .b = GPIO_DT_SPEC_INST_GET(n, b_gpios), \ + .resolution = DT_INST_PROP_OR(n, resolution, 1), \ + .steps = DT_INST_PROP_OR(n, steps, 0), \ + }; \ + DEVICE_DT_INST_DEFINE(n, ec11_init, NULL, &ec11_data_##n, &ec11_cfg_##n, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &ec11_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(EC11_INST) diff --git a/app/module/drivers/sensor/ec11/ec11.h b/app/module/drivers/sensor/ec11/ec11.h new file mode 100644 index 000000000000..4e2e5d2641c3 --- /dev/null +++ b/app/module/drivers/sensor/ec11/ec11.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include + +struct ec11_config { + const struct gpio_dt_spec a; + const struct gpio_dt_spec b; + + const uint16_t steps; + const uint8_t resolution; +}; + +struct ec11_data { + uint8_t ab_state; + int8_t pulses; + int8_t ticks; + int8_t delta; + +#ifdef CONFIG_EC11_TRIGGER + struct gpio_callback a_gpio_cb; + struct gpio_callback b_gpio_cb; + const struct device *dev; + + sensor_trigger_handler_t handler; + const struct sensor_trigger *trigger; + +#if defined(CONFIG_EC11_TRIGGER_OWN_THREAD) + K_THREAD_STACK_MEMBER(thread_stack, CONFIG_EC11_THREAD_STACK_SIZE); + struct k_sem gpio_sem; + struct k_thread thread; +#elif defined(CONFIG_EC11_TRIGGER_GLOBAL_THREAD) + struct k_work work; +#endif + +#endif /* CONFIG_EC11_TRIGGER */ +}; + +#ifdef CONFIG_EC11_TRIGGER + +int ec11_trigger_set(const struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); + +int ec11_init_interrupt(const struct device *dev); +#endif diff --git a/app/module/drivers/sensor/ec11/ec11_trigger.c b/app/module/drivers/sensor/ec11/ec11_trigger.c new file mode 100644 index 000000000000..f9384a667e54 --- /dev/null +++ b/app/module/drivers/sensor/ec11/ec11_trigger.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT alps_ec11 + +#include +#include +#include +#include +#include + +#include "ec11.h" + +extern struct ec11_data ec11_driver; + +#include +LOG_MODULE_DECLARE(EC11, CONFIG_SENSOR_LOG_LEVEL); + +static inline void setup_int(const struct device *dev, bool enable) { + const struct ec11_config *cfg = dev->config; + + LOG_DBG("enabled %s", (enable ? "true" : "false")); + + if (gpio_pin_interrupt_configure_dt(&cfg->a, enable ? GPIO_INT_EDGE_BOTH : GPIO_INT_DISABLE)) { + LOG_WRN("Unable to set A pin GPIO interrupt"); + } + + if (gpio_pin_interrupt_configure_dt(&cfg->b, enable ? GPIO_INT_EDGE_BOTH : GPIO_INT_DISABLE)) { + LOG_WRN("Unable to set A pin GPIO interrupt"); + } +} + +static void ec11_a_gpio_callback(const struct device *dev, struct gpio_callback *cb, + uint32_t pins) { + struct ec11_data *drv_data = CONTAINER_OF(cb, struct ec11_data, a_gpio_cb); + + LOG_DBG(""); + + setup_int(drv_data->dev, false); + +#if defined(CONFIG_EC11_TRIGGER_OWN_THREAD) + k_sem_give(&drv_data->gpio_sem); +#elif defined(CONFIG_EC11_TRIGGER_GLOBAL_THREAD) + k_work_submit(&drv_data->work); +#endif +} + +static void ec11_b_gpio_callback(const struct device *dev, struct gpio_callback *cb, + uint32_t pins) { + struct ec11_data *drv_data = CONTAINER_OF(cb, struct ec11_data, b_gpio_cb); + + LOG_DBG(""); + + setup_int(drv_data->dev, false); + +#if defined(CONFIG_EC11_TRIGGER_OWN_THREAD) + k_sem_give(&drv_data->gpio_sem); +#elif defined(CONFIG_EC11_TRIGGER_GLOBAL_THREAD) + k_work_submit(&drv_data->work); +#endif +} + +static void ec11_thread_cb(const struct device *dev) { + struct ec11_data *drv_data = dev->data; + + drv_data->handler(dev, drv_data->trigger); + + setup_int(dev, true); +} + +#ifdef CONFIG_EC11_TRIGGER_OWN_THREAD +static void ec11_thread(int dev_ptr, int unused) { + const struct device *dev = INT_TO_POINTER(dev_ptr); + struct ec11_data *drv_data = dev->data; + + ARG_UNUSED(unused); + + while (1) { + k_sem_take(&drv_data->gpio_sem, K_FOREVER); + ec11_thread_cb(dev); + } +} +#endif + +#ifdef CONFIG_EC11_TRIGGER_GLOBAL_THREAD +static void ec11_work_cb(struct k_work *work) { + struct ec11_data *drv_data = CONTAINER_OF(work, struct ec11_data, work); + + LOG_DBG(""); + + ec11_thread_cb(drv_data->dev); +} +#endif + +int ec11_trigger_set(const struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) { + struct ec11_data *drv_data = dev->data; + + setup_int(dev, false); + + k_msleep(5); + + drv_data->trigger = trig; + drv_data->handler = handler; + + setup_int(dev, true); + + return 0; +} + +int ec11_init_interrupt(const struct device *dev) { + struct ec11_data *drv_data = dev->data; + const struct ec11_config *drv_cfg = dev->config; + + drv_data->dev = dev; + /* setup gpio interrupt */ + + gpio_init_callback(&drv_data->a_gpio_cb, ec11_a_gpio_callback, BIT(drv_cfg->a.pin)); + + if (gpio_add_callback(drv_cfg->a.port, &drv_data->a_gpio_cb) < 0) { + LOG_DBG("Failed to set A callback!"); + return -EIO; + } + + gpio_init_callback(&drv_data->b_gpio_cb, ec11_b_gpio_callback, BIT(drv_cfg->b.pin)); + + if (gpio_add_callback(drv_cfg->b.port, &drv_data->b_gpio_cb) < 0) { + LOG_DBG("Failed to set B callback!"); + return -EIO; + } + +#if defined(CONFIG_EC11_TRIGGER_OWN_THREAD) + k_sem_init(&drv_data->gpio_sem, 0, UINT_MAX); + + k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_EC11_THREAD_STACK_SIZE, + (k_thread_entry_t)ec11_thread, dev, 0, NULL, + K_PRIO_COOP(CONFIG_EC11_THREAD_PRIORITY), 0, K_NO_WAIT); +#elif defined(CONFIG_EC11_TRIGGER_GLOBAL_THREAD) + k_work_init(&drv_data->work, ec11_work_cb); +#endif + + return 0; +} diff --git a/app/module/drivers/sensor/max17048/CMakeLists.txt b/app/module/drivers/sensor/max17048/CMakeLists.txt new file mode 100644 index 000000000000..e895fa11fb8c --- /dev/null +++ b/app/module/drivers/sensor/max17048/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +zephyr_include_directories(.) + +zephyr_library() + +zephyr_library_sources_ifdef(CONFIG_MAX17048 max17048.c) +zephyr_library_sources_ifndef(CONFIG_MAX17048 ${ZEPHYR_BASE}/misc/empty_file.c) diff --git a/app/module/drivers/sensor/max17048/Kconfig b/app/module/drivers/sensor/max17048/Kconfig new file mode 100644 index 000000000000..8a7ec16e85d2 --- /dev/null +++ b/app/module/drivers/sensor/max17048/Kconfig @@ -0,0 +1,23 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +DT_COMPAT_MAXIM_MAX17048 := maxim,max17048 + +menuconfig MAX17048 + bool "MAX17048/9 I2C-based Fuel Gauge" + default $(dt_compat_enabled,$(DT_COMPAT_MAXIM_MAX17048)) + depends on I2C + select ZMK_BATTERY + help + Enable driver for MAX17048/9 I2C-based Fuel Gauge. Supports measuring + battery voltage and state-of-charge. + +if MAX17048 + +config SENSOR_MAX17048_INIT_PRIORITY + int "Init priority" + default 75 + help + Device driver initialization priority. + +endif #MAX17048 diff --git a/app/module/drivers/sensor/max17048/max17048.c b/app/module/drivers/sensor/max17048/max17048.c new file mode 100644 index 000000000000..24cfe093f4a6 --- /dev/null +++ b/app/module/drivers/sensor/max17048/max17048.c @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT maxim_max17048 + +#include +#include +#include +#include +#include +#include + +#include "max17048.h" + +#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL +#include +LOG_MODULE_REGISTER(sensor_max17048); + +static int read_register(const struct device *dev, uint8_t reg, uint16_t *value) { + + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + struct max17048_config *config = (struct max17048_config *)dev->config; + + uint8_t data[2] = {0}; + int ret = i2c_burst_read_dt(&config->i2c_bus, reg, &data[0], sizeof(data)); + if (ret != 0) { + LOG_DBG("i2c_write_read FAIL %d\n", ret); + return ret; + } + + // the register values are returned in big endian (MSB first) + *value = sys_get_be16(data); + return 0; +} + +static int write_register(const struct device *dev, uint8_t reg, uint16_t value) { + + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + struct max17048_config *config = (struct max17048_config *)dev->config; + + uint8_t data[2] = {0}; + sys_put_be16(value, &data[0]); + + return i2c_burst_write_dt(&config->i2c_bus, reg, &data[0], sizeof(data)); +} + +static int set_rcomp_value(const struct device *dev, uint8_t rcomp_value) { + + struct max17048_drv_data *const drv_data = (struct max17048_drv_data *const)dev->data; + k_sem_take(&drv_data->lock, K_FOREVER); + + uint16_t tmp = 0; + int err = read_register(dev, REG_CONFIG, &tmp); + if (err != 0) { + goto done; + } + + tmp = ((uint16_t)rcomp_value << 8) | (tmp & 0xFF); + err = write_register(dev, REG_CONFIG, tmp); + if (err != 0) { + goto done; + } + + LOG_DBG("set RCOMP to %d", rcomp_value); + +done: + k_sem_give(&drv_data->lock); + return err; +} + +static int set_sleep_enabled(const struct device *dev, bool sleep) { + + struct max17048_drv_data *const drv_data = (struct max17048_drv_data *const)dev->data; + k_sem_take(&drv_data->lock, K_FOREVER); + + uint16_t tmp = 0; + int err = read_register(dev, REG_CONFIG, &tmp); + if (err != 0) { + goto done; + } + + if (sleep) { + tmp |= 0x80; + } else { + tmp &= ~0x0080; + } + + err = write_register(dev, REG_CONFIG, tmp); + if (err != 0) { + goto done; + } + + LOG_DBG("sleep mode %s", sleep ? "enabled" : "disabled"); + +done: + k_sem_give(&drv_data->lock); + return err; +} + +static int max17048_sample_fetch(const struct device *dev, enum sensor_channel chan) { + + struct max17048_drv_data *const drv_data = dev->data; + k_sem_take(&drv_data->lock, K_FOREVER); + + int err = 0; + + if (chan == SENSOR_CHAN_GAUGE_STATE_OF_CHARGE || chan == SENSOR_CHAN_ALL) { + err = read_register(dev, REG_STATE_OF_CHARGE, &drv_data->raw_state_of_charge); + if (err != 0) { + LOG_WRN("failed to read state-of-charge: %d", err); + goto done; + } + LOG_DBG("read soc: %d", drv_data->raw_state_of_charge); + + } else if (chan == SENSOR_CHAN_GAUGE_VOLTAGE || chan == SENSOR_CHAN_ALL) { + err = read_register(dev, REG_VCELL, &drv_data->raw_vcell); + if (err != 0) { + LOG_WRN("failed to read vcell: %d", err); + goto done; + } + LOG_DBG("read vcell: %d", drv_data->raw_vcell); + + } else { + LOG_DBG("unsupported channel %d", chan); + err = -ENOTSUP; + } + +done: + k_sem_give(&drv_data->lock); + return err; +} + +static int max17048_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) { + int err = 0; + + struct max17048_drv_data *const drv_data = dev->data; + k_sem_take(&drv_data->lock, K_FOREVER); + + struct max17048_drv_data *const data = dev->data; + unsigned int tmp = 0; + + switch (chan) { + case SENSOR_CHAN_GAUGE_VOLTAGE: + // 1250 / 16 = 78.125 + tmp = data->raw_vcell * 1250 / 16; + val->val1 = tmp / 1000000; + val->val2 = tmp % 1000000; + break; + + case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE: + val->val1 = (data->raw_state_of_charge >> 8); + val->val2 = (data->raw_state_of_charge & 0xFF) * 1000000 / 256; + break; + + default: + err = -ENOTSUP; + break; + } + + k_sem_give(&drv_data->lock); + return err; +} + +static int max17048_init(const struct device *dev) { + struct max17048_drv_data *drv_data = dev->data; + const struct max17048_config *config = dev->config; + + if (!device_is_ready(config->i2c_bus.bus)) { + LOG_WRN("i2c bus not ready!"); + return -EINVAL; + } + + uint16_t ic_version = 0; + int err = read_register(dev, REG_VERSION, &ic_version); + if (err != 0) { + LOG_WRN("could not get IC version!"); + return err; + } + + // the functions below need the semaphore, so initialise it here + k_sem_init(&drv_data->lock, 1, 1); + + // bring the device out of sleep + set_sleep_enabled(dev, false); + + // set the default rcomp value -- 0x97, as stated in the datasheet + set_rcomp_value(dev, 0x97); + + LOG_INF("device initialised at 0x%x (version %d)", config->i2c_bus.addr, ic_version); + + return 0; +} + +static const struct sensor_driver_api max17048_api_table = {.sample_fetch = max17048_sample_fetch, + .channel_get = max17048_channel_get}; + +#define MAX17048_INIT(inst) \ + static struct max17048_config max17048_##inst##_config = {.i2c_bus = \ + I2C_DT_SPEC_INST_GET(inst)}; \ + \ + static struct max17048_drv_data max17048_##inst##_drvdata = { \ + .raw_state_of_charge = 0, \ + .raw_charge_rate = 0, \ + .raw_vcell = 0, \ + }; \ + \ + /* This has to init after SPI master */ \ + DEVICE_DT_INST_DEFINE(inst, max17048_init, NULL, &max17048_##inst##_drvdata, \ + &max17048_##inst##_config, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ + &max17048_api_table); + +DT_INST_FOREACH_STATUS_OKAY(MAX17048_INIT) diff --git a/app/module/drivers/sensor/max17048/max17048.h b/app/module/drivers/sensor/max17048/max17048.h new file mode 100644 index 000000000000..984f5c70f4e0 --- /dev/null +++ b/app/module/drivers/sensor/max17048/max17048.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define REG_VCELL 0x02 +#define REG_STATE_OF_CHARGE 0x04 +#define REG_MODE 0x06 +#define REG_VERSION 0x08 +#define REG_HIBERNATE 0x0A +#define REG_CONFIG 0x0C +#define REG_VALERT 0x14 +#define REG_CHARGE_RATE 0x16 +#define REG_VRESET 0x18 +#define REG_STATUS 0x1A + +struct max17048_config { + struct i2c_dt_spec i2c_bus; +}; + +struct max17048_drv_data { + struct k_sem lock; + + uint16_t raw_state_of_charge; + uint16_t raw_charge_rate; + uint16_t raw_vcell; +}; + +#ifdef __cplusplus +} +#endif diff --git a/app/module/dts/bindings/display/gooddisplay,il0323.yaml b/app/module/dts/bindings/display/gooddisplay,il0323.yaml new file mode 100644 index 000000000000..46fc7326584a --- /dev/null +++ b/app/module/dts/bindings/display/gooddisplay,il0323.yaml @@ -0,0 +1,61 @@ +# Copyright (c) 2020, Phytec Messtechnik GmbH, Peter Johanson +# SPDX-License-Identifier: Apache-2.0 + +description: IL0323 EPD display controller + +compatible: "gooddisplay,il0323" + +include: spi-device.yaml + +properties: + height: + type: int + required: true + description: Height in pixel of the panel driven by the controller + + width: + type: int + required: true + description: Width in pixel of the panel driven by the controller + + reset-gpios: + type: phandle-array + required: true + description: RESET pin. + + The RESET pin of GD7965 is active low. + If connected directly the MCU pin should be configured + as active low. + + dc-gpios: + type: phandle-array + required: true + description: DC pin. + + The DC pin of GD7965 is active low (transmission command byte). + If connected directly the MCU pin should be configured + as active low. + + busy-gpios: + type: phandle-array + required: true + description: BUSY pin. + + The BUSY pin of GD7965 is active low. + If connected directly the MCU pin should be configured + as active low. + + pwr: + type: uint8-array + required: true + description: Power Setting (PWR) values + + cdi: + type: int + required: true + description: VCOM and data interval value + + tcon: + type: int + required: true + description: TCON setting value diff --git a/app/module/dts/bindings/gpio/maxim,max7318.yaml b/app/module/dts/bindings/gpio/maxim,max7318.yaml new file mode 100644 index 000000000000..6c309768d44f --- /dev/null +++ b/app/module/dts/bindings/gpio/maxim,max7318.yaml @@ -0,0 +1,26 @@ +# +# Copyright (c) 2022 The ZMK Contributors +# +# SPDX-License-Identifier: MIT +# + +description: > + This is a representation of the Maxim MAX7318 I2C Gpio Expander. + +compatible: "maxim,max7318" + +include: [gpio-controller.yaml, i2c-device.yaml] + +properties: + "#gpio-cells": + const: 2 + + ngpios: + type: int + required: true + const: 16 + description: Number of gpios supported + +gpio-cells: + - pin + - flags diff --git a/app/module/dts/bindings/gpio/zmk,gpio-595.yaml b/app/module/dts/bindings/gpio/zmk,gpio-595.yaml new file mode 100644 index 000000000000..605c969df591 --- /dev/null +++ b/app/module/dts/bindings/gpio/zmk,gpio-595.yaml @@ -0,0 +1,30 @@ +# +# Copyright (c) 2022 The ZMK Contributors +# +# SPDX-License-Identifier: MIT +# + +description: > + This is a representation of the 595 Shift Register. + +compatible: "zmk,gpio-595" + +include: [gpio-controller.yaml, spi-device.yaml] + +properties: + "#gpio-cells": + const: 2 + + ngpios: + type: int + required: true + enum: + - 8 + - 16 + - 24 + - 32 + description: Number of gpios supported + +gpio-cells: + - pin + - flags diff --git a/app/module/dts/bindings/kscan/zmk,kscan-gpio-charlieplex.yaml b/app/module/dts/bindings/kscan/zmk,kscan-gpio-charlieplex.yaml new file mode 100644 index 000000000000..f8da1d27bb91 --- /dev/null +++ b/app/module/dts/bindings/kscan/zmk,kscan-gpio-charlieplex.yaml @@ -0,0 +1,31 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: GPIO keyboard charlieplex matrix controller + +compatible: "zmk,kscan-gpio-charlieplex" + +include: kscan.yaml + +properties: + gpios: + type: phandle-array + required: true + interrupt-gpios: + type: phandle-array + debounce-press-ms: + type: int + default: 5 + description: Debounce time for key press in milliseconds. Use 0 for eager debouncing. + debounce-release-ms: + type: int + default: 5 + description: Debounce time for key release in milliseconds. + debounce-scan-period-ms: + type: int + default: 1 + description: Time between reads in milliseconds when any key is pressed. + poll-period-ms: + type: int + default: 1 + description: Time between reads in milliseconds diff --git a/app/module/dts/bindings/kscan/zmk,kscan-gpio-demux.yaml b/app/module/dts/bindings/kscan/zmk,kscan-gpio-demux.yaml new file mode 100644 index 000000000000..a2d8d2449ade --- /dev/null +++ b/app/module/dts/bindings/kscan/zmk,kscan-gpio-demux.yaml @@ -0,0 +1,22 @@ +# Copyright (c) 2020, The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: GPIO keyboard demux controller + +compatible: "zmk,kscan-gpio-demux" + +include: kscan.yaml + +properties: + input-gpios: + type: phandle-array + required: true + output-gpios: + type: phandle-array + required: true + debounce-period: + type: int + default: 5 + polling-interval-msec: + type: int + default: 25 diff --git a/app/module/dts/bindings/kscan/zmk,kscan-gpio-direct.yaml b/app/module/dts/bindings/kscan/zmk,kscan-gpio-direct.yaml new file mode 100644 index 000000000000..f477b591f87b --- /dev/null +++ b/app/module/dts/bindings/kscan/zmk,kscan-gpio-direct.yaml @@ -0,0 +1,37 @@ +# Copyright (c) 2020, Pete Johanson +# SPDX-License-Identifier: MIT + +description: Direct GPIO keyboard KSCAN controller + +compatible: "zmk,kscan-gpio-direct" + +include: kscan.yaml + +properties: + input-gpios: + type: phandle-array + required: true + debounce-period: + type: int + required: false + deprecated: true + description: Deprecated. Use debounce-press-ms and debounce-release-ms instead. + debounce-press-ms: + type: int + default: 5 + description: Debounce time for key press in milliseconds. Use 0 for eager debouncing. + debounce-release-ms: + type: int + default: 5 + description: Debounce time for key release in milliseconds. + debounce-scan-period-ms: + type: int + default: 1 + description: Time between reads in milliseconds when any key is pressed. + poll-period-ms: + type: int + default: 10 + description: Time between reads in milliseconds when no key is pressed and ZMK_KSCAN_DIRECT_POLLING is enabled. + toggle-mode: + type: boolean + description: Enable toggle-switch mode. diff --git a/app/module/dts/bindings/kscan/zmk,kscan-gpio-matrix.yaml b/app/module/dts/bindings/kscan/zmk,kscan-gpio-matrix.yaml new file mode 100644 index 000000000000..2ec6dc6cfa3f --- /dev/null +++ b/app/module/dts/bindings/kscan/zmk,kscan-gpio-matrix.yaml @@ -0,0 +1,43 @@ +# Copyright (c) 2020, Pete Johanson +# SPDX-License-Identifier: MIT + +description: GPIO keyboard matrix controller + +compatible: "zmk,kscan-gpio-matrix" + +include: kscan.yaml + +properties: + row-gpios: + type: phandle-array + required: true + col-gpios: + type: phandle-array + required: true + debounce-period: + type: int + required: false + deprecated: true + description: Deprecated. Use debounce-press-ms and debounce-release-ms instead. + debounce-press-ms: + type: int + default: 5 + description: Debounce time for key press in milliseconds. Use 0 for eager debouncing. + debounce-release-ms: + type: int + default: 5 + description: Debounce time for key release in milliseconds. + debounce-scan-period-ms: + type: int + default: 1 + description: Time between reads in milliseconds when any key is pressed. + poll-period-ms: + type: int + default: 10 + description: Time between reads in milliseconds when no key is pressed and ZMK_KSCAN_MATRIX_POLLING is enabled. + diode-direction: + type: string + default: row2col + enum: + - row2col + - col2row diff --git a/app/module/dts/bindings/sensor/alps,ec11.yaml b/app/module/dts/bindings/sensor/alps,ec11.yaml new file mode 100644 index 000000000000..46dad31d23dc --- /dev/null +++ b/app/module/dts/bindings/sensor/alps,ec11.yaml @@ -0,0 +1,27 @@ +description: | + Sensor driver for the Alps EC11 rotary encoder + +compatible: "alps,ec11" + +properties: + label: + type: string + required: false + deprecated: true + a-gpios: + type: phandle-array + required: true + description: A pin for the encoder + b-gpios: + type: phandle-array + required: true + description: A pin for the encoder + resolution: + type: int + description: Number of pulses per tick + deprecated: true + required: false + steps: + type: int + description: Number of pulses in one full rotation + required: false diff --git a/app/module/dts/bindings/sensor/maxim,max17048.yml b/app/module/dts/bindings/sensor/maxim,max17048.yml new file mode 100644 index 000000000000..786f4b8686d9 --- /dev/null +++ b/app/module/dts/bindings/sensor/maxim,max17048.yml @@ -0,0 +1,12 @@ +# +# Copyright (c) 2022 The ZMK Contributors +# +# SPDX-License-Identifier: MIT +# + +description: > + This is a representation of the Maxim max17048 I2C Fuel Gauge. + +compatible: "maxim,max17048" + +include: [i2c-device.yaml] diff --git a/app/module/dts/bindings/sensor/zmk,battery-nrf-vddh.yaml b/app/module/dts/bindings/sensor/zmk,battery-nrf-vddh.yaml new file mode 100644 index 000000000000..28b7541b8199 --- /dev/null +++ b/app/module/dts/bindings/sensor/zmk,battery-nrf-vddh.yaml @@ -0,0 +1,6 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Battery SoC monitoring using nRF VDDH + +compatible: "zmk,battery-nrf-vddh" diff --git a/app/module/dts/bindings/sensor/zmk,battery-voltage-divider.yaml b/app/module/dts/bindings/sensor/zmk,battery-voltage-divider.yaml new file mode 100644 index 000000000000..d9e07b797e8d --- /dev/null +++ b/app/module/dts/bindings/sensor/zmk,battery-voltage-divider.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Battery SoC monitoring using voltage divider + +compatible: "zmk,battery-voltage-divider" + +include: voltage-divider.yaml diff --git a/app/module/include/dt-bindings/zmk/kscan_mock.h b/app/module/include/dt-bindings/zmk/kscan_mock.h new file mode 100644 index 000000000000..eff218b2f451 --- /dev/null +++ b/app/module/include/dt-bindings/zmk/kscan_mock.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#define ZMK_MOCK_IS_PRESS(v) ((v & (0x01 << 31)) != 0) +#define ZMK_MOCK_PRESS(row, col, msec) (row + (col << 8) + (msec << 16) + (0x01 << 31)) +#define ZMK_MOCK_RELEASE(row, col, msec) (row + (col << 8) + (msec << 16)) +#define ZMK_MOCK_ROW(v) (v & 0xFF) +#define ZMK_MOCK_COL(v) ((v >> 8) & 0xFF) +#define ZMK_MOCK_MSEC(v) ((v & ~(0x01 << 31)) >> 16) diff --git a/app/module/include/zmk/debounce.h b/app/module/include/zmk/debounce.h new file mode 100644 index 000000000000..afa775a023df --- /dev/null +++ b/app/module/include/zmk/debounce.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include + +#define DEBOUNCE_COUNTER_BITS 14 +#define DEBOUNCE_COUNTER_MAX BIT_MASK(DEBOUNCE_COUNTER_BITS) + +struct zmk_debounce_state { + bool pressed : 1; + bool changed : 1; + uint16_t counter : DEBOUNCE_COUNTER_BITS; +}; + +struct zmk_debounce_config { + /** Duration a switch must be pressed to latch as pressed. */ + uint32_t debounce_press_ms; + /** Duration a switch must be released to latch as released. */ + uint32_t debounce_release_ms; +}; + +/** + * Debounces one switch. + * + * @param state The state for the switch to debounce. + * @param active Is the switch currently pressed? + * @param elapsed_ms Time elapsed since the previous update in milliseconds. + * @param config Debounce settings. + */ +void zmk_debounce_update(struct zmk_debounce_state *state, const bool active, const int elapsed_ms, + const struct zmk_debounce_config *config); + +/** + * @returns whether the switch is either latched as pressed or it is potentially + * pressed but the debouncer has not yet made a decision. If this returns true, + * the kscan driver should continue to poll quickly. + */ +bool zmk_debounce_is_active(const struct zmk_debounce_state *state); + +/** + * @returns whether the switch is latched as pressed. + */ +bool zmk_debounce_is_pressed(const struct zmk_debounce_state *state); + +/** + * @returns whether the pressed state of the switch changed in the last call to + * debounce_update. + */ +bool zmk_debounce_get_changed(const struct zmk_debounce_state *state); diff --git a/app/module/lib/CMakeLists.txt b/app/module/lib/CMakeLists.txt new file mode 100644 index 000000000000..146b3637b683 --- /dev/null +++ b/app/module/lib/CMakeLists.txt @@ -0,0 +1,2 @@ + +add_subdirectory_ifdef(CONFIG_ZMK_DEBOUNCE zmk_debounce) \ No newline at end of file diff --git a/app/module/lib/Kconfig b/app/module/lib/Kconfig new file mode 100644 index 000000000000..8f2f06017d3d --- /dev/null +++ b/app/module/lib/Kconfig @@ -0,0 +1,2 @@ + +rsource "zmk_debounce/Kconfig" \ No newline at end of file diff --git a/app/module/lib/zmk_debounce/CMakeLists.txt b/app/module/lib/zmk_debounce/CMakeLists.txt new file mode 100644 index 000000000000..0a65dde1109d --- /dev/null +++ b/app/module/lib/zmk_debounce/CMakeLists.txt @@ -0,0 +1,3 @@ + +zephyr_library() +zephyr_library_sources(debounce.c) \ No newline at end of file diff --git a/app/module/lib/zmk_debounce/Kconfig b/app/module/lib/zmk_debounce/Kconfig new file mode 100644 index 000000000000..cd0321e8569a --- /dev/null +++ b/app/module/lib/zmk_debounce/Kconfig @@ -0,0 +1,3 @@ + +config ZMK_DEBOUNCE + bool "Debounce Support" \ No newline at end of file diff --git a/app/module/lib/zmk_debounce/debounce.c b/app/module/lib/zmk_debounce/debounce.c new file mode 100644 index 000000000000..6f4885b745c6 --- /dev/null +++ b/app/module/lib/zmk_debounce/debounce.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +static uint32_t get_threshold(const struct zmk_debounce_state *state, + const struct zmk_debounce_config *config) { + return state->pressed ? config->debounce_release_ms : config->debounce_press_ms; +} + +static void increment_counter(struct zmk_debounce_state *state, const int elapsed_ms) { + if (state->counter + elapsed_ms > DEBOUNCE_COUNTER_MAX) { + state->counter = DEBOUNCE_COUNTER_MAX; + } else { + state->counter += elapsed_ms; + } +} + +static void decrement_counter(struct zmk_debounce_state *state, const int elapsed_ms) { + if (state->counter < elapsed_ms) { + state->counter = 0; + } else { + state->counter -= elapsed_ms; + } +} + +void zmk_debounce_update(struct zmk_debounce_state *state, const bool active, const int elapsed_ms, + const struct zmk_debounce_config *config) { + // This uses a variation of the integrator debouncing described at + // https://www.kennethkuhn.com/electronics/debounce.c + // Every update where "active" does not match the current state, we increment + // a counter, otherwise we decrement it. When the counter reaches a + // threshold, the state flips and we reset the counter. + state->changed = false; + + if (active == state->pressed) { + decrement_counter(state, elapsed_ms); + return; + } + + const uint32_t flip_threshold = get_threshold(state, config); + + if (state->counter < flip_threshold) { + increment_counter(state, elapsed_ms); + return; + } + + state->pressed = !state->pressed; + state->counter = 0; + state->changed = true; +} + +bool zmk_debounce_is_active(const struct zmk_debounce_state *state) { + return state->pressed || state->counter > 0; +} + +bool zmk_debounce_is_pressed(const struct zmk_debounce_state *state) { return state->pressed; } + +bool zmk_debounce_get_changed(const struct zmk_debounce_state *state) { return state->changed; } \ No newline at end of file diff --git a/app/module/zephyr/module.yml b/app/module/zephyr/module.yml new file mode 100644 index 000000000000..219b2cfd201f --- /dev/null +++ b/app/module/zephyr/module.yml @@ -0,0 +1,5 @@ +build: + cmake: . + kconfig: Kconfig + settings: + dts_root: . diff --git a/app/package-lock.json b/app/package-lock.json new file mode 100644 index 000000000000..060fcba0f48d --- /dev/null +++ b/app/package-lock.json @@ -0,0 +1,39 @@ +{ + "name": "zmkfirmware", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "zmkfirmware", + "version": "1.0.0", + "license": "MIT", + "devDependencies": { + "prettier": "^2.8.7" + } + }, + "node_modules/prettier": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz", + "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + } + }, + "dependencies": { + "prettier": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz", + "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==", + "dev": true + } + } +} diff --git a/app/package.json b/app/package.json new file mode 100644 index 000000000000..e1a7957fbceb --- /dev/null +++ b/app/package.json @@ -0,0 +1,23 @@ +{ + "name": "zmkfirmware", + "version": "1.0.0", + "description": "ZMK Firmware tooling", + "private": "true", + "scripts": { + "prettier:check": "prettier --check boards/**/*.yml", + "prettier:format": "prettier --write boards/**/*.yml" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/zmkfirware/zmk.git" + }, + "author": "ZMK Contributors", + "license": "MIT", + "bugs": { + "url": "https://github.com/zmkfirware/zmk/issues" + }, + "homepage": "https://zmk.dev/", + "devDependencies": { + "prettier": "^2.8.7" + } +} diff --git a/app/prj.conf b/app/prj.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/run-ble-test.sh b/app/run-ble-test.sh new file mode 100755 index 000000000000..9984caa14e20 --- /dev/null +++ b/app/run-ble-test.sh @@ -0,0 +1,107 @@ +#!/bin/bash + +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if [ -z "$1" ]; then + echo "Usage: ./run-ble-test.sh " + exit 1 +fi + +path=$1 +if [ "$path" = "all" ]; then + path="tests" +fi + +if [ -z "${BSIM_OUT_PATH}" ]; then + echo "BSIM_OUT_PATH needs to be set before running this script." + exit 1 +fi + +if [ -z "$BLE_TESTS_NO_CENTRAL_BUILD" ]; then + if ! [ -e build/tests/ble/central ]; then + west build -d build/tests/ble/central -b nrf52_bsim tests/ble/central > /dev/null 2>&1 + else + west build -d build/tests/ble/central + fi + + cp build/tests/ble/central/zephyr/zephyr.exe "${BSIM_OUT_PATH}/bin/ble_test_central.exe" + + if ! [ -e build/tests/ble/private_central ]; then + west build -d build/tests/ble/private_central -b nrf52_bsim tests/ble/central -- -DCONFIG_BT_PRIVACY=y -DCONFIG_BT_SCAN_WITH_IDENTITY=n > /dev/null 2>&1 + else + west build -d build/tests/ble/private_central + fi + + cp build/tests/ble/private_central/zephyr/zephyr.exe "${BSIM_OUT_PATH}/bin/ble_test_private_central.exe" +fi + +testcases=$(find $path -name nrf52_bsim.keymap -exec dirname \{\} \;) +num_cases=$(echo "$testcases" | wc -l) +if [ $num_cases -gt 1 ] || [ "$testcases" != "${path%%/}" ]; then + echo "$testcases" + echo "" > ./build/tests/pass-fail.log + echo "$testcases" | BLE_TESTS_QUIET_OUTPUT=y BLE_TESTS_NO_CENTRAL_BUILD=y xargs -L 1 -P ${J:-4} ./run-ble-test.sh + err=$? + sort -k2 ./build/tests/pass-fail.log + exit $err +fi + +testcase="$path" +echo "Running $testcase:" + +west build -d build/$testcase -b nrf52_bsim -- -DZMK_CONFIG="$(pwd)/$testcase" > /dev/null 2>&1 +if [ $? -gt 0 ]; then + echo "FAILED: $testcase did not build" | tee -a ./build/tests/pass-fail.log + exit 1 +fi + +if [ -n "${BLE_TESTS_QUIET_OUTPUT}" ]; then + output_dev="/dev/null" +else + output_dev="/dev/stdout" +fi + +exe_name=${testcase//\//_} + +start_dir=$(pwd) +cp build/$testcase/zephyr/zmk.exe "${BSIM_OUT_PATH}/bin/${exe_name}" +pushd "${BSIM_OUT_PATH}/bin" > /dev/null 2>&1 +if [ -e "${start_dir}/build/$testcase/output.log" ]; then + rm "${start_dir}/build/$testcase/output.log" +fi + +central_counts=$(wc -l ${start_dir}/${testcase}/centrals.txt | cut -d' ' -f1) +./${exe_name} -d=0 -s=${exe_name} | tee -a "${start_dir}/build/$testcase/output.log" > "${output_dev}" & +./bs_device_handbrake -s=${exe_name} -d=1 -r=10 > "${output_dev}" & + +cat "${start_dir}/${testcase}/centrals.txt" | +while IFS= read -r line +do + ${line} -s=${exe_name} | tee -a "${start_dir}/build/$testcase/output.log" > "${output_dev}" & +done + +./bs_2G4_phy_v1 -s=${exe_name} -D=$(( 2 + central_counts )) -sim_length=50e6 > "${output_dev}" 2>&1 + +popd > /dev/null 2>&1 + +cat build/$testcase/output.log | sed -E -n -f $testcase/events.patterns > build/$testcase/filtered_output.log + +diff -auZ $testcase/snapshot.log build/$testcase/filtered_output.log +if [ $? -gt 0 ]; then + if [ -f $testcase/pending ]; then + echo "PENDING: $testcase" | tee -a ./build/tests/pass-fail.log + exit 0 + fi + + if [ -n "${ZMK_TESTS_AUTO_ACCEPT}" ]; then + echo "Auto-accepting failure for $testcase" + cp build/$testcase/filtered_output.log $testcase/snapshot.log + else + echo "FAILED: $testcase" | tee -a ./build/tests/pass-fail.log + exit 1 + fi +fi + +echo "PASS: $testcase" | tee -a ./build/tests/pass-fail.log +exit 0 diff --git a/app/run-test.sh b/app/run-test.sh new file mode 100755 index 000000000000..cfd376686c81 --- /dev/null +++ b/app/run-test.sh @@ -0,0 +1,54 @@ +#!/bin/sh + +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if [ -z "$1" ]; then + echo "Usage: ./run-test.sh " + exit 1 +fi + +path="$1" +if [ $path = "all" ]; then + path="tests" +fi + +testcases=$(find $path -name native_posix_64.keymap -exec dirname \{\} \;) +num_cases=$(echo "$testcases" | wc -l) +if [ $num_cases -gt 1 ] || [ "$testcases" != "$path" ]; then + echo "" > ./build/tests/pass-fail.log + echo "$testcases" | xargs -L 1 -P ${J:-4} ./run-test.sh + err=$? + sort -k2 ./build/tests/pass-fail.log + exit $err +fi + +testcase="$path" +echo "Running $testcase:" + +west build -d build/$testcase -b native_posix_64 -- -DZMK_CONFIG="$(pwd)/$testcase" > /dev/null 2>&1 +if [ $? -gt 0 ]; then + echo "FAILED: $testcase did not build" | tee -a ./build/tests/pass-fail.log + exit 1 +fi + +./build/$testcase/zephyr/zmk.exe | sed -e "s/.*> //" | tee build/$testcase/keycode_events_full.log | sed -n -f $testcase/events.patterns > build/$testcase/keycode_events.log +diff -auZ $testcase/keycode_events.snapshot build/$testcase/keycode_events.log +if [ $? -gt 0 ]; then + if [ -f $testcase/pending ]; then + echo "PENDING: $testcase" | tee -a ./build/tests/pass-fail.log + exit 0 + fi + + + if [ -n "${ZMK_TESTS_AUTO_ACCEPT}" ]; then + echo "Auto-accepting failure for $testcase" + cp build/$testcase/keycode_events.log $testcase/keycode_events.snapshot + else + echo "FAILED: $testcase" | tee -a ./build/tests/pass-fail.log + exit 1 + fi +fi + +echo "PASS: $testcase" | tee -a ./build/tests/pass-fail.log +exit 0 diff --git a/app/scripts/requirements.txt b/app/scripts/requirements.txt new file mode 100644 index 000000000000..60d6f3aec07a --- /dev/null +++ b/app/scripts/requirements.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Convert YAML to JSON for validation +remarshal>=0.14.0 + +# Perform our hardware metadata validation +jsonschema>=3.2.0 \ No newline at end of file diff --git a/app/scripts/west-commands.yml b/app/scripts/west-commands.yml new file mode 100644 index 000000000000..64583a90678e --- /dev/null +++ b/app/scripts/west-commands.yml @@ -0,0 +1,14 @@ +# Copyright (c) 2020 ZMK Contributors +# SPDX-License-Identifier: MIT + +west-commands: + - file: scripts/west_commands/test.py + commands: + - name: test + class: Test + help: run ZMK testsuite + - file: scripts/west_commands/metadata.py + commands: + - name: metadata + class: Metadata + help: Operate on ZMK metadata files diff --git a/app/scripts/west_commands/metadata.py b/app/scripts/west_commands/metadata.py new file mode 100644 index 000000000000..244fb9bf6fd6 --- /dev/null +++ b/app/scripts/west_commands/metadata.py @@ -0,0 +1,64 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT +"""Metadata command for ZMK.""" + +from functools import cached_property +import glob +import json +import jsonschema +import sys +import yaml + +from west.commands import WestCommand +from west import log # use this for user output + + +class Metadata(WestCommand): + def __init__(self): + super().__init__( + name="metadata", + help="ZMK hardware metadata commands", + description="Operate on the board/shield metadata.", + ) + + def do_add_parser(self, parser_adder): + parser = parser_adder.add_parser( + self.name, help=self.help, description=self.description + ) + + parser.add_argument( + "subcommand", + default="check", + help='The subcommand to run. Defaults to "check".', + nargs="?", + ) + return parser # gets stored as self.parser + + @cached_property + def schema(self): + return json.load(open("../schema/hardware-metadata.schema.json", "r")) + + def validate_file(self, file): + print("Validating: " + file) + with open(file, "r") as stream: + try: + jsonschema.validate(yaml.safe_load(stream), self.schema) + except yaml.YAMLError as exc: + print("Failed loading metadata yaml: " + file) + print(exc) + return False + except jsonschema.ValidationError as vexc: + print("Failed validation of: " + file) + print(vexc) + return False + return True + + def do_run(self, args, unknown_args): + status = all( + [ + self.validate_file(f) + for f in glob.glob("boards/**/*.zmk.yml", recursive=True) + ] + ) + + sys.exit(0 if status else 1) diff --git a/app/scripts/west_commands/test.py b/app/scripts/west_commands/test.py new file mode 100644 index 000000000000..531334913b46 --- /dev/null +++ b/app/scripts/west_commands/test.py @@ -0,0 +1,41 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT +"""Test runner for ZMK.""" + +import os +import subprocess + +from west.commands import WestCommand +from west import log # use this for user output + + +class Test(WestCommand): + def __init__(self): + super().__init__( + name="test", + help="run ZMK testsuite", + description="Run the ZMK testsuite.", + ) + + def do_add_parser(self, parser_adder): + parser = parser_adder.add_parser( + self.name, + help=self.help, + description=self.description, + ) + + parser.add_argument( + "test_path", + default="all", + help='The path to the test. Defaults to "all".', + nargs="?", + ) + return parser + + def do_run(self, args, unknown_args): + # the run-test script assumes the app directory is the current dir. + os.chdir(f"{self.topdir}/app") + completed_process = subprocess.run( + [f"{self.topdir}/app/run-test.sh", args.test_path] + ) + exit(completed_process.returncode) diff --git a/app/src/activity.c b/app/src/activity.c new file mode 100644 index 000000000000..41fe2e15dc41 --- /dev/null +++ b/app/src/activity.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include + +#include + +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) +#include +#endif + +bool is_usb_power_present() { +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + return zmk_usb_is_powered(); +#else + return false; +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ +} + +static enum zmk_activity_state activity_state; + +static uint32_t activity_last_uptime; + +#define MAX_IDLE_MS CONFIG_ZMK_IDLE_TIMEOUT + +#if IS_ENABLED(CONFIG_ZMK_SLEEP) +#define MAX_SLEEP_MS CONFIG_ZMK_IDLE_SLEEP_TIMEOUT +#endif + +int raise_event() { + return ZMK_EVENT_RAISE(new_zmk_activity_state_changed( + (struct zmk_activity_state_changed){.state = activity_state})); +} + +int set_state(enum zmk_activity_state state) { + if (activity_state == state) + return 0; + + activity_state = state; + return raise_event(); +} + +enum zmk_activity_state zmk_activity_get_state() { return activity_state; } + +int activity_event_listener(const zmk_event_t *eh) { + activity_last_uptime = k_uptime_get(); + + return set_state(ZMK_ACTIVITY_ACTIVE); +} + +void activity_work_handler(struct k_work *work) { + int32_t current = k_uptime_get(); + int32_t inactive_time = current - activity_last_uptime; +#if IS_ENABLED(CONFIG_ZMK_SLEEP) + if (inactive_time > MAX_SLEEP_MS && !is_usb_power_present()) { + // Put devices in suspend power mode before sleeping + set_state(ZMK_ACTIVITY_SLEEP); + pm_state_force(0U, &(struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0}); + } else +#endif /* IS_ENABLED(CONFIG_ZMK_SLEEP) */ + if (inactive_time > MAX_IDLE_MS) { + set_state(ZMK_ACTIVITY_IDLE); + } +} + +K_WORK_DEFINE(activity_work, activity_work_handler); + +void activity_expiry_function() { k_work_submit(&activity_work); } + +K_TIMER_DEFINE(activity_timer, activity_expiry_function, NULL); + +int activity_init() { + activity_last_uptime = k_uptime_get(); + + k_timer_start(&activity_timer, K_SECONDS(1), K_SECONDS(1)); + return 0; +} + +ZMK_LISTENER(activity, activity_event_listener); +ZMK_SUBSCRIPTION(activity, zmk_position_state_changed); +ZMK_SUBSCRIPTION(activity, zmk_sensor_event); + +SYS_INIT(activity_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/app/src/backlight.c b/app/src/backlight.c new file mode 100644 index 000000000000..f633ddb728b6 --- /dev/null +++ b/app/src/backlight.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +BUILD_ASSERT(DT_HAS_CHOSEN(zmk_backlight), + "CONFIG_ZMK_BACKLIGHT is enabled but no zmk,backlight chosen node found"); + +static const struct device *const backlight_dev = DEVICE_DT_GET(DT_CHOSEN(zmk_backlight)); + +#define CHILD_COUNT(...) +1 +#define DT_NUM_CHILD(node_id) (DT_FOREACH_CHILD(node_id, CHILD_COUNT)) + +#define BACKLIGHT_NUM_LEDS (DT_NUM_CHILD(DT_CHOSEN(zmk_backlight))) + +#define BRT_MAX 100 + +struct backlight_state { + uint8_t brightness; + bool on; +}; + +static struct backlight_state state = {.brightness = CONFIG_ZMK_BACKLIGHT_BRT_START, + .on = IS_ENABLED(CONFIG_ZMK_BACKLIGHT_ON_START)}; + +static int zmk_backlight_update() { + uint8_t brt = zmk_backlight_get_brt(); + LOG_DBG("Update backlight brightness: %d%%", brt); + + for (int i = 0; i < BACKLIGHT_NUM_LEDS; i++) { + int rc = led_set_brightness(backlight_dev, i, brt); + if (rc != 0) { + LOG_ERR("Failed to update backlight LED %d: %d", i, rc); + return rc; + } + } + return 0; +} + +#if IS_ENABLED(CONFIG_SETTINGS) +static int backlight_settings_load_cb(const char *name, size_t len, settings_read_cb read_cb, + void *cb_arg, void *param) { + const char *next; + if (settings_name_steq(name, "state", &next) && !next) { + if (len != sizeof(state)) { + return -EINVAL; + } + + int rc = read_cb(cb_arg, &state, sizeof(state)); + return MIN(rc, 0); + } + return -ENOENT; +} + +static void backlight_save_work_handler(struct k_work *work) { + settings_save_one("backlight/state", &state, sizeof(state)); +} + +static struct k_work_delayable backlight_save_work; +#endif + +static int zmk_backlight_init(const struct device *_arg) { + if (!device_is_ready(backlight_dev)) { + LOG_ERR("Backlight device \"%s\" is not ready", backlight_dev->name); + return -ENODEV; + } + +#if IS_ENABLED(CONFIG_SETTINGS) + settings_subsys_init(); + int rc = settings_load_subtree_direct("backlight", backlight_settings_load_cb, NULL); + if (rc != 0) { + LOG_ERR("Failed to load backlight settings: %d", rc); + } + k_work_init_delayable(&backlight_save_work, backlight_save_work_handler); +#endif +#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB) + state.on = zmk_usb_is_powered(); +#endif + return zmk_backlight_update(); +} + +static int zmk_backlight_update_and_save() { + int rc = zmk_backlight_update(); + if (rc != 0) { + return rc; + } + +#if IS_ENABLED(CONFIG_SETTINGS) + int ret = k_work_reschedule(&backlight_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE)); + return MIN(ret, 0); +#else + return 0; +#endif +} + +int zmk_backlight_on() { + state.brightness = MAX(state.brightness, CONFIG_ZMK_BACKLIGHT_BRT_STEP); + state.on = true; + return zmk_backlight_update_and_save(); +} + +int zmk_backlight_off() { + state.on = false; + return zmk_backlight_update_and_save(); +} + +int zmk_backlight_toggle() { return state.on ? zmk_backlight_off() : zmk_backlight_on(); } + +bool zmk_backlight_is_on() { return state.on; } + +int zmk_backlight_set_brt(uint8_t brightness) { + state.brightness = MIN(brightness, BRT_MAX); + state.on = (state.brightness > 0); + return zmk_backlight_update_and_save(); +} + +uint8_t zmk_backlight_get_brt() { return state.on ? state.brightness : 0; } + +uint8_t zmk_backlight_calc_brt(int direction) { + int brt = state.brightness + (direction * CONFIG_ZMK_BACKLIGHT_BRT_STEP); + return CLAMP(brt, 0, BRT_MAX); +} + +uint8_t zmk_backlight_calc_brt_cycle() { + if (state.brightness == BRT_MAX) { + return 0; + } else { + return zmk_backlight_calc_brt(1); + } +} + +#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE) || IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB) +static int backlight_auto_state(bool *prev_state, bool new_state) { + if (state.on == new_state) { + return 0; + } + state.on = new_state && *prev_state; + *prev_state = !new_state; + return zmk_backlight_update(); +} + +static int backlight_event_listener(const zmk_event_t *eh) { + +#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE) + if (as_zmk_activity_state_changed(eh)) { + static bool prev_state = false; + return backlight_auto_state(&prev_state, zmk_activity_get_state() == ZMK_ACTIVITY_ACTIVE); + } +#endif + +#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB) + if (as_zmk_usb_conn_state_changed(eh)) { + static bool prev_state = false; + return backlight_auto_state(&prev_state, zmk_usb_is_powered()); + } +#endif + + return -ENOTSUP; +} + +ZMK_LISTENER(backlight, backlight_event_listener); +#endif // IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE) || + // IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB) + +#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE) +ZMK_SUBSCRIPTION(backlight, zmk_activity_state_changed); +#endif + +#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB) +ZMK_SUBSCRIPTION(backlight, zmk_usb_conn_state_changed); +#endif + +SYS_INIT(zmk_backlight_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/app/src/battery.c b/app/src/battery.c new file mode 100644 index 000000000000..e76797ef9979 --- /dev/null +++ b/app/src/battery.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include +#include + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include +#include +#include + +static uint8_t last_state_of_charge = 0; + +uint8_t zmk_battery_state_of_charge() { return last_state_of_charge; } + +#if DT_HAS_CHOSEN(zmk_battery) +static const struct device *const battery = DEVICE_DT_GET(DT_CHOSEN(zmk_battery)); +#else +#warning \ + "Using a node labeled BATTERY for the battery sensor is deprecated. Set a zmk,battery chosen node instead. (Ignore this if you don't have a battery sensor.)" +static const struct device *battery; +#endif + +static int zmk_battery_update(const struct device *battery) { + struct sensor_value state_of_charge; + + int rc = sensor_sample_fetch_chan(battery, SENSOR_CHAN_GAUGE_STATE_OF_CHARGE); + + if (rc != 0) { + LOG_DBG("Failed to fetch battery values: %d", rc); + return rc; + } + + rc = sensor_channel_get(battery, SENSOR_CHAN_GAUGE_STATE_OF_CHARGE, &state_of_charge); + + if (rc != 0) { + LOG_DBG("Failed to get battery state of charge: %d", rc); + return rc; + } + + if (last_state_of_charge != state_of_charge.val1) { + last_state_of_charge = state_of_charge.val1; +#if IS_ENABLED(CONFIG_BT_BAS) + LOG_DBG("Setting BAS GATT battery level to %d.", last_state_of_charge); + + rc = bt_bas_set_battery_level(last_state_of_charge); + + if (rc != 0) { + LOG_WRN("Failed to set BAS GATT battery level (err %d)", rc); + return rc; + } +#endif + rc = ZMK_EVENT_RAISE(new_zmk_battery_state_changed( + (struct zmk_battery_state_changed){.state_of_charge = last_state_of_charge})); + } + + return rc; +} + +static void zmk_battery_work(struct k_work *work) { + int rc = zmk_battery_update(battery); + + if (rc != 0) { + LOG_DBG("Failed to update battery value: %d.", rc); + } +} + +K_WORK_DEFINE(battery_work, zmk_battery_work); + +static void zmk_battery_timer(struct k_timer *timer) { + k_work_submit_to_queue(zmk_workqueue_lowprio_work_q(), &battery_work); +} + +K_TIMER_DEFINE(battery_timer, zmk_battery_timer, NULL); + +static void zmk_battery_start_reporting() { + k_timer_start(&battery_timer, K_NO_WAIT, K_SECONDS(CONFIG_ZMK_BATTERY_REPORT_INTERVAL)); +} + +static int zmk_battery_init(const struct device *_arg) { +#if !DT_HAS_CHOSEN(zmk_battery) + battery = device_get_binding("BATTERY"); + + if (battery == NULL) { + return -ENODEV; + } + + LOG_WRN("Finding battery device labeled BATTERY is deprecated. Use zmk,battery chosen node."); +#endif + + if (!device_is_ready(battery)) { + LOG_ERR("Battery device \"%s\" is not ready", battery->name); + return -ENODEV; + } + + zmk_battery_start_reporting(); + return 0; +} + +static int battery_event_listener(const zmk_event_t *eh) { + + if (as_zmk_activity_state_changed(eh)) { + switch (zmk_activity_get_state()) { + case ZMK_ACTIVITY_ACTIVE: + zmk_battery_start_reporting(); + return 0; + case ZMK_ACTIVITY_IDLE: + case ZMK_ACTIVITY_SLEEP: + k_timer_stop(&battery_timer); + return 0; + default: + break; + } + } + return -ENOTSUP; +} + +ZMK_LISTENER(battery, battery_event_listener); + +ZMK_SUBSCRIPTION(battery, zmk_activity_state_changed); + +SYS_INIT(zmk_battery_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/app/src/behavior.c b/app/src/behavior.c new file mode 100644 index 000000000000..fd2b0ec17540 --- /dev/null +++ b/app/src/behavior.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +const struct device *zmk_behavior_get_binding(const char *name) { + return behavior_get_binding(name); +} + +const struct device *z_impl_behavior_get_binding(const char *name) { + if (name == NULL || name[0] == '\0') { + return NULL; + } + + STRUCT_SECTION_FOREACH(zmk_behavior_ref, item) { + if (z_device_is_ready(item->device) && item->device->name == name) { + return item->device; + } + } + + STRUCT_SECTION_FOREACH(zmk_behavior_ref, item) { + if (z_device_is_ready(item->device) && strcmp(item->device->name, name) == 0) { + return item->device; + } + } + + return NULL; +} + +#if IS_ENABLED(CONFIG_LOG) +static int check_behavior_names(const struct device *dev) { + ARG_UNUSED(dev); + + // Behavior names must be unique, but we don't have a good way to enforce this + // at compile time, so log an error at runtime if they aren't unique. + ptrdiff_t count; + STRUCT_SECTION_COUNT(zmk_behavior_ref, &count); + + for (ptrdiff_t i = 0; i < count; i++) { + const struct zmk_behavior_ref *current; + STRUCT_SECTION_GET(zmk_behavior_ref, i, ¤t); + + for (ptrdiff_t j = i + 1; j < count; j++) { + const struct zmk_behavior_ref *other; + STRUCT_SECTION_GET(zmk_behavior_ref, j, &other); + + if (strcmp(current->device->name, other->device->name) == 0) { + LOG_ERR("Multiple behaviors have the same name '%s'", current->device->name); + } + } + } + + return 0; +} + +SYS_INIT(check_behavior_names, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); +#endif // IS_ENABLED(CONFIG_LOG) diff --git a/app/src/behavior_queue.c b/app/src/behavior_queue.c new file mode 100644 index 000000000000..1511e755d4f0 --- /dev/null +++ b/app/src/behavior_queue.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +struct q_item { + uint32_t position; + struct zmk_behavior_binding binding; + bool press : 1; + uint32_t wait : 31; +}; + +K_MSGQ_DEFINE(zmk_behavior_queue_msgq, sizeof(struct q_item), CONFIG_ZMK_BEHAVIORS_QUEUE_SIZE, 4); + +static void behavior_queue_process_next(struct k_work *work); +static K_WORK_DELAYABLE_DEFINE(queue_work, behavior_queue_process_next); + +static void behavior_queue_process_next(struct k_work *work) { + struct q_item item = {.wait = 0}; + + while (k_msgq_get(&zmk_behavior_queue_msgq, &item, K_NO_WAIT) == 0) { + LOG_DBG("Invoking %s: 0x%02x 0x%02x", item.binding.behavior_dev, item.binding.param1, + item.binding.param2); + + struct zmk_behavior_binding_event event = {.position = item.position, + .timestamp = k_uptime_get()}; + + if (item.press) { + behavior_keymap_binding_pressed(&item.binding, event); + } else { + behavior_keymap_binding_released(&item.binding, event); + } + + LOG_DBG("Processing next queued behavior in %dms", item.wait); + + if (item.wait > 0) { + k_work_schedule(&queue_work, K_MSEC(item.wait)); + break; + } + } +} + +int zmk_behavior_queue_add(uint32_t position, const struct zmk_behavior_binding binding, bool press, + uint32_t wait) { + struct q_item item = {.press = press, .binding = binding, .wait = wait}; + + const int ret = k_msgq_put(&zmk_behavior_queue_msgq, &item, K_NO_WAIT); + if (ret < 0) { + return ret; + } + + if (!k_work_delayable_is_pending(&queue_work)) { + behavior_queue_process_next(&queue_work.work); + } + + return 0; +} diff --git a/app/src/behaviors/behavior_backlight.c b/app/src/behaviors/behavior_backlight.c new file mode 100644 index 000000000000..42967e398c3f --- /dev/null +++ b/app/src/behaviors/behavior_backlight.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_backlight + +#include +#include +#include + +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +static int behavior_backlight_init(const struct device *dev) { return 0; } + +static int +on_keymap_binding_convert_central_state_dependent_params(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + switch (binding->param1) { + case BL_TOG_CMD: + binding->param1 = zmk_backlight_is_on() ? BL_OFF_CMD : BL_ON_CMD; + break; + case BL_INC_CMD: + binding->param1 = BL_SET_CMD; + binding->param2 = zmk_backlight_calc_brt(1); + break; + case BL_DEC_CMD: + binding->param1 = BL_SET_CMD; + binding->param2 = zmk_backlight_calc_brt(-1); + break; + case BL_CYCLE_CMD: + binding->param1 = BL_SET_CMD; + binding->param2 = zmk_backlight_calc_brt_cycle(); + break; + default: + return 0; + } + + LOG_DBG("Backlight relative to absolute (%d/%d)", binding->param1, binding->param2); + + return 0; +} + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + switch (binding->param1) { + case BL_ON_CMD: + return zmk_backlight_on(); + case BL_OFF_CMD: + return zmk_backlight_off(); + case BL_TOG_CMD: + return zmk_backlight_toggle(); + case BL_INC_CMD: { + uint8_t brt = zmk_backlight_calc_brt(1); + return zmk_backlight_set_brt(brt); + } + case BL_DEC_CMD: { + uint8_t brt = zmk_backlight_calc_brt(-1); + return zmk_backlight_set_brt(brt); + } + case BL_CYCLE_CMD: { + uint8_t brt = zmk_backlight_calc_brt_cycle(); + return zmk_backlight_set_brt(brt); + } + case BL_SET_CMD: + return zmk_backlight_set_brt(binding->param2); + default: + LOG_ERR("Unknown backlight command: %d", binding->param1); + } + + return -ENOTSUP; +} + +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + return ZMK_BEHAVIOR_OPAQUE; +} + +static const struct behavior_driver_api behavior_backlight_driver_api = { + .binding_convert_central_state_dependent_params = + on_keymap_binding_convert_central_state_dependent_params, + .binding_pressed = on_keymap_binding_pressed, + .binding_released = on_keymap_binding_released, + .locality = BEHAVIOR_LOCALITY_GLOBAL, +}; + +BEHAVIOR_DT_INST_DEFINE(0, behavior_backlight_init, NULL, NULL, NULL, APPLICATION, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_backlight_driver_api); + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/behaviors/behavior_bt.c b/app/src/behaviors/behavior_bt.c new file mode 100644 index 000000000000..18a626b9bae4 --- /dev/null +++ b/app/src/behaviors/behavior_bt.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_bluetooth + +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include + +#include + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + switch (binding->param1) { + case BT_CLR_CMD: + return zmk_ble_clear_bonds(); + case BT_NXT_CMD: + return zmk_ble_prof_next(); + case BT_PRV_CMD: + return zmk_ble_prof_prev(); + case BT_SEL_CMD: + return zmk_ble_prof_select(binding->param2); + case BT_DISC_CMD: + return zmk_ble_prof_disconnect(binding->param2); + default: + LOG_ERR("Unknown BT command: %d", binding->param1); + } + + return -ENOTSUP; +} + +static int behavior_bt_init(const struct device *dev) { return 0; }; + +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + return ZMK_BEHAVIOR_OPAQUE; +} + +static const struct behavior_driver_api behavior_bt_driver_api = { + .binding_pressed = on_keymap_binding_pressed, + .binding_released = on_keymap_binding_released, +}; + +BEHAVIOR_DT_INST_DEFINE(0, behavior_bt_init, NULL, NULL, NULL, APPLICATION, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_bt_driver_api); + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/behaviors/behavior_caps_word.c b/app/src/behaviors/behavior_caps_word.c new file mode 100644 index 000000000000..53ea489f846c --- /dev/null +++ b/app/src/behaviors/behavior_caps_word.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_caps_word + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +struct caps_word_continue_item { + uint16_t page; + uint32_t id; + uint8_t implicit_modifiers; +}; + +struct behavior_caps_word_config { + zmk_mod_flags_t mods; + uint8_t index; + uint8_t continuations_count; + struct caps_word_continue_item continuations[]; +}; + +struct behavior_caps_word_data { + bool active; +}; + +static void activate_caps_word(const struct device *dev) { + struct behavior_caps_word_data *data = dev->data; + + data->active = true; +} + +static void deactivate_caps_word(const struct device *dev) { + struct behavior_caps_word_data *data = dev->data; + + data->active = false; +} + +static int on_caps_word_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); + struct behavior_caps_word_data *data = dev->data; + + if (data->active) { + deactivate_caps_word(dev); + } else { + activate_caps_word(dev); + } + + return ZMK_BEHAVIOR_OPAQUE; +} + +static int on_caps_word_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + return ZMK_BEHAVIOR_OPAQUE; +} + +static const struct behavior_driver_api behavior_caps_word_driver_api = { + .binding_pressed = on_caps_word_binding_pressed, + .binding_released = on_caps_word_binding_released, +}; + +static int caps_word_keycode_state_changed_listener(const zmk_event_t *eh); + +ZMK_LISTENER(behavior_caps_word, caps_word_keycode_state_changed_listener); +ZMK_SUBSCRIPTION(behavior_caps_word, zmk_keycode_state_changed); + +static const struct device *devs[DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT)]; + +static bool caps_word_is_caps_includelist(const struct behavior_caps_word_config *config, + uint16_t usage_page, uint8_t usage_id, + uint8_t implicit_modifiers) { + for (int i = 0; i < config->continuations_count; i++) { + const struct caps_word_continue_item *continuation = &config->continuations[i]; + LOG_DBG("Comparing with 0x%02X - 0x%02X (with implicit mods: 0x%02X)", continuation->page, + continuation->id, continuation->implicit_modifiers); + + if (continuation->page == usage_page && continuation->id == usage_id && + (continuation->implicit_modifiers & + (implicit_modifiers | zmk_hid_get_explicit_mods())) == + continuation->implicit_modifiers) { + LOG_DBG("Continuing capsword, found included usage: 0x%02X - 0x%02X", usage_page, + usage_id); + return true; + } + } + + return false; +} + +static bool caps_word_is_alpha(uint8_t usage_id) { + return (usage_id >= HID_USAGE_KEY_KEYBOARD_A && usage_id <= HID_USAGE_KEY_KEYBOARD_Z); +} + +static bool caps_word_is_numeric(uint8_t usage_id) { + return (usage_id >= HID_USAGE_KEY_KEYBOARD_1_AND_EXCLAMATION && + usage_id <= HID_USAGE_KEY_KEYBOARD_0_AND_RIGHT_PARENTHESIS); +} + +static void caps_word_enhance_usage(const struct behavior_caps_word_config *config, + struct zmk_keycode_state_changed *ev) { + if (ev->usage_page != HID_USAGE_KEY || !caps_word_is_alpha(ev->keycode)) { + return; + } + + LOG_DBG("Enhancing usage 0x%02X with modifiers: 0x%02X", ev->keycode, config->mods); + ev->implicit_modifiers |= config->mods; +} + +static int caps_word_keycode_state_changed_listener(const zmk_event_t *eh) { + struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh); + if (ev == NULL || !ev->state) { + return ZMK_EV_EVENT_BUBBLE; + } + + for (int i = 0; i < DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT); i++) { + const struct device *dev = devs[i]; + if (dev == NULL) { + continue; + } + + struct behavior_caps_word_data *data = dev->data; + if (!data->active) { + continue; + } + + const struct behavior_caps_word_config *config = dev->config; + + caps_word_enhance_usage(config, ev); + + if (!caps_word_is_alpha(ev->keycode) && !caps_word_is_numeric(ev->keycode) && + !is_mod(ev->usage_page, ev->keycode) && + !caps_word_is_caps_includelist(config, ev->usage_page, ev->keycode, + ev->implicit_modifiers)) { + LOG_DBG("Deactivating caps_word for 0x%02X - 0x%02X", ev->usage_page, ev->keycode); + deactivate_caps_word(dev); + } + } + + return ZMK_EV_EVENT_BUBBLE; +} + +static int behavior_caps_word_init(const struct device *dev) { + const struct behavior_caps_word_config *config = dev->config; + devs[config->index] = dev; + return 0; +} + +#define CAPS_WORD_LABEL(i, _n) DT_INST_LABEL(i) + +#define PARSE_BREAK(i) \ + { \ + .page = ZMK_HID_USAGE_PAGE(i), .id = ZMK_HID_USAGE_ID(i), \ + .implicit_modifiers = SELECT_MODS(i) \ + } + +#define BREAK_ITEM(i, n) PARSE_BREAK(DT_INST_PROP_BY_IDX(n, continue_list, i)) + +#define KP_INST(n) \ + static struct behavior_caps_word_data behavior_caps_word_data_##n = {.active = false}; \ + static struct behavior_caps_word_config behavior_caps_word_config_##n = { \ + .index = n, \ + .mods = DT_INST_PROP_OR(n, mods, MOD_LSFT), \ + .continuations = {LISTIFY(DT_INST_PROP_LEN(n, continue_list), BREAK_ITEM, (, ), n)}, \ + .continuations_count = DT_INST_PROP_LEN(n, continue_list), \ + }; \ + BEHAVIOR_DT_INST_DEFINE(n, behavior_caps_word_init, NULL, &behavior_caps_word_data_##n, \ + &behavior_caps_word_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_caps_word_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KP_INST) + +#endif diff --git a/app/src/behaviors/behavior_ext_power.c b/app/src/behaviors/behavior_ext_power.c new file mode 100644 index 000000000000..0af30b0081b9 --- /dev/null +++ b/app/src/behaviors/behavior_ext_power.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_ext_power + +#include +#include +#include +#include + +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +static int +on_keymap_binding_convert_central_state_dependent_params(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *ext_power = device_get_binding("EXT_POWER"); + if (ext_power == NULL) { + LOG_ERR("Unable to retrieve ext_power device: %d", binding->param1); + return -EIO; + } + + if (binding->param1 == EXT_POWER_TOGGLE_CMD) { + binding->param1 = ext_power_get(ext_power) > 0 ? EXT_POWER_OFF_CMD : EXT_POWER_ON_CMD; + } + + return 0; +} + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *ext_power = device_get_binding("EXT_POWER"); + if (ext_power == NULL) { + LOG_ERR("Unable to retrieve ext_power device: %d", binding->param1); + return -EIO; + } + + switch (binding->param1) { + case EXT_POWER_OFF_CMD: + return ext_power_disable(ext_power); + case EXT_POWER_ON_CMD: + return ext_power_enable(ext_power); + case EXT_POWER_TOGGLE_CMD: + if (ext_power_get(ext_power) > 0) + return ext_power_disable(ext_power); + else + return ext_power_enable(ext_power); + default: + LOG_ERR("Unknown ext_power command: %d", binding->param1); + } + + return -ENOTSUP; +} + +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + return ZMK_BEHAVIOR_OPAQUE; +} + +static int behavior_ext_power_init(const struct device *dev) { return 0; }; + +static const struct behavior_driver_api behavior_ext_power_driver_api = { + .binding_convert_central_state_dependent_params = + on_keymap_binding_convert_central_state_dependent_params, + .binding_pressed = on_keymap_binding_pressed, + .binding_released = on_keymap_binding_released, + .locality = BEHAVIOR_LOCALITY_GLOBAL, +}; + +BEHAVIOR_DT_INST_DEFINE(0, behavior_ext_power_init, NULL, NULL, NULL, APPLICATION, + CONFIG_APPLICATION_INIT_PRIORITY, &behavior_ext_power_driver_api); + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/behaviors/behavior_hold_tap.c b/app/src/behaviors/behavior_hold_tap.c new file mode 100644 index 000000000000..ea0448a4fd5c --- /dev/null +++ b/app/src/behaviors/behavior_hold_tap.c @@ -0,0 +1,724 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_hold_tap + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +#define ZMK_BHV_HOLD_TAP_MAX_HELD 10 +#define ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS 40 + +// increase if you have keyboard with more keys. +#define ZMK_BHV_HOLD_TAP_POSITION_NOT_USED 9999 + +enum flavor { + FLAVOR_HOLD_PREFERRED, + FLAVOR_BALANCED, + FLAVOR_TAP_PREFERRED, + FLAVOR_TAP_UNLESS_INTERRUPTED, +}; + +enum status { + STATUS_UNDECIDED, + STATUS_TAP, + STATUS_HOLD_INTERRUPT, + STATUS_HOLD_TIMER, +}; + +enum decision_moment { + HT_KEY_UP, + HT_OTHER_KEY_DOWN, + HT_OTHER_KEY_UP, + HT_TIMER_EVENT, + HT_QUICK_TAP, +}; + +struct behavior_hold_tap_config { + int tapping_term_ms; + char *hold_behavior_dev; + char *tap_behavior_dev; + int quick_tap_ms; + int require_prior_idle_ms; + enum flavor flavor; + bool retro_tap; + bool hold_trigger_on_release; + int32_t hold_trigger_key_positions_len; + int32_t hold_trigger_key_positions[]; +}; + +// this data is specific for each hold-tap +struct active_hold_tap { + int32_t position; + uint32_t param_hold; + uint32_t param_tap; + int64_t timestamp; + enum status status; + const struct behavior_hold_tap_config *config; + struct k_work_delayable work; + bool work_is_cancelled; + + // initialized to -1, which is to be interpreted as "no other key has been pressed yet" + int32_t position_of_first_other_key_pressed; +}; + +// The undecided hold tap is the hold tap that needs to be decided before +// other keypress events can be released. While the undecided_hold_tap is +// not NULL, most events are captured in captured_events. +// After the hold_tap is decided, it will stay in the active_hold_taps until +// its key-up has been processed and the delayed work is cleaned up. +struct active_hold_tap *undecided_hold_tap = NULL; +struct active_hold_tap active_hold_taps[ZMK_BHV_HOLD_TAP_MAX_HELD] = {}; +// We capture most position_state_changed events and some modifiers_state_changed events. +const zmk_event_t *captured_events[ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS] = {}; + +// Keep track of which key was tapped most recently for the standard, if it is a hold-tap +// a position, will be given, if not it will just be INT32_MIN +struct last_tapped { + int32_t position; + int64_t timestamp; +}; + +// Set time stamp to large negative number initially for test suites, but not +// int64 min since it will overflow if -1 is added +struct last_tapped last_tapped = {INT32_MIN, INT32_MIN}; + +static void store_last_tapped(int64_t timestamp) { + if (timestamp > last_tapped.timestamp) { + last_tapped.position = INT32_MIN; + last_tapped.timestamp = timestamp; + } +} + +static void store_last_hold_tapped(struct active_hold_tap *hold_tap) { + last_tapped.position = hold_tap->position; + last_tapped.timestamp = hold_tap->timestamp; +} + +static bool is_quick_tap(struct active_hold_tap *hold_tap) { + if ((last_tapped.timestamp + hold_tap->config->require_prior_idle_ms) > hold_tap->timestamp) { + return true; + } else { + return (last_tapped.position == hold_tap->position) && + (last_tapped.timestamp + hold_tap->config->quick_tap_ms) > hold_tap->timestamp; + } +} + +static int capture_event(const zmk_event_t *event) { + for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) { + if (captured_events[i] == NULL) { + captured_events[i] = event; + return 0; + } + } + return -ENOMEM; +} + +static struct zmk_position_state_changed *find_captured_keydown_event(uint32_t position) { + struct zmk_position_state_changed *last_match = NULL; + for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) { + const zmk_event_t *eh = captured_events[i]; + if (eh == NULL) { + return last_match; + } + struct zmk_position_state_changed *position_event = as_zmk_position_state_changed(eh); + if (position_event == NULL) { + continue; + } + + if (position_event->position == position && position_event->state) { + last_match = position_event; + } + } + return last_match; +} + +const struct zmk_listener zmk_listener_behavior_hold_tap; + +static void release_captured_events() { + if (undecided_hold_tap != NULL) { + return; + } + + // We use a trick to prevent copying the captured_events array. + // + // Events for different mod-tap instances are separated by a NULL pointer. + // + // The first event popped will never be catched by the next active hold-tap + // because to start capturing a mod-tap-key-down event must first completely + // go through the events queue. + // + // Example of this release process; + // [mt2_down, k1_down, k1_up, mt2_up, null, ...] + // ^ + // mt2_down position event isn't captured because no hold-tap is active. + // mt2_down behavior event is handled, now we have an undecided hold-tap + // [null, k1_down, k1_up, mt2_up, null, ...] + // ^ + // k1_down is captured by the mt2 mod-tap + // !note that searches for find_captured_keydown_event by the mt2 behavior will stop at the + // first null encountered [mt1_down, null, k1_up, mt2_up, null, ...] + // ^ + // k1_up event is captured by the new hold-tap: + // [k1_down, k1_up, null, mt2_up, null, ...] + // ^ + // mt2_up event is not captured but causes release of mt2 behavior + // [k1_down, k1_up, null, null, null, ...] + // now mt2 will start releasing it's own captured positions. + for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) { + const zmk_event_t *captured_event = captured_events[i]; + if (captured_event == NULL) { + return; + } + captured_events[i] = NULL; + if (undecided_hold_tap != NULL) { + k_msleep(10); + } + + struct zmk_position_state_changed *position_event; + struct zmk_keycode_state_changed *modifier_event; + if ((position_event = as_zmk_position_state_changed(captured_event)) != NULL) { + LOG_DBG("Releasing key position event for position %d %s", position_event->position, + (position_event->state ? "pressed" : "released")); + } else if ((modifier_event = as_zmk_keycode_state_changed(captured_event)) != NULL) { + LOG_DBG("Releasing mods changed event 0x%02X %s", modifier_event->keycode, + (modifier_event->state ? "pressed" : "released")); + } + ZMK_EVENT_RAISE_AT(captured_event, behavior_hold_tap); + } +} + +static struct active_hold_tap *find_hold_tap(uint32_t position) { + for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) { + if (active_hold_taps[i].position == position) { + return &active_hold_taps[i]; + } + } + return NULL; +} + +static struct active_hold_tap *store_hold_tap(uint32_t position, uint32_t param_hold, + uint32_t param_tap, int64_t timestamp, + const struct behavior_hold_tap_config *config) { + for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) { + if (active_hold_taps[i].position != ZMK_BHV_HOLD_TAP_POSITION_NOT_USED) { + continue; + } + active_hold_taps[i].position = position; + active_hold_taps[i].status = STATUS_UNDECIDED; + active_hold_taps[i].config = config; + active_hold_taps[i].param_hold = param_hold; + active_hold_taps[i].param_tap = param_tap; + active_hold_taps[i].timestamp = timestamp; + active_hold_taps[i].position_of_first_other_key_pressed = -1; + return &active_hold_taps[i]; + } + return NULL; +} + +static void clear_hold_tap(struct active_hold_tap *hold_tap) { + hold_tap->position = ZMK_BHV_HOLD_TAP_POSITION_NOT_USED; + hold_tap->status = STATUS_UNDECIDED; + hold_tap->work_is_cancelled = false; +} + +static void decide_balanced(struct active_hold_tap *hold_tap, enum decision_moment event) { + switch (event) { + case HT_KEY_UP: + hold_tap->status = STATUS_TAP; + return; + case HT_OTHER_KEY_UP: + hold_tap->status = STATUS_HOLD_INTERRUPT; + return; + case HT_TIMER_EVENT: + hold_tap->status = STATUS_HOLD_TIMER; + return; + case HT_QUICK_TAP: + hold_tap->status = STATUS_TAP; + return; + default: + return; + } +} + +static void decide_tap_preferred(struct active_hold_tap *hold_tap, enum decision_moment event) { + switch (event) { + case HT_KEY_UP: + hold_tap->status = STATUS_TAP; + return; + case HT_TIMER_EVENT: + hold_tap->status = STATUS_HOLD_TIMER; + return; + case HT_QUICK_TAP: + hold_tap->status = STATUS_TAP; + return; + default: + return; + } +} + +static void decide_tap_unless_interrupted(struct active_hold_tap *hold_tap, + enum decision_moment event) { + switch (event) { + case HT_KEY_UP: + hold_tap->status = STATUS_TAP; + return; + case HT_OTHER_KEY_DOWN: + hold_tap->status = STATUS_HOLD_INTERRUPT; + return; + case HT_TIMER_EVENT: + hold_tap->status = STATUS_TAP; + return; + case HT_QUICK_TAP: + hold_tap->status = STATUS_TAP; + return; + default: + return; + } +} + +static void decide_hold_preferred(struct active_hold_tap *hold_tap, enum decision_moment event) { + switch (event) { + case HT_KEY_UP: + hold_tap->status = STATUS_TAP; + return; + case HT_OTHER_KEY_DOWN: + hold_tap->status = STATUS_HOLD_INTERRUPT; + return; + case HT_TIMER_EVENT: + hold_tap->status = STATUS_HOLD_TIMER; + return; + case HT_QUICK_TAP: + hold_tap->status = STATUS_TAP; + return; + default: + return; + } +} + +static inline const char *flavor_str(enum flavor flavor) { + switch (flavor) { + case FLAVOR_HOLD_PREFERRED: + return "hold-preferred"; + case FLAVOR_BALANCED: + return "balanced"; + case FLAVOR_TAP_PREFERRED: + return "tap-preferred"; + case FLAVOR_TAP_UNLESS_INTERRUPTED: + return "tap-unless-interrupted"; + default: + return "UNKNOWN FLAVOR"; + } +} + +static inline const char *status_str(enum status status) { + switch (status) { + case STATUS_UNDECIDED: + return "undecided"; + case STATUS_HOLD_TIMER: + return "hold-timer"; + case STATUS_HOLD_INTERRUPT: + return "hold-interrupt"; + case STATUS_TAP: + return "tap"; + default: + return "UNKNOWN STATUS"; + } +} + +static inline const char *decision_moment_str(enum decision_moment decision_moment) { + switch (decision_moment) { + case HT_KEY_UP: + return "key-up"; + case HT_OTHER_KEY_DOWN: + return "other-key-down"; + case HT_OTHER_KEY_UP: + return "other-key-up"; + case HT_QUICK_TAP: + return "quick-tap"; + case HT_TIMER_EVENT: + return "timer"; + default: + return "UNKNOWN STATUS"; + } +} + +static int press_binding(struct active_hold_tap *hold_tap) { + if (hold_tap->config->retro_tap && hold_tap->status == STATUS_HOLD_TIMER) { + return 0; + } + + struct zmk_behavior_binding_event event = { + .position = hold_tap->position, + .timestamp = hold_tap->timestamp, + }; + + struct zmk_behavior_binding binding = {0}; + if (hold_tap->status == STATUS_HOLD_TIMER || hold_tap->status == STATUS_HOLD_INTERRUPT) { + binding.behavior_dev = hold_tap->config->hold_behavior_dev; + binding.param1 = hold_tap->param_hold; + } else { + binding.behavior_dev = hold_tap->config->tap_behavior_dev; + binding.param1 = hold_tap->param_tap; + store_last_hold_tapped(hold_tap); + } + return behavior_keymap_binding_pressed(&binding, event); +} + +static int release_binding(struct active_hold_tap *hold_tap) { + if (hold_tap->config->retro_tap && hold_tap->status == STATUS_HOLD_TIMER) { + return 0; + } + + struct zmk_behavior_binding_event event = { + .position = hold_tap->position, + .timestamp = hold_tap->timestamp, + }; + + struct zmk_behavior_binding binding = {0}; + if (hold_tap->status == STATUS_HOLD_TIMER || hold_tap->status == STATUS_HOLD_INTERRUPT) { + binding.behavior_dev = hold_tap->config->hold_behavior_dev; + binding.param1 = hold_tap->param_hold; + } else { + binding.behavior_dev = hold_tap->config->tap_behavior_dev; + binding.param1 = hold_tap->param_tap; + } + return behavior_keymap_binding_released(&binding, event); +} + +static bool is_first_other_key_pressed_trigger_key(struct active_hold_tap *hold_tap) { + for (int i = 0; i < hold_tap->config->hold_trigger_key_positions_len; i++) { + if (hold_tap->config->hold_trigger_key_positions[i] == + hold_tap->position_of_first_other_key_pressed) { + return true; + } + } + return false; +} + +// Force a tap decision if the positional conditions for a hold decision are not met. +static void decide_positional_hold(struct active_hold_tap *hold_tap) { + // Only force a tap decision if the positional hold/tap feature is enabled. + if (!(hold_tap->config->hold_trigger_key_positions_len > 0)) { + return; + } + + // Only force a tap decision if another key was pressed after + // the hold/tap key. + if (hold_tap->position_of_first_other_key_pressed == -1) { + return; + } + + // Only force a tap decision if the first other key to be pressed + // (after the hold/tap key) is not one of the trigger keys. + if (is_first_other_key_pressed_trigger_key(hold_tap)) { + return; + } + + // Since the positional key conditions have failed, force a TAP decision. + hold_tap->status = STATUS_TAP; +} + +static void decide_hold_tap(struct active_hold_tap *hold_tap, + enum decision_moment decision_moment) { + if (hold_tap->status != STATUS_UNDECIDED) { + return; + } + + if (hold_tap != undecided_hold_tap) { + LOG_DBG("ERROR found undecided tap hold that is not the active tap hold"); + return; + } + + // If the hold-tap behavior is still undecided, attempt to decide it. + switch (hold_tap->config->flavor) { + case FLAVOR_HOLD_PREFERRED: + decide_hold_preferred(hold_tap, decision_moment); + break; + case FLAVOR_BALANCED: + decide_balanced(hold_tap, decision_moment); + break; + case FLAVOR_TAP_PREFERRED: + decide_tap_preferred(hold_tap, decision_moment); + break; + case FLAVOR_TAP_UNLESS_INTERRUPTED: + decide_tap_unless_interrupted(hold_tap, decision_moment); + break; + } + + if (hold_tap->status == STATUS_UNDECIDED) { + return; + } + + decide_positional_hold(hold_tap); + + // Since the hold-tap has been decided, clean up undecided_hold_tap and + // execute the decided behavior. + LOG_DBG("%d decided %s (%s decision moment %s)", hold_tap->position, + status_str(hold_tap->status), flavor_str(hold_tap->config->flavor), + decision_moment_str(decision_moment)); + undecided_hold_tap = NULL; + press_binding(hold_tap); + release_captured_events(); +} + +static void decide_retro_tap(struct active_hold_tap *hold_tap) { + if (!hold_tap->config->retro_tap) { + return; + } + if (hold_tap->status == STATUS_HOLD_TIMER) { + release_binding(hold_tap); + LOG_DBG("%d retro tap", hold_tap->position); + hold_tap->status = STATUS_TAP; + press_binding(hold_tap); + return; + } +} + +static void update_hold_status_for_retro_tap(uint32_t ignore_position) { + for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) { + struct active_hold_tap *hold_tap = &active_hold_taps[i]; + if (hold_tap->position == ignore_position || + hold_tap->position == ZMK_BHV_HOLD_TAP_POSITION_NOT_USED || + hold_tap->config->retro_tap == false) { + continue; + } + if (hold_tap->status == STATUS_HOLD_TIMER) { + LOG_DBG("Update hold tap %d status to hold-interrupt", hold_tap->position); + hold_tap->status = STATUS_HOLD_INTERRUPT; + press_binding(hold_tap); + } + } +} + +static int on_hold_tap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); + const struct behavior_hold_tap_config *cfg = dev->config; + + if (undecided_hold_tap != NULL) { + LOG_DBG("ERROR another hold-tap behavior is undecided."); + // if this happens, make sure the behavior events occur AFTER other position events. + return ZMK_BEHAVIOR_OPAQUE; + } + + struct active_hold_tap *hold_tap = + store_hold_tap(event.position, binding->param1, binding->param2, event.timestamp, cfg); + if (hold_tap == NULL) { + LOG_ERR("unable to store hold-tap info, did you press more than %d hold-taps?", + ZMK_BHV_HOLD_TAP_MAX_HELD); + return ZMK_BEHAVIOR_OPAQUE; + } + + LOG_DBG("%d new undecided hold_tap", event.position); + undecided_hold_tap = hold_tap; + + if (is_quick_tap(hold_tap)) { + decide_hold_tap(hold_tap, HT_QUICK_TAP); + } + + // if this behavior was queued we have to adjust the timer to only + // wait for the remaining time. + int32_t tapping_term_ms_left = (hold_tap->timestamp + cfg->tapping_term_ms) - k_uptime_get(); + k_work_schedule(&hold_tap->work, K_MSEC(tapping_term_ms_left)); + + return ZMK_BEHAVIOR_OPAQUE; +} + +static int on_hold_tap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + struct active_hold_tap *hold_tap = find_hold_tap(event.position); + if (hold_tap == NULL) { + LOG_ERR("ACTIVE_HOLD_TAP_CLEANED_UP_TOO_EARLY"); + return ZMK_BEHAVIOR_OPAQUE; + } + + // If these events were queued, the timer event may be queued too late or not at all. + // We insert a timer event before the TH_KEY_UP event to verify. + int work_cancel_result = k_work_cancel_delayable(&hold_tap->work); + if (event.timestamp > (hold_tap->timestamp + hold_tap->config->tapping_term_ms)) { + decide_hold_tap(hold_tap, HT_TIMER_EVENT); + } + + decide_hold_tap(hold_tap, HT_KEY_UP); + decide_retro_tap(hold_tap); + release_binding(hold_tap); + + if (work_cancel_result == -EINPROGRESS) { + // let the timer handler clean up + // if we'd clear now, the timer may call back for an uninitialized active_hold_tap. + LOG_DBG("%d hold-tap timer work in event queue", event.position); + hold_tap->work_is_cancelled = true; + } else { + LOG_DBG("%d cleaning up hold-tap", event.position); + clear_hold_tap(hold_tap); + } + + return ZMK_BEHAVIOR_OPAQUE; +} + +static const struct behavior_driver_api behavior_hold_tap_driver_api = { + .binding_pressed = on_hold_tap_binding_pressed, + .binding_released = on_hold_tap_binding_released, +}; + +static int position_state_changed_listener(const zmk_event_t *eh) { + struct zmk_position_state_changed *ev = as_zmk_position_state_changed(eh); + + update_hold_status_for_retro_tap(ev->position); + + if (undecided_hold_tap == NULL) { + LOG_DBG("%d bubble (no undecided hold_tap active)", ev->position); + return ZMK_EV_EVENT_BUBBLE; + } + + // Store the position of pressed key for positional hold-tap purposes. + if ((undecided_hold_tap->config->hold_trigger_on_release != + ev->state) // key has been pressed and hold_trigger_on_release is not set, or key + // has been released and hold_trigger_on_release is set + && (undecided_hold_tap->position_of_first_other_key_pressed == + -1) // no other key has been pressed yet + ) { + undecided_hold_tap->position_of_first_other_key_pressed = ev->position; + } + + if (undecided_hold_tap->position == ev->position) { + if (ev->state) { // keydown + LOG_ERR("hold-tap listener should be called before before most other listeners!"); + return ZMK_EV_EVENT_BUBBLE; + } else { // keyup + LOG_DBG("%d bubble undecided hold-tap keyrelease event", undecided_hold_tap->position); + return ZMK_EV_EVENT_BUBBLE; + } + } + + // If these events were queued, the timer event may be queued too late or not at all. + // We make a timer decision before the other key events are handled if the timer would + // have run out. + if (ev->timestamp > + (undecided_hold_tap->timestamp + undecided_hold_tap->config->tapping_term_ms)) { + decide_hold_tap(undecided_hold_tap, HT_TIMER_EVENT); + } + + if (undecided_hold_tap == NULL) { + return ZMK_EV_EVENT_BUBBLE; + } + + if (!ev->state && find_captured_keydown_event(ev->position) == NULL) { + // no keydown event has been captured, let it bubble. + // we'll catch modifiers later in modifier_state_changed_listener + LOG_DBG("%d bubbling %d %s event", undecided_hold_tap->position, ev->position, + ev->state ? "down" : "up"); + return ZMK_EV_EVENT_BUBBLE; + } + + LOG_DBG("%d capturing %d %s event", undecided_hold_tap->position, ev->position, + ev->state ? "down" : "up"); + capture_event(eh); + decide_hold_tap(undecided_hold_tap, ev->state ? HT_OTHER_KEY_DOWN : HT_OTHER_KEY_UP); + return ZMK_EV_EVENT_CAPTURED; +} + +static int keycode_state_changed_listener(const zmk_event_t *eh) { + // we want to catch layer-up events too... how? + struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh); + + if (ev->state && !is_mod(ev->usage_page, ev->keycode)) { + store_last_tapped(ev->timestamp); + } + + if (undecided_hold_tap == NULL) { + // LOG_DBG("0x%02X bubble (no undecided hold_tap active)", ev->keycode); + return ZMK_EV_EVENT_BUBBLE; + } + + if (!is_mod(ev->usage_page, ev->keycode)) { + // LOG_DBG("0x%02X bubble (not a mod)", ev->keycode); + return ZMK_EV_EVENT_BUBBLE; + } + + // only key-up events will bubble through position_state_changed_listener + // if a undecided_hold_tap is active. + LOG_DBG("%d capturing 0x%02X %s event", undecided_hold_tap->position, ev->keycode, + ev->state ? "down" : "up"); + capture_event(eh); + return ZMK_EV_EVENT_CAPTURED; +} + +int behavior_hold_tap_listener(const zmk_event_t *eh) { + if (as_zmk_position_state_changed(eh) != NULL) { + return position_state_changed_listener(eh); + } else if (as_zmk_keycode_state_changed(eh) != NULL) { + return keycode_state_changed_listener(eh); + } + return ZMK_EV_EVENT_BUBBLE; +} + +ZMK_LISTENER(behavior_hold_tap, behavior_hold_tap_listener); +ZMK_SUBSCRIPTION(behavior_hold_tap, zmk_position_state_changed); +// this should be modifiers_state_changed, but unfrotunately that's not implemented yet. +ZMK_SUBSCRIPTION(behavior_hold_tap, zmk_keycode_state_changed); + +void behavior_hold_tap_timer_work_handler(struct k_work *item) { + struct active_hold_tap *hold_tap = CONTAINER_OF(item, struct active_hold_tap, work); + + if (hold_tap->work_is_cancelled) { + clear_hold_tap(hold_tap); + } else { + decide_hold_tap(hold_tap, HT_TIMER_EVENT); + } +} + +static int behavior_hold_tap_init(const struct device *dev) { + static bool init_first_run = true; + + if (init_first_run) { + for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) { + k_work_init_delayable(&active_hold_taps[i].work, behavior_hold_tap_timer_work_handler); + active_hold_taps[i].position = ZMK_BHV_HOLD_TAP_POSITION_NOT_USED; + } + } + init_first_run = false; + return 0; +} + +#define KP_INST(n) \ + static struct behavior_hold_tap_config behavior_hold_tap_config_##n = { \ + .tapping_term_ms = DT_INST_PROP(n, tapping_term_ms), \ + .hold_behavior_dev = DEVICE_DT_NAME(DT_INST_PHANDLE_BY_IDX(n, bindings, 0)), \ + .tap_behavior_dev = DEVICE_DT_NAME(DT_INST_PHANDLE_BY_IDX(n, bindings, 1)), \ + .quick_tap_ms = DT_INST_PROP(n, quick_tap_ms), \ + .require_prior_idle_ms = DT_INST_PROP(n, global_quick_tap) \ + ? DT_INST_PROP(n, quick_tap_ms) \ + : DT_INST_PROP(n, require_prior_idle_ms), \ + .flavor = DT_ENUM_IDX(DT_DRV_INST(n), flavor), \ + .retro_tap = DT_INST_PROP(n, retro_tap), \ + .hold_trigger_on_release = DT_INST_PROP(n, hold_trigger_on_release), \ + .hold_trigger_key_positions = DT_INST_PROP(n, hold_trigger_key_positions), \ + .hold_trigger_key_positions_len = DT_INST_PROP_LEN(n, hold_trigger_key_positions), \ + }; \ + BEHAVIOR_DT_INST_DEFINE(n, behavior_hold_tap_init, NULL, NULL, &behavior_hold_tap_config_##n, \ + APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + &behavior_hold_tap_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KP_INST) + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/behaviors/behavior_key_press.c b/app/src/behaviors/behavior_key_press.c new file mode 100644 index 000000000000..5549b4b462bf --- /dev/null +++ b/app/src/behaviors/behavior_key_press.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_key_press + +#include +#include +#include + +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +static int behavior_key_press_init(const struct device *dev) { return 0; }; + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); + return ZMK_EVENT_RAISE( + zmk_keycode_state_changed_from_encoded(binding->param1, true, event.timestamp)); +} + +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); + return ZMK_EVENT_RAISE( + zmk_keycode_state_changed_from_encoded(binding->param1, false, event.timestamp)); +} + +static const struct behavior_driver_api behavior_key_press_driver_api = { + .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released}; + +#define KP_INST(n) \ + BEHAVIOR_DT_INST_DEFINE(n, behavior_key_press_init, NULL, NULL, NULL, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_key_press_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KP_INST) diff --git a/app/src/behaviors/behavior_key_repeat.c b/app/src/behaviors/behavior_key_repeat.c new file mode 100644 index 000000000000..85377f3faf32 --- /dev/null +++ b/app/src/behaviors/behavior_key_repeat.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_key_repeat + +#include +#include +#include +#include +#include + +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +struct behavior_key_repeat_config { + uint8_t index; + uint8_t usage_pages_count; + uint16_t usage_pages[]; +}; + +struct behavior_key_repeat_data { + struct zmk_keycode_state_changed last_keycode_pressed; + struct zmk_keycode_state_changed current_keycode_pressed; +}; + +static int on_key_repeat_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); + struct behavior_key_repeat_data *data = dev->data; + + if (data->last_keycode_pressed.usage_page == 0) { + return ZMK_BEHAVIOR_OPAQUE; + } + + memcpy(&data->current_keycode_pressed, &data->last_keycode_pressed, + sizeof(struct zmk_keycode_state_changed)); + data->current_keycode_pressed.timestamp = k_uptime_get(); + + ZMK_EVENT_RAISE(new_zmk_keycode_state_changed(data->current_keycode_pressed)); + + return ZMK_BEHAVIOR_OPAQUE; +} + +static int on_key_repeat_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); + struct behavior_key_repeat_data *data = dev->data; + + if (data->current_keycode_pressed.usage_page == 0) { + return ZMK_BEHAVIOR_OPAQUE; + } + + data->current_keycode_pressed.timestamp = k_uptime_get(); + data->current_keycode_pressed.state = false; + + ZMK_EVENT_RAISE(new_zmk_keycode_state_changed(data->current_keycode_pressed)); + return ZMK_BEHAVIOR_OPAQUE; +} + +static const struct behavior_driver_api behavior_key_repeat_driver_api = { + .binding_pressed = on_key_repeat_binding_pressed, + .binding_released = on_key_repeat_binding_released, +}; + +static int key_repeat_keycode_state_changed_listener(const zmk_event_t *eh); + +ZMK_LISTENER(behavior_key_repeat, key_repeat_keycode_state_changed_listener); +ZMK_SUBSCRIPTION(behavior_key_repeat, zmk_keycode_state_changed); + +static const struct device *devs[DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT)]; + +static int key_repeat_keycode_state_changed_listener(const zmk_event_t *eh) { + struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh); + if (ev == NULL || !ev->state) { + return ZMK_EV_EVENT_BUBBLE; + } + + for (int i = 0; i < DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT); i++) { + const struct device *dev = devs[i]; + if (dev == NULL) { + continue; + } + + struct behavior_key_repeat_data *data = dev->data; + const struct behavior_key_repeat_config *config = dev->config; + + for (int u = 0; u < config->usage_pages_count; u++) { + if (config->usage_pages[u] == ev->usage_page) { + memcpy(&data->last_keycode_pressed, ev, sizeof(struct zmk_keycode_state_changed)); + data->last_keycode_pressed.implicit_modifiers |= zmk_hid_get_explicit_mods(); + break; + } + } + } + + return ZMK_EV_EVENT_BUBBLE; +} + +static int behavior_key_repeat_init(const struct device *dev) { + const struct behavior_key_repeat_config *config = dev->config; + devs[config->index] = dev; + return 0; +} + +#define KR_INST(n) \ + static struct behavior_key_repeat_data behavior_key_repeat_data_##n = {}; \ + static struct behavior_key_repeat_config behavior_key_repeat_config_##n = { \ + .index = n, \ + .usage_pages = DT_INST_PROP(n, usage_pages), \ + .usage_pages_count = DT_INST_PROP_LEN(n, usage_pages), \ + }; \ + BEHAVIOR_DT_INST_DEFINE(n, behavior_key_repeat_init, NULL, &behavior_key_repeat_data_##n, \ + &behavior_key_repeat_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_key_repeat_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KR_INST) + +#endif diff --git a/app/src/behaviors/behavior_key_toggle.c b/app/src/behaviors/behavior_key_toggle.c new file mode 100644 index 000000000000..0ab1bd023622 --- /dev/null +++ b/app/src/behaviors/behavior_key_toggle.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_key_toggle + +#include +#include +#include + +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +static int behavior_key_toggle_init(const struct device *dev) { return 0; } + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); + bool pressed = zmk_hid_is_pressed(binding->param1); + return ZMK_EVENT_RAISE( + zmk_keycode_state_changed_from_encoded(binding->param1, !pressed, event.timestamp)); +} + +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + return 0; +} + +static const struct behavior_driver_api behavior_key_toggle_driver_api = { + .binding_pressed = on_keymap_binding_pressed, + .binding_released = on_keymap_binding_released, +}; + +#define KT_INST(n) \ + BEHAVIOR_DT_INST_DEFINE(n, behavior_key_toggle_init, NULL, NULL, NULL, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_key_toggle_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KT_INST) diff --git a/app/src/behaviors/behavior_macro.c b/app/src/behaviors/behavior_macro.c new file mode 100644 index 000000000000..1cb76dbd1bcd --- /dev/null +++ b/app/src/behaviors/behavior_macro.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +enum behavior_macro_mode { + MACRO_MODE_TAP, + MACRO_MODE_PRESS, + MACRO_MODE_RELEASE, +}; + +enum param_source { PARAM_SOURCE_BINDING, PARAM_SOURCE_MACRO_1ST, PARAM_SOURCE_MACRO_2ND }; + +struct behavior_macro_trigger_state { + uint32_t wait_ms; + uint32_t tap_ms; + enum behavior_macro_mode mode; + uint16_t start_index; + uint16_t count; + enum param_source param1_source; + enum param_source param2_source; +}; + +struct behavior_macro_state { + struct behavior_macro_trigger_state release_state; + + uint32_t press_bindings_count; +}; + +struct behavior_macro_config { + uint32_t default_wait_ms; + uint32_t default_tap_ms; + uint32_t count; + struct zmk_behavior_binding bindings[]; +}; + +#define TAP_MODE DEVICE_DT_NAME(DT_INST(0, zmk_macro_control_mode_tap)) +#define PRESS_MODE DEVICE_DT_NAME(DT_INST(0, zmk_macro_control_mode_press)) +#define REL_MODE DEVICE_DT_NAME(DT_INST(0, zmk_macro_control_mode_release)) + +#define TAP_TIME DEVICE_DT_NAME(DT_INST(0, zmk_macro_control_tap_time)) +#define WAIT_TIME DEVICE_DT_NAME(DT_INST(0, zmk_macro_control_wait_time)) +#define WAIT_REL DEVICE_DT_NAME(DT_INST(0, zmk_macro_pause_for_release)) + +#define P1TO1 DEVICE_DT_NAME(DT_INST(0, zmk_macro_param_1to1)) +#define P1TO2 DEVICE_DT_NAME(DT_INST(0, zmk_macro_param_1to2)) +#define P2TO1 DEVICE_DT_NAME(DT_INST(0, zmk_macro_param_2to1)) +#define P2TO2 DEVICE_DT_NAME(DT_INST(0, zmk_macro_param_2to2)) + +#define ZM_IS_NODE_MATCH(a, b) (strcmp(a, b) == 0) +#define IS_TAP_MODE(dev) ZM_IS_NODE_MATCH(dev, TAP_MODE) +#define IS_PRESS_MODE(dev) ZM_IS_NODE_MATCH(dev, PRESS_MODE) +#define IS_RELEASE_MODE(dev) ZM_IS_NODE_MATCH(dev, REL_MODE) + +#define IS_TAP_TIME(dev) ZM_IS_NODE_MATCH(dev, TAP_TIME) +#define IS_WAIT_TIME(dev) ZM_IS_NODE_MATCH(dev, WAIT_TIME) +#define IS_PAUSE(dev) ZM_IS_NODE_MATCH(dev, WAIT_REL) + +#define IS_P1TO1(dev) ZM_IS_NODE_MATCH(dev, P1TO1) +#define IS_P1TO2(dev) ZM_IS_NODE_MATCH(dev, P1TO2) +#define IS_P2TO1(dev) ZM_IS_NODE_MATCH(dev, P2TO1) +#define IS_P2TO2(dev) ZM_IS_NODE_MATCH(dev, P2TO2) + +static bool handle_control_binding(struct behavior_macro_trigger_state *state, + const struct zmk_behavior_binding *binding) { + if (IS_TAP_MODE(binding->behavior_dev)) { + state->mode = MACRO_MODE_TAP; + LOG_DBG("macro mode set: tap"); + } else if (IS_PRESS_MODE(binding->behavior_dev)) { + state->mode = MACRO_MODE_PRESS; + LOG_DBG("macro mode set: press"); + } else if (IS_RELEASE_MODE(binding->behavior_dev)) { + state->mode = MACRO_MODE_RELEASE; + LOG_DBG("macro mode set: release"); + } else if (IS_TAP_TIME(binding->behavior_dev)) { + state->tap_ms = binding->param1; + LOG_DBG("macro tap time set: %d", state->tap_ms); + } else if (IS_WAIT_TIME(binding->behavior_dev)) { + state->wait_ms = binding->param1; + LOG_DBG("macro wait time set: %d", state->wait_ms); + } else if (IS_P1TO1(binding->behavior_dev)) { + state->param1_source = PARAM_SOURCE_MACRO_1ST; + LOG_DBG("macro param: 1to1"); + } else if (IS_P1TO2(binding->behavior_dev)) { + state->param2_source = PARAM_SOURCE_MACRO_1ST; + LOG_DBG("macro param: 1to2"); + } else if (IS_P2TO1(binding->behavior_dev)) { + state->param1_source = PARAM_SOURCE_MACRO_2ND; + LOG_DBG("macro param: 2to1"); + } else if (IS_P2TO2(binding->behavior_dev)) { + state->param2_source = PARAM_SOURCE_MACRO_2ND; + LOG_DBG("macro param: 2to2"); + } else { + return false; + } + + return true; +} + +static int behavior_macro_init(const struct device *dev) { + const struct behavior_macro_config *cfg = dev->config; + struct behavior_macro_state *state = dev->data; + state->press_bindings_count = cfg->count; + state->release_state.start_index = cfg->count; + state->release_state.count = 0; + + LOG_DBG("Precalculate initial release state:"); + for (int i = 0; i < cfg->count; i++) { + if (handle_control_binding(&state->release_state, &cfg->bindings[i])) { + // Updated state used for initial state on release. + } else if (IS_PAUSE(cfg->bindings[i].behavior_dev)) { + state->release_state.start_index = i + 1; + state->release_state.count = cfg->count - state->release_state.start_index; + state->press_bindings_count = i; + LOG_DBG("Release will resume at %d", state->release_state.start_index); + break; + } else { + // Ignore regular invokable bindings + } + } + + return 0; +}; + +static uint32_t select_param(enum param_source param_source, uint32_t source_binding, + const struct zmk_behavior_binding *macro_binding) { + switch (param_source) { + case PARAM_SOURCE_MACRO_1ST: + return macro_binding->param1; + case PARAM_SOURCE_MACRO_2ND: + return macro_binding->param2; + default: + return source_binding; + } +}; + +static void replace_params(struct behavior_macro_trigger_state *state, + struct zmk_behavior_binding *binding, + const struct zmk_behavior_binding *macro_binding) { + binding->param1 = select_param(state->param1_source, binding->param1, macro_binding); + binding->param2 = select_param(state->param2_source, binding->param2, macro_binding); + + state->param1_source = PARAM_SOURCE_BINDING; + state->param2_source = PARAM_SOURCE_BINDING; +} + +static void queue_macro(uint32_t position, const struct zmk_behavior_binding bindings[], + struct behavior_macro_trigger_state state, + const struct zmk_behavior_binding *macro_binding) { + LOG_DBG("Iterating macro bindings - starting: %d, count: %d", state.start_index, state.count); + for (int i = state.start_index; i < state.start_index + state.count; i++) { + if (!handle_control_binding(&state, &bindings[i])) { + struct zmk_behavior_binding binding = bindings[i]; + replace_params(&state, &binding, macro_binding); + + switch (state.mode) { + case MACRO_MODE_TAP: + zmk_behavior_queue_add(position, binding, true, state.tap_ms); + zmk_behavior_queue_add(position, binding, false, state.wait_ms); + break; + case MACRO_MODE_PRESS: + zmk_behavior_queue_add(position, binding, true, state.wait_ms); + break; + case MACRO_MODE_RELEASE: + zmk_behavior_queue_add(position, binding, false, state.wait_ms); + break; + default: + LOG_ERR("Unknown macro mode: %d", state.mode); + break; + } + } + } +} + +static int on_macro_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); + const struct behavior_macro_config *cfg = dev->config; + struct behavior_macro_state *state = dev->data; + struct behavior_macro_trigger_state trigger_state = {.mode = MACRO_MODE_TAP, + .tap_ms = cfg->default_tap_ms, + .wait_ms = cfg->default_wait_ms, + .start_index = 0, + .count = state->press_bindings_count}; + + queue_macro(event.position, cfg->bindings, trigger_state, binding); + + return ZMK_BEHAVIOR_OPAQUE; +} + +static int on_macro_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); + const struct behavior_macro_config *cfg = dev->config; + struct behavior_macro_state *state = dev->data; + + queue_macro(event.position, cfg->bindings, state->release_state, binding); + + return ZMK_BEHAVIOR_OPAQUE; +} + +static const struct behavior_driver_api behavior_macro_driver_api = { + .binding_pressed = on_macro_binding_pressed, + .binding_released = on_macro_binding_released, +}; + +#define TRANSFORMED_BEHAVIORS(n) \ + {LISTIFY(DT_PROP_LEN(n, bindings), ZMK_KEYMAP_EXTRACT_BINDING, (, ), n)}, + +#define MACRO_INST(inst) \ + static struct behavior_macro_state behavior_macro_state_##inst = {}; \ + static struct behavior_macro_config behavior_macro_config_##inst = { \ + .default_wait_ms = DT_PROP_OR(inst, wait_ms, CONFIG_ZMK_MACRO_DEFAULT_WAIT_MS), \ + .default_tap_ms = DT_PROP_OR(inst, tap_ms, CONFIG_ZMK_MACRO_DEFAULT_TAP_MS), \ + .count = DT_PROP_LEN(inst, bindings), \ + .bindings = TRANSFORMED_BEHAVIORS(inst)}; \ + BEHAVIOR_DT_DEFINE(inst, behavior_macro_init, NULL, &behavior_macro_state_##inst, \ + &behavior_macro_config_##inst, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_macro_driver_api); + +DT_FOREACH_STATUS_OKAY(zmk_behavior_macro, MACRO_INST) +DT_FOREACH_STATUS_OKAY(zmk_behavior_macro_one_param, MACRO_INST) +DT_FOREACH_STATUS_OKAY(zmk_behavior_macro_two_param, MACRO_INST) diff --git a/app/src/behaviors/behavior_mod_morph.c b/app/src/behaviors/behavior_mod_morph.c new file mode 100644 index 000000000000..176b0f696eca --- /dev/null +++ b/app/src/behaviors/behavior_mod_morph.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_mod_morph + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +struct behavior_mod_morph_config { + struct zmk_behavior_binding normal_binding; + struct zmk_behavior_binding morph_binding; + zmk_mod_flags_t mods; + zmk_mod_flags_t masked_mods; +}; + +struct behavior_mod_morph_data { + struct zmk_behavior_binding *pressed_binding; +}; + +static int on_mod_morph_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); + const struct behavior_mod_morph_config *cfg = dev->config; + struct behavior_mod_morph_data *data = dev->data; + + if (data->pressed_binding != NULL) { + LOG_ERR("Can't press the same mod-morph twice"); + return -ENOTSUP; + } + + if (zmk_hid_get_explicit_mods() & cfg->mods) { + zmk_hid_masked_modifiers_set(cfg->masked_mods); + data->pressed_binding = (struct zmk_behavior_binding *)&cfg->morph_binding; + } else { + data->pressed_binding = (struct zmk_behavior_binding *)&cfg->normal_binding; + } + return behavior_keymap_binding_pressed(data->pressed_binding, event); +} + +static int on_mod_morph_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); + struct behavior_mod_morph_data *data = dev->data; + + if (data->pressed_binding == NULL) { + LOG_ERR("Mod-morph already released"); + return -ENOTSUP; + } + + struct zmk_behavior_binding *pressed_binding = data->pressed_binding; + data->pressed_binding = NULL; + int err; + err = behavior_keymap_binding_released(pressed_binding, event); + zmk_hid_masked_modifiers_clear(); + return err; +} + +static const struct behavior_driver_api behavior_mod_morph_driver_api = { + .binding_pressed = on_mod_morph_binding_pressed, + .binding_released = on_mod_morph_binding_released, +}; + +static int behavior_mod_morph_init(const struct device *dev) { return 0; } + +#define _TRANSFORM_ENTRY(idx, node) \ + { \ + .behavior_dev = DEVICE_DT_NAME(DT_INST_PHANDLE_BY_IDX(node, bindings, idx)), \ + .param1 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param1), (0), \ + (DT_INST_PHA_BY_IDX(node, bindings, idx, param1))), \ + .param2 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param2), (0), \ + (DT_INST_PHA_BY_IDX(node, bindings, idx, param2))), \ + } + +#define KP_INST(n) \ + static struct behavior_mod_morph_config behavior_mod_morph_config_##n = { \ + .normal_binding = _TRANSFORM_ENTRY(0, n), \ + .morph_binding = _TRANSFORM_ENTRY(1, n), \ + .mods = DT_INST_PROP(n, mods), \ + .masked_mods = COND_CODE_0(DT_INST_NODE_HAS_PROP(n, keep_mods), (DT_INST_PROP(n, mods)), \ + (DT_INST_PROP(n, mods) & ~DT_INST_PROP(n, keep_mods))), \ + }; \ + static struct behavior_mod_morph_data behavior_mod_morph_data_##n = {}; \ + BEHAVIOR_DT_INST_DEFINE(n, behavior_mod_morph_init, NULL, &behavior_mod_morph_data_##n, \ + &behavior_mod_morph_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mod_morph_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KP_INST) + +#endif diff --git a/app/src/behaviors/behavior_momentary_layer.c b/app/src/behaviors/behavior_momentary_layer.c new file mode 100644 index 000000000000..94da6441e76d --- /dev/null +++ b/app/src/behaviors/behavior_momentary_layer.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_momentary_layer + +#include +#include +#include + +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +struct behavior_mo_config {}; +struct behavior_mo_data {}; + +static int behavior_mo_init(const struct device *dev) { return 0; }; + +static int mo_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d layer %d", event.position, binding->param1); + return zmk_keymap_layer_activate(binding->param1); +} + +static int mo_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d layer %d", event.position, binding->param1); + return zmk_keymap_layer_deactivate(binding->param1); +} + +static const struct behavior_driver_api behavior_mo_driver_api = { + .binding_pressed = mo_keymap_binding_pressed, .binding_released = mo_keymap_binding_released}; + +static const struct behavior_mo_config behavior_mo_config = {}; + +static struct behavior_mo_data behavior_mo_data; + +BEHAVIOR_DT_INST_DEFINE(0, behavior_mo_init, NULL, &behavior_mo_data, &behavior_mo_config, + APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mo_driver_api); diff --git a/app/src/behaviors/behavior_mouse_key_press.c b/app/src/behaviors/behavior_mouse_key_press.c new file mode 100644 index 000000000000..e79bb74771d4 --- /dev/null +++ b/app/src/behaviors/behavior_mouse_key_press.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_mouse_key_press + +#include +#include +#include + +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +static int behavior_mouse_key_press_init(const struct device *dev) { return 0; }; + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); + + return ZMK_EVENT_RAISE( + zmk_mouse_button_state_changed_from_encoded(binding->param1, true, event.timestamp)); +} + +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); + return ZMK_EVENT_RAISE( + zmk_mouse_button_state_changed_from_encoded(binding->param1, false, event.timestamp)); +} + +static const struct behavior_driver_api behavior_mouse_key_press_driver_api = { + .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released}; + +#define MKP_INST(n) \ + BEHAVIOR_DT_INST_DEFINE(n, behavior_mouse_key_press_init, NULL, NULL, NULL, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + &behavior_mouse_key_press_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(MKP_INST) + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/behaviors/behavior_none.c b/app/src/behaviors/behavior_none.c new file mode 100644 index 000000000000..57208f36ae1a --- /dev/null +++ b/app/src/behaviors/behavior_none.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_none + +#include +#include +#include + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +static int behavior_none_init(const struct device *dev) { return 0; }; + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + return ZMK_BEHAVIOR_OPAQUE; +} + +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + return ZMK_BEHAVIOR_OPAQUE; +} + +static const struct behavior_driver_api behavior_none_driver_api = { + .binding_pressed = on_keymap_binding_pressed, + .binding_released = on_keymap_binding_released, +}; + +BEHAVIOR_DT_INST_DEFINE(0, behavior_none_init, NULL, NULL, NULL, APPLICATION, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_none_driver_api); + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/behaviors/behavior_outputs.c b/app/src/behaviors/behavior_outputs.c new file mode 100644 index 000000000000..1185aaabf2c4 --- /dev/null +++ b/app/src/behaviors/behavior_outputs.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_outputs + +#include +#include +#include + +#include + +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + switch (binding->param1) { + case OUT_TOG: + return zmk_endpoints_toggle_transport(); + case OUT_USB: + return zmk_endpoints_select_transport(ZMK_TRANSPORT_USB); + case OUT_BLE: + return zmk_endpoints_select_transport(ZMK_TRANSPORT_BLE); + default: + LOG_ERR("Unknown output command: %d", binding->param1); + } + + return -ENOTSUP; +} + +static int behavior_out_init(const struct device *dev) { return 0; } + +static const struct behavior_driver_api behavior_outputs_driver_api = { + .binding_pressed = on_keymap_binding_pressed, +}; + +BEHAVIOR_DT_INST_DEFINE(0, behavior_out_init, NULL, NULL, NULL, APPLICATION, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_outputs_driver_api); + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/behaviors/behavior_reset.c b/app/src/behaviors/behavior_reset.c new file mode 100644 index 000000000000..6a2731ecad4d --- /dev/null +++ b/app/src/behaviors/behavior_reset.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_reset + +#include +#include +#include + +#include + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) +struct behavior_reset_config { + int type; +}; + +static int behavior_reset_init(const struct device *dev) { return 0; }; + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); + const struct behavior_reset_config *cfg = dev->config; + + // TODO: Correct magic code for going into DFU? + // See + // https://github.com/adafruit/Adafruit_nRF52_Bootloader/blob/d6b28e66053eea467166f44875e3c7ec741cb471/src/main.c#L107 + sys_reboot(cfg->type); + return ZMK_BEHAVIOR_OPAQUE; +} + +static const struct behavior_driver_api behavior_reset_driver_api = { + .binding_pressed = on_keymap_binding_pressed, + .locality = BEHAVIOR_LOCALITY_EVENT_SOURCE, +}; + +#define RST_INST(n) \ + static const struct behavior_reset_config behavior_reset_config_##n = { \ + .type = DT_INST_PROP(n, type)}; \ + BEHAVIOR_DT_INST_DEFINE(n, behavior_reset_init, NULL, NULL, &behavior_reset_config_##n, \ + APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + &behavior_reset_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(RST_INST) + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/behaviors/behavior_rgb_underglow.c b/app/src/behaviors/behavior_rgb_underglow.c new file mode 100644 index 000000000000..7a478eb781fe --- /dev/null +++ b/app/src/behaviors/behavior_rgb_underglow.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_rgb_underglow + +#include +#include +#include + +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +static int behavior_rgb_underglow_init(const struct device *dev) { return 0; } + +static int +on_keymap_binding_convert_central_state_dependent_params(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + switch (binding->param1) { + case RGB_TOG_CMD: { + bool state; + int err = zmk_rgb_underglow_get_state(&state); + if (err) { + LOG_ERR("Failed to get RGB underglow state (err %d)", err); + return err; + } + + binding->param1 = state ? RGB_OFF_CMD : RGB_ON_CMD; + break; + } + case RGB_BRI_CMD: { + struct zmk_led_hsb color = zmk_rgb_underglow_calc_brt(1); + + binding->param1 = RGB_COLOR_HSB_CMD; + binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b); + break; + } + case RGB_BRD_CMD: { + struct zmk_led_hsb color = zmk_rgb_underglow_calc_brt(-1); + + binding->param1 = RGB_COLOR_HSB_CMD; + binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b); + break; + } + case RGB_HUI_CMD: { + struct zmk_led_hsb color = zmk_rgb_underglow_calc_hue(1); + + binding->param1 = RGB_COLOR_HSB_CMD; + binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b); + break; + } + case RGB_HUD_CMD: { + struct zmk_led_hsb color = zmk_rgb_underglow_calc_hue(-1); + + binding->param1 = RGB_COLOR_HSB_CMD; + binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b); + break; + } + case RGB_SAI_CMD: { + struct zmk_led_hsb color = zmk_rgb_underglow_calc_sat(1); + + binding->param1 = RGB_COLOR_HSB_CMD; + binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b); + break; + } + case RGB_SAD_CMD: { + struct zmk_led_hsb color = zmk_rgb_underglow_calc_sat(-1); + + binding->param1 = RGB_COLOR_HSB_CMD; + binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b); + break; + } + case RGB_EFR_CMD: { + binding->param1 = RGB_EFS_CMD; + binding->param2 = zmk_rgb_underglow_calc_effect(-1); + break; + } + case RGB_EFF_CMD: { + binding->param1 = RGB_EFS_CMD; + binding->param2 = zmk_rgb_underglow_calc_effect(1); + break; + } + default: + return 0; + } + + LOG_DBG("RGB relative convert to absolute (%d/%d)", binding->param1, binding->param2); + + return 0; +}; + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + switch (binding->param1) { + case RGB_TOG_CMD: + return zmk_rgb_underglow_toggle(); + case RGB_ON_CMD: + return zmk_rgb_underglow_on(); + case RGB_OFF_CMD: + return zmk_rgb_underglow_off(); + case RGB_HUI_CMD: + return zmk_rgb_underglow_change_hue(1); + case RGB_HUD_CMD: + return zmk_rgb_underglow_change_hue(-1); + case RGB_SAI_CMD: + return zmk_rgb_underglow_change_sat(1); + case RGB_SAD_CMD: + return zmk_rgb_underglow_change_sat(-1); + case RGB_BRI_CMD: + return zmk_rgb_underglow_change_brt(1); + case RGB_BRD_CMD: + return zmk_rgb_underglow_change_brt(-1); + case RGB_SPI_CMD: + return zmk_rgb_underglow_change_spd(1); + case RGB_SPD_CMD: + return zmk_rgb_underglow_change_spd(-1); + case RGB_EFS_CMD: + return zmk_rgb_underglow_select_effect(binding->param2); + case RGB_EFF_CMD: + return zmk_rgb_underglow_cycle_effect(1); + case RGB_EFR_CMD: + return zmk_rgb_underglow_cycle_effect(-1); + case RGB_COLOR_HSB_CMD: + return zmk_rgb_underglow_set_hsb((struct zmk_led_hsb){.h = (binding->param2 >> 16) & 0xFFFF, + .s = (binding->param2 >> 8) & 0xFF, + .b = binding->param2 & 0xFF}); + } + + return -ENOTSUP; +} + +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + return ZMK_BEHAVIOR_OPAQUE; +} + +static const struct behavior_driver_api behavior_rgb_underglow_driver_api = { + .binding_convert_central_state_dependent_params = + on_keymap_binding_convert_central_state_dependent_params, + .binding_pressed = on_keymap_binding_pressed, + .binding_released = on_keymap_binding_released, + .locality = BEHAVIOR_LOCALITY_GLOBAL, +}; + +BEHAVIOR_DT_INST_DEFINE(0, behavior_rgb_underglow_init, NULL, NULL, NULL, APPLICATION, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_rgb_underglow_driver_api); + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/behaviors/behavior_sensor_rotate.c b/app/src/behaviors/behavior_sensor_rotate.c new file mode 100644 index 000000000000..f77beca188d7 --- /dev/null +++ b/app/src/behaviors/behavior_sensor_rotate.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_sensor_rotate + +#include + +#include + +#include "behavior_sensor_rotate_common.h" + +static const struct behavior_driver_api behavior_sensor_rotate_driver_api = { + .sensor_binding_accept_data = zmk_behavior_sensor_rotate_common_accept_data, + .sensor_binding_process = zmk_behavior_sensor_rotate_common_process}; + +static int behavior_sensor_rotate_init(const struct device *dev) { return 0; }; + +#define _TRANSFORM_ENTRY(idx, node) \ + { \ + .behavior_dev = DEVICE_DT_NAME(DT_INST_PHANDLE_BY_IDX(node, bindings, idx)), \ + .param1 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param1), (0), \ + (DT_INST_PHA_BY_IDX(node, bindings, idx, param1))), \ + .param2 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param2), (0), \ + (DT_INST_PHA_BY_IDX(node, bindings, idx, param2))), \ + } + +#define SENSOR_ROTATE_INST(n) \ + static struct behavior_sensor_rotate_config behavior_sensor_rotate_config_##n = { \ + .cw_binding = _TRANSFORM_ENTRY(0, n), \ + .ccw_binding = _TRANSFORM_ENTRY(1, n), \ + .tap_ms = DT_INST_PROP_OR(n, tap_ms, 5), \ + .override_params = false, \ + }; \ + static struct behavior_sensor_rotate_data behavior_sensor_rotate_data_##n = {}; \ + BEHAVIOR_DT_INST_DEFINE(n, behavior_sensor_rotate_init, NULL, \ + &behavior_sensor_rotate_data_##n, &behavior_sensor_rotate_config_##n, \ + APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + &behavior_sensor_rotate_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(SENSOR_ROTATE_INST) diff --git a/app/src/behaviors/behavior_sensor_rotate_common.c b/app/src/behaviors/behavior_sensor_rotate_common.c new file mode 100644 index 000000000000..94bf40c18d4e --- /dev/null +++ b/app/src/behaviors/behavior_sensor_rotate_common.c @@ -0,0 +1,98 @@ + +#include +#include +#include +#include + +#include +#include + +#include "behavior_sensor_rotate_common.h" + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +int zmk_behavior_sensor_rotate_common_accept_data( + struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, + const struct zmk_sensor_config *sensor_config, size_t channel_data_size, + const struct zmk_sensor_channel_data *channel_data) { + const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); + struct behavior_sensor_rotate_data *data = dev->data; + + const struct sensor_value value = channel_data[0].value; + int triggers; + int sensor_index = ZMK_SENSOR_POSITION_FROM_VIRTUAL_KEY_POSITION(event.position); + + // Some funky special casing for "old encoder behavior" where ticks where reported in val2 only, + // instead of rotational degrees in val1. + // REMOVE ME: Remove after a grace period of old ec11 sensor behavior + if (value.val1 == 0) { + triggers = value.val2; + } else { + struct sensor_value remainder = data->remainder[sensor_index][event.layer]; + + remainder.val1 += value.val1; + remainder.val2 += value.val2; + + if (remainder.val2 >= 1000000 || remainder.val2 <= 1000000) { + remainder.val1 += remainder.val2 / 1000000; + remainder.val2 %= 1000000; + } + + int trigger_degrees = 360 / sensor_config->triggers_per_rotation; + triggers = remainder.val1 / trigger_degrees; + remainder.val1 %= trigger_degrees; + + data->remainder[sensor_index][event.layer] = remainder; + } + + LOG_DBG( + "val1: %d, val2: %d, remainder: %d/%d triggers: %d inc keycode 0x%02X dec keycode 0x%02X", + value.val1, value.val2, data->remainder[sensor_index][event.layer].val1, + data->remainder[sensor_index][event.layer].val2, triggers, binding->param1, + binding->param2); + + data->triggers[sensor_index][event.layer] = triggers; + return 0; +} + +int zmk_behavior_sensor_rotate_common_process(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event, + enum behavior_sensor_binding_process_mode mode) { + const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); + const struct behavior_sensor_rotate_config *cfg = dev->config; + struct behavior_sensor_rotate_data *data = dev->data; + + const int sensor_index = ZMK_SENSOR_POSITION_FROM_VIRTUAL_KEY_POSITION(event.position); + + if (mode != BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_TRIGGER) { + data->triggers[sensor_index][event.layer] = 0; + return ZMK_BEHAVIOR_TRANSPARENT; + } + + int triggers = data->triggers[sensor_index][event.layer]; + + struct zmk_behavior_binding triggered_binding; + if (triggers > 0) { + triggered_binding = cfg->cw_binding; + if (cfg->override_params) { + triggered_binding.param1 = binding->param1; + } + } else if (triggers < 0) { + triggers = -triggers; + triggered_binding = cfg->ccw_binding; + if (cfg->override_params) { + triggered_binding.param1 = binding->param2; + } + } else { + return ZMK_BEHAVIOR_TRANSPARENT; + } + + LOG_DBG("Sensor binding: %s", binding->behavior_dev); + + for (int i = 0; i < triggers; i++) { + zmk_behavior_queue_add(event.position, triggered_binding, true, cfg->tap_ms); + zmk_behavior_queue_add(event.position, triggered_binding, false, 0); + } + + return ZMK_BEHAVIOR_OPAQUE; +} diff --git a/app/src/behaviors/behavior_sensor_rotate_common.h b/app/src/behaviors/behavior_sensor_rotate_common.h new file mode 100644 index 000000000000..c92ac3d5e5f2 --- /dev/null +++ b/app/src/behaviors/behavior_sensor_rotate_common.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +struct behavior_sensor_rotate_config { + struct zmk_behavior_binding cw_binding; + struct zmk_behavior_binding ccw_binding; + int tap_ms; + bool override_params; +}; + +struct behavior_sensor_rotate_data { + struct sensor_value remainder[ZMK_KEYMAP_SENSORS_LEN][ZMK_KEYMAP_LAYERS_LEN]; + int triggers[ZMK_KEYMAP_SENSORS_LEN][ZMK_KEYMAP_LAYERS_LEN]; +}; + +int zmk_behavior_sensor_rotate_common_accept_data( + struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, + const struct zmk_sensor_config *sensor_config, size_t channel_data_size, + const struct zmk_sensor_channel_data *channel_data); +int zmk_behavior_sensor_rotate_common_process(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event, + enum behavior_sensor_binding_process_mode mode); \ No newline at end of file diff --git a/app/src/behaviors/behavior_sensor_rotate_var.c b/app/src/behaviors/behavior_sensor_rotate_var.c new file mode 100644 index 000000000000..0d3d22b29e01 --- /dev/null +++ b/app/src/behaviors/behavior_sensor_rotate_var.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_sensor_rotate_var + +#include + +#include + +#include "behavior_sensor_rotate_common.h" + +static const struct behavior_driver_api behavior_sensor_rotate_var_driver_api = { + .sensor_binding_accept_data = zmk_behavior_sensor_rotate_common_accept_data, + .sensor_binding_process = zmk_behavior_sensor_rotate_common_process}; + +static int behavior_sensor_rotate_var_init(const struct device *dev) { return 0; }; + +#define SENSOR_ROTATE_VAR_INST(n) \ + static struct behavior_sensor_rotate_config behavior_sensor_rotate_var_config_##n = { \ + .cw_binding = {.behavior_dev = DEVICE_DT_NAME(DT_INST_PHANDLE_BY_IDX(n, bindings, 0))}, \ + .ccw_binding = {.behavior_dev = DEVICE_DT_NAME(DT_INST_PHANDLE_BY_IDX(n, bindings, 1))}, \ + .tap_ms = DT_INST_PROP(n, tap_ms), \ + .override_params = true, \ + }; \ + static struct behavior_sensor_rotate_data behavior_sensor_rotate_var_data_##n = {}; \ + BEHAVIOR_DT_INST_DEFINE( \ + n, behavior_sensor_rotate_var_init, NULL, &behavior_sensor_rotate_var_data_##n, \ + &behavior_sensor_rotate_var_config_##n, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + &behavior_sensor_rotate_var_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(SENSOR_ROTATE_VAR_INST) diff --git a/app/src/behaviors/behavior_sticky_key.c b/app/src/behaviors/behavior_sticky_key.c new file mode 100644 index 000000000000..67f7728628e7 --- /dev/null +++ b/app/src/behaviors/behavior_sticky_key.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_sticky_key + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +#define KEY_PRESS DEVICE_DT_NAME(DT_INST(0, zmk_behavior_key_press)) + +#define ZMK_BHV_STICKY_KEY_MAX_HELD 10 + +#define ZMK_BHV_STICKY_KEY_POSITION_FREE UINT32_MAX + +struct behavior_sticky_key_config { + uint32_t release_after_ms; + bool quick_release; + bool ignore_modifiers; + struct zmk_behavior_binding behavior; +}; + +struct active_sticky_key { + uint32_t position; + uint32_t param1; + uint32_t param2; + const struct behavior_sticky_key_config *config; + // timer data. + bool timer_started; + bool timer_cancelled; + int64_t release_at; + struct k_work_delayable release_timer; + // usage page and keycode for the key that is being modified by this sticky key + uint8_t modified_key_usage_page; + uint32_t modified_key_keycode; +}; + +struct active_sticky_key active_sticky_keys[ZMK_BHV_STICKY_KEY_MAX_HELD] = {}; + +static struct active_sticky_key *store_sticky_key(uint32_t position, uint32_t param1, + uint32_t param2, + const struct behavior_sticky_key_config *config) { + for (int i = 0; i < ZMK_BHV_STICKY_KEY_MAX_HELD; i++) { + struct active_sticky_key *const sticky_key = &active_sticky_keys[i]; + if (sticky_key->position != ZMK_BHV_STICKY_KEY_POSITION_FREE || + sticky_key->timer_cancelled) { + continue; + } + sticky_key->position = position; + sticky_key->param1 = param1; + sticky_key->param2 = param2; + sticky_key->config = config; + sticky_key->release_at = 0; + sticky_key->timer_cancelled = false; + sticky_key->timer_started = false; + sticky_key->modified_key_usage_page = 0; + sticky_key->modified_key_keycode = 0; + return sticky_key; + } + return NULL; +} + +static void clear_sticky_key(struct active_sticky_key *sticky_key) { + sticky_key->position = ZMK_BHV_STICKY_KEY_POSITION_FREE; +} + +static struct active_sticky_key *find_sticky_key(uint32_t position) { + for (int i = 0; i < ZMK_BHV_STICKY_KEY_MAX_HELD; i++) { + if (active_sticky_keys[i].position == position && !active_sticky_keys[i].timer_cancelled) { + return &active_sticky_keys[i]; + } + } + return NULL; +} + +static inline int press_sticky_key_behavior(struct active_sticky_key *sticky_key, + int64_t timestamp) { + struct zmk_behavior_binding binding = { + .behavior_dev = sticky_key->config->behavior.behavior_dev, + .param1 = sticky_key->param1, + .param2 = sticky_key->param2, + }; + struct zmk_behavior_binding_event event = { + .position = sticky_key->position, + .timestamp = timestamp, + }; + return behavior_keymap_binding_pressed(&binding, event); +} + +static inline int release_sticky_key_behavior(struct active_sticky_key *sticky_key, + int64_t timestamp) { + struct zmk_behavior_binding binding = { + .behavior_dev = sticky_key->config->behavior.behavior_dev, + .param1 = sticky_key->param1, + .param2 = sticky_key->param2, + }; + struct zmk_behavior_binding_event event = { + .position = sticky_key->position, + .timestamp = timestamp, + }; + + clear_sticky_key(sticky_key); + return behavior_keymap_binding_released(&binding, event); +} + +static int stop_timer(struct active_sticky_key *sticky_key) { + int timer_cancel_result = k_work_cancel_delayable(&sticky_key->release_timer); + if (timer_cancel_result == -EINPROGRESS) { + // too late to cancel, we'll let the timer handler clear up. + sticky_key->timer_cancelled = true; + } + return timer_cancel_result; +} + +static int on_sticky_key_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); + const struct behavior_sticky_key_config *cfg = dev->config; + struct active_sticky_key *sticky_key; + sticky_key = find_sticky_key(event.position); + if (sticky_key != NULL) { + stop_timer(sticky_key); + release_sticky_key_behavior(sticky_key, event.timestamp); + } + sticky_key = store_sticky_key(event.position, binding->param1, binding->param2, cfg); + if (sticky_key == NULL) { + LOG_ERR("unable to store sticky key, did you press more than %d sticky_key?", + ZMK_BHV_STICKY_KEY_MAX_HELD); + return ZMK_BEHAVIOR_OPAQUE; + } + + press_sticky_key_behavior(sticky_key, event.timestamp); + LOG_DBG("%d new sticky_key", event.position); + return ZMK_BEHAVIOR_OPAQUE; +} + +static int on_sticky_key_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + struct active_sticky_key *sticky_key = find_sticky_key(event.position); + if (sticky_key == NULL) { + LOG_ERR("ACTIVE STICKY KEY CLEARED TOO EARLY"); + return ZMK_BEHAVIOR_OPAQUE; + } + + if (sticky_key->modified_key_usage_page != 0 && sticky_key->modified_key_keycode != 0) { + LOG_DBG("Another key was pressed while the sticky key was pressed. Act like a normal key."); + return release_sticky_key_behavior(sticky_key, event.timestamp); + } + + // No other key was pressed. Start the timer. + sticky_key->timer_started = true; + sticky_key->release_at = event.timestamp + sticky_key->config->release_after_ms; + // adjust timer in case this behavior was queued by a hold-tap + int32_t ms_left = sticky_key->release_at - k_uptime_get(); + if (ms_left > 0) { + k_work_schedule(&sticky_key->release_timer, K_MSEC(ms_left)); + } + return ZMK_BEHAVIOR_OPAQUE; +} + +static const struct behavior_driver_api behavior_sticky_key_driver_api = { + .binding_pressed = on_sticky_key_binding_pressed, + .binding_released = on_sticky_key_binding_released, +}; + +static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh); + +ZMK_LISTENER(behavior_sticky_key, sticky_key_keycode_state_changed_listener); +ZMK_SUBSCRIPTION(behavior_sticky_key, zmk_keycode_state_changed); + +static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh) { + struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh); + if (ev == NULL) { + return ZMK_EV_EVENT_BUBBLE; + } + + // keep track whether the event has been reraised, so we only reraise it once + bool event_reraised = false; + + // reraising the event frees it, so make a copy of any event data we might + // need after it's been freed. + const struct zmk_keycode_state_changed ev_copy = *ev; + + for (int i = 0; i < ZMK_BHV_STICKY_KEY_MAX_HELD; i++) { + struct active_sticky_key *sticky_key = &active_sticky_keys[i]; + if (sticky_key->position == ZMK_BHV_STICKY_KEY_POSITION_FREE) { + continue; + } + + if (strcmp(sticky_key->config->behavior.behavior_dev, KEY_PRESS) == 0 && + ZMK_HID_USAGE_ID(sticky_key->param1) == ev_copy.keycode && + ZMK_HID_USAGE_PAGE(sticky_key->param1) == ev_copy.usage_page && + SELECT_MODS(sticky_key->param1) == ev_copy.implicit_modifiers) { + // don't catch key down events generated by the sticky key behavior itself + continue; + } + + // If this event was queued, the timer may be triggered late or not at all. + // Release the sticky key if the timer should've run out in the meantime. + if (sticky_key->release_at != 0 && ev_copy.timestamp > sticky_key->release_at) { + stop_timer(sticky_key); + release_sticky_key_behavior(sticky_key, sticky_key->release_at); + continue; + } + + if (ev_copy.state) { // key down + if (sticky_key->config->ignore_modifiers && + is_mod(ev_copy.usage_page, ev_copy.keycode)) { + // ignore modifier key press so we can stack sticky keys and combine with other + // modifiers + continue; + } + if (sticky_key->modified_key_usage_page != 0 || sticky_key->modified_key_keycode != 0) { + // this sticky key is already in use for a keycode + continue; + } + if (sticky_key->timer_started) { + stop_timer(sticky_key); + if (sticky_key->config->quick_release) { + // immediately release the sticky key after the key press is handled. + if (!event_reraised) { + ZMK_EVENT_RAISE_AFTER(eh, behavior_sticky_key); + event_reraised = true; + } + release_sticky_key_behavior(sticky_key, ev_copy.timestamp); + } + } + sticky_key->modified_key_usage_page = ev_copy.usage_page; + sticky_key->modified_key_keycode = ev_copy.keycode; + } else { // key up + if (sticky_key->timer_started && + sticky_key->modified_key_usage_page == ev_copy.usage_page && + sticky_key->modified_key_keycode == ev_copy.keycode) { + stop_timer(sticky_key); + release_sticky_key_behavior(sticky_key, ev_copy.timestamp); + } + } + } + if (event_reraised) { + return ZMK_EV_EVENT_CAPTURED; + } + return ZMK_EV_EVENT_BUBBLE; +} + +void behavior_sticky_key_timer_handler(struct k_work *item) { + struct active_sticky_key *sticky_key = + CONTAINER_OF(item, struct active_sticky_key, release_timer); + if (sticky_key->position == ZMK_BHV_STICKY_KEY_POSITION_FREE) { + return; + } + if (sticky_key->timer_cancelled) { + sticky_key->timer_cancelled = false; + } else { + release_sticky_key_behavior(sticky_key, sticky_key->release_at); + } +} + +static int behavior_sticky_key_init(const struct device *dev) { + static bool init_first_run = true; + if (init_first_run) { + for (int i = 0; i < ZMK_BHV_STICKY_KEY_MAX_HELD; i++) { + k_work_init_delayable(&active_sticky_keys[i].release_timer, + behavior_sticky_key_timer_handler); + active_sticky_keys[i].position = ZMK_BHV_STICKY_KEY_POSITION_FREE; + } + } + init_first_run = false; + return 0; +} + +struct behavior_sticky_key_data {}; +static struct behavior_sticky_key_data behavior_sticky_key_data; + +#define KP_INST(n) \ + static struct behavior_sticky_key_config behavior_sticky_key_config_##n = { \ + .behavior = ZMK_KEYMAP_EXTRACT_BINDING(0, DT_DRV_INST(n)), \ + .release_after_ms = DT_INST_PROP(n, release_after_ms), \ + .ignore_modifiers = DT_INST_PROP(n, ignore_modifiers), \ + .quick_release = DT_INST_PROP(n, quick_release), \ + }; \ + BEHAVIOR_DT_INST_DEFINE(n, behavior_sticky_key_init, NULL, &behavior_sticky_key_data, \ + &behavior_sticky_key_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_sticky_key_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KP_INST) + +#endif diff --git a/app/src/behaviors/behavior_tap_dance.c b/app/src/behaviors/behavior_tap_dance.c new file mode 100644 index 000000000000..306d5ca760b5 --- /dev/null +++ b/app/src/behaviors/behavior_tap_dance.c @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_tap_dance + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +#define ZMK_BHV_TAP_DANCE_MAX_HELD 10 + +#define ZMK_BHV_TAP_DANCE_POSITION_FREE UINT32_MAX + +struct behavior_tap_dance_config { + uint32_t tapping_term_ms; + size_t behavior_count; + struct zmk_behavior_binding *behaviors; +}; + +struct active_tap_dance { + // Tap Dance Data + int counter; + uint32_t position; + uint32_t param1; + uint32_t param2; + bool is_pressed; + const struct behavior_tap_dance_config *config; + + // Timer Data + bool timer_started; + bool timer_cancelled; + bool tap_dance_decided; + int64_t release_at; + struct k_work_delayable release_timer; +}; + +struct active_tap_dance active_tap_dances[ZMK_BHV_TAP_DANCE_MAX_HELD] = {}; + +static struct active_tap_dance *find_tap_dance(uint32_t position) { + for (int i = 0; i < ZMK_BHV_TAP_DANCE_MAX_HELD; i++) { + if (active_tap_dances[i].position == position && !active_tap_dances[i].timer_cancelled) { + return &active_tap_dances[i]; + } + } + return NULL; +} + +static int new_tap_dance(uint32_t position, const struct behavior_tap_dance_config *config, + struct active_tap_dance **tap_dance) { + for (int i = 0; i < ZMK_BHV_TAP_DANCE_MAX_HELD; i++) { + struct active_tap_dance *const ref_dance = &active_tap_dances[i]; + if (ref_dance->position == ZMK_BHV_TAP_DANCE_POSITION_FREE) { + ref_dance->counter = 0; + ref_dance->position = position; + ref_dance->config = config; + ref_dance->release_at = 0; + ref_dance->is_pressed = true; + ref_dance->timer_started = true; + ref_dance->timer_cancelled = false; + ref_dance->tap_dance_decided = false; + *tap_dance = ref_dance; + return 0; + } + } + return -ENOMEM; +} + +static void clear_tap_dance(struct active_tap_dance *tap_dance) { + tap_dance->position = ZMK_BHV_TAP_DANCE_POSITION_FREE; +} + +static int stop_timer(struct active_tap_dance *tap_dance) { + int timer_cancel_result = k_work_cancel_delayable(&tap_dance->release_timer); + if (timer_cancel_result == -EINPROGRESS) { + // too late to cancel, we'll let the timer handler clear up. + tap_dance->timer_cancelled = true; + } + return timer_cancel_result; +} + +static void reset_timer(struct active_tap_dance *tap_dance, + struct zmk_behavior_binding_event event) { + tap_dance->release_at = event.timestamp + tap_dance->config->tapping_term_ms; + int32_t ms_left = tap_dance->release_at - k_uptime_get(); + if (ms_left > 0) { + k_work_schedule(&tap_dance->release_timer, K_MSEC(ms_left)); + LOG_DBG("Successfully reset timer at position %d", tap_dance->position); + } +} + +static inline int press_tap_dance_behavior(struct active_tap_dance *tap_dance, int64_t timestamp) { + tap_dance->tap_dance_decided = true; + struct zmk_behavior_binding binding = tap_dance->config->behaviors[tap_dance->counter - 1]; + struct zmk_behavior_binding_event event = { + .position = tap_dance->position, + .timestamp = timestamp, + }; + return behavior_keymap_binding_pressed(&binding, event); +} + +static inline int release_tap_dance_behavior(struct active_tap_dance *tap_dance, + int64_t timestamp) { + struct zmk_behavior_binding binding = tap_dance->config->behaviors[tap_dance->counter - 1]; + struct zmk_behavior_binding_event event = { + .position = tap_dance->position, + .timestamp = timestamp, + }; + clear_tap_dance(tap_dance); + return behavior_keymap_binding_released(&binding, event); +} + +static int on_tap_dance_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); + const struct behavior_tap_dance_config *cfg = dev->config; + struct active_tap_dance *tap_dance; + tap_dance = find_tap_dance(event.position); + if (tap_dance == NULL) { + if (new_tap_dance(event.position, cfg, &tap_dance) == -ENOMEM) { + LOG_ERR("Unable to create new tap dance. Insufficient space in active_tap_dances[]."); + return ZMK_BEHAVIOR_OPAQUE; + } + LOG_DBG("%d created new tap dance", event.position); + } + tap_dance->is_pressed = true; + LOG_DBG("%d tap dance pressed", event.position); + stop_timer(tap_dance); + // Increment the counter on keypress. If the counter has reached its maximum + // value, invoke the last binding available. + if (tap_dance->counter < cfg->behavior_count) { + tap_dance->counter++; + } + if (tap_dance->counter == cfg->behavior_count) { + // LOG_DBG("Tap dance has been decided via maximum counter value"); + press_tap_dance_behavior(tap_dance, event.timestamp); + return ZMK_EV_EVENT_BUBBLE; + } + reset_timer(tap_dance, event); + return ZMK_BEHAVIOR_OPAQUE; +} + +static int on_tap_dance_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("%d tap dance keybind released", event.position); + struct active_tap_dance *tap_dance = find_tap_dance(event.position); + if (tap_dance == NULL) { + LOG_ERR("ACTIVE TAP DANCE CLEARED TOO EARLY"); + return ZMK_BEHAVIOR_OPAQUE; + } + tap_dance->is_pressed = false; + if (tap_dance->tap_dance_decided) { + release_tap_dance_behavior(tap_dance, event.timestamp); + } + return ZMK_BEHAVIOR_OPAQUE; +} + +void behavior_tap_dance_timer_handler(struct k_work *item) { + struct active_tap_dance *tap_dance = CONTAINER_OF(item, struct active_tap_dance, release_timer); + if (tap_dance->position == ZMK_BHV_TAP_DANCE_POSITION_FREE) { + return; + } + if (tap_dance->timer_cancelled) { + return; + } + LOG_DBG("Tap dance has been decided via timer. Counter reached: %d", tap_dance->counter); + press_tap_dance_behavior(tap_dance, tap_dance->release_at); + if (tap_dance->is_pressed) { + return; + } + release_tap_dance_behavior(tap_dance, tap_dance->release_at); +} + +static const struct behavior_driver_api behavior_tap_dance_driver_api = { + .binding_pressed = on_tap_dance_binding_pressed, + .binding_released = on_tap_dance_binding_released, +}; + +static int tap_dance_position_state_changed_listener(const zmk_event_t *eh); + +ZMK_LISTENER(behavior_tap_dance, tap_dance_position_state_changed_listener); +ZMK_SUBSCRIPTION(behavior_tap_dance, zmk_position_state_changed); + +static int tap_dance_position_state_changed_listener(const zmk_event_t *eh) { + struct zmk_position_state_changed *ev = as_zmk_position_state_changed(eh); + if (ev == NULL) { + return ZMK_EV_EVENT_BUBBLE; + } + if (!ev->state) { + LOG_DBG("Ignore upstroke at position %d.", ev->position); + return ZMK_EV_EVENT_BUBBLE; + } + for (int i = 0; i < ZMK_BHV_TAP_DANCE_MAX_HELD; i++) { + struct active_tap_dance *tap_dance = &active_tap_dances[i]; + if (tap_dance->position == ZMK_BHV_TAP_DANCE_POSITION_FREE) { + continue; + } + if (tap_dance->position == ev->position) { + continue; + } + stop_timer(tap_dance); + LOG_DBG("Tap dance interrupted, activating tap-dance at %d", tap_dance->position); + if (!tap_dance->tap_dance_decided) { + press_tap_dance_behavior(tap_dance, ev->timestamp); + if (!tap_dance->is_pressed) { + release_tap_dance_behavior(tap_dance, ev->timestamp); + } + return ZMK_EV_EVENT_BUBBLE; + } + } + return ZMK_EV_EVENT_BUBBLE; +} + +static int behavior_tap_dance_init(const struct device *dev) { + static bool init_first_run = true; + if (init_first_run) { + for (int i = 0; i < ZMK_BHV_TAP_DANCE_MAX_HELD; i++) { + k_work_init_delayable(&active_tap_dances[i].release_timer, + behavior_tap_dance_timer_handler); + clear_tap_dance(&active_tap_dances[i]); + } + } + init_first_run = false; + return 0; +} + +#define _TRANSFORM_ENTRY(idx, node) ZMK_KEYMAP_EXTRACT_BINDING(idx, node) + +#define TRANSFORMED_BINDINGS(node) \ + { LISTIFY(DT_INST_PROP_LEN(node, bindings), _TRANSFORM_ENTRY, (, ), DT_DRV_INST(node)) } + +#define KP_INST(n) \ + static struct zmk_behavior_binding \ + behavior_tap_dance_config_##n##_bindings[DT_INST_PROP_LEN(n, bindings)] = \ + TRANSFORMED_BINDINGS(n); \ + static struct behavior_tap_dance_config behavior_tap_dance_config_##n = { \ + .tapping_term_ms = DT_INST_PROP(n, tapping_term_ms), \ + .behaviors = behavior_tap_dance_config_##n##_bindings, \ + .behavior_count = DT_INST_PROP_LEN(n, bindings)}; \ + BEHAVIOR_DT_INST_DEFINE(n, behavior_tap_dance_init, NULL, NULL, \ + &behavior_tap_dance_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_tap_dance_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KP_INST) + +#endif \ No newline at end of file diff --git a/app/src/behaviors/behavior_to_layer.c b/app/src/behaviors/behavior_to_layer.c new file mode 100644 index 000000000000..9a58bf602c72 --- /dev/null +++ b/app/src/behaviors/behavior_to_layer.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_to_layer + +#include +#include +#include + +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +static int behavior_to_init(const struct device *dev) { return 0; }; + +static int to_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d layer %d", event.position, binding->param1); + zmk_keymap_layer_to(binding->param1); + return ZMK_BEHAVIOR_OPAQUE; +} + +static int to_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d layer %d", event.position, binding->param1); + return ZMK_BEHAVIOR_OPAQUE; +} + +static const struct behavior_driver_api behavior_to_driver_api = { + .binding_pressed = to_keymap_binding_pressed, + .binding_released = to_keymap_binding_released, +}; + +BEHAVIOR_DT_INST_DEFINE(0, behavior_to_init, NULL, NULL, NULL, APPLICATION, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_to_driver_api); + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/behaviors/behavior_toggle_layer.c b/app/src/behaviors/behavior_toggle_layer.c new file mode 100644 index 000000000000..154cf9cdf40a --- /dev/null +++ b/app/src/behaviors/behavior_toggle_layer.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_toggle_layer + +#include +#include +#include + +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +struct behavior_tog_config {}; +struct behavior_tog_data {}; + +static int behavior_tog_init(const struct device *dev) { return 0; }; + +static int tog_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d layer %d", event.position, binding->param1); + return zmk_keymap_layer_toggle(binding->param1); +} + +static int tog_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d layer %d", event.position, binding->param1); + return ZMK_BEHAVIOR_OPAQUE; +} + +static const struct behavior_driver_api behavior_tog_driver_api = { + .binding_pressed = tog_keymap_binding_pressed, + .binding_released = tog_keymap_binding_released, +}; + +static const struct behavior_tog_config behavior_tog_config = {}; + +static struct behavior_tog_data behavior_tog_data; + +BEHAVIOR_DT_INST_DEFINE(0, behavior_tog_init, NULL, &behavior_tog_data, &behavior_tog_config, + APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_tog_driver_api); + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/behaviors/behavior_transparent.c b/app/src/behaviors/behavior_transparent.c new file mode 100644 index 000000000000..ddf62ce0ae81 --- /dev/null +++ b/app/src/behaviors/behavior_transparent.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_transparent + +#include +#include +#include + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +static int behavior_transparent_init(const struct device *dev) { return 0; }; + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + return ZMK_BEHAVIOR_TRANSPARENT; +} + +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + return ZMK_BEHAVIOR_TRANSPARENT; +} + +static const struct behavior_driver_api behavior_transparent_driver_api = { + .binding_pressed = on_keymap_binding_pressed, + .binding_released = on_keymap_binding_released, +}; + +BEHAVIOR_DT_INST_DEFINE(0, behavior_transparent_init, NULL, NULL, NULL, APPLICATION, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_transparent_driver_api); + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/ble.c b/app/src/ble.c new file mode 100644 index 000000000000..a5f973a42cfb --- /dev/null +++ b/app/src/ble.c @@ -0,0 +1,771 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#if IS_ENABLED(CONFIG_SETTINGS) + +#include + +#endif + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include +#include + +#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) +#include + +#define PASSKEY_DIGITS 6 + +static struct bt_conn *auth_passkey_entry_conn; +RING_BUF_DECLARE(passkey_entries, PASSKEY_DIGITS); + +#endif /* IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) */ + +enum advertising_type { + ZMK_ADV_NONE, + ZMK_ADV_DIR, + ZMK_ADV_CONN, +} advertising_status; + +#define CURR_ADV(adv) (adv << 4) + +#define ZMK_ADV_CONN_NAME \ + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME, BT_GAP_ADV_FAST_INT_MIN_2, \ + BT_GAP_ADV_FAST_INT_MAX_2, NULL) + +static struct zmk_ble_profile profiles[ZMK_BLE_PROFILE_COUNT]; +static uint8_t active_profile; + +#define DEVICE_NAME CONFIG_BT_DEVICE_NAME +#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) + +BUILD_ASSERT(DEVICE_NAME_LEN <= 16, "ERROR: BLE device name is too long. Max length: 16"); + +static const struct bt_data zmk_ble_ad[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), + BT_DATA_BYTES(BT_DATA_GAP_APPEARANCE, 0xC1, 0x03), + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA_BYTES(BT_DATA_UUID16_SOME, 0x12, 0x18, /* HID Service */ + 0x0f, 0x18 /* Battery Service */ + ), +}; + +#if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) + +static bt_addr_le_t peripheral_addrs[ZMK_SPLIT_BLE_PERIPHERAL_COUNT]; + +#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */ + +static void raise_profile_changed_event() { + ZMK_EVENT_RAISE(new_zmk_ble_active_profile_changed((struct zmk_ble_active_profile_changed){ + .index = active_profile, .profile = &profiles[active_profile]})); +} + +static void raise_profile_changed_event_callback(struct k_work *work) { + raise_profile_changed_event(); +} + +K_WORK_DEFINE(raise_profile_changed_event_work, raise_profile_changed_event_callback); + +bool zmk_ble_active_profile_is_open() { + return !bt_addr_le_cmp(&profiles[active_profile].peer, BT_ADDR_LE_ANY); +} + +void set_profile_address(uint8_t index, const bt_addr_le_t *addr) { + char setting_name[15]; + char addr_str[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); + + memcpy(&profiles[index].peer, addr, sizeof(bt_addr_le_t)); + sprintf(setting_name, "ble/profiles/%d", index); + LOG_DBG("Setting profile addr for %s to %s", setting_name, addr_str); +#if IS_ENABLED(CONFIG_SETTINGS) + settings_save_one(setting_name, &profiles[index], sizeof(struct zmk_ble_profile)); +#endif + k_work_submit(&raise_profile_changed_event_work); +} + +bool zmk_ble_active_profile_is_connected() { + struct bt_conn *conn; + struct bt_conn_info info; + bt_addr_le_t *addr = zmk_ble_active_profile_addr(); + if (!bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) { + return false; + } else if ((conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr)) == NULL) { + return false; + } + + bt_conn_get_info(conn, &info); + + bt_conn_unref(conn); + + return info.state == BT_CONN_STATE_CONNECTED; +} + +#define CHECKED_ADV_STOP() \ + err = bt_le_adv_stop(); \ + advertising_status = ZMK_ADV_NONE; \ + if (err) { \ + LOG_ERR("Failed to stop advertising (err %d)", err); \ + return err; \ + } + +#define CHECKED_DIR_ADV() \ + addr = zmk_ble_active_profile_addr(); \ + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr); \ + if (conn != NULL) { /* TODO: Check status of connection */ \ + LOG_DBG("Skipping advertising, profile host is already connected"); \ + bt_conn_unref(conn); \ + return 0; \ + } \ + err = bt_le_adv_start(BT_LE_ADV_CONN_DIR_LOW_DUTY(addr), zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), \ + NULL, 0); \ + if (err) { \ + LOG_ERR("Advertising failed to start (err %d)", err); \ + return err; \ + } \ + advertising_status = ZMK_ADV_DIR; + +#define CHECKED_OPEN_ADV() \ + err = bt_le_adv_start(ZMK_ADV_CONN_NAME, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0); \ + if (err) { \ + LOG_ERR("Advertising failed to start (err %d)", err); \ + return err; \ + } \ + advertising_status = ZMK_ADV_CONN; + +int update_advertising() { + int err = 0; + bt_addr_le_t *addr; + struct bt_conn *conn; + enum advertising_type desired_adv = ZMK_ADV_NONE; + + if (zmk_ble_active_profile_is_open()) { + desired_adv = ZMK_ADV_CONN; + } else if (!zmk_ble_active_profile_is_connected()) { + desired_adv = ZMK_ADV_CONN; + // Need to fix directed advertising for privacy centrals. See + // https://github.com/zephyrproject-rtos/zephyr/pull/14984 char + // addr_str[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(zmk_ble_active_profile_addr(), addr_str, + // sizeof(addr_str)); + + // LOG_DBG("Directed advertising to %s", addr_str); + // desired_adv = ZMK_ADV_DIR; + } + LOG_DBG("advertising from %d to %d", advertising_status, desired_adv); + + switch (desired_adv + CURR_ADV(advertising_status)) { + case ZMK_ADV_NONE + CURR_ADV(ZMK_ADV_DIR): + case ZMK_ADV_NONE + CURR_ADV(ZMK_ADV_CONN): + CHECKED_ADV_STOP(); + break; + case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_DIR): + case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_CONN): + CHECKED_ADV_STOP(); + CHECKED_DIR_ADV(); + break; + case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_NONE): + CHECKED_DIR_ADV(); + break; + case ZMK_ADV_CONN + CURR_ADV(ZMK_ADV_DIR): + CHECKED_ADV_STOP(); + CHECKED_OPEN_ADV(); + break; + case ZMK_ADV_CONN + CURR_ADV(ZMK_ADV_NONE): + CHECKED_OPEN_ADV(); + break; + } + + return 0; +}; + +static void update_advertising_callback(struct k_work *work) { update_advertising(); } + +K_WORK_DEFINE(update_advertising_work, update_advertising_callback); + +int zmk_ble_clear_bonds() { + LOG_DBG(""); + + if (bt_addr_le_cmp(&profiles[active_profile].peer, BT_ADDR_LE_ANY)) { + LOG_DBG("Unpairing!"); + bt_unpair(BT_ID_DEFAULT, &profiles[active_profile].peer); + set_profile_address(active_profile, BT_ADDR_LE_ANY); + } + + update_advertising(); + + return 0; +}; + +int zmk_ble_active_profile_index() { return active_profile; } + +int zmk_ble_profile_index(const bt_addr_le_t *addr) { + for (int i = 0; i < ZMK_BLE_PROFILE_COUNT; i++) { + if (bt_addr_le_cmp(addr, &profiles[i].peer) == 0) { + return i; + } + } + return -ENODEV; +} + +#if IS_ENABLED(CONFIG_SETTINGS) +static void ble_save_profile_work(struct k_work *work) { + settings_save_one("ble/active_profile", &active_profile, sizeof(active_profile)); +} + +static struct k_work_delayable ble_save_work; +#endif + +static int ble_save_profile() { +#if IS_ENABLED(CONFIG_SETTINGS) + return k_work_reschedule(&ble_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE)); +#else + return 0; +#endif +} + +int zmk_ble_prof_select(uint8_t index) { + if (index >= ZMK_BLE_PROFILE_COUNT) { + return -ERANGE; + } + + LOG_DBG("profile %d", index); + if (active_profile == index) { + return 0; + } + + active_profile = index; + ble_save_profile(); + + update_advertising(); + + raise_profile_changed_event(); + + return 0; +}; + +int zmk_ble_prof_next() { + LOG_DBG(""); + return zmk_ble_prof_select((active_profile + 1) % ZMK_BLE_PROFILE_COUNT); +}; + +int zmk_ble_prof_prev() { + LOG_DBG(""); + return zmk_ble_prof_select((active_profile + ZMK_BLE_PROFILE_COUNT - 1) % + ZMK_BLE_PROFILE_COUNT); +}; + +int zmk_ble_prof_disconnect(uint8_t index) { + if (index >= ZMK_BLE_PROFILE_COUNT) + return -ERANGE; + + bt_addr_le_t *addr = &profiles[index].peer; + struct bt_conn *conn; + int result; + + if (!bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) { + return -ENODEV; + } else if ((conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr)) == NULL) { + return -ENODEV; + } + + result = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + LOG_DBG("Disconnected from profile %d: %d", index, result); + + bt_conn_unref(conn); + return result; +} + +bt_addr_le_t *zmk_ble_active_profile_addr() { return &profiles[active_profile].peer; } + +char *zmk_ble_active_profile_name() { return profiles[active_profile].name; } + +#if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) + +int zmk_ble_put_peripheral_addr(const bt_addr_le_t *addr) { + for (int i = 0; i < ZMK_SPLIT_BLE_PERIPHERAL_COUNT; i++) { + // If the address is recognized and already stored in settings, return + // index and no additional action is necessary. + if (bt_addr_le_cmp(&peripheral_addrs[i], addr) == 0) { + LOG_DBG("Found existing peripheral address in slot %d", i); + return i; + } else { + char addr_str[BT_ADDR_LE_STR_LEN]; + bt_addr_le_to_str(&peripheral_addrs[i], addr_str, sizeof(addr_str)); + LOG_DBG("peripheral slot %d occupied by %s", i, addr_str); + } + + // If the peripheral address slot is open, store new peripheral in the + // slot and return index. This compares against BT_ADDR_LE_ANY as that + // is the zero value. + if (bt_addr_le_cmp(&peripheral_addrs[i], BT_ADDR_LE_ANY) == 0) { + char addr_str[BT_ADDR_LE_STR_LEN]; + bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); + LOG_DBG("Storing peripheral %s in slot %d", addr_str, i); + bt_addr_le_copy(&peripheral_addrs[i], addr); + + char setting_name[32]; + sprintf(setting_name, "ble/peripheral_addresses/%d", i); + settings_save_one(setting_name, addr, sizeof(bt_addr_le_t)); + + return i; + } + } + + // The peripheral does not match a known peripheral and there is no + // available slot. + return -ENOMEM; +} + +#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */ + +#if IS_ENABLED(CONFIG_SETTINGS) + +static int ble_profiles_handle_set(const char *name, size_t len, settings_read_cb read_cb, + void *cb_arg) { + const char *next; + + LOG_DBG("Setting BLE value %s", name); + + if (settings_name_steq(name, "profiles", &next) && next) { + char *endptr; + uint8_t idx = strtoul(next, &endptr, 10); + if (*endptr != '\0') { + LOG_WRN("Invalid profile index: %s", next); + return -EINVAL; + } + + if (len != sizeof(struct zmk_ble_profile)) { + LOG_ERR("Invalid profile size (got %d expected %d)", len, + sizeof(struct zmk_ble_profile)); + return -EINVAL; + } + + if (idx >= ZMK_BLE_PROFILE_COUNT) { + LOG_WRN("Profile address for index %d is larger than max of %d", idx, + ZMK_BLE_PROFILE_COUNT); + return -EINVAL; + } + + int err = read_cb(cb_arg, &profiles[idx], sizeof(struct zmk_ble_profile)); + if (err <= 0) { + LOG_ERR("Failed to handle profile address from settings (err %d)", err); + return err; + } + + char addr_str[BT_ADDR_LE_STR_LEN]; + bt_addr_le_to_str(&profiles[idx].peer, addr_str, sizeof(addr_str)); + + LOG_DBG("Loaded %s address for profile %d", addr_str, idx); + } else if (settings_name_steq(name, "active_profile", &next) && !next) { + if (len != sizeof(active_profile)) { + return -EINVAL; + } + + int err = read_cb(cb_arg, &active_profile, sizeof(active_profile)); + if (err <= 0) { + LOG_ERR("Failed to handle active profile from settings (err %d)", err); + return err; + } + } +#if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) + else if (settings_name_steq(name, "peripheral_addresses", &next) && next) { + if (len != sizeof(bt_addr_le_t)) { + return -EINVAL; + } + + int i = atoi(next); + if (i < 0 || i >= ZMK_SPLIT_BLE_PERIPHERAL_COUNT) { + LOG_ERR("Failed to store peripheral address in memory"); + } else { + int err = read_cb(cb_arg, &peripheral_addrs[i], sizeof(bt_addr_le_t)); + if (err <= 0) { + LOG_ERR("Failed to handle peripheral address from settings (err %d)", err); + return err; + } + } + } +#endif + + return 0; +}; + +struct settings_handler profiles_handler = {.name = "ble", .h_set = ble_profiles_handle_set}; +#endif /* IS_ENABLED(CONFIG_SETTINGS) */ + +static bool is_conn_active_profile(const struct bt_conn *conn) { + return bt_addr_le_cmp(bt_conn_get_dst(conn), &profiles[active_profile].peer) == 0; +} + +static void connected(struct bt_conn *conn, uint8_t err) { + char addr[BT_ADDR_LE_STR_LEN]; + struct bt_conn_info info; + LOG_DBG("Connected thread: %p", k_current_get()); + + bt_conn_get_info(conn, &info); + + if (info.role != BT_CONN_ROLE_PERIPHERAL) { + LOG_DBG("SKIPPING FOR ROLE %d", info.role); + return; + } + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + advertising_status = ZMK_ADV_NONE; + + if (err) { + LOG_WRN("Failed to connect to %s (%u)", addr, err); + update_advertising(); + return; + } + + LOG_DBG("Connected %s", addr); + +#if !IS_ENABLED(CONFIG_BT_GATT_AUTO_SEC_REQ) + if (bt_conn_set_security(conn, BT_SECURITY_L2)) { + LOG_ERR("Failed to set security"); + } +#endif // !IS_ENABLED(CONFIG_BT_GATT_AUTO_SEC_REQ) + + update_advertising(); + + if (is_conn_active_profile(conn)) { + LOG_DBG("Active profile connected"); + k_work_submit(&raise_profile_changed_event_work); + } +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) { + char addr[BT_ADDR_LE_STR_LEN]; + struct bt_conn_info info; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + LOG_DBG("Disconnected from %s (reason 0x%02x)", addr, reason); + + bt_conn_get_info(conn, &info); + + if (info.role != BT_CONN_ROLE_PERIPHERAL) { + LOG_DBG("SKIPPING FOR ROLE %d", info.role); + return; + } + + // We need to do this in a work callback, otherwise the advertising update will still see the + // connection for a profile as active, and not start advertising yet. + k_work_submit(&update_advertising_work); + + if (is_conn_active_profile(conn)) { + LOG_DBG("Active profile disconnected"); + k_work_submit(&raise_profile_changed_event_work); + } +} + +static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) { + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (!err) { + LOG_DBG("Security changed: %s level %u", addr, level); + } else { + LOG_ERR("Security failed: %s level %u err %d", addr, level, err); + } +} + +static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency, + uint16_t timeout) { + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + LOG_DBG("%s: interval %d latency %d timeout %d", addr, interval, latency, timeout); +} + +static struct bt_conn_cb conn_callbacks = { + .connected = connected, + .disconnected = disconnected, + .security_changed = security_changed, + .le_param_updated = le_param_updated, +}; + +/* +static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey) { + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + LOG_DBG("Passkey for %s: %06u", addr, passkey); +} +*/ + +#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) + +static void auth_passkey_entry(struct bt_conn *conn) { + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + LOG_DBG("Passkey entry requested for %s", addr); + ring_buf_reset(&passkey_entries); + auth_passkey_entry_conn = bt_conn_ref(conn); +} + +#endif + +static void auth_cancel(struct bt_conn *conn) { + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + +#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) + if (auth_passkey_entry_conn) { + bt_conn_unref(auth_passkey_entry_conn); + auth_passkey_entry_conn = NULL; + } + + ring_buf_reset(&passkey_entries); +#endif + + LOG_DBG("Pairing cancelled: %s", addr); +} + +static bool pairing_allowed_for_current_profile(struct bt_conn *conn) { + return zmk_ble_active_profile_is_open() || + (IS_ENABLED(CONFIG_BT_SMP_ALLOW_UNAUTH_OVERWRITE) && + bt_addr_le_cmp(zmk_ble_active_profile_addr(), bt_conn_get_dst(conn)) == 0); +} + +static enum bt_security_err auth_pairing_accept(struct bt_conn *conn, + const struct bt_conn_pairing_feat *const feat) { + struct bt_conn_info info; + bt_conn_get_info(conn, &info); + + LOG_DBG("role %d, open? %s", info.role, zmk_ble_active_profile_is_open() ? "yes" : "no"); + if (info.role == BT_CONN_ROLE_PERIPHERAL && !pairing_allowed_for_current_profile(conn)) { + LOG_WRN("Rejecting pairing request to taken profile %d", active_profile); + return BT_SECURITY_ERR_PAIR_NOT_ALLOWED; + } + + return BT_SECURITY_ERR_SUCCESS; +}; + +static void auth_pairing_complete(struct bt_conn *conn, bool bonded) { + struct bt_conn_info info; + char addr[BT_ADDR_LE_STR_LEN]; + const bt_addr_le_t *dst = bt_conn_get_dst(conn); + + bt_addr_le_to_str(dst, addr, sizeof(addr)); + bt_conn_get_info(conn, &info); + + if (info.role != BT_CONN_ROLE_PERIPHERAL) { + LOG_DBG("SKIPPING FOR ROLE %d", info.role); + return; + } + + if (!pairing_allowed_for_current_profile(conn)) { + LOG_ERR("Pairing completed but current profile is not open: %s", addr); + bt_unpair(BT_ID_DEFAULT, dst); + return; + } + + set_profile_address(active_profile, dst); + update_advertising(); +}; + +static struct bt_conn_auth_cb zmk_ble_auth_cb_display = { + .pairing_accept = auth_pairing_accept, +// .passkey_display = auth_passkey_display, + +#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) + .passkey_entry = auth_passkey_entry, +#endif + .cancel = auth_cancel, +}; + +static struct bt_conn_auth_info_cb zmk_ble_auth_info_cb_display = { + .pairing_complete = auth_pairing_complete, +}; + +static void zmk_ble_ready(int err) { + LOG_DBG("ready? %d", err); + if (err) { + LOG_ERR("Bluetooth init failed (err %d)", err); + return; + } + + update_advertising(); +} + +static int zmk_ble_init(const struct device *_arg) { + int err = bt_enable(NULL); + + if (err) { + LOG_ERR("BLUETOOTH FAILED (%d)", err); + return err; + } + +#if IS_ENABLED(CONFIG_SETTINGS) + settings_subsys_init(); + + err = settings_register(&profiles_handler); + if (err) { + LOG_ERR("Failed to setup the profile settings handler (err %d)", err); + return err; + } + + k_work_init_delayable(&ble_save_work, ble_save_profile_work); + + settings_load_subtree("ble"); + settings_load_subtree("bt"); + +#endif + +#if IS_ENABLED(CONFIG_ZMK_BLE_CLEAR_BONDS_ON_START) + LOG_WRN("Clearing all existing BLE bond information from the keyboard"); + + bt_unpair(BT_ID_DEFAULT, NULL); + + for (int i = 0; i < 8; i++) { + char setting_name[15]; + sprintf(setting_name, "ble/profiles/%d", i); + + err = settings_delete(setting_name); + if (err) { + LOG_ERR("Failed to delete setting: %d", err); + } + } + + // Hardcoding a reasonable hardcoded value of peripheral addresses + // to clear so we properly clear a split central as well. + for (int i = 0; i < 8; i++) { + char setting_name[32]; + sprintf(setting_name, "ble/peripheral_addresses/%d", i); + + err = settings_delete(setting_name); + if (err) { + LOG_ERR("Failed to delete setting: %d", err); + } + } + +#endif // IS_ENABLED(CONFIG_ZMK_BLE_CLEAR_BONDS_ON_START) + + bt_conn_cb_register(&conn_callbacks); + bt_conn_auth_cb_register(&zmk_ble_auth_cb_display); + bt_conn_auth_info_cb_register(&zmk_ble_auth_info_cb_display); + + zmk_ble_ready(0); + + return 0; +} + +#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) + +static bool zmk_ble_numeric_usage_to_value(const zmk_key_t key, const zmk_key_t one, + const zmk_key_t zero, uint8_t *value) { + if (key < one || key > zero) { + return false; + } + + *value = (key == zero) ? 0 : (key - one + 1); + return true; +} + +static int zmk_ble_handle_key_user(struct zmk_keycode_state_changed *event) { + zmk_key_t key = event->keycode; + + LOG_DBG("key %d", key); + + if (!auth_passkey_entry_conn) { + LOG_DBG("No connection for passkey entry"); + return ZMK_EV_EVENT_BUBBLE; + } + + if (event->state) { + LOG_DBG("Key press, ignoring"); + return ZMK_EV_EVENT_HANDLED; + } + + if (key == HID_USAGE_KEY_KEYBOARD_ESCAPE) { + bt_conn_auth_cancel(auth_passkey_entry_conn); + return ZMK_EV_EVENT_HANDLED; + } + + if (key == HID_USAGE_KEY_KEYBOARD_RETURN || key == HID_USAGE_KEY_KEYBOARD_RETURN_ENTER) { + uint8_t digits[PASSKEY_DIGITS]; + uint32_t count = ring_buf_get(&passkey_entries, digits, PASSKEY_DIGITS); + + uint32_t passkey = 0; + for (int i = 0; i < count; i++) { + passkey = (passkey * 10) + digits[i]; + } + + LOG_DBG("Final passkey: %d", passkey); + bt_conn_auth_passkey_entry(auth_passkey_entry_conn, passkey); + bt_conn_unref(auth_passkey_entry_conn); + auth_passkey_entry_conn = NULL; + return ZMK_EV_EVENT_HANDLED; + } + + uint8_t val; + if (!(zmk_ble_numeric_usage_to_value(key, HID_USAGE_KEY_KEYBOARD_1_AND_EXCLAMATION, + HID_USAGE_KEY_KEYBOARD_0_AND_RIGHT_PARENTHESIS, &val) || + zmk_ble_numeric_usage_to_value(key, HID_USAGE_KEY_KEYPAD_1_AND_END, + HID_USAGE_KEY_KEYPAD_0_AND_INSERT, &val))) { + LOG_DBG("Key not a number, ignoring"); + return ZMK_EV_EVENT_HANDLED; + } + + if (ring_buf_space_get(&passkey_entries) <= 0) { + uint8_t discard_val; + ring_buf_get(&passkey_entries, &discard_val, 1); + } + ring_buf_put(&passkey_entries, &val, 1); + LOG_DBG("value entered: %d, digits collected so far: %d", val, + ring_buf_size_get(&passkey_entries)); + + return ZMK_EV_EVENT_HANDLED; +} + +static int zmk_ble_listener(const zmk_event_t *eh) { + struct zmk_keycode_state_changed *kc_state; + + kc_state = as_zmk_keycode_state_changed(eh); + + if (kc_state != NULL) { + return zmk_ble_handle_key_user(kc_state); + } + + return 0; +} + +ZMK_LISTENER(zmk_ble, zmk_ble_listener); +ZMK_SUBSCRIPTION(zmk_ble, zmk_keycode_state_changed); +#endif /* IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) */ + +SYS_INIT(zmk_ble_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY); diff --git a/app/src/combo.c b/app/src/combo.c new file mode 100644 index 000000000000..0d5c2a6e237b --- /dev/null +++ b/app/src/combo.c @@ -0,0 +1,548 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_combos + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +struct combo_cfg { + int32_t key_positions[CONFIG_ZMK_COMBO_MAX_KEYS_PER_COMBO]; + int32_t key_position_len; + struct zmk_behavior_binding behavior; + int32_t timeout_ms; + int32_t require_prior_idle_ms; + // if slow release is set, the combo releases when the last key is released. + // otherwise, the combo releases when the first key is released. + bool slow_release; + // the virtual key position is a key position outside the range used by the keyboard. + // it is necessary so hold-taps can uniquely identify a behavior. + int32_t virtual_key_position; + int32_t layers_len; + int8_t layers[]; +}; + +struct active_combo { + struct combo_cfg *combo; + // key_positions_pressed is filled with key_positions when the combo is pressed. + // The keys are removed from this array when they are released. + // Once this array is empty, the behavior is released. + const zmk_event_t *key_positions_pressed[CONFIG_ZMK_COMBO_MAX_KEYS_PER_COMBO]; +}; + +struct combo_candidate { + struct combo_cfg *combo; + // the time after which this behavior should be removed from candidates. + // by keeping track of when the candidate should be cleared there is no + // possibility of accidental releases. + int64_t timeout_at; +}; + +// set of keys pressed +const zmk_event_t *pressed_keys[CONFIG_ZMK_COMBO_MAX_KEYS_PER_COMBO] = {NULL}; +// the set of candidate combos based on the currently pressed_keys +struct combo_candidate candidates[CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY]; +// the last candidate that was completely pressed +struct combo_cfg *fully_pressed_combo = NULL; +// a lookup dict that maps a key position to all combos on that position +struct combo_cfg *combo_lookup[ZMK_KEYMAP_LEN][CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY] = {NULL}; +// combos that have been activated and still have (some) keys pressed +// this array is always contiguous from 0. +struct active_combo active_combos[CONFIG_ZMK_COMBO_MAX_PRESSED_COMBOS] = {NULL}; +int active_combo_count = 0; + +struct k_work_delayable timeout_task; +int64_t timeout_task_timeout_at; + +// this keeps track of the last non-combo, non-mod key tap +int64_t last_tapped_timestamp = INT32_MIN; +// this keeps track of the last time a combo was pressed +int64_t last_combo_timestamp = INT32_MIN; + +static void store_last_tapped(int64_t timestamp) { + if (timestamp > last_combo_timestamp) { + last_tapped_timestamp = timestamp; + } +} + +// Store the combo key pointer in the combos array, one pointer for each key position +// The combos are sorted shortest-first, then by virtual-key-position. +static int initialize_combo(struct combo_cfg *new_combo) { + for (int i = 0; i < new_combo->key_position_len; i++) { + int32_t position = new_combo->key_positions[i]; + if (position >= ZMK_KEYMAP_LEN) { + LOG_ERR("Unable to initialize combo, key position %d does not exist", position); + return -EINVAL; + } + + struct combo_cfg *insert_combo = new_combo; + bool set = false; + for (int j = 0; j < CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY; j++) { + struct combo_cfg *combo_at_j = combo_lookup[position][j]; + if (combo_at_j == NULL) { + combo_lookup[position][j] = insert_combo; + set = true; + break; + } + if (combo_at_j->key_position_len < insert_combo->key_position_len || + (combo_at_j->key_position_len == insert_combo->key_position_len && + combo_at_j->virtual_key_position < insert_combo->virtual_key_position)) { + continue; + } + // put insert_combo in this spot, move all other combos up. + combo_lookup[position][j] = insert_combo; + insert_combo = combo_at_j; + } + if (!set) { + LOG_ERR("Too many combos for key position %d, CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY %d.", + position, CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY); + return -ENOMEM; + } + } + return 0; +} + +static bool combo_active_on_layer(struct combo_cfg *combo, uint8_t layer) { + if (combo->layers[0] == -1) { + // -1 in the first layer position is global layer scope + return true; + } + for (int j = 0; j < combo->layers_len; j++) { + if (combo->layers[j] == layer) { + return true; + } + } + return false; +} + +static bool is_quick_tap(struct combo_cfg *combo, int64_t timestamp) { + return (last_tapped_timestamp + combo->require_prior_idle_ms) > timestamp; +} + +static int setup_candidates_for_first_keypress(int32_t position, int64_t timestamp) { + int number_of_combo_candidates = 0; + uint8_t highest_active_layer = zmk_keymap_highest_layer_active(); + for (int i = 0; i < CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY; i++) { + struct combo_cfg *combo = combo_lookup[position][i]; + if (combo == NULL) { + return number_of_combo_candidates; + } + if (combo_active_on_layer(combo, highest_active_layer) && !is_quick_tap(combo, timestamp)) { + candidates[number_of_combo_candidates].combo = combo; + candidates[number_of_combo_candidates].timeout_at = timestamp + combo->timeout_ms; + number_of_combo_candidates++; + } + // LOG_DBG("combo timeout %d %d %d", position, i, candidates[i].timeout_at); + } + return number_of_combo_candidates; +} + +static int filter_candidates(int32_t position) { + // this code iterates over candidates and the lookup together to filter in O(n) + // assuming they are both sorted on key_position_len, virtal_key_position + int matches = 0, lookup_idx = 0, candidate_idx = 0; + while (lookup_idx < CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY && + candidate_idx < CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY) { + struct combo_cfg *candidate = candidates[candidate_idx].combo; + struct combo_cfg *lookup = combo_lookup[position][lookup_idx]; + if (candidate == NULL || lookup == NULL) { + break; + } + if (candidate->virtual_key_position == lookup->virtual_key_position) { + candidates[matches] = candidates[candidate_idx]; + matches++; + candidate_idx++; + lookup_idx++; + } else if (candidate->key_position_len > lookup->key_position_len) { + lookup_idx++; + } else if (candidate->key_position_len < lookup->key_position_len) { + candidate_idx++; + } else if (candidate->virtual_key_position > lookup->virtual_key_position) { + lookup_idx++; + } else if (candidate->virtual_key_position < lookup->virtual_key_position) { + candidate_idx++; + } + } + // clear unmatched candidates + for (int i = matches; i < CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY; i++) { + candidates[i].combo = NULL; + } + // LOG_DBG("combo matches after filter %d", matches); + return matches; +} + +static int64_t first_candidate_timeout() { + int64_t first_timeout = LONG_MAX; + for (int i = 0; i < CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY; i++) { + if (candidates[i].combo == NULL) { + break; + } + if (candidates[i].timeout_at < first_timeout) { + first_timeout = candidates[i].timeout_at; + } + } + return first_timeout; +} + +static inline bool candidate_is_completely_pressed(struct combo_cfg *candidate) { + // this code assumes set(pressed_keys) <= set(candidate->key_positions) + // this invariant is enforced by filter_candidates + // since events may have been reraised after clearing one or more slots at + // the start of pressed_keys (see: release_pressed_keys), we have to check + // that each key needed to trigger the combo was pressed, not just the last. + for (int i = 0; i < candidate->key_position_len; i++) { + if (pressed_keys[i] == NULL) { + return false; + } + } + return true; +} + +static int cleanup(); + +static int filter_timed_out_candidates(int64_t timestamp) { + int remaining_candidates = 0; + for (int i = 0; i < CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY; i++) { + struct combo_candidate *candidate = &candidates[i]; + if (candidate->combo == NULL) { + break; + } + if (candidate->timeout_at > timestamp) { + bool need_to_bubble_up = remaining_candidates != i; + if (need_to_bubble_up) { + // bubble up => reorder candidates so they're contiguous + candidates[remaining_candidates].combo = candidate->combo; + candidates[remaining_candidates].timeout_at = candidate->timeout_at; + // clear the previous location + candidates[i].combo = NULL; + candidates[i].timeout_at = 0; + } + + remaining_candidates++; + } else { + candidate->combo = NULL; + } + } + + LOG_DBG( + "after filtering out timed out combo candidates: remaining_candidates=%d timestamp=%lld", + remaining_candidates, timestamp); + + return remaining_candidates; +} + +static int clear_candidates() { + for (int i = 0; i < CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY; i++) { + if (candidates[i].combo == NULL) { + return i; + } + candidates[i].combo = NULL; + } + return CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY; +} + +static int capture_pressed_key(const zmk_event_t *ev) { + for (int i = 0; i < CONFIG_ZMK_COMBO_MAX_KEYS_PER_COMBO; i++) { + if (pressed_keys[i] != NULL) { + continue; + } + pressed_keys[i] = ev; + return ZMK_EV_EVENT_CAPTURED; + } + return ZMK_EV_EVENT_BUBBLE; +} + +const struct zmk_listener zmk_listener_combo; + +static int release_pressed_keys() { + for (int i = 0; i < CONFIG_ZMK_COMBO_MAX_KEYS_PER_COMBO; i++) { + const zmk_event_t *captured_event = pressed_keys[i]; + if (pressed_keys[i] == NULL) { + return i; + } + pressed_keys[i] = NULL; + if (i == 0) { + LOG_DBG("combo: releasing position event %d", + as_zmk_position_state_changed(captured_event)->position); + ZMK_EVENT_RELEASE(captured_event) + } else { + // reprocess events (see tests/combo/fully-overlapping-combos-3 for why this is needed) + LOG_DBG("combo: reraising position event %d", + as_zmk_position_state_changed(captured_event)->position); + ZMK_EVENT_RAISE(captured_event); + } + } + return CONFIG_ZMK_COMBO_MAX_KEYS_PER_COMBO; +} + +static inline int press_combo_behavior(struct combo_cfg *combo, int32_t timestamp) { + struct zmk_behavior_binding_event event = { + .position = combo->virtual_key_position, + .timestamp = timestamp, + }; + + last_combo_timestamp = timestamp; + + return behavior_keymap_binding_pressed(&combo->behavior, event); +} + +static inline int release_combo_behavior(struct combo_cfg *combo, int32_t timestamp) { + struct zmk_behavior_binding_event event = { + .position = combo->virtual_key_position, + .timestamp = timestamp, + }; + + return behavior_keymap_binding_released(&combo->behavior, event); +} + +static void move_pressed_keys_to_active_combo(struct active_combo *active_combo) { + int combo_length = active_combo->combo->key_position_len; + for (int i = 0; i < combo_length; i++) { + active_combo->key_positions_pressed[i] = pressed_keys[i]; + pressed_keys[i] = NULL; + } + // move any other pressed keys up + for (int i = 0; i + combo_length < CONFIG_ZMK_COMBO_MAX_KEYS_PER_COMBO; i++) { + if (pressed_keys[i + combo_length] == NULL) { + return; + } + pressed_keys[i] = pressed_keys[i + combo_length]; + pressed_keys[i + combo_length] = NULL; + } +} + +static struct active_combo *store_active_combo(struct combo_cfg *combo) { + for (int i = 0; i < CONFIG_ZMK_COMBO_MAX_PRESSED_COMBOS; i++) { + if (active_combos[i].combo == NULL) { + active_combos[i].combo = combo; + active_combo_count++; + return &active_combos[i]; + } + } + LOG_ERR("Unable to store combo; already %d active. Increase " + "CONFIG_ZMK_COMBO_MAX_PRESSED_COMBOS", + CONFIG_ZMK_COMBO_MAX_PRESSED_COMBOS); + return NULL; +} + +static void activate_combo(struct combo_cfg *combo) { + struct active_combo *active_combo = store_active_combo(combo); + if (active_combo == NULL) { + // unable to store combo + release_pressed_keys(); + return; + } + move_pressed_keys_to_active_combo(active_combo); + press_combo_behavior( + combo, as_zmk_position_state_changed(active_combo->key_positions_pressed[0])->timestamp); +} + +static void deactivate_combo(int active_combo_index) { + active_combo_count--; + if (active_combo_index != active_combo_count) { + memcpy(&active_combos[active_combo_index], &active_combos[active_combo_count], + sizeof(struct active_combo)); + } + active_combos[active_combo_count].combo = NULL; + active_combos[active_combo_count] = (struct active_combo){0}; +} + +/* returns true if a key was released. */ +static bool release_combo_key(int32_t position, int64_t timestamp) { + for (int combo_idx = 0; combo_idx < active_combo_count; combo_idx++) { + struct active_combo *active_combo = &active_combos[combo_idx]; + + bool key_released = false; + bool all_keys_pressed = true; + bool all_keys_released = true; + for (int i = 0; i < active_combo->combo->key_position_len; i++) { + if (active_combo->key_positions_pressed[i] == NULL) { + all_keys_pressed = false; + } else if (as_zmk_position_state_changed(active_combo->key_positions_pressed[i]) + ->position != position) { + all_keys_released = false; + } else { // not null and position matches + ZMK_EVENT_FREE(active_combo->key_positions_pressed[i]); + active_combo->key_positions_pressed[i] = NULL; + key_released = true; + } + } + + if (key_released) { + if ((active_combo->combo->slow_release && all_keys_released) || + (!active_combo->combo->slow_release && all_keys_pressed)) { + release_combo_behavior(active_combo->combo, timestamp); + } + if (all_keys_released) { + deactivate_combo(combo_idx); + } + return true; + } + } + return false; +} + +static int cleanup() { + k_work_cancel_delayable(&timeout_task); + clear_candidates(); + if (fully_pressed_combo != NULL) { + activate_combo(fully_pressed_combo); + fully_pressed_combo = NULL; + } + return release_pressed_keys(); +} + +static void update_timeout_task() { + int64_t first_timeout = first_candidate_timeout(); + if (timeout_task_timeout_at == first_timeout) { + return; + } + if (first_timeout == LLONG_MAX) { + timeout_task_timeout_at = 0; + k_work_cancel_delayable(&timeout_task); + return; + } + if (k_work_schedule(&timeout_task, K_MSEC(first_timeout - k_uptime_get())) >= 0) { + timeout_task_timeout_at = first_timeout; + } +} + +static int position_state_down(const zmk_event_t *ev, struct zmk_position_state_changed *data) { + int num_candidates; + if (candidates[0].combo == NULL) { + num_candidates = setup_candidates_for_first_keypress(data->position, data->timestamp); + if (num_candidates == 0) { + return ZMK_EV_EVENT_BUBBLE; + } + } else { + filter_timed_out_candidates(data->timestamp); + num_candidates = filter_candidates(data->position); + } + update_timeout_task(); + + struct combo_cfg *candidate_combo = candidates[0].combo; + LOG_DBG("combo: capturing position event %d", data->position); + int ret = capture_pressed_key(ev); + switch (num_candidates) { + case 0: + cleanup(); + return ret; + case 1: + if (candidate_is_completely_pressed(candidate_combo)) { + fully_pressed_combo = candidate_combo; + cleanup(); + } + return ret; + default: + if (candidate_is_completely_pressed(candidate_combo)) { + fully_pressed_combo = candidate_combo; + } + return ret; + } +} + +static int position_state_up(const zmk_event_t *ev, struct zmk_position_state_changed *data) { + int released_keys = cleanup(); + if (release_combo_key(data->position, data->timestamp)) { + return ZMK_EV_EVENT_HANDLED; + } + if (released_keys > 1) { + // The second and further key down events are re-raised. To preserve + // correct order for e.g. hold-taps, reraise the key up event too. + ZMK_EVENT_RAISE(ev); + return ZMK_EV_EVENT_CAPTURED; + } + return ZMK_EV_EVENT_BUBBLE; +} + +static void combo_timeout_handler(struct k_work *item) { + if (timeout_task_timeout_at == 0 || k_uptime_get() < timeout_task_timeout_at) { + // timer was cancelled or rescheduled. + return; + } + if (filter_timed_out_candidates(timeout_task_timeout_at) == 0) { + cleanup(); + } + update_timeout_task(); +} + +static int position_state_changed_listener(const zmk_event_t *ev) { + struct zmk_position_state_changed *data = as_zmk_position_state_changed(ev); + if (data == NULL) { + return ZMK_EV_EVENT_BUBBLE; + } + + if (data->state) { // keydown + return position_state_down(ev, data); + } else { // keyup + return position_state_up(ev, data); + } +} + +static int keycode_state_changed_listener(const zmk_event_t *eh) { + struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh); + if (ev->state && !is_mod(ev->usage_page, ev->keycode)) { + store_last_tapped(ev->timestamp); + } + return ZMK_EV_EVENT_BUBBLE; +} + +int behavior_combo_listener(const zmk_event_t *eh) { + if (as_zmk_position_state_changed(eh) != NULL) { + return position_state_changed_listener(eh); + } else if (as_zmk_keycode_state_changed(eh) != NULL) { + return keycode_state_changed_listener(eh); + } + return ZMK_EV_EVENT_BUBBLE; +} + +ZMK_LISTENER(combo, behavior_combo_listener); +ZMK_SUBSCRIPTION(combo, zmk_position_state_changed); +ZMK_SUBSCRIPTION(combo, zmk_keycode_state_changed); + +#define COMBO_INST(n) \ + static struct combo_cfg combo_config_##n = { \ + .timeout_ms = DT_PROP(n, timeout_ms), \ + .require_prior_idle_ms = DT_PROP(n, require_prior_idle_ms), \ + .key_positions = DT_PROP(n, key_positions), \ + .key_position_len = DT_PROP_LEN(n, key_positions), \ + .behavior = ZMK_KEYMAP_EXTRACT_BINDING(0, n), \ + .virtual_key_position = ZMK_VIRTUAL_KEY_POSITION_COMBO(__COUNTER__), \ + .slow_release = DT_PROP(n, slow_release), \ + .layers = DT_PROP(n, layers), \ + .layers_len = DT_PROP_LEN(n, layers), \ + }; + +#define INITIALIZE_COMBO(n) initialize_combo(&combo_config_##n); + +DT_INST_FOREACH_CHILD(0, COMBO_INST) + +static int combo_init() { + k_work_init_delayable(&timeout_task, combo_timeout_handler); + DT_INST_FOREACH_CHILD(0, INITIALIZE_COMBO); + return 0; +} + +SYS_INIT(combo_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); + +#endif diff --git a/app/src/conditional_layer.c b/app/src/conditional_layer.c new file mode 100644 index 000000000000..9ba02a5ce4c8 --- /dev/null +++ b/app/src/conditional_layer.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_conditional_layers + +#include +#include + +#include +#include + +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +static K_SEM_DEFINE(conditional_layer_sem, 1, 1); + +// Conditional layer configuration that activates the specified then-layer when all if-layers are +// active. With two if-layers, this is referred to as "tri-layer", and is commonly used to activate +// a third "adjust" layer if and only if the "lower" and "raise" layers are both active. +struct conditional_layer_cfg { + // A bitmask of each layer that must be pressed for this conditional layer config to activate. + zmk_keymap_layers_state_t if_layers_state_mask; + + // The layer number that should be active while all layers in the if-layers mask are active. + int8_t then_layer; +}; + +#define IF_LAYER_BIT(node_id, prop, idx) BIT(DT_PROP_BY_IDX(node_id, prop, idx)) | + +// Evaluates to conditional_layer_cfg struct initializer. +#define CONDITIONAL_LAYER_DECL(n) \ + { \ + .if_layers_state_mask = DT_FOREACH_PROP_ELEM(n, if_layers, IF_LAYER_BIT) 0, \ + .then_layer = DT_PROP(n, then_layer), \ + }, + +// All conditional layer configurations in the keymap. +static const struct conditional_layer_cfg CONDITIONAL_LAYER_CFGS[] = { + DT_INST_FOREACH_CHILD(0, CONDITIONAL_LAYER_DECL)}; + +static const int32_t NUM_CONDITIONAL_LAYER_CFGS = + sizeof(CONDITIONAL_LAYER_CFGS) / sizeof(*CONDITIONAL_LAYER_CFGS); + +static void conditional_layer_activate(int8_t layer) { + // This may trigger another event that could, in turn, activate additional then-layers. However, + // the process will eventually terminate (at worst, when every layer is active). + if (!zmk_keymap_layer_active(layer)) { + LOG_DBG("layer %d", layer); + zmk_keymap_layer_activate(layer); + } +} + +static void conditional_layer_deactivate(int8_t layer) { + // This may deactivate a then-layer that's already active via another mechanism (e.g., a + // momentary layer behavior). However, the same problem arises when multiple keys with the same + // &mo binding are held and then one is released, so it's probably not an issue in practice. + if (zmk_keymap_layer_active(layer)) { + LOG_DBG("layer %d", layer); + zmk_keymap_layer_deactivate(layer); + } +} + +static int layer_state_changed_listener(const zmk_event_t *ev) { + static bool conditional_layer_updates_needed; + + conditional_layer_updates_needed = true; + + // Semaphore ensures we don't re-enter the loop in the middle of doing update, and + // ensures that "waterfalling layer updates" are all processed to trigger subsequent + // nested conditional layers properly. + if (k_sem_take(&conditional_layer_sem, K_NO_WAIT) < 0) { + return 0; + } + + while (conditional_layer_updates_needed) { + int8_t max_then_layer = -1; + uint32_t then_layers = 0; + uint32_t then_layer_state = 0; + + conditional_layer_updates_needed = false; + + // On layer state changes, examines each conditional layer config to determine if then-layer + // in the config should activate based on the currently active set of if-layers. + for (int i = 0; i < NUM_CONDITIONAL_LAYER_CFGS; i++) { + const struct conditional_layer_cfg *cfg = CONDITIONAL_LAYER_CFGS + i; + zmk_keymap_layers_state_t mask = cfg->if_layers_state_mask; + then_layers |= BIT(cfg->then_layer); + max_then_layer = MAX(max_then_layer, cfg->then_layer); + + // Activate then-layer if and only if all if-layers are already active. Note that we + // reevaluate the current layer state for each config since activation of one layer can + // also trigger activation of another. + if ((zmk_keymap_layer_state() & mask) == mask) { + then_layer_state |= BIT(cfg->then_layer); + } + } + + for (uint8_t layer = 0; layer <= max_then_layer; layer++) { + if ((BIT(layer) & then_layers) != 0U) { + if ((BIT(layer) & then_layer_state) != 0U) { + conditional_layer_activate(layer); + } else { + conditional_layer_deactivate(layer); + } + } + } + } + + k_sem_give(&conditional_layer_sem); + return 0; +} + +ZMK_LISTENER(conditional_layer, layer_state_changed_listener); +ZMK_SUBSCRIPTION(conditional_layer, zmk_layer_state_changed); + +#endif diff --git a/app/src/display/CMakeLists.txt b/app/src/display/CMakeLists.txt new file mode 100644 index 000000000000..d289f07419b4 --- /dev/null +++ b/app/src/display/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +target_sources_ifdef(CONFIG_ZMK_DISPLAY app PRIVATE main.c) +target_sources_ifdef(CONFIG_ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN app PRIVATE status_screen.c) + +add_subdirectory_ifdef(CONFIG_ZMK_DISPLAY widgets/) diff --git a/app/src/display/Kconfig b/app/src/display/Kconfig new file mode 100644 index 000000000000..a20294810805 --- /dev/null +++ b/app/src/display/Kconfig @@ -0,0 +1,181 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +menuconfig ZMK_DISPLAY + bool "Enable ZMK Display" + default n + select DISPLAY + select LVGL + select LV_CONF_MINIMAL + +if ZMK_DISPLAY + +config ZMK_DISPLAY_BLANK_ON_IDLE + bool "Blank display on idle" + default y if SSD1306 + +if LV_USE_THEME_MONO + +config ZMK_DISPLAY_INVERT + bool "Invert display colors" + +endif + +choice LV_TXT_ENC + default LV_TXT_ENC_UTF8 + +endchoice + +config LV_MEM_CUSTOM + default y + +config LV_Z_MEM_POOL_MIN_SIZE + default 32 + +config LV_Z_MEM_POOL_MAX_SIZE + default 8192 + +choice ZMK_DISPLAY_STATUS_SCREEN + prompt "Default status screen for displays" + +config ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN + bool "Built in status screen" + select LV_OBJ_LABEL + imply LV_USE_THEME_MONO + imply ZMK_WIDGET_LAYER_STATUS + imply ZMK_WIDGET_BATTERY_STATUS + imply ZMK_WIDGET_OUTPUT_STATUS + imply ZMK_WIDGET_PERIPHERAL_STATUS + +config ZMK_DISPLAY_STATUS_SCREEN_CUSTOM + bool "Custom status screen" + +endchoice + +choice ZMK_DISPLAY_WORK_QUEUE + prompt "Work queue selection for UI updates" + +config ZMK_DISPLAY_WORK_QUEUE_SYSTEM + bool "Use default system work queue for UI updates" + +config ZMK_DISPLAY_WORK_QUEUE_DEDICATED + bool "Use dedicated work queue for UI updates" + +endchoice + +if ZMK_DISPLAY_WORK_QUEUE_DEDICATED + +config ZMK_DISPLAY_DEDICATED_THREAD_STACK_SIZE + int "Stack size for dedicated UI thread/queue" + default 2048 + +config ZMK_DISPLAY_DEDICATED_THREAD_PRIORITY + int "Thread priority for dedicated UI thread/queue" + default 5 + +endif # ZMK_DISPLAY_WORK_QUEUE_DEDICATED + +if ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN + +config LV_FONT_MONTSERRAT_16 + default y + +choice LV_FONT_DEFAULT + default LV_FONT_DEFAULT_MONTSERRAT_16 + +endchoice + +config LV_FONT_MONTSERRAT_12 + default y + +endif # ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN + +choice ZMK_LV_FONT_DEFAULT_SMALL + prompt "Select theme default small font" + default ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_12 + help + Select theme default small font + + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_8 + bool "Montserrat 8" + select LV_FONT_MONTSERRAT_8 + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_12 + bool "Montserrat 12" + select LV_FONT_MONTSERRAT_12 + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_14 + bool "Montserrat 14" + select LV_FONT_MONTSERRAT_14 + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_16 + bool "Montserrat 16" + select LV_FONT_MONTSERRAT_16 + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_18 + bool "Montserrat 18" + select LV_FONT_MONTSERRAT_18 + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_20 + bool "Montserrat 20" + select LV_FONT_MONTSERRAT_20 + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_22 + bool "Montserrat 22" + select LV_FONT_MONTSERRAT_22 + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_24 + bool "Montserrat 24" + select LV_FONT_MONTSERRAT_24 + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_26 + bool "Montserrat 26" + select LV_FONT_MONTSERRAT_26 + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_28 + bool "Montserrat 28" + select LV_FONT_MONTSERRAT_28 + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_30 + bool "Montserrat 30" + select LV_FONT_MONTSERRAT_30 + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_32 + bool "Montserrat 32" + select LV_FONT_MONTSERRAT_32 + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_34 + bool "Montserrat 34" + select LV_FONT_MONTSERRAT_34 + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_36 + bool "Montserrat 36" + select LV_FONT_MONTSERRAT_36 + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_38 + bool "Montserrat 38" + select LV_FONT_MONTSERRAT_38 + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_40 + bool "Montserrat 40" + select LV_FONT_MONTSERRAT_40 + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_42 + bool "Montserrat 42" + select LV_FONT_MONTSERRAT_42 + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_44 + bool "Montserrat 44" + select LV_FONT_MONTSERRAT_44 + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_46 + bool "Montserrat 46" + select LV_FONT_MONTSERRAT_46 + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_48 + bool "Montserrat 48" + select LV_FONT_MONTSERRAT_48 + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_12_SUBPX + bool "Montserrat 12 sub-pixel" + select LV_FONT_MONTSERRAT_12_SUBPX + config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_28_COMPRESSED + bool "Montserrat 28 compressed" + select LV_FONT_MONTSERRAT_28_COMPRESSED + config ZMK_LV_FONT_DEFAULT_SMALL_DEJAVU_16_PERSIAN_HEBREW + bool "Dejavu 16 Persian, Hebrew, Arabic letters" + select LV_FONT_DEJAVU_16_PERSIAN_HEBREW + config ZMK_LV_FONT_DEFAULT_SMALL_SIMSUN_16_CJK + bool "Simsun 16 CJK" + select LV_FONT_SIMSUN_16_CJK + config ZMK_LV_FONT_DEFAULT_SMALL_UNSCII_8 + bool "UNSCII 8 (Perfect monospace font)" + select LV_FONT_UNSCII_8 + config ZMK_LV_FONT_DEFAULT_SMALL_UNSCII_16 + bool "UNSCII 16 (Perfect monospace font)" + select LV_FONT_UNSCII_16 +endchoice + +rsource "widgets/Kconfig" + +endif diff --git a/app/src/display/main.c b/app/src/display/main.c new file mode 100644 index 000000000000..e15e2de0c9a9 --- /dev/null +++ b/app/src/display/main.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include + +#include "theme.h" + +#include +#include +#include + +static const struct device *display = DEVICE_DT_GET(DT_CHOSEN(zephyr_display)); +static bool initialized = false; + +static lv_obj_t *screen; + +__attribute__((weak)) lv_obj_t *zmk_display_status_screen() { return NULL; } + +void display_tick_cb(struct k_work *work) { lv_task_handler(); } + +#define TICK_MS 10 + +K_WORK_DEFINE(display_tick_work, display_tick_cb); + +#if IS_ENABLED(CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED) + +K_THREAD_STACK_DEFINE(display_work_stack_area, CONFIG_ZMK_DISPLAY_DEDICATED_THREAD_STACK_SIZE); + +static struct k_work_q display_work_q; + +#endif + +struct k_work_q *zmk_display_work_q() { +#if IS_ENABLED(CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED) + return &display_work_q; +#else + return &k_sys_work_q; +#endif +} + +void display_timer_cb() { k_work_submit_to_queue(zmk_display_work_q(), &display_tick_work); } + +K_TIMER_DEFINE(display_timer, display_timer_cb, NULL); + +void unblank_display_cb(struct k_work *work) { + display_blanking_off(display); + k_timer_start(&display_timer, K_MSEC(TICK_MS), K_MSEC(TICK_MS)); +} + +#if IS_ENABLED(CONFIG_ZMK_DISPLAY_BLANK_ON_IDLE) + +void blank_display_cb(struct k_work *work) { + k_timer_stop(&display_timer); + display_blanking_on(display); +} +K_WORK_DEFINE(blank_display_work, blank_display_cb); +K_WORK_DEFINE(unblank_display_work, unblank_display_cb); + +static void start_display_updates() { + if (display == NULL) { + return; + } + + k_work_submit_to_queue(zmk_display_work_q(), &unblank_display_work); +} + +static void stop_display_updates() { + if (display == NULL) { + return; + } + + k_work_submit_to_queue(zmk_display_work_q(), &blank_display_work); +} + +#endif + +int zmk_display_is_initialized() { return initialized; } + +static void initialize_theme() { +#if IS_ENABLED(CONFIG_LV_USE_THEME_MONO) + lv_disp_t *disp = lv_disp_get_default(); + lv_theme_t *theme = + lv_theme_mono_init(disp, IS_ENABLED(CONFIG_ZMK_DISPLAY_INVERT), CONFIG_LV_FONT_DEFAULT); + theme->font_small = CONFIG_ZMK_LV_FONT_DEFAULT_SMALL; + + disp->theme = theme; +#endif // CONFIG_LV_USE_THEME_MONO +} + +void initialize_display(struct k_work *work) { + LOG_DBG(""); + + if (!device_is_ready(display)) { + LOG_ERR("Failed to find display device"); + return; + } + + initialized = true; + + initialize_theme(); + + screen = zmk_display_status_screen(); + + if (screen == NULL) { + LOG_ERR("No status screen provided"); + return; + } + + lv_scr_load(screen); + + unblank_display_cb(work); +} + +K_WORK_DEFINE(init_work, initialize_display); + +int zmk_display_init() { +#if IS_ENABLED(CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED) + k_work_queue_start(&display_work_q, display_work_stack_area, + K_THREAD_STACK_SIZEOF(display_work_stack_area), + CONFIG_ZMK_DISPLAY_DEDICATED_THREAD_PRIORITY, NULL); +#endif + + k_work_submit_to_queue(zmk_display_work_q(), &init_work); + + LOG_DBG(""); + return 0; +} + +#if IS_ENABLED(CONFIG_ZMK_DISPLAY_BLANK_ON_IDLE) +int display_event_handler(const zmk_event_t *eh) { + struct zmk_activity_state_changed *ev = as_zmk_activity_state_changed(eh); + if (ev == NULL) { + return -ENOTSUP; + } + + switch (ev->state) { + case ZMK_ACTIVITY_ACTIVE: + start_display_updates(); + break; + case ZMK_ACTIVITY_IDLE: + case ZMK_ACTIVITY_SLEEP: + stop_display_updates(); + break; + default: + LOG_WRN("Unhandled activity state: %d", ev->state); + return -EINVAL; + } + return 0; +} + +ZMK_LISTENER(display, display_event_handler); +ZMK_SUBSCRIPTION(display, zmk_activity_state_changed); + +#endif /* IS_ENABLED(CONFIG_ZMK_DISPLAY_BLANK_ON_IDLE) */ diff --git a/app/src/display/status_screen.c b/app/src/display/status_screen.c new file mode 100644 index 000000000000..58de09ae4031 --- /dev/null +++ b/app/src/display/status_screen.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if IS_ENABLED(CONFIG_ZMK_WIDGET_BATTERY_STATUS) +static struct zmk_widget_battery_status battery_status_widget; +#endif + +#if IS_ENABLED(CONFIG_ZMK_WIDGET_OUTPUT_STATUS) +static struct zmk_widget_output_status output_status_widget; +#endif + +#if IS_ENABLED(CONFIG_ZMK_WIDGET_PERIPHERAL_STATUS) +static struct zmk_widget_peripheral_status peripheral_status_widget; +#endif + +#if IS_ENABLED(CONFIG_ZMK_WIDGET_LAYER_STATUS) +static struct zmk_widget_layer_status layer_status_widget; +#endif + +#if IS_ENABLED(CONFIG_ZMK_WIDGET_WPM_STATUS) +static struct zmk_widget_wpm_status wpm_status_widget; +#endif + +lv_obj_t *zmk_display_status_screen() { + lv_obj_t *screen; + screen = lv_obj_create(NULL); + +#if IS_ENABLED(CONFIG_ZMK_WIDGET_BATTERY_STATUS) + zmk_widget_battery_status_init(&battery_status_widget, screen); + lv_obj_align(zmk_widget_battery_status_obj(&battery_status_widget), LV_ALIGN_TOP_RIGHT, 0, 0); +#endif + +#if IS_ENABLED(CONFIG_ZMK_WIDGET_OUTPUT_STATUS) + zmk_widget_output_status_init(&output_status_widget, screen); + lv_obj_align(zmk_widget_output_status_obj(&output_status_widget), LV_ALIGN_TOP_LEFT, 0, 0); +#endif + +#if IS_ENABLED(CONFIG_ZMK_WIDGET_PERIPHERAL_STATUS) + zmk_widget_peripheral_status_init(&peripheral_status_widget, screen); + lv_obj_align(zmk_widget_peripheral_status_obj(&peripheral_status_widget), LV_ALIGN_TOP_LEFT, 0, + 0); +#endif + +#if IS_ENABLED(CONFIG_ZMK_WIDGET_LAYER_STATUS) + zmk_widget_layer_status_init(&layer_status_widget, screen); + lv_obj_set_style_text_font(zmk_widget_layer_status_obj(&layer_status_widget), + lv_theme_get_font_small(screen), LV_PART_MAIN); + lv_obj_align(zmk_widget_layer_status_obj(&layer_status_widget), LV_ALIGN_BOTTOM_LEFT, 0, 0); +#endif + +#if IS_ENABLED(CONFIG_ZMK_WIDGET_WPM_STATUS) + zmk_widget_wpm_status_init(&wpm_status_widget, screen); + lv_obj_align(zmk_widget_wpm_status_obj(&wpm_status_widget), LV_ALIGN_BOTTOM_RIGHT, 0, 0); +#endif + return screen; +} diff --git a/app/src/display/theme.c b/app/src/display/theme.c new file mode 100644 index 000000000000..3ad41dac3e9b --- /dev/null +++ b/app/src/display/theme.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +#if defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_8) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_8 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_10) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_10 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_12) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_12 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_14) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_14 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_16) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_16 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_18) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_18 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_20) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_20 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_22) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_22 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_24) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_24 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_26) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_26 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_28) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_28 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_30) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_30 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_32) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_32 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_34) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_34 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_36) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_36 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_38) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_38 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_40) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_40 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_42) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_42 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_44) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_44 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_46) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_46 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_48) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_48 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_12_SUBPX) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_12_subpx +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_28_COMPRESSED) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_28_compressed +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_DEJAVU_16_PERSIAN_HEBREW) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_dejavu_16_persian_hebrew +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_SIMSUN_16_CJK) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_simsun_16_cjk +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_UNSCII_8) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_unscii_8 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_UNSCII_16) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_unscii_16 +#endif + +void zmk_display_theme_init(lv_obj_t *obj) { + lv_theme_t *theme = lv_theme_get_from_obj(obj); + + if (theme == NULL) { + return; + } + + theme->font_small = CONFIG_ZMK_LV_FONT_DEFAULT_SMALL; +} \ No newline at end of file diff --git a/app/src/display/theme.h b/app/src/display/theme.h new file mode 100644 index 000000000000..94bf7f397935 --- /dev/null +++ b/app/src/display/theme.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +#if defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_8) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_8 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_10) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_10 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_12) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_12 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_14) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_14 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_16) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_16 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_18) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_18 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_20) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_20 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_22) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_22 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_24) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_24 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_26) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_26 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_28) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_28 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_30) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_30 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_32) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_32 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_34) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_34 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_36) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_36 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_38) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_38 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_40) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_40 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_42) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_42 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_44) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_44 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_46) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_46 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_48) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_48 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_12_SUBPX) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_12_subpx +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_28_COMPRESSED) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_28_compressed +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_DEJAVU_16_PERSIAN_HEBREW) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_dejavu_16_persian_hebrew +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_SIMSUN_16_CJK) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_simsun_16_cjk +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_UNSCII_8) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_unscii_8 +#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_UNSCII_16) +#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_unscii_16 +#endif diff --git a/app/src/display/widgets/CMakeLists.txt b/app/src/display/widgets/CMakeLists.txt new file mode 100644 index 000000000000..fbf07072768d --- /dev/null +++ b/app/src/display/widgets/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +target_sources_ifdef(CONFIG_ZMK_WIDGET_BATTERY_STATUS app PRIVATE battery_status.c) +target_sources_ifdef(CONFIG_ZMK_WIDGET_OUTPUT_STATUS app PRIVATE output_status.c) +target_sources_ifdef(CONFIG_ZMK_WIDGET_PERIPHERAL_STATUS app PRIVATE peripheral_status.c) +target_sources_ifdef(CONFIG_ZMK_WIDGET_LAYER_STATUS app PRIVATE layer_status.c) +target_sources_ifdef(CONFIG_ZMK_WIDGET_WPM_STATUS app PRIVATE wpm_status.c) diff --git a/app/src/display/widgets/Kconfig b/app/src/display/widgets/Kconfig new file mode 100644 index 000000000000..7ec20c1fe4de --- /dev/null +++ b/app/src/display/widgets/Kconfig @@ -0,0 +1,39 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +menu "ZMK Display Widgets" + +config ZMK_WIDGET_LAYER_STATUS + bool "Widget for highest, active layer using small icons" + depends on !ZMK_SPLIT || ZMK_SPLIT_ROLE_CENTRAL + select LV_USE_LABEL + +config ZMK_WIDGET_BATTERY_STATUS + bool "Widget for battery charge information, using small icons" + depends on BT + select LV_USE_LABEL + +if ZMK_WIDGET_BATTERY_STATUS + +config ZMK_WIDGET_BATTERY_STATUS_SHOW_PERCENTAGE + bool "Show battery level percentage in text" + +endif + +config ZMK_WIDGET_OUTPUT_STATUS + bool "Widget for keyboard output status icons" + depends on BT && (!ZMK_SPLIT_BLE || ZMK_SPLIT_ROLE_CENTRAL) + select LV_USE_LABEL + +config ZMK_WIDGET_PERIPHERAL_STATUS + bool "Widget for split peripheral status icons" + depends on BT && ZMK_SPLIT_BLE && !ZMK_SPLIT_ROLE_CENTRAL + select LV_USE_LABEL + +config ZMK_WIDGET_WPM_STATUS + bool "Widget for displaying typed words per minute" + depends on !ZMK_SPLIT || ZMK_SPLIT_ROLE_CENTRAL + select LV_USE_LABEL + select ZMK_WPM + +endmenu diff --git a/app/src/display/widgets/battery_status.c b/app/src/display/widgets/battery_status.c new file mode 100644 index 000000000000..e35f890ac6cf --- /dev/null +++ b/app/src/display/widgets/battery_status.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include +#include +#include + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); + +struct battery_status_state { + uint8_t level; +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + bool usb_present; +#endif +}; + +static void set_battery_symbol(lv_obj_t *label, struct battery_status_state state) { + char text[9] = {}; + + uint8_t level = state.level; + +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + if (state.usb_present) { + strcpy(text, LV_SYMBOL_CHARGE " "); + } +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + +#if IS_ENABLED(CONFIG_ZMK_WIDGET_BATTERY_STATUS_SHOW_PERCENTAGE) + char perc[5] = {}; + snprintf(perc, sizeof(perc), "%3u%%", level); + strcat(text, perc); +#else + if (level > 95) { + strcat(text, LV_SYMBOL_BATTERY_FULL); + } else if (level > 65) { + strcat(text, LV_SYMBOL_BATTERY_3); + } else if (level > 35) { + strcat(text, LV_SYMBOL_BATTERY_2); + } else if (level > 5) { + strcat(text, LV_SYMBOL_BATTERY_1); + } else { + strcat(text, LV_SYMBOL_BATTERY_EMPTY); + } +#endif + lv_label_set_text(label, text); +} + +void battery_status_update_cb(struct battery_status_state state) { + struct zmk_widget_battery_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_battery_symbol(widget->obj, state); } +} + +static struct battery_status_state battery_status_get_state(const zmk_event_t *eh) { + return (struct battery_status_state) { + .level = bt_bas_get_battery_level(), +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + .usb_present = zmk_usb_is_powered(), +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + }; +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_battery_status, struct battery_status_state, + battery_status_update_cb, battery_status_get_state) + +ZMK_SUBSCRIPTION(widget_battery_status, zmk_battery_state_changed); +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) +ZMK_SUBSCRIPTION(widget_battery_status, zmk_usb_conn_state_changed); +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + +int zmk_widget_battery_status_init(struct zmk_widget_battery_status *widget, lv_obj_t *parent) { + widget->obj = lv_label_create(parent); + + sys_slist_append(&widgets, &widget->node); + + widget_battery_status_init(); + return 0; +} + +lv_obj_t *zmk_widget_battery_status_obj(struct zmk_widget_battery_status *widget) { + return widget->obj; +} diff --git a/app/src/display/widgets/layer_status.c b/app/src/display/widgets/layer_status.c new file mode 100644 index 000000000000..73c2268e4cc3 --- /dev/null +++ b/app/src/display/widgets/layer_status.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include +#include +#include + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); + +struct layer_status_state { + uint8_t index; + const char *label; +}; + +static void set_layer_symbol(lv_obj_t *label, struct layer_status_state state) { + if (state.label == NULL) { + char text[7] = {}; + + sprintf(text, LV_SYMBOL_KEYBOARD " %i", state.index); + + lv_label_set_text(label, text); + } else { + char text[13] = {}; + + snprintf(text, sizeof(text), LV_SYMBOL_KEYBOARD " %s", state.label); + + lv_label_set_text(label, text); + } +} + +static void layer_status_update_cb(struct layer_status_state state) { + struct zmk_widget_layer_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_layer_symbol(widget->obj, state); } +} + +static struct layer_status_state layer_status_get_state(const zmk_event_t *eh) { + uint8_t index = zmk_keymap_highest_layer_active(); + return (struct layer_status_state){.index = index, .label = zmk_keymap_layer_name(index)}; +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_layer_status, struct layer_status_state, layer_status_update_cb, + layer_status_get_state) + +ZMK_SUBSCRIPTION(widget_layer_status, zmk_layer_state_changed); + +int zmk_widget_layer_status_init(struct zmk_widget_layer_status *widget, lv_obj_t *parent) { + widget->obj = lv_label_create(parent); + + sys_slist_append(&widgets, &widget->node); + + widget_layer_status_init(); + return 0; +} + +lv_obj_t *zmk_widget_layer_status_obj(struct zmk_widget_layer_status *widget) { + return widget->obj; +} \ No newline at end of file diff --git a/app/src/display/widgets/output_status.c b/app/src/display/widgets/output_status.c new file mode 100644 index 000000000000..da29a95f393a --- /dev/null +++ b/app/src/display/widgets/output_status.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include +#include +#include +#include +#include + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); + +struct output_status_state { + struct zmk_endpoint_instance selected_endpoint; + bool active_profile_connected; + bool active_profile_bonded; +}; + +static struct output_status_state get_state(const zmk_event_t *_eh) { + return (struct output_status_state){.selected_endpoint = zmk_endpoints_selected(), + .active_profile_connected = + zmk_ble_active_profile_is_connected(), + .active_profile_bonded = !zmk_ble_active_profile_is_open()}; + ; +} + +static void set_status_symbol(lv_obj_t *label, struct output_status_state state) { + char text[10] = {}; + + switch (state.selected_endpoint.transport) { + case ZMK_TRANSPORT_USB: + strcat(text, LV_SYMBOL_USB); + break; + case ZMK_TRANSPORT_BLE: + if (state.active_profile_bonded) { + if (state.active_profile_connected) { + snprintf(text, sizeof(text), LV_SYMBOL_WIFI " %i " LV_SYMBOL_OK, + state.selected_endpoint.ble.profile_index + 1); + } else { + snprintf(text, sizeof(text), LV_SYMBOL_WIFI " %i " LV_SYMBOL_CLOSE, + state.selected_endpoint.ble.profile_index + 1); + } + } else { + snprintf(text, sizeof(text), LV_SYMBOL_WIFI " %i " LV_SYMBOL_SETTINGS, + state.selected_endpoint.ble.profile_index + 1); + } + break; + } + + lv_label_set_text(label, text); +} + +static void output_status_update_cb(struct output_status_state state) { + struct zmk_widget_output_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_status_symbol(widget->obj, state); } +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_output_status, struct output_status_state, + output_status_update_cb, get_state) +ZMK_SUBSCRIPTION(widget_output_status, zmk_endpoint_changed); +// We don't get an endpoint changed event when the active profile connects/disconnects +// but there wasn't another endpoint to switch from/to, so update on BLE events too. +#if defined(CONFIG_ZMK_BLE) +ZMK_SUBSCRIPTION(widget_output_status, zmk_ble_active_profile_changed); +#endif + +int zmk_widget_output_status_init(struct zmk_widget_output_status *widget, lv_obj_t *parent) { + widget->obj = lv_label_create(parent); + + sys_slist_append(&widgets, &widget->node); + + widget_output_status_init(); + return 0; +} + +lv_obj_t *zmk_widget_output_status_obj(struct zmk_widget_output_status *widget) { + return widget->obj; +} diff --git a/app/src/display/widgets/peripheral_status.c b/app/src/display/widgets/peripheral_status.c new file mode 100644 index 000000000000..fdfe4d9cb5a0 --- /dev/null +++ b/app/src/display/widgets/peripheral_status.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include +#include + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); + +struct peripheral_status_state { + bool connected; +}; + +static struct peripheral_status_state get_state(const zmk_event_t *_eh) { + return (struct peripheral_status_state){.connected = zmk_split_bt_peripheral_is_connected()}; +} + +static void set_status_symbol(lv_obj_t *label, struct peripheral_status_state state) { + const char *text = + state.connected ? (LV_SYMBOL_WIFI " " LV_SYMBOL_OK) : (LV_SYMBOL_WIFI " " LV_SYMBOL_CLOSE); + + LOG_DBG("connected? %s", state.connected ? "true" : "false"); + lv_label_set_text(label, text); +} + +static void output_status_update_cb(struct peripheral_status_state state) { + struct zmk_widget_peripheral_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_status_symbol(widget->obj, state); } +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_peripheral_status, struct peripheral_status_state, + output_status_update_cb, get_state) +ZMK_SUBSCRIPTION(widget_peripheral_status, zmk_split_peripheral_status_changed); + +int zmk_widget_peripheral_status_init(struct zmk_widget_peripheral_status *widget, + lv_obj_t *parent) { + widget->obj = lv_label_create(parent); + + sys_slist_append(&widgets, &widget->node); + + widget_peripheral_status_init(); + return 0; +} + +lv_obj_t *zmk_widget_peripheral_status_obj(struct zmk_widget_peripheral_status *widget) { + return widget->obj; +} diff --git a/app/src/display/widgets/wpm_status.c b/app/src/display/widgets/wpm_status.c new file mode 100644 index 000000000000..9ae8b540e9f6 --- /dev/null +++ b/app/src/display/widgets/wpm_status.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include +#include +#include + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); + +struct wpm_status_state { + uint8_t wpm; +}; + +struct wpm_status_state wpm_status_get_state(const zmk_event_t *eh) { + return (struct wpm_status_state){.wpm = zmk_wpm_get_state()}; +}; + +void set_wpm_symbol(lv_obj_t *label, struct wpm_status_state state) { + char text[4] = {}; + + LOG_DBG("WPM changed to %i", state.wpm); + snprintf(text, sizeof(text), "%i", state.wpm); + + lv_label_set_text(label, text); + lv_obj_align(label, LV_ALIGN_BOTTOM_RIGHT, 0, 0); +} + +void wpm_status_update_cb(struct wpm_status_state state) { + struct zmk_widget_wpm_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_wpm_symbol(widget->obj, state); } +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_wpm_status, struct wpm_status_state, wpm_status_update_cb, + wpm_status_get_state) +ZMK_SUBSCRIPTION(widget_wpm_status, zmk_wpm_state_changed); + +int zmk_widget_wpm_status_init(struct zmk_widget_wpm_status *widget, lv_obj_t *parent) { + widget->obj = lv_label_create(parent); + lv_obj_align(widget->obj, LV_ALIGN_RIGHT_MID, 0, 0); + + sys_slist_append(&widgets, &widget->node); + + widget_wpm_status_init(); + return 0; +} + +lv_obj_t *zmk_widget_wpm_status_obj(struct zmk_widget_wpm_status *widget) { return widget->obj; } diff --git a/app/src/endpoints.c b/app/src/endpoints.c new file mode 100644 index 000000000000..098e04e27769 --- /dev/null +++ b/app/src/endpoints.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#define DEFAULT_TRANSPORT \ + COND_CODE_1(IS_ENABLED(CONFIG_ZMK_BLE), (ZMK_TRANSPORT_BLE), (ZMK_TRANSPORT_USB)) + +static struct zmk_endpoint_instance current_instance = {}; +static enum zmk_transport preferred_transport = + ZMK_TRANSPORT_USB; /* Used if multiple endpoints are ready */ + +static void update_current_endpoint(void); + +#if IS_ENABLED(CONFIG_SETTINGS) +static void endpoints_save_preferred_work(struct k_work *work) { + settings_save_one("endpoints/preferred", &preferred_transport, sizeof(preferred_transport)); +} + +static struct k_work_delayable endpoints_save_work; +#endif + +static int endpoints_save_preferred(void) { +#if IS_ENABLED(CONFIG_SETTINGS) + return k_work_reschedule(&endpoints_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE)); +#else + return 0; +#endif +} + +bool zmk_endpoint_instance_eq(struct zmk_endpoint_instance a, struct zmk_endpoint_instance b) { + if (a.transport != b.transport) { + return false; + } + + switch (a.transport) { + case ZMK_TRANSPORT_USB: + return true; + + case ZMK_TRANSPORT_BLE: + return a.ble.profile_index == b.ble.profile_index; + } + + LOG_ERR("Invalid transport %d", a.transport); + return false; +} + +int zmk_endpoint_instance_to_str(struct zmk_endpoint_instance endpoint, char *str, size_t len) { + switch (endpoint.transport) { + case ZMK_TRANSPORT_USB: + return snprintf(str, len, "USB"); + + case ZMK_TRANSPORT_BLE: + return snprintf(str, len, "BLE:%d", endpoint.ble.profile_index); + + default: + return snprintf(str, len, "Invalid"); + } +} + +#define INSTANCE_INDEX_OFFSET_USB 0 +#define INSTANCE_INDEX_OFFSET_BLE ZMK_ENDPOINT_USB_COUNT + +int zmk_endpoint_instance_to_index(struct zmk_endpoint_instance endpoint) { + switch (endpoint.transport) { + case ZMK_TRANSPORT_USB: + return INSTANCE_INDEX_OFFSET_USB; + + case ZMK_TRANSPORT_BLE: + return INSTANCE_INDEX_OFFSET_BLE + endpoint.ble.profile_index; + } + + LOG_ERR("Invalid transport %d", endpoint.transport); + return 0; +} + +int zmk_endpoints_select_transport(enum zmk_transport transport) { + LOG_DBG("Selected endpoint transport %d", transport); + + if (preferred_transport == transport) { + return 0; + } + + preferred_transport = transport; + + endpoints_save_preferred(); + + update_current_endpoint(); + + return 0; +} + +int zmk_endpoints_toggle_transport(void) { + enum zmk_transport new_transport = + (preferred_transport == ZMK_TRANSPORT_USB) ? ZMK_TRANSPORT_BLE : ZMK_TRANSPORT_USB; + return zmk_endpoints_select_transport(new_transport); +} + +struct zmk_endpoint_instance zmk_endpoints_selected(void) { + return current_instance; +} + +static int send_keyboard_report(void) { + switch (current_instance.transport) { +#if IS_ENABLED(CONFIG_ZMK_USB) + case ZMK_TRANSPORT_USB: { + int err = zmk_usb_hid_send_keyboard_report(); + if (err) { + LOG_ERR("FAILED TO SEND OVER USB: %d", err); + } + return err; + } +#endif /* IS_ENABLED(CONFIG_ZMK_USB) */ + +#if IS_ENABLED(CONFIG_ZMK_BLE) + case ZMK_TRANSPORT_BLE: { + struct zmk_hid_keyboard_report *keyboard_report = zmk_hid_get_keyboard_report(); + int err = zmk_hog_send_keyboard_report(&keyboard_report->body); + if (err) { + LOG_ERR("FAILED TO SEND OVER HOG: %d", err); + } + return err; + } +#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */ + } + + LOG_ERR("Unsupported endpoint transport %d", current_instance.transport); + return -ENOTSUP; +} + +static int send_consumer_report(void) { + switch (current_instance.transport) { +#if IS_ENABLED(CONFIG_ZMK_USB) + case ZMK_TRANSPORT_USB: { + int err = zmk_usb_hid_send_consumer_report(); + if (err) { + LOG_ERR("FAILED TO SEND OVER USB: %d", err); + } + return err; + } +#endif /* IS_ENABLED(CONFIG_ZMK_USB) */ + +#if IS_ENABLED(CONFIG_ZMK_BLE) + case ZMK_TRANSPORT_BLE: { + struct zmk_hid_consumer_report *consumer_report = zmk_hid_get_consumer_report(); + int err = zmk_hog_send_consumer_report(&consumer_report->body); + if (err) { + LOG_ERR("FAILED TO SEND OVER HOG: %d", err); + } + return err; + } +#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */ + } + + LOG_ERR("Unsupported endpoint transport %d", current_instance.transport); + return -ENOTSUP; +} + +int zmk_endpoints_send_report(uint16_t usage_page) { + + LOG_DBG("usage page 0x%02X", usage_page); + switch (usage_page) { + case HID_USAGE_KEY: + return send_keyboard_report(); + + case HID_USAGE_CONSUMER: + return send_consumer_report(); + } + + LOG_ERR("Unsupported usage page %d", usage_page); + return -ENOTSUP; +} + +#if IS_ENABLED(CONFIG_ZMK_MOUSE) +int zmk_endpoints_send_mouse_report() { + switch (current_instance.transport) { +#if IS_ENABLED(CONFIG_ZMK_USB) + case ZMK_TRANSPORT_USB: { + int err = zmk_usb_hid_send_mouse_report(); + if (err) { + LOG_ERR("FAILED TO SEND OVER USB: %d", err); + } + return err; + } +#endif /* IS_ENABLED(CONFIG_ZMK_USB) */ + +#if IS_ENABLED(CONFIG_ZMK_BLE) + case ZMK_TRANSPORT_BLE: { + struct zmk_hid_mouse_report *mouse_report = zmk_hid_get_mouse_report(); + int err = zmk_hog_send_mouse_report(&mouse_report->body); + if (err) { + LOG_ERR("FAILED TO SEND OVER HOG: %d", err); + } + return err; + } +#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */ + } + + LOG_ERR("Unsupported endpoint transport %d", current_instance.transport); + return -ENOTSUP; +} +#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) + +#if IS_ENABLED(CONFIG_SETTINGS) + +static int endpoints_handle_set(const char *name, size_t len, settings_read_cb read_cb, + void *cb_arg) { + LOG_DBG("Setting endpoint value %s", name); + + if (settings_name_steq(name, "preferred", NULL)) { + if (len != sizeof(enum zmk_transport)) { + LOG_ERR("Invalid endpoint size (got %d expected %d)", len, sizeof(enum zmk_transport)); + return -EINVAL; + } + + int err = read_cb(cb_arg, &preferred_transport, sizeof(enum zmk_transport)); + if (err <= 0) { + LOG_ERR("Failed to read preferred endpoint from settings (err %d)", err); + return err; + } + + update_current_endpoint(); + } + + return 0; +} + +struct settings_handler endpoints_handler = {.name = "endpoints", .h_set = endpoints_handle_set}; +#endif /* IS_ENABLED(CONFIG_SETTINGS) */ + +static bool is_usb_ready(void) { +#if IS_ENABLED(CONFIG_ZMK_USB) + return zmk_usb_is_hid_ready(); +#else + return false; +#endif +} + +static bool is_ble_ready(void) { +#if IS_ENABLED(CONFIG_ZMK_BLE) + return zmk_ble_active_profile_is_connected(); +#else + return false; +#endif +} + +static enum zmk_transport get_selected_transport(void) { + if (is_ble_ready()) { + if (is_usb_ready()) { + LOG_DBG("Both endpoint transports are ready. Using %d", preferred_transport); + return preferred_transport; + } + + LOG_DBG("Only BLE is ready."); + return ZMK_TRANSPORT_BLE; + } + + if (is_usb_ready()) { + LOG_DBG("Only USB is ready."); + return ZMK_TRANSPORT_USB; + } + + LOG_DBG("No endpoint transports are ready."); + return DEFAULT_TRANSPORT; +} + +static struct zmk_endpoint_instance get_selected_instance(void) { + struct zmk_endpoint_instance instance = {.transport = get_selected_transport()}; + + switch (instance.transport) { +#if IS_ENABLED(CONFIG_ZMK_BLE) + case ZMK_TRANSPORT_BLE: + instance.ble.profile_index = zmk_ble_active_profile_index(); + break; +#endif // IS_ENABLED(CONFIG_ZMK_BLE) + + default: + // No extra data for this transport. + break; + } + + return instance; +} + +static int zmk_endpoints_init(const struct device *_arg) { +#if IS_ENABLED(CONFIG_SETTINGS) + settings_subsys_init(); + + int err = settings_register(&endpoints_handler); + if (err) { + LOG_ERR("Failed to register the endpoints settings handler (err %d)", err); + return err; + } + + k_work_init_delayable(&endpoints_save_work, endpoints_save_preferred_work); + + settings_load_subtree("endpoints"); +#endif + + current_instance = get_selected_instance(); + + return 0; +} + +static void disconnect_current_endpoint() { + zmk_hid_keyboard_clear(); + zmk_hid_consumer_clear(); +#if IS_ENABLED(CONFIG_ZMK_MOUSE) + zmk_hid_mouse_clear(); +#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) + + zmk_endpoints_send_report(HID_USAGE_KEY); + zmk_endpoints_send_report(HID_USAGE_CONSUMER); +} + +static void update_current_endpoint(void) { + struct zmk_endpoint_instance new_instance = get_selected_instance(); + + if (!zmk_endpoint_instance_eq(new_instance, current_instance)) { + // Cancel all current keypresses so keys don't stay held on the old endpoint. + disconnect_current_endpoint(); + + current_instance = new_instance; + + char endpoint_str[ZMK_ENDPOINT_STR_LEN]; + zmk_endpoint_instance_to_str(current_instance, endpoint_str, sizeof(endpoint_str)); + LOG_INF("Endpoint changed: %s", endpoint_str); + + ZMK_EVENT_RAISE( + new_zmk_endpoint_changed((struct zmk_endpoint_changed){.endpoint = current_instance})); + } +} + +static int endpoint_listener(const zmk_event_t *eh) { + update_current_endpoint(); + return 0; +} + +ZMK_LISTENER(endpoint_listener, endpoint_listener); +#if IS_ENABLED(CONFIG_ZMK_USB) +ZMK_SUBSCRIPTION(endpoint_listener, zmk_usb_conn_state_changed); +#endif +#if IS_ENABLED(CONFIG_ZMK_BLE) +ZMK_SUBSCRIPTION(endpoint_listener, zmk_ble_active_profile_changed); +#endif + +SYS_INIT(zmk_endpoints_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/app/src/event_manager.c b/app/src/event_manager.c new file mode 100644 index 000000000000..0f4a5547cc22 --- /dev/null +++ b/app/src/event_manager.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include + +extern struct zmk_event_type *__event_type_start[]; +extern struct zmk_event_type *__event_type_end[]; + +extern struct zmk_event_subscription __event_subscriptions_start[]; +extern struct zmk_event_subscription __event_subscriptions_end[]; + +int zmk_event_manager_handle_from(zmk_event_t *event, uint8_t start_index) { + int ret = 0; + uint8_t len = __event_subscriptions_end - __event_subscriptions_start; + for (int i = start_index; i < len; i++) { + struct zmk_event_subscription *ev_sub = __event_subscriptions_start + i; + if (ev_sub->event_type != event->event) { + continue; + } + event->last_listener_index = i; + ret = ev_sub->listener->callback(event); + switch (ret) { + case ZMK_EV_EVENT_BUBBLE: + continue; + case ZMK_EV_EVENT_HANDLED: + LOG_DBG("Listener handled the event"); + ret = 0; + goto release; + case ZMK_EV_EVENT_CAPTURED: + LOG_DBG("Listener captured the event"); + // Listeners are expected to free events they capture + return 0; + default: + LOG_DBG("Listener returned an error: %d", ret); + goto release; + } + } + +release: + k_free(event); + return ret; +} + +int zmk_event_manager_raise(zmk_event_t *event) { return zmk_event_manager_handle_from(event, 0); } + +int zmk_event_manager_raise_after(zmk_event_t *event, const struct zmk_listener *listener) { + uint8_t len = __event_subscriptions_end - __event_subscriptions_start; + for (int i = 0; i < len; i++) { + struct zmk_event_subscription *ev_sub = __event_subscriptions_start + i; + + if (ev_sub->event_type == event->event && ev_sub->listener == listener) { + return zmk_event_manager_handle_from(event, i + 1); + } + } + + LOG_WRN("Unable to find where to raise this after event"); + + return -EINVAL; +} + +int zmk_event_manager_raise_at(zmk_event_t *event, const struct zmk_listener *listener) { + uint8_t len = __event_subscriptions_end - __event_subscriptions_start; + for (int i = 0; i < len; i++) { + struct zmk_event_subscription *ev_sub = __event_subscriptions_start + i; + + if (ev_sub->event_type == event->event && ev_sub->listener == listener) { + return zmk_event_manager_handle_from(event, i); + } + } + + LOG_WRN("Unable to find where to raise this event"); + + return -EINVAL; +} + +int zmk_event_manager_release(zmk_event_t *event) { + return zmk_event_manager_handle_from(event, event->last_listener_index + 1); +} diff --git a/app/src/events/activity_state_changed.c b/app/src/events/activity_state_changed.c new file mode 100644 index 000000000000..95be678e4643 --- /dev/null +++ b/app/src/events/activity_state_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_activity_state_changed); \ No newline at end of file diff --git a/app/src/events/battery_state_changed.c b/app/src/events/battery_state_changed.c new file mode 100644 index 000000000000..508ee971d69a --- /dev/null +++ b/app/src/events/battery_state_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_battery_state_changed); \ No newline at end of file diff --git a/app/src/events/ble_active_profile_changed.c b/app/src/events/ble_active_profile_changed.c new file mode 100644 index 000000000000..dccbc7e097e6 --- /dev/null +++ b/app/src/events/ble_active_profile_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_ble_active_profile_changed); \ No newline at end of file diff --git a/app/src/events/endpoint_changed.c b/app/src/events/endpoint_changed.c new file mode 100644 index 000000000000..6b152156febb --- /dev/null +++ b/app/src/events/endpoint_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_endpoint_changed); diff --git a/app/src/events/hid_indicators_changed.c b/app/src/events/hid_indicators_changed.c new file mode 100644 index 000000000000..ded368354d0d --- /dev/null +++ b/app/src/events/hid_indicators_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_hid_indicators_changed); diff --git a/app/src/events/keycode_state_changed.c b/app/src/events/keycode_state_changed.c new file mode 100644 index 000000000000..a134f34186d9 --- /dev/null +++ b/app/src/events/keycode_state_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_keycode_state_changed); diff --git a/app/src/events/layer_state_changed.c b/app/src/events/layer_state_changed.c new file mode 100644 index 000000000000..79326ccc6d4c --- /dev/null +++ b/app/src/events/layer_state_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_layer_state_changed); \ No newline at end of file diff --git a/app/src/events/modifiers_state_changed.c b/app/src/events/modifiers_state_changed.c new file mode 100644 index 000000000000..f44d90dda9cd --- /dev/null +++ b/app/src/events/modifiers_state_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_modifiers_state_changed); \ No newline at end of file diff --git a/app/src/events/mouse_button_state_changed.c b/app/src/events/mouse_button_state_changed.c new file mode 100644 index 000000000000..419a7ce956d4 --- /dev/null +++ b/app/src/events/mouse_button_state_changed.c @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +ZMK_EVENT_IMPL(zmk_mouse_button_state_changed); diff --git a/app/src/events/position_state_changed.c b/app/src/events/position_state_changed.c new file mode 100644 index 000000000000..7b9be89f2d5d --- /dev/null +++ b/app/src/events/position_state_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_position_state_changed); \ No newline at end of file diff --git a/app/src/events/sensor_event.c b/app/src/events/sensor_event.c new file mode 100644 index 000000000000..bec1e6e7ebda --- /dev/null +++ b/app/src/events/sensor_event.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_sensor_event); \ No newline at end of file diff --git a/app/src/events/split_peripheral_status_changed.c b/app/src/events/split_peripheral_status_changed.c new file mode 100644 index 000000000000..3f4c967d0688 --- /dev/null +++ b/app/src/events/split_peripheral_status_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_split_peripheral_status_changed); \ No newline at end of file diff --git a/app/src/events/usb_conn_state_changed.c b/app/src/events/usb_conn_state_changed.c new file mode 100644 index 000000000000..ae1f05037ac4 --- /dev/null +++ b/app/src/events/usb_conn_state_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_usb_conn_state_changed); \ No newline at end of file diff --git a/app/src/events/wpm_state_changed.c b/app/src/events/wpm_state_changed.c new file mode 100644 index 000000000000..f16f54d292e5 --- /dev/null +++ b/app/src/events/wpm_state_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_wpm_state_changed); \ No newline at end of file diff --git a/app/src/ext_power_generic.c b/app/src/ext_power_generic.c new file mode 100644 index 000000000000..52896f198713 --- /dev/null +++ b/app/src/ext_power_generic.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_ext_power_generic + +#include +#include +#include +#include +#include +#include +#include + +#include + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +struct ext_power_generic_config { + const struct gpio_dt_spec control; + const uint16_t init_delay_ms; +}; + +struct ext_power_generic_data { + bool status; +#if IS_ENABLED(CONFIG_SETTINGS) + bool settings_init; +#endif +}; + +#if IS_ENABLED(CONFIG_SETTINGS) +static void ext_power_save_state_work(struct k_work *work) { + char setting_path[40]; + const struct device *ext_power = DEVICE_DT_GET(DT_DRV_INST(0)); + struct ext_power_generic_data *data = ext_power->data; + + snprintf(setting_path, sizeof(setting_path), "ext_power/state/%s", ext_power->name); + settings_save_one(setting_path, &data->status, sizeof(data->status)); +} + +static struct k_work_delayable ext_power_save_work; +#endif + +int ext_power_save_state() { +#if IS_ENABLED(CONFIG_SETTINGS) + int ret = k_work_reschedule(&ext_power_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE)); + return MIN(ret, 0); +#else + return 0; +#endif +} + +static int ext_power_generic_enable(const struct device *dev) { + struct ext_power_generic_data *data = dev->data; + const struct ext_power_generic_config *config = dev->config; + + if (gpio_pin_set_dt(&config->control, 1)) { + LOG_WRN("Failed to set ext-power control pin"); + return -EIO; + } + data->status = true; + return ext_power_save_state(); +} + +static int ext_power_generic_disable(const struct device *dev) { + struct ext_power_generic_data *data = dev->data; + const struct ext_power_generic_config *config = dev->config; + + if (gpio_pin_set_dt(&config->control, 0)) { + LOG_WRN("Failed to set ext-power control pin"); + LOG_WRN("Failed to clear ext-power control pin"); + return -EIO; + } + data->status = false; + return ext_power_save_state(); +} + +static int ext_power_generic_get(const struct device *dev) { + struct ext_power_generic_data *data = dev->data; + return data->status; +} + +#if IS_ENABLED(CONFIG_SETTINGS) +static int ext_power_settings_set_status(const struct device *dev, size_t len, + settings_read_cb read_cb, void *cb_arg) { + struct ext_power_generic_data *data = dev->data; + + if (len != sizeof(data->status)) { + return -EINVAL; + } + + int rc = read_cb(cb_arg, &data->status, sizeof(data->status)); + if (rc >= 0) { + data->settings_init = true; + + if (data->status) { + ext_power_generic_enable(dev); + } else { + ext_power_generic_disable(dev); + } + + return 0; + } + return rc; +} + +static int ext_power_settings_set(const char *name, size_t len, settings_read_cb read_cb, + void *cb_arg) { + const struct device *ext_power = DEVICE_DT_GET(DT_DRV_INST(0)); + + const char *next; + if (settings_name_steq(name, ext_power->name, &next) && !next) { + return ext_power_settings_set_status(ext_power, len, read_cb, cb_arg); + } + + return -ENOENT; +} + +struct settings_handler ext_power_conf = {.name = "ext_power/state", + .h_set = ext_power_settings_set}; +#endif + +static int ext_power_generic_init(const struct device *dev) { + struct ext_power_generic_data *data = dev->data; + const struct ext_power_generic_config *config = dev->config; + + if (gpio_pin_configure_dt(&config->control, GPIO_OUTPUT_INACTIVE)) { + LOG_ERR("Failed to configure ext-power control pin"); + return -EIO; + } + +#if IS_ENABLED(CONFIG_SETTINGS) + settings_subsys_init(); + + int err = settings_register(&ext_power_conf); + if (err) { + LOG_ERR("Failed to register the ext_power settings handler (err %d)", err); + return err; + } + + k_work_init_delayable(&ext_power_save_work, ext_power_save_state_work); + + // Set default value (on) if settings isn't set + settings_load_subtree("ext_power"); + if (!data->settings_init) { + + data->status = true; + k_work_schedule(&ext_power_save_work, K_NO_WAIT); + + ext_power_enable(dev); + } +#else + // Default to the ext_power being open when no settings + ext_power_enable(dev); +#endif + + if (config->init_delay_ms) { + k_msleep(config->init_delay_ms); + } + + return 0; +} + +#ifdef CONFIG_PM_DEVICE +static int ext_power_generic_pm_action(const struct device *dev, enum pm_device_action action) { + switch (action) { + case PM_DEVICE_ACTION_RESUME: + ext_power_generic_enable(dev); + return 0; + case PM_DEVICE_ACTION_SUSPEND: + ext_power_generic_disable(dev); + return 0; + default: + return -ENOTSUP; + } +} +#endif /* CONFIG_PM_DEVICE */ + +static const struct ext_power_generic_config config = { + .control = GPIO_DT_SPEC_INST_GET(0, control_gpios), + .init_delay_ms = DT_INST_PROP_OR(0, init_delay_ms, 0)}; + +static struct ext_power_generic_data data = { + .status = false, +#if IS_ENABLED(CONFIG_SETTINGS) + .settings_init = false, +#endif +}; + +static const struct ext_power_api api = {.enable = ext_power_generic_enable, + .disable = ext_power_generic_disable, + .get = ext_power_generic_get}; + +#define ZMK_EXT_POWER_INIT_PRIORITY 81 + +PM_DEVICE_DT_INST_DEFINE(0, ext_power_generic_pm_action); +DEVICE_DT_INST_DEFINE(0, ext_power_generic_init, PM_DEVICE_DT_INST_GET(0), &data, &config, + POST_KERNEL, ZMK_EXT_POWER_INIT_PRIORITY, &api); + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/hid.c b/app/src/hid.c new file mode 100644 index 000000000000..1ea2afb16216 --- /dev/null +++ b/app/src/hid.c @@ -0,0 +1,447 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "zmk/keys.h" +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include + +static struct zmk_hid_keyboard_report keyboard_report = { + + .report_id = ZMK_HID_REPORT_ID_KEYBOARD, .body = {.modifiers = 0, ._reserved = 0, .keys = {0}}}; + +static struct zmk_hid_consumer_report consumer_report = {.report_id = ZMK_HID_REPORT_ID_CONSUMER, + .body = {.keys = {0}}}; + +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + +static zmk_hid_boot_report_t boot_report = {.modifiers = 0, ._reserved = 0, .keys = {0}}; +static uint8_t keys_held = 0; + +#endif /* IS_ENABLED(CONFIG_ZMK_USB_BOOT) */ + +#if IS_ENABLED(CONFIG_ZMK_MOUSE) + +static struct zmk_hid_mouse_report mouse_report = {.report_id = ZMK_HID_REPORT_ID_MOUSE, + .body = {.buttons = 0}}; + +#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) + +// Keep track of how often a modifier was pressed. +// Only release the modifier if the count is 0. +static int explicit_modifier_counts[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +static zmk_mod_flags_t explicit_modifiers = 0; +static zmk_mod_flags_t implicit_modifiers = 0; +static zmk_mod_flags_t masked_modifiers = 0; + +#define SET_MODIFIERS(mods) \ + { \ + keyboard_report.body.modifiers = (mods & ~masked_modifiers) | implicit_modifiers; \ + LOG_DBG("Modifiers set to 0x%02X", keyboard_report.body.modifiers); \ + } + +#define GET_MODIFIERS (keyboard_report.body.modifiers) + +zmk_mod_flags_t zmk_hid_get_explicit_mods() { return explicit_modifiers; } + +int zmk_hid_register_mod(zmk_mod_t modifier) { + explicit_modifier_counts[modifier]++; + LOG_DBG("Modifier %d count %d", modifier, explicit_modifier_counts[modifier]); + WRITE_BIT(explicit_modifiers, modifier, true); + zmk_mod_flags_t current = GET_MODIFIERS; + SET_MODIFIERS(explicit_modifiers); + return current == GET_MODIFIERS ? 0 : 1; +} + +int zmk_hid_unregister_mod(zmk_mod_t modifier) { + if (explicit_modifier_counts[modifier] <= 0) { + LOG_ERR("Tried to unregister modifier %d too often", modifier); + return -EINVAL; + } + explicit_modifier_counts[modifier]--; + LOG_DBG("Modifier %d count: %d", modifier, explicit_modifier_counts[modifier]); + if (explicit_modifier_counts[modifier] == 0) { + LOG_DBG("Modifier %d released", modifier); + WRITE_BIT(explicit_modifiers, modifier, false); + } + zmk_mod_flags_t current = GET_MODIFIERS; + SET_MODIFIERS(explicit_modifiers); + return current == GET_MODIFIERS ? 0 : 1; +} + +bool zmk_hid_mod_is_pressed(zmk_mod_t modifier) { + zmk_mod_flags_t mod_flag = 1 << modifier; + return (zmk_hid_get_explicit_mods() & mod_flag) == mod_flag; +} + +int zmk_hid_register_mods(zmk_mod_flags_t modifiers) { + int ret = 0; + for (zmk_mod_t i = 0; i < 8; i++) { + if (modifiers & (1 << i)) { + ret += zmk_hid_register_mod(i); + } + } + return ret; +} + +int zmk_hid_unregister_mods(zmk_mod_flags_t modifiers) { + int ret = 0; + for (zmk_mod_t i = 0; i < 8; i++) { + if (modifiers & (1 << i)) { + ret += zmk_hid_unregister_mod(i); + } + } + + return ret; +} + +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + +static zmk_hid_boot_report_t *boot_report_rollover(uint8_t modifiers) { + boot_report.modifiers = modifiers; + for (int i = 0; i < HID_BOOT_KEY_LEN; i++) { + boot_report.keys[i] = HID_ERROR_ROLLOVER; + } + return &boot_report; +} + +#endif /* IS_ENABLED(CONFIG_ZMK_USB_BOOT) */ + +#if IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_NKRO) + +#define TOGGLE_KEYBOARD(code, val) WRITE_BIT(keyboard_report.body.keys[code / 8], code % 8, val) + +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) +zmk_hid_boot_report_t *zmk_hid_get_boot_report() { + if (keys_held > HID_BOOT_KEY_LEN) { + return boot_report_rollover(keyboard_report.body.modifiers); + } + + boot_report.modifiers = keyboard_report.body.modifiers; + memset(&boot_report.keys, 0, HID_BOOT_KEY_LEN); + int ix = 0; + uint8_t base_code = 0; + for (int i = 0; i < (ZMK_HID_KEYBOARD_NKRO_MAX_USAGE + 1) / 8; ++i) { + if (ix == keys_held) { + break; + } + if (!keyboard_report.body.keys[i]) { + continue; + } + base_code = i * 8; + for (int j = 0; j < 8; ++j) { + if (keyboard_report.body.keys[i] & BIT(j)) { + boot_report.keys[ix++] = base_code + j; + } + } + } + return &boot_report; +} +#endif + +static inline int select_keyboard_usage(zmk_key_t usage) { + if (usage > ZMK_HID_KEYBOARD_NKRO_MAX_USAGE) { + return -EINVAL; + } + TOGGLE_KEYBOARD(usage, 1); +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + ++keys_held; +#endif + return 0; +} + +static inline int deselect_keyboard_usage(zmk_key_t usage) { + if (usage > ZMK_HID_KEYBOARD_NKRO_MAX_USAGE) { + return -EINVAL; + } + TOGGLE_KEYBOARD(usage, 0); +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + --keys_held; +#endif + return 0; +} + +static inline bool check_keyboard_usage(zmk_key_t usage) { + if (usage > ZMK_HID_KEYBOARD_NKRO_MAX_USAGE) { + return false; + } + return keyboard_report.body.keys[usage / 8] & (1 << (usage % 8)); +} + +#elif IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_HKRO) + +#define TOGGLE_KEYBOARD(match, val) \ + for (int idx = 0; idx < CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE; idx++) { \ + if (keyboard_report.body.keys[idx] != match) { \ + continue; \ + } \ + keyboard_report.body.keys[idx] = val; \ + if (val) { \ + break; \ + } \ + } + +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) +zmk_hid_boot_report_t *zmk_hid_get_boot_report() { + if (keys_held > HID_BOOT_KEY_LEN) { + return boot_report_rollover(keyboard_report.body.modifiers); + } + +#if CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE != HID_BOOT_KEY_LEN + // Form a boot report from a report of different size. + + boot_report.modifiers = keyboard_report.body.modifiers; + + int out = 0; + for (int i = 0; i < CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE; i++) { + uint8_t key = keyboard_report.body.keys[i]; + if (key) { + boot_report.keys[out++] = key; + if (out == keys_held) { + break; + } + } + } + + while (out < HID_BOOT_KEY_LEN) { + boot_report.keys[out++] = 0; + } + + return &boot_report; +#else + return &keyboard_report.body; +#endif /* CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE != HID_BOOT_KEY_LEN */ +} +#endif /* IS_ENABLED(CONFIG_ZMK_USB_BOOT) */ + +static inline int select_keyboard_usage(zmk_key_t usage) { + TOGGLE_KEYBOARD(0U, usage); +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + ++keys_held; +#endif + return 0; +} + +static inline int deselect_keyboard_usage(zmk_key_t usage) { + TOGGLE_KEYBOARD(usage, 0U); +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + --keys_held; +#endif + return 0; +} + +static inline int check_keyboard_usage(zmk_key_t usage) { + for (int idx = 0; idx < CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE; idx++) { + if (keyboard_report.body.keys[idx] == usage) { + return true; + } + } + return false; +} + +#else +#error "A proper HID report type must be selected" +#endif + +#define TOGGLE_CONSUMER(match, val) \ + COND_CODE_1(IS_ENABLED(CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_BASIC), \ + (if (val > 0xFF) { return -ENOTSUP; }), ()) \ + for (int idx = 0; idx < CONFIG_ZMK_HID_CONSUMER_REPORT_SIZE; idx++) { \ + if (consumer_report.body.keys[idx] != match) { \ + continue; \ + } \ + consumer_report.body.keys[idx] = val; \ + if (val) { \ + break; \ + } \ + } + +int zmk_hid_implicit_modifiers_press(zmk_mod_flags_t new_implicit_modifiers) { + implicit_modifiers = new_implicit_modifiers; + zmk_mod_flags_t current = GET_MODIFIERS; + SET_MODIFIERS(explicit_modifiers); + return current == GET_MODIFIERS ? 0 : 1; +} + +int zmk_hid_implicit_modifiers_release() { + implicit_modifiers = 0; + zmk_mod_flags_t current = GET_MODIFIERS; + SET_MODIFIERS(explicit_modifiers); + return current == GET_MODIFIERS ? 0 : 1; +} + +int zmk_hid_masked_modifiers_set(zmk_mod_flags_t new_masked_modifiers) { + masked_modifiers = new_masked_modifiers; + zmk_mod_flags_t current = GET_MODIFIERS; + SET_MODIFIERS(explicit_modifiers); + return current == GET_MODIFIERS ? 0 : 1; +} + +int zmk_hid_masked_modifiers_clear() { + masked_modifiers = 0; + zmk_mod_flags_t current = GET_MODIFIERS; + SET_MODIFIERS(explicit_modifiers); + return current == GET_MODIFIERS ? 0 : 1; +} + +int zmk_hid_keyboard_press(zmk_key_t code) { + if (code >= HID_USAGE_KEY_KEYBOARD_LEFTCONTROL && code <= HID_USAGE_KEY_KEYBOARD_RIGHT_GUI) { + return zmk_hid_register_mod(code - HID_USAGE_KEY_KEYBOARD_LEFTCONTROL); + } + select_keyboard_usage(code); + return 0; +}; + +int zmk_hid_keyboard_release(zmk_key_t code) { + if (code >= HID_USAGE_KEY_KEYBOARD_LEFTCONTROL && code <= HID_USAGE_KEY_KEYBOARD_RIGHT_GUI) { + return zmk_hid_unregister_mod(code - HID_USAGE_KEY_KEYBOARD_LEFTCONTROL); + } + deselect_keyboard_usage(code); + return 0; +}; + +bool zmk_hid_keyboard_is_pressed(zmk_key_t code) { + if (code >= HID_USAGE_KEY_KEYBOARD_LEFTCONTROL && code <= HID_USAGE_KEY_KEYBOARD_RIGHT_GUI) { + return zmk_hid_mod_is_pressed(code - HID_USAGE_KEY_KEYBOARD_LEFTCONTROL); + } + return check_keyboard_usage(code); +} + +void zmk_hid_keyboard_clear() { memset(&keyboard_report.body, 0, sizeof(keyboard_report.body)); } + +int zmk_hid_consumer_press(zmk_key_t code) { + TOGGLE_CONSUMER(0U, code); + return 0; +}; + +int zmk_hid_consumer_release(zmk_key_t code) { + TOGGLE_CONSUMER(code, 0U); + return 0; +}; + +void zmk_hid_consumer_clear() { memset(&consumer_report.body, 0, sizeof(consumer_report.body)); } + +bool zmk_hid_consumer_is_pressed(zmk_key_t key) { + for (int idx = 0; idx < CONFIG_ZMK_HID_CONSUMER_REPORT_SIZE; idx++) { + if (consumer_report.body.keys[idx] == key) { + return true; + } + } + return false; +} + +int zmk_hid_press(uint32_t usage) { + switch (ZMK_HID_USAGE_PAGE(usage)) { + case HID_USAGE_KEY: + return zmk_hid_keyboard_press(ZMK_HID_USAGE_ID(usage)); + case HID_USAGE_CONSUMER: + return zmk_hid_consumer_press(ZMK_HID_USAGE_ID(usage)); + } + return -EINVAL; +} + +int zmk_hid_release(uint32_t usage) { + switch (ZMK_HID_USAGE_PAGE(usage)) { + case HID_USAGE_KEY: + return zmk_hid_keyboard_release(ZMK_HID_USAGE_ID(usage)); + case HID_USAGE_CONSUMER: + return zmk_hid_consumer_release(ZMK_HID_USAGE_ID(usage)); + } + return -EINVAL; +} + +bool zmk_hid_is_pressed(uint32_t usage) { + switch (ZMK_HID_USAGE_PAGE(usage)) { + case HID_USAGE_KEY: + return zmk_hid_keyboard_is_pressed(ZMK_HID_USAGE_ID(usage)); + case HID_USAGE_CONSUMER: + return zmk_hid_consumer_is_pressed(ZMK_HID_USAGE_ID(usage)); + } + return false; +} + +#if IS_ENABLED(CONFIG_ZMK_MOUSE) + +// Keep track of how often a button was pressed. +// Only release the button if the count is 0. +static int explicit_button_counts[5] = {0, 0, 0, 0, 0}; +static zmk_mod_flags_t explicit_buttons = 0; + +#define SET_MOUSE_BUTTONS(btns) \ + { \ + mouse_report.body.buttons = btns; \ + LOG_DBG("Mouse buttons set to 0x%02X", mouse_report.body.buttons); \ + } + +int zmk_hid_mouse_button_press(zmk_mouse_button_t button) { + if (button >= ZMK_HID_MOUSE_NUM_BUTTONS) { + return -EINVAL; + } + + explicit_button_counts[button]++; + LOG_DBG("Button %d count %d", button, explicit_button_counts[button]); + WRITE_BIT(explicit_buttons, button, true); + SET_MOUSE_BUTTONS(explicit_buttons); + return 0; +} + +int zmk_hid_mouse_button_release(zmk_mouse_button_t button) { + if (button >= ZMK_HID_MOUSE_NUM_BUTTONS) { + return -EINVAL; + } + + if (explicit_button_counts[button] <= 0) { + LOG_ERR("Tried to release button %d too often", button); + return -EINVAL; + } + explicit_button_counts[button]--; + LOG_DBG("Button %d count: %d", button, explicit_button_counts[button]); + if (explicit_button_counts[button] == 0) { + LOG_DBG("Button %d released", button); + WRITE_BIT(explicit_buttons, button, false); + } + SET_MOUSE_BUTTONS(explicit_buttons); + return 0; +} + +int zmk_hid_mouse_buttons_press(zmk_mouse_button_flags_t buttons) { + for (zmk_mouse_button_t i = 0; i < ZMK_HID_MOUSE_NUM_BUTTONS; i++) { + if (buttons & BIT(i)) { + zmk_hid_mouse_button_press(i); + } + } + return 0; +} + +int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons) { + for (zmk_mouse_button_t i = 0; i < ZMK_HID_MOUSE_NUM_BUTTONS; i++) { + if (buttons & BIT(i)) { + zmk_hid_mouse_button_release(i); + } + } + return 0; +} +void zmk_hid_mouse_clear() { memset(&mouse_report.body, 0, sizeof(mouse_report.body)); } + +#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) + +struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report() { + return &keyboard_report; +} + +struct zmk_hid_consumer_report *zmk_hid_get_consumer_report() { + return &consumer_report; +} + +#if IS_ENABLED(CONFIG_ZMK_MOUSE) + +struct zmk_hid_mouse_report *zmk_hid_get_mouse_report() { + return &mouse_report; +} + +#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) diff --git a/app/src/hid_indicators.c b/app/src/hid_indicators.c new file mode 100644 index 000000000000..50b2fbcc9bad --- /dev/null +++ b/app/src/hid_indicators.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +static zmk_hid_indicators_t hid_indicators[ZMK_ENDPOINT_COUNT]; + +zmk_hid_indicators_t zmk_hid_indicators_get_current_profile(void) { + return zmk_hid_indicators_get_profile(zmk_endpoints_selected()); +} + +zmk_hid_indicators_t zmk_hid_indicators_get_profile(struct zmk_endpoint_instance endpoint) { + const int profile = zmk_endpoint_instance_to_index(endpoint); + return hid_indicators[profile]; +} + +static void raise_led_changed_event(struct k_work *_work) { + const zmk_hid_indicators_t indicators = zmk_hid_indicators_get_current_profile(); + + ZMK_EVENT_RAISE(new_zmk_hid_indicators_changed( + (struct zmk_hid_indicators_changed){.indicators = indicators})); + +#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) && IS_ENABLED(CONFIG_ZMK_SPLIT_BLE) + zmk_split_bt_update_hid_indicator(indicators); +#endif +} + +static K_WORK_DEFINE(led_changed_work, raise_led_changed_event); + +void zmk_hid_indicators_set_profile(zmk_hid_indicators_t indicators, + struct zmk_endpoint_instance endpoint) { + int profile = zmk_endpoint_instance_to_index(endpoint); + + // This write is not happening on the main thread. To prevent potential data races, every + // operation involving hid_indicators must be atomic. Currently, each function either reads + // or writes only one entry at a time, so it is safe to do these operations without a lock. + hid_indicators[profile] = indicators; + + k_work_submit(&led_changed_work); +} + +void zmk_hid_indicators_process_report(struct zmk_hid_led_report_body *report, + struct zmk_endpoint_instance endpoint) { + const zmk_hid_indicators_t indicators = (zmk_hid_indicators_t)report->leds; + zmk_hid_indicators_set_profile(indicators, endpoint); + + LOG_DBG("Update HID indicators: endpoint=%d, indicators=%x", endpoint.transport, indicators); +} + +static int profile_listener(const zmk_event_t *eh) { + raise_led_changed_event(NULL); + return 0; +} + +static ZMK_LISTENER(profile_listener, profile_listener); +static ZMK_SUBSCRIPTION(profile_listener, zmk_endpoint_changed); diff --git a/app/src/hid_listener.c b/app/src/hid_listener.c new file mode 100644 index 000000000000..2b8470820a1a --- /dev/null +++ b/app/src/hid_listener.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include +#include +#include + +static int hid_listener_keycode_pressed(const struct zmk_keycode_state_changed *ev) { + int err, explicit_mods_changed, implicit_mods_changed; + + if (!is_mod(ev->usage_page, ev->keycode) && + zmk_hid_is_pressed(ZMK_HID_USAGE(ev->usage_page, ev->keycode))) { + LOG_DBG("unregistering usage_page 0x%02X keycode 0x%02X since it was already pressed", + ev->usage_page, ev->keycode); + err = zmk_hid_release(ZMK_HID_USAGE(ev->usage_page, ev->keycode)); + if (err < 0) { + LOG_DBG("Unable to pre-release keycode (%d)", err); + return err; + } + err = zmk_endpoints_send_report(ev->usage_page); + if (err < 0) { + LOG_ERR("Failed to send key report for pre-releasing keycode (%d)", err); + } + } + + LOG_DBG("usage_page 0x%02X keycode 0x%02X implicit_mods 0x%02X explicit_mods 0x%02X", + ev->usage_page, ev->keycode, ev->implicit_modifiers, ev->explicit_modifiers); + err = zmk_hid_press(ZMK_HID_USAGE(ev->usage_page, ev->keycode)); + if (err < 0) { + LOG_DBG("Unable to press keycode"); + return err; + } + explicit_mods_changed = zmk_hid_register_mods(ev->explicit_modifiers); + implicit_mods_changed = zmk_hid_implicit_modifiers_press(ev->implicit_modifiers); + if (ev->usage_page != HID_USAGE_KEY && + (explicit_mods_changed > 0 || implicit_mods_changed > 0)) { + err = zmk_endpoints_send_report(HID_USAGE_KEY); + if (err < 0) { + LOG_ERR("Failed to send key report for changed mofifiers for consumer page event (%d)", + err); + } + } + + return zmk_endpoints_send_report(ev->usage_page); +} + +static int hid_listener_keycode_released(const struct zmk_keycode_state_changed *ev) { + int err, explicit_mods_changed, implicit_mods_changed; + + LOG_DBG("usage_page 0x%02X keycode 0x%02X implicit_mods 0x%02X explicit_mods 0x%02X", + ev->usage_page, ev->keycode, ev->implicit_modifiers, ev->explicit_modifiers); + err = zmk_hid_release(ZMK_HID_USAGE(ev->usage_page, ev->keycode)); + if (err < 0) { + LOG_DBG("Unable to release keycode"); + return err; + } + + explicit_mods_changed = zmk_hid_unregister_mods(ev->explicit_modifiers); + // There is a minor issue with this code. + // If LC(A) is pressed, then LS(B), then LC(A) is released, the shift for B will be released + // prematurely. This causes if LS(B) to repeat like Bbbbbbbb when pressed for a long time. + // Solving this would require keeping track of which key's implicit modifiers are currently + // active and only releasing modifiers at that time. + implicit_mods_changed = zmk_hid_implicit_modifiers_release(); + ; + if (ev->usage_page != HID_USAGE_KEY && + (explicit_mods_changed > 0 || implicit_mods_changed > 0)) { + err = zmk_endpoints_send_report(HID_USAGE_KEY); + if (err < 0) { + LOG_ERR("Failed to send key report for changed mofifiers for consumer page event (%d)", + err); + } + } + return zmk_endpoints_send_report(ev->usage_page); +} + +int hid_listener(const zmk_event_t *eh) { + const struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh); + if (ev) { + if (ev->state) { + hid_listener_keycode_pressed(ev); + } else { + hid_listener_keycode_released(ev); + } + } + return 0; +} + +ZMK_LISTENER(hid_listener, hid_listener); +ZMK_SUBSCRIPTION(hid_listener, zmk_keycode_state_changed); diff --git a/app/src/hog.c b/app/src/hog.c new file mode 100644 index 000000000000..1baf00b53b50 --- /dev/null +++ b/app/src/hog.c @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include + +#include +#include +#include +#include +#if IS_ENABLED(CONFIG_ZMK_HID_INDICATORS) +#include +#endif // IS_ENABLED(CONFIG_ZMK_HID_INDICATORS) + +enum { + HIDS_REMOTE_WAKE = BIT(0), + HIDS_NORMALLY_CONNECTABLE = BIT(1), +}; + +struct hids_info { + uint16_t version; /* version number of base USB HID Specification */ + uint8_t code; /* country HID Device hardware is localized for. */ + uint8_t flags; +} __packed; + +struct hids_report { + uint8_t id; /* report id */ + uint8_t type; /* report type */ +} __packed; + +static struct hids_info info = { + .version = 0x0000, + .code = 0x00, + .flags = HIDS_NORMALLY_CONNECTABLE | HIDS_REMOTE_WAKE, +}; + +enum { + HIDS_INPUT = 0x01, + HIDS_OUTPUT = 0x02, + HIDS_FEATURE = 0x03, +}; + +static struct hids_report input = { + .id = ZMK_HID_REPORT_ID_KEYBOARD, + .type = HIDS_INPUT, +}; + +#if IS_ENABLED(CONFIG_ZMK_HID_INDICATORS) + +static struct hids_report led_indicators = { + .id = ZMK_HID_REPORT_ID_LEDS, + .type = HIDS_OUTPUT, +}; + +#endif // IS_ENABLED(CONFIG_ZMK_HID_INDICATORS) + +static struct hids_report consumer_input = { + .id = ZMK_HID_REPORT_ID_CONSUMER, + .type = HIDS_INPUT, +}; + +#if IS_ENABLED(CONFIG_ZMK_MOUSE) + +static struct hids_report mouse_input = { + .id = ZMK_HID_REPORT_ID_MOUSE, + .type = HIDS_INPUT, +}; + +#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) + +static bool host_requests_notification = false; +static uint8_t ctrl_point; +// static uint8_t proto_mode; + +static ssize_t read_hids_info(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) { + return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data, + sizeof(struct hids_info)); +} + +static ssize_t read_hids_report_ref(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) { + return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data, + sizeof(struct hids_report)); +} + +static ssize_t read_hids_report_map(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) { + return bt_gatt_attr_read(conn, attr, buf, len, offset, zmk_hid_report_desc, + sizeof(zmk_hid_report_desc)); +} + +static ssize_t read_hids_input_report(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) { + struct zmk_hid_keyboard_report_body *report_body = &zmk_hid_get_keyboard_report()->body; + return bt_gatt_attr_read(conn, attr, buf, len, offset, report_body, + sizeof(struct zmk_hid_keyboard_report_body)); +} + +#if IS_ENABLED(CONFIG_ZMK_HID_INDICATORS) +static ssize_t write_hids_leds_report(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) { + if (offset != 0) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + if (len != sizeof(struct zmk_hid_led_report_body)) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); + } + + struct zmk_hid_led_report_body *report = (struct zmk_hid_led_report_body *)buf; + int profile = zmk_ble_profile_index(bt_conn_get_dst(conn)); + if (profile < 0) { + return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY); + } + + struct zmk_endpoint_instance endpoint = {.transport = ZMK_TRANSPORT_BLE, + .ble = { + .profile_index = profile, + }}; + zmk_hid_indicators_process_report(report, endpoint); + + return len; +} + +#endif // IS_ENABLED(CONFIG_ZMK_HID_INDICATORS) + +static ssize_t read_hids_consumer_input_report(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) { + struct zmk_hid_consumer_report_body *report_body = &zmk_hid_get_consumer_report()->body; + return bt_gatt_attr_read(conn, attr, buf, len, offset, report_body, + sizeof(struct zmk_hid_consumer_report_body)); +} + +#if IS_ENABLED(CONFIG_ZMK_MOUSE) +static ssize_t read_hids_mouse_input_report(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) { + struct zmk_hid_mouse_report_body *report_body = &zmk_hid_get_mouse_report()->body; + return bt_gatt_attr_read(conn, attr, buf, len, offset, report_body, + sizeof(struct zmk_hid_mouse_report_body)); +} +#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) + +// static ssize_t write_proto_mode(struct bt_conn *conn, +// const struct bt_gatt_attr *attr, +// const void *buf, uint16_t len, uint16_t offset, +// uint8_t flags) +// { +// printk("PROTO CHANGED\n"); +// return 0; +// } + +static void input_ccc_changed(const struct bt_gatt_attr *attr, uint16_t value) { + host_requests_notification = (value == BT_GATT_CCC_NOTIFY) ? 1 : 0; +} + +static ssize_t write_ctrl_point(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, uint8_t flags) { + uint8_t *value = attr->user_data; + + if (offset + len > sizeof(ctrl_point)) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + memcpy(value + offset, buf, len); + + return len; +} + +/* HID Service Declaration */ +BT_GATT_SERVICE_DEFINE( + hog_svc, BT_GATT_PRIMARY_SERVICE(BT_UUID_HIDS), + // BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_PROTOCOL_MODE, BT_GATT_CHRC_WRITE_WITHOUT_RESP, + // BT_GATT_PERM_WRITE, NULL, write_proto_mode, &proto_mode), + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_INFO, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, read_hids_info, + NULL, &info), + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT_MAP, BT_GATT_CHRC_READ, BT_GATT_PERM_READ_ENCRYPT, + read_hids_report_map, NULL, NULL), + + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ_ENCRYPT, read_hids_input_report, NULL, NULL), + BT_GATT_CCC(input_ccc_changed, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref, + NULL, &input), + + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ_ENCRYPT, read_hids_consumer_input_report, NULL, NULL), + BT_GATT_CCC(input_ccc_changed, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref, + NULL, &consumer_input), + +#if IS_ENABLED(CONFIG_ZMK_MOUSE) + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ_ENCRYPT, read_hids_mouse_input_report, NULL, NULL), + BT_GATT_CCC(input_ccc_changed, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref, + NULL, &mouse_input), +#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) + +#if IS_ENABLED(CONFIG_ZMK_HID_INDICATORS) + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, + BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP, + BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, NULL, + write_hids_leds_report, NULL), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref, + NULL, &led_indicators), +#endif // IS_ENABLED(CONFIG_ZMK_HID_INDICATORS) + + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_CTRL_POINT, BT_GATT_CHRC_WRITE_WITHOUT_RESP, + BT_GATT_PERM_WRITE, NULL, write_ctrl_point, &ctrl_point)); + +struct bt_conn *destination_connection() { + struct bt_conn *conn; + bt_addr_le_t *addr = zmk_ble_active_profile_addr(); + LOG_DBG("Address pointer %p", addr); + if (!bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) { + LOG_WRN("Not sending, no active address for current profile"); + return NULL; + } else if ((conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr)) == NULL) { + LOG_WRN("Not sending, not connected to active profile"); + return NULL; + } + + return conn; +} + +K_THREAD_STACK_DEFINE(hog_q_stack, CONFIG_ZMK_BLE_THREAD_STACK_SIZE); + +struct k_work_q hog_work_q; + +K_MSGQ_DEFINE(zmk_hog_keyboard_msgq, sizeof(struct zmk_hid_keyboard_report_body), + CONFIG_ZMK_BLE_KEYBOARD_REPORT_QUEUE_SIZE, 4); + +void send_keyboard_report_callback(struct k_work *work) { + struct zmk_hid_keyboard_report_body report; + + while (k_msgq_get(&zmk_hog_keyboard_msgq, &report, K_NO_WAIT) == 0) { + struct bt_conn *conn = destination_connection(); + if (conn == NULL) { + return; + } + + struct bt_gatt_notify_params notify_params = { + .attr = &hog_svc.attrs[5], + .data = &report, + .len = sizeof(report), + }; + + int err = bt_gatt_notify_cb(conn, ¬ify_params); + if (err) { + LOG_ERR("Error notifying %d", err); + } + + bt_conn_unref(conn); + } +} + +K_WORK_DEFINE(hog_keyboard_work, send_keyboard_report_callback); + +int zmk_hog_send_keyboard_report(struct zmk_hid_keyboard_report_body *report) { + int err = k_msgq_put(&zmk_hog_keyboard_msgq, report, K_MSEC(100)); + if (err) { + switch (err) { + case -EAGAIN: { + LOG_WRN("Keyboard message queue full, popping first message and queueing again"); + struct zmk_hid_keyboard_report_body discarded_report; + k_msgq_get(&zmk_hog_keyboard_msgq, &discarded_report, K_NO_WAIT); + return zmk_hog_send_keyboard_report(report); + } + default: + LOG_WRN("Failed to queue keyboard report to send (%d)", err); + return err; + } + } + + k_work_submit_to_queue(&hog_work_q, &hog_keyboard_work); + + return 0; +}; + +K_MSGQ_DEFINE(zmk_hog_consumer_msgq, sizeof(struct zmk_hid_consumer_report_body), + CONFIG_ZMK_BLE_CONSUMER_REPORT_QUEUE_SIZE, 4); + +void send_consumer_report_callback(struct k_work *work) { + struct zmk_hid_consumer_report_body report; + + while (k_msgq_get(&zmk_hog_consumer_msgq, &report, K_NO_WAIT) == 0) { + struct bt_conn *conn = destination_connection(); + if (conn == NULL) { + return; + } + + struct bt_gatt_notify_params notify_params = { + .attr = &hog_svc.attrs[9], + .data = &report, + .len = sizeof(report), + }; + + int err = bt_gatt_notify_cb(conn, ¬ify_params); + if (err) { + LOG_DBG("Error notifying %d", err); + } + + bt_conn_unref(conn); + } +}; + +K_WORK_DEFINE(hog_consumer_work, send_consumer_report_callback); + +int zmk_hog_send_consumer_report(struct zmk_hid_consumer_report_body *report) { + int err = k_msgq_put(&zmk_hog_consumer_msgq, report, K_MSEC(100)); + if (err) { + switch (err) { + case -EAGAIN: { + LOG_WRN("Consumer message queue full, popping first message and queueing again"); + struct zmk_hid_consumer_report_body discarded_report; + k_msgq_get(&zmk_hog_consumer_msgq, &discarded_report, K_NO_WAIT); + return zmk_hog_send_consumer_report(report); + } + default: + LOG_WRN("Failed to queue consumer report to send (%d)", err); + return err; + } + } + + k_work_submit_to_queue(&hog_work_q, &hog_consumer_work); + + return 0; +}; + +#if IS_ENABLED(CONFIG_ZMK_MOUSE) + +K_MSGQ_DEFINE(zmk_hog_mouse_msgq, sizeof(struct zmk_hid_mouse_report_body), + CONFIG_ZMK_BLE_MOUSE_REPORT_QUEUE_SIZE, 4); + +void send_mouse_report_callback(struct k_work *work) { + struct zmk_hid_mouse_report_body report; + while (k_msgq_get(&zmk_hog_mouse_msgq, &report, K_NO_WAIT) == 0) { + struct bt_conn *conn = destination_connection(); + if (conn == NULL) { + return; + } + + struct bt_gatt_notify_params notify_params = { + .attr = &hog_svc.attrs[13], + .data = &report, + .len = sizeof(report), + }; + + int err = bt_gatt_notify_cb(conn, ¬ify_params); + if (err) { + LOG_DBG("Error notifying %d", err); + } + + bt_conn_unref(conn); + } +}; + +int zmk_hog_send_mouse_report(struct zmk_hid_mouse_report_body *report) { + struct bt_conn *conn = destination_connection(); + if (conn == NULL) { + return 1; + } + + struct bt_gatt_notify_params notify_params = { + .attr = &hog_svc.attrs[13], + .data = report, + .len = sizeof(*report), + }; + + int err = bt_gatt_notify_cb(conn, ¬ify_params); + if (err) { + LOG_DBG("Error notifying %d", err); + return err; + } + + bt_conn_unref(conn); + + return 0; +}; + +#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) + +int zmk_hog_init(const struct device *_arg) { + static const struct k_work_queue_config queue_config = {.name = "HID Over GATT Send Work"}; + k_work_queue_start(&hog_work_q, hog_q_stack, K_THREAD_STACK_SIZEOF(hog_q_stack), + CONFIG_ZMK_BLE_THREAD_PRIORITY, &queue_config); + + return 0; +} + +SYS_INIT(zmk_hog_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY); diff --git a/app/src/keymap.c b/app/src/keymap.c new file mode 100644 index 000000000000..d275feafbb57 --- /dev/null +++ b/app/src/keymap.c @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include +#include + +#include +#if ZMK_BLE_IS_CENTRAL +#include +#endif + +#include +#include +#include +#include + +static zmk_keymap_layers_state_t _zmk_keymap_layer_state = 0; +static uint8_t _zmk_keymap_layer_default = 0; + +#define DT_DRV_COMPAT zmk_keymap + +#define TRANSFORMED_LAYER(node) \ + { LISTIFY(DT_PROP_LEN(node, bindings), ZMK_KEYMAP_EXTRACT_BINDING, (, ), node) } + +#if ZMK_KEYMAP_HAS_SENSORS +#define _TRANSFORM_SENSOR_ENTRY(idx, layer) \ + { \ + .behavior_dev = DEVICE_DT_NAME(DT_PHANDLE_BY_IDX(layer, sensor_bindings, idx)), \ + .param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, sensor_bindings, idx, param1), (0), \ + (DT_PHA_BY_IDX(layer, sensor_bindings, idx, param1))), \ + .param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, sensor_bindings, idx, param2), (0), \ + (DT_PHA_BY_IDX(layer, sensor_bindings, idx, param2))), \ + } + +#define SENSOR_LAYER(node) \ + COND_CODE_1( \ + DT_NODE_HAS_PROP(node, sensor_bindings), \ + ({LISTIFY(DT_PROP_LEN(node, sensor_bindings), _TRANSFORM_SENSOR_ENTRY, (, ), node)}), \ + ({})) + +#endif /* ZMK_KEYMAP_HAS_SENSORS */ + +#define LAYER_NAME(node) DT_PROP_OR(node, display_name, DT_PROP_OR(node, label, NULL)) + +// State + +// When a behavior handles a key position "down" event, we record the layer state +// here so that even if that layer is deactivated before the "up", event, we +// still send the release event to the behavior in that layer also. +static uint32_t zmk_keymap_active_behavior_layer[ZMK_KEYMAP_LEN]; + +static struct zmk_behavior_binding zmk_keymap[ZMK_KEYMAP_LAYERS_LEN][ZMK_KEYMAP_LEN] = { + DT_INST_FOREACH_CHILD_SEP(0, TRANSFORMED_LAYER, (, ))}; + +static const char *zmk_keymap_layer_names[ZMK_KEYMAP_LAYERS_LEN] = { + DT_INST_FOREACH_CHILD_SEP(0, LAYER_NAME, (, ))}; + +#if ZMK_KEYMAP_HAS_SENSORS + +static struct zmk_behavior_binding + zmk_sensor_keymap[ZMK_KEYMAP_LAYERS_LEN][ZMK_KEYMAP_SENSORS_LEN] = { + DT_INST_FOREACH_CHILD_SEP(0, SENSOR_LAYER, (, ))}; + +#endif /* ZMK_KEYMAP_HAS_SENSORS */ + +static inline int set_layer_state(uint8_t layer, bool state) { + if (layer >= ZMK_KEYMAP_LAYERS_LEN) { + return -EINVAL; + } + + // Default layer should *always* remain active + if (layer == _zmk_keymap_layer_default && !state) { + return 0; + } + + zmk_keymap_layers_state_t old_state = _zmk_keymap_layer_state; + WRITE_BIT(_zmk_keymap_layer_state, layer, state); + // Don't send state changes unless there was an actual change + if (old_state != _zmk_keymap_layer_state) { + LOG_DBG("layer_changed: layer %d state %d", layer, state); + ZMK_EVENT_RAISE(create_layer_state_changed(layer, state)); + } + + return 0; +} + +uint8_t zmk_keymap_layer_default() { return _zmk_keymap_layer_default; } + +zmk_keymap_layers_state_t zmk_keymap_layer_state() { return _zmk_keymap_layer_state; } + +bool zmk_keymap_layer_active_with_state(uint8_t layer, zmk_keymap_layers_state_t state_to_test) { + // The default layer is assumed to be ALWAYS ACTIVE so we include an || here to ensure nobody + // breaks up that assumption by accident + return (state_to_test & (BIT(layer))) == (BIT(layer)) || layer == _zmk_keymap_layer_default; +}; + +bool zmk_keymap_layer_active(uint8_t layer) { + return zmk_keymap_layer_active_with_state(layer, _zmk_keymap_layer_state); +}; + +uint8_t zmk_keymap_highest_layer_active() { + for (uint8_t layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer > 0; layer--) { + if (zmk_keymap_layer_active(layer)) { + return layer; + } + } + return zmk_keymap_layer_default(); +} + +int zmk_keymap_layer_activate(uint8_t layer) { return set_layer_state(layer, true); }; + +int zmk_keymap_layer_deactivate(uint8_t layer) { return set_layer_state(layer, false); }; + +int zmk_keymap_layer_toggle(uint8_t layer) { + if (zmk_keymap_layer_active(layer)) { + return zmk_keymap_layer_deactivate(layer); + } + + return zmk_keymap_layer_activate(layer); +}; + +int zmk_keymap_layer_to(uint8_t layer) { + for (int i = ZMK_KEYMAP_LAYERS_LEN - 1; i >= 0; i--) { + zmk_keymap_layer_deactivate(i); + } + + zmk_keymap_layer_activate(layer); + + return 0; +} + +bool is_active_layer(uint8_t layer, zmk_keymap_layers_state_t layer_state) { + return (layer_state & BIT(layer)) == BIT(layer) || layer == _zmk_keymap_layer_default; +} + +const char *zmk_keymap_layer_name(uint8_t layer) { + if (layer >= ZMK_KEYMAP_LAYERS_LEN) { + return NULL; + } + + return zmk_keymap_layer_names[layer]; +} + +int invoke_locally(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, + bool pressed) { + if (pressed) { + return behavior_keymap_binding_pressed(binding, event); + } else { + return behavior_keymap_binding_released(binding, event); + } +} + +int zmk_keymap_apply_position_state(uint8_t source, int layer, uint32_t position, bool pressed, + int64_t timestamp) { + // We want to make a copy of this, since it may be converted from + // relative to absolute before being invoked + struct zmk_behavior_binding binding = zmk_keymap[layer][position]; + const struct device *behavior; + struct zmk_behavior_binding_event event = { + .layer = layer, + .position = position, + .timestamp = timestamp, + }; + + LOG_DBG("layer: %d position: %d, binding name: %s", layer, position, binding.behavior_dev); + + behavior = zmk_behavior_get_binding(binding.behavior_dev); + + if (!behavior) { + LOG_WRN("No behavior assigned to %d on layer %d", position, layer); + return 1; + } + + int err = behavior_keymap_binding_convert_central_state_dependent_params(&binding, event); + if (err) { + LOG_ERR("Failed to convert relative to absolute behavior binding (err %d)", err); + return err; + } + + enum behavior_locality locality = BEHAVIOR_LOCALITY_CENTRAL; + err = behavior_get_locality(behavior, &locality); + if (err) { + LOG_ERR("Failed to get behavior locality %d", err); + return err; + } + + switch (locality) { + case BEHAVIOR_LOCALITY_CENTRAL: + return invoke_locally(&binding, event, pressed); + case BEHAVIOR_LOCALITY_EVENT_SOURCE: +#if ZMK_BLE_IS_CENTRAL + if (source == ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL) { + return invoke_locally(&binding, event, pressed); + } else { + return zmk_split_bt_invoke_behavior(source, &binding, event, pressed); + } +#else + return invoke_locally(&binding, event, pressed); +#endif + case BEHAVIOR_LOCALITY_GLOBAL: +#if ZMK_BLE_IS_CENTRAL + for (int i = 0; i < ZMK_SPLIT_BLE_PERIPHERAL_COUNT; i++) { + zmk_split_bt_invoke_behavior(i, &binding, event, pressed); + } +#endif + return invoke_locally(&binding, event, pressed); + } + + return -ENOTSUP; +} + +int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pressed, + int64_t timestamp) { + if (pressed) { + zmk_keymap_active_behavior_layer[position] = _zmk_keymap_layer_state; + } + for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= _zmk_keymap_layer_default; layer--) { + if (zmk_keymap_layer_active_with_state(layer, zmk_keymap_active_behavior_layer[position])) { + int ret = zmk_keymap_apply_position_state(source, layer, position, pressed, timestamp); + if (ret > 0) { + LOG_DBG("behavior processing to continue to next layer"); + continue; + } else if (ret < 0) { + LOG_DBG("Behavior returned error: %d", ret); + return ret; + } else { + return ret; + } + } + } + + return -ENOTSUP; +} + +#if ZMK_KEYMAP_HAS_SENSORS +int zmk_keymap_sensor_event(uint8_t sensor_index, + const struct zmk_sensor_channel_data *channel_data, + size_t channel_data_size, int64_t timestamp) { + bool opaque_response = false; + + for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= 0; layer--) { + struct zmk_behavior_binding *binding = &zmk_sensor_keymap[layer][sensor_index]; + + LOG_DBG("layer: %d sensor_index: %d, binding name: %s", layer, sensor_index, + binding->behavior_dev); + + const struct device *behavior = zmk_behavior_get_binding(binding->behavior_dev); + if (!behavior) { + LOG_DBG("No behavior assigned to %d on layer %d", sensor_index, layer); + continue; + } + + struct zmk_behavior_binding_event event = { + .layer = layer, + .position = ZMK_VIRTUAL_KEY_POSITION_SENSOR(sensor_index), + .timestamp = timestamp, + }; + + int ret = behavior_sensor_keymap_binding_accept_data( + binding, event, zmk_sensors_get_config_at_index(sensor_index), channel_data_size, + channel_data); + + if (ret < 0) { + LOG_WRN("behavior data accept for behavior %s returned an error (%d). Processing to " + "continue to next layer", + binding->behavior_dev, ret); + continue; + } + + enum behavior_sensor_binding_process_mode mode = + (!opaque_response && layer >= _zmk_keymap_layer_default && + zmk_keymap_layer_active(layer)) + ? BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_TRIGGER + : BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_DISCARD; + + ret = behavior_sensor_keymap_binding_process(binding, event, mode); + + if (ret == ZMK_BEHAVIOR_OPAQUE) { + LOG_DBG("sensor event processing complete, behavior response was opaque"); + opaque_response = true; + } else if (ret < 0) { + LOG_DBG("Behavior returned error: %d", ret); + return ret; + } + } + + return 0; +} + +#endif /* ZMK_KEYMAP_HAS_SENSORS */ + +int keymap_listener(const zmk_event_t *eh) { + const struct zmk_position_state_changed *pos_ev; + if ((pos_ev = as_zmk_position_state_changed(eh)) != NULL) { + return zmk_keymap_position_state_changed(pos_ev->source, pos_ev->position, pos_ev->state, + pos_ev->timestamp); + } + +#if ZMK_KEYMAP_HAS_SENSORS + const struct zmk_sensor_event *sensor_ev; + if ((sensor_ev = as_zmk_sensor_event(eh)) != NULL) { + return zmk_keymap_sensor_event(sensor_ev->sensor_index, sensor_ev->channel_data, + sensor_ev->channel_data_size, sensor_ev->timestamp); + } +#endif /* ZMK_KEYMAP_HAS_SENSORS */ + + return -ENOTSUP; +} + +ZMK_LISTENER(keymap, keymap_listener); +ZMK_SUBSCRIPTION(keymap, zmk_position_state_changed); + +#if ZMK_KEYMAP_HAS_SENSORS +ZMK_SUBSCRIPTION(keymap, zmk_sensor_event); +#endif /* ZMK_KEYMAP_HAS_SENSORS */ diff --git a/app/src/kscan.c b/app/src/kscan.c new file mode 100644 index 000000000000..62d0cf0756e0 --- /dev/null +++ b/app/src/kscan.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include + +#define ZMK_KSCAN_EVENT_STATE_PRESSED 0 +#define ZMK_KSCAN_EVENT_STATE_RELEASED 1 + +struct zmk_kscan_event { + uint32_t row; + uint32_t column; + uint32_t state; +}; + +struct zmk_kscan_msg_processor { + struct k_work work; +} msg_processor; + +K_MSGQ_DEFINE(zmk_kscan_msgq, sizeof(struct zmk_kscan_event), CONFIG_ZMK_KSCAN_EVENT_QUEUE_SIZE, 4); + +static void zmk_kscan_callback(const struct device *dev, uint32_t row, uint32_t column, + bool pressed) { + struct zmk_kscan_event ev = { + .row = row, + .column = column, + .state = (pressed ? ZMK_KSCAN_EVENT_STATE_PRESSED : ZMK_KSCAN_EVENT_STATE_RELEASED)}; + + k_msgq_put(&zmk_kscan_msgq, &ev, K_NO_WAIT); + k_work_submit(&msg_processor.work); +} + +void zmk_kscan_process_msgq(struct k_work *item) { + struct zmk_kscan_event ev; + + while (k_msgq_get(&zmk_kscan_msgq, &ev, K_NO_WAIT) == 0) { + bool pressed = (ev.state == ZMK_KSCAN_EVENT_STATE_PRESSED); + int32_t position = zmk_matrix_transform_row_column_to_position(ev.row, ev.column); + + if (position < 0) { + LOG_WRN("Not found in transform: row: %d, col: %d, pressed: %s", ev.row, ev.column, + (pressed ? "true" : "false")); + continue; + } + + LOG_DBG("Row: %d, col: %d, position: %d, pressed: %s", ev.row, ev.column, position, + (pressed ? "true" : "false")); + ZMK_EVENT_RAISE(new_zmk_position_state_changed( + (struct zmk_position_state_changed){.source = ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL, + .state = pressed, + .position = position, + .timestamp = k_uptime_get()})); + } +} + +int zmk_kscan_init(const struct device *dev) { + if (dev == NULL) { + LOG_ERR("Failed to get the KSCAN device"); + return -EINVAL; + } + + k_work_init(&msg_processor.work, zmk_kscan_process_msgq); + + kscan_config(dev, zmk_kscan_callback); + kscan_enable_callback(dev); + + return 0; +} diff --git a/app/src/main.c b/app/src/main.c new file mode 100644 index 000000000000..3fd6b116608f --- /dev/null +++ b/app/src/main.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include + +void main(void) { + LOG_INF("Welcome to ZMK!\n"); + + if (zmk_kscan_init(DEVICE_DT_GET(ZMK_MATRIX_NODE_ID)) != 0) { + return; + } + +#ifdef CONFIG_ZMK_DISPLAY + zmk_display_init(); +#endif /* CONFIG_ZMK_DISPLAY */ +} diff --git a/app/src/matrix_transform.c b/app/src/matrix_transform.c new file mode 100644 index 000000000000..6c616d5e8240 --- /dev/null +++ b/app/src/matrix_transform.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +#ifdef ZMK_KEYMAP_TRANSFORM_NODE + +/* the transform in the device tree is a list of (row,column) pairs that is + * indexed by by the keymap position of that key. We want to invert this in + * order to be able to quickly determine what keymap position a particular + * row,column pair is associated with, using a single lookup. + * + * We do this by creating the `transform` array at compile time, which is + * indexed by (row * ZMK_MATRIX_COLS) + column, and the value contains an + * encoded keymap index it is associated with. The keymap index is encoded + * by adding INDEX_OFFSET to it, because not all row,column pairs have an + * associated keymap index (some matrices are sparse), C globals are + * initialized to 0, and the keymap index of 0 is a valid index. We want to + * be able to detect the condition when an unassigned matrix position is + * pressed and we want to return an error. + */ + +#define INDEX_OFFSET 1 + +#define TRANSFORM_ENTRY(i, _) \ + [(KT_ROW(DT_PROP_BY_IDX(ZMK_KEYMAP_TRANSFORM_NODE, map, i)) * ZMK_MATRIX_COLS) + \ + KT_COL(DT_PROP_BY_IDX(ZMK_KEYMAP_TRANSFORM_NODE, map, i))] = i + INDEX_OFFSET + +static uint32_t transform[] = {LISTIFY(ZMK_KEYMAP_LEN, TRANSFORM_ENTRY, (, ), 0)}; + +#endif + +int32_t zmk_matrix_transform_row_column_to_position(uint32_t row, uint32_t column) { +#if DT_NODE_HAS_PROP(ZMK_KEYMAP_TRANSFORM_NODE, col_offset) + column += DT_PROP(ZMK_KEYMAP_TRANSFORM_NODE, col_offset); +#endif + +#if DT_NODE_HAS_PROP(ZMK_KEYMAP_TRANSFORM_NODE, row_offset) + row += DT_PROP(ZMK_KEYMAP_TRANSFORM_NODE, row_offset); +#endif + + const uint32_t matrix_index = (row * ZMK_MATRIX_COLS) + column; + +#ifdef ZMK_KEYMAP_TRANSFORM_NODE + if (matrix_index >= ARRAY_SIZE(transform)) { + return -EINVAL; + } + + const uint32_t value = transform[matrix_index]; + + if (!value) { + return -EINVAL; + } + + return value - INDEX_OFFSET; +#else + return matrix_index; +#endif /* ZMK_KEYMAP_TRANSFORM_NODE */ +}; diff --git a/app/src/mouse.c b/app/src/mouse.c new file mode 100644 index 000000000000..c1b9ac0261e2 --- /dev/null +++ b/app/src/mouse.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include + +static void listener_mouse_button_pressed(const struct zmk_mouse_button_state_changed *ev) { + LOG_DBG("buttons: 0x%02X", ev->buttons); + zmk_hid_mouse_buttons_press(ev->buttons); + zmk_endpoints_send_mouse_report(); +} + +static void listener_mouse_button_released(const struct zmk_mouse_button_state_changed *ev) { + LOG_DBG("buttons: 0x%02X", ev->buttons); + zmk_hid_mouse_buttons_release(ev->buttons); + zmk_endpoints_send_mouse_report(); +} + +int mouse_listener(const zmk_event_t *eh) { + const struct zmk_mouse_button_state_changed *mbt_ev = as_zmk_mouse_button_state_changed(eh); + if (mbt_ev) { + if (mbt_ev->state) { + listener_mouse_button_pressed(mbt_ev); + } else { + listener_mouse_button_released(mbt_ev); + } + return 0; + } + return 0; +} + +ZMK_LISTENER(mouse_listener, mouse_listener); +ZMK_SUBSCRIPTION(mouse_listener, zmk_mouse_button_state_changed); diff --git a/app/src/rgb_underglow.c b/app/src/rgb_underglow.c new file mode 100644 index 000000000000..9d4f2cf1cab3 --- /dev/null +++ b/app/src/rgb_underglow.c @@ -0,0 +1,518 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if !DT_HAS_CHOSEN(zmk_underglow) + +#error "A zmk,underglow chosen node must be declared" + +#endif + +#define STRIP_CHOSEN DT_CHOSEN(zmk_underglow) +#define STRIP_NUM_PIXELS DT_PROP(STRIP_CHOSEN, chain_length) + +#define HUE_MAX 360 +#define SAT_MAX 100 +#define BRT_MAX 100 + +BUILD_ASSERT(CONFIG_ZMK_RGB_UNDERGLOW_BRT_MIN <= CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX, + "ERROR: RGB underglow maximum brightness is less than minimum brightness"); + +enum rgb_underglow_effect { + UNDERGLOW_EFFECT_SOLID, + UNDERGLOW_EFFECT_BREATHE, + UNDERGLOW_EFFECT_SPECTRUM, + UNDERGLOW_EFFECT_SWIRL, + UNDERGLOW_EFFECT_NUMBER // Used to track number of underglow effects +}; + +struct rgb_underglow_state { + struct zmk_led_hsb color; + uint8_t animation_speed; + uint8_t current_effect; + uint16_t animation_step; + bool on; +}; + +static const struct device *led_strip; + +static struct led_rgb pixels[STRIP_NUM_PIXELS]; + +static struct rgb_underglow_state state; + +#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER) +static const struct device *const ext_power = DEVICE_DT_GET(DT_INST(0, zmk_ext_power_generic)); +#endif + +static struct zmk_led_hsb hsb_scale_min_max(struct zmk_led_hsb hsb) { + hsb.b = CONFIG_ZMK_RGB_UNDERGLOW_BRT_MIN + + (CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX - CONFIG_ZMK_RGB_UNDERGLOW_BRT_MIN) * hsb.b / BRT_MAX; + return hsb; +} + +static struct zmk_led_hsb hsb_scale_zero_max(struct zmk_led_hsb hsb) { + hsb.b = hsb.b * CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX / BRT_MAX; + return hsb; +} + +static struct led_rgb hsb_to_rgb(struct zmk_led_hsb hsb) { + float r, g, b; + + uint8_t i = hsb.h / 60; + float v = hsb.b / ((float)BRT_MAX); + float s = hsb.s / ((float)SAT_MAX); + float f = hsb.h / ((float)HUE_MAX) * 6 - i; + float p = v * (1 - s); + float q = v * (1 - f * s); + float t = v * (1 - (1 - f) * s); + + switch (i % 6) { + case 0: + r = v; + g = t; + b = p; + break; + case 1: + r = q; + g = v; + b = p; + break; + case 2: + r = p; + g = v; + b = t; + break; + case 3: + r = p; + g = q; + b = v; + break; + case 4: + r = t; + g = p; + b = v; + break; + case 5: + r = v; + g = p; + b = q; + break; + } + + struct led_rgb rgb = {r : r * 255, g : g * 255, b : b * 255}; + + return rgb; +} + +static void zmk_rgb_underglow_effect_solid() { + for (int i = 0; i < STRIP_NUM_PIXELS; i++) { + pixels[i] = hsb_to_rgb(hsb_scale_min_max(state.color)); + } +} + +static void zmk_rgb_underglow_effect_breathe() { + for (int i = 0; i < STRIP_NUM_PIXELS; i++) { + struct zmk_led_hsb hsb = state.color; + hsb.b = abs(state.animation_step - 1200) / 12; + + pixels[i] = hsb_to_rgb(hsb_scale_zero_max(hsb)); + } + + state.animation_step += state.animation_speed * 10; + + if (state.animation_step > 2400) { + state.animation_step = 0; + } +} + +static void zmk_rgb_underglow_effect_spectrum() { + for (int i = 0; i < STRIP_NUM_PIXELS; i++) { + struct zmk_led_hsb hsb = state.color; + hsb.h = state.animation_step; + + pixels[i] = hsb_to_rgb(hsb_scale_min_max(hsb)); + } + + state.animation_step += state.animation_speed; + state.animation_step = state.animation_step % HUE_MAX; +} + +static void zmk_rgb_underglow_effect_swirl() { + for (int i = 0; i < STRIP_NUM_PIXELS; i++) { + struct zmk_led_hsb hsb = state.color; + hsb.h = (HUE_MAX / STRIP_NUM_PIXELS * i + state.animation_step) % HUE_MAX; + + pixels[i] = hsb_to_rgb(hsb_scale_min_max(hsb)); + } + + state.animation_step += state.animation_speed * 2; + state.animation_step = state.animation_step % HUE_MAX; +} + +static void zmk_rgb_underglow_tick(struct k_work *work) { + switch (state.current_effect) { + case UNDERGLOW_EFFECT_SOLID: + zmk_rgb_underglow_effect_solid(); + break; + case UNDERGLOW_EFFECT_BREATHE: + zmk_rgb_underglow_effect_breathe(); + break; + case UNDERGLOW_EFFECT_SPECTRUM: + zmk_rgb_underglow_effect_spectrum(); + break; + case UNDERGLOW_EFFECT_SWIRL: + zmk_rgb_underglow_effect_swirl(); + break; + } + + int err = led_strip_update_rgb(led_strip, pixels, STRIP_NUM_PIXELS); + if (err < 0) { + LOG_ERR("Failed to update the RGB strip (%d)", err); + } +} + +K_WORK_DEFINE(underglow_tick_work, zmk_rgb_underglow_tick); + +static void zmk_rgb_underglow_tick_handler(struct k_timer *timer) { + if (!state.on) { + return; + } + + k_work_submit_to_queue(zmk_workqueue_lowprio_work_q(), &underglow_tick_work); +} + +K_TIMER_DEFINE(underglow_tick, zmk_rgb_underglow_tick_handler, NULL); + +#if IS_ENABLED(CONFIG_SETTINGS) +static int rgb_settings_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) { + const char *next; + int rc; + + if (settings_name_steq(name, "state", &next) && !next) { + if (len != sizeof(state)) { + return -EINVAL; + } + + rc = read_cb(cb_arg, &state, sizeof(state)); + if (rc >= 0) { + return 0; + } + + return rc; + } + + return -ENOENT; +} + +struct settings_handler rgb_conf = {.name = "rgb/underglow", .h_set = rgb_settings_set}; + +static void zmk_rgb_underglow_save_state_work() { + settings_save_one("rgb/underglow/state", &state, sizeof(state)); +} + +static struct k_work_delayable underglow_save_work; +#endif + +static int zmk_rgb_underglow_init(const struct device *_arg) { + led_strip = DEVICE_DT_GET(STRIP_CHOSEN); + +#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER) + if (!device_is_ready(ext_power)) { + LOG_ERR("External power device \"%s\" is not ready", ext_power->name); + return -ENODEV; + } +#endif + + state = (struct rgb_underglow_state){ + color : { + h : CONFIG_ZMK_RGB_UNDERGLOW_HUE_START, + s : CONFIG_ZMK_RGB_UNDERGLOW_SAT_START, + b : CONFIG_ZMK_RGB_UNDERGLOW_BRT_START, + }, + animation_speed : CONFIG_ZMK_RGB_UNDERGLOW_SPD_START, + current_effect : CONFIG_ZMK_RGB_UNDERGLOW_EFF_START, + animation_step : 0, + on : IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_ON_START) + }; + +#if IS_ENABLED(CONFIG_SETTINGS) + settings_subsys_init(); + + int err = settings_register(&rgb_conf); + if (err) { + LOG_ERR("Failed to register the ext_power settings handler (err %d)", err); + return err; + } + + k_work_init_delayable(&underglow_save_work, zmk_rgb_underglow_save_state_work); + + settings_load_subtree("rgb/underglow"); +#endif + +#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_USB) + state.on = zmk_usb_is_powered(); +#endif + + if (state.on) { + k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(50)); + } + + return 0; +} + +int zmk_rgb_underglow_save_state() { +#if IS_ENABLED(CONFIG_SETTINGS) + int ret = k_work_reschedule(&underglow_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE)); + return MIN(ret, 0); +#else + return 0; +#endif +} + +int zmk_rgb_underglow_get_state(bool *on_off) { + if (!led_strip) + return -ENODEV; + + *on_off = state.on; + return 0; +} + +int zmk_rgb_underglow_on() { + if (!led_strip) + return -ENODEV; + +#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER) + if (ext_power != NULL) { + int rc = ext_power_enable(ext_power); + if (rc != 0) { + LOG_ERR("Unable to enable EXT_POWER: %d", rc); + } + } +#endif + + state.on = true; + state.animation_step = 0; + k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(50)); + + return zmk_rgb_underglow_save_state(); +} + +static void zmk_rgb_underglow_off_handler(struct k_work *work) { + for (int i = 0; i < STRIP_NUM_PIXELS; i++) { + pixels[i] = (struct led_rgb){r : 0, g : 0, b : 0}; + } + + led_strip_update_rgb(led_strip, pixels, STRIP_NUM_PIXELS); +} + +K_WORK_DEFINE(underglow_off_work, zmk_rgb_underglow_off_handler); + +int zmk_rgb_underglow_off() { + if (!led_strip) + return -ENODEV; + +#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER) + if (ext_power != NULL) { + int rc = ext_power_disable(ext_power); + if (rc != 0) { + LOG_ERR("Unable to disable EXT_POWER: %d", rc); + } + } +#endif + + k_work_submit_to_queue(zmk_workqueue_lowprio_work_q(), &underglow_off_work); + + k_timer_stop(&underglow_tick); + state.on = false; + + return zmk_rgb_underglow_save_state(); +} + +int zmk_rgb_underglow_calc_effect(int direction) { + return (state.current_effect + UNDERGLOW_EFFECT_NUMBER + direction) % UNDERGLOW_EFFECT_NUMBER; +} + +int zmk_rgb_underglow_select_effect(int effect) { + if (!led_strip) + return -ENODEV; + + if (effect < 0 || effect >= UNDERGLOW_EFFECT_NUMBER) { + return -EINVAL; + } + + state.current_effect = effect; + state.animation_step = 0; + + return zmk_rgb_underglow_save_state(); +} + +int zmk_rgb_underglow_cycle_effect(int direction) { + return zmk_rgb_underglow_select_effect(zmk_rgb_underglow_calc_effect(direction)); +} + +int zmk_rgb_underglow_toggle() { + return state.on ? zmk_rgb_underglow_off() : zmk_rgb_underglow_on(); +} + +int zmk_rgb_underglow_set_hsb(struct zmk_led_hsb color) { + if (color.h > HUE_MAX || color.s > SAT_MAX || color.b > BRT_MAX) { + return -ENOTSUP; + } + + state.color = color; + + return 0; +} + +struct zmk_led_hsb zmk_rgb_underglow_calc_hue(int direction) { + struct zmk_led_hsb color = state.color; + + color.h += HUE_MAX + (direction * CONFIG_ZMK_RGB_UNDERGLOW_HUE_STEP); + color.h %= HUE_MAX; + + return color; +} + +struct zmk_led_hsb zmk_rgb_underglow_calc_sat(int direction) { + struct zmk_led_hsb color = state.color; + + int s = color.s + (direction * CONFIG_ZMK_RGB_UNDERGLOW_SAT_STEP); + if (s < 0) { + s = 0; + } else if (s > SAT_MAX) { + s = SAT_MAX; + } + color.s = s; + + return color; +} + +struct zmk_led_hsb zmk_rgb_underglow_calc_brt(int direction) { + struct zmk_led_hsb color = state.color; + + int b = color.b + (direction * CONFIG_ZMK_RGB_UNDERGLOW_BRT_STEP); + color.b = CLAMP(b, 0, BRT_MAX); + + return color; +} + +int zmk_rgb_underglow_change_hue(int direction) { + if (!led_strip) + return -ENODEV; + + state.color = zmk_rgb_underglow_calc_hue(direction); + + return zmk_rgb_underglow_save_state(); +} + +int zmk_rgb_underglow_change_sat(int direction) { + if (!led_strip) + return -ENODEV; + + state.color = zmk_rgb_underglow_calc_sat(direction); + + return zmk_rgb_underglow_save_state(); +} + +int zmk_rgb_underglow_change_brt(int direction) { + if (!led_strip) + return -ENODEV; + + state.color = zmk_rgb_underglow_calc_brt(direction); + + return zmk_rgb_underglow_save_state(); +} + +int zmk_rgb_underglow_change_spd(int direction) { + if (!led_strip) + return -ENODEV; + + if (state.animation_speed == 1 && direction < 0) { + return 0; + } + + state.animation_speed += direction; + + if (state.animation_speed > 5) { + state.animation_speed = 5; + } + + return zmk_rgb_underglow_save_state(); +} + +#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE) || \ + IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_USB) +static int rgb_underglow_auto_state(bool *prev_state, bool new_state) { + if (state.on == new_state) { + return 0; + } + if (new_state) { + state.on = *prev_state; + *prev_state = false; + return zmk_rgb_underglow_on(); + } else { + state.on = false; + *prev_state = true; + return zmk_rgb_underglow_off(); + } +} + +static int rgb_underglow_event_listener(const zmk_event_t *eh) { + +#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE) + if (as_zmk_activity_state_changed(eh)) { + static bool prev_state = false; + return rgb_underglow_auto_state(&prev_state, + zmk_activity_get_state() == ZMK_ACTIVITY_ACTIVE); + } +#endif + +#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_USB) + if (as_zmk_usb_conn_state_changed(eh)) { + static bool prev_state = false; + return rgb_underglow_auto_state(&prev_state, zmk_usb_is_powered()); + } +#endif + + return -ENOTSUP; +} + +ZMK_LISTENER(rgb_underglow, rgb_underglow_event_listener); +#endif // IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE) || + // IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_USB) + +#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE) +ZMK_SUBSCRIPTION(rgb_underglow, zmk_activity_state_changed); +#endif + +#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_USB) +ZMK_SUBSCRIPTION(rgb_underglow, zmk_usb_conn_state_changed); +#endif + +SYS_INIT(zmk_rgb_underglow_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/app/src/sensors.c b/app/src/sensors.c new file mode 100644 index 000000000000..60f2bd2a33f8 --- /dev/null +++ b/app/src/sensors.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include + +#if ZMK_KEYMAP_HAS_SENSORS + +struct sensors_item_cfg { + const struct zmk_sensor_config *config; + const struct device *dev; + struct sensor_trigger trigger; + uint8_t sensor_index; +}; + +#define _SENSOR_ITEM(idx, node) \ + { \ + .dev = DEVICE_DT_GET_OR_NULL(node), \ + .trigger = {.type = SENSOR_TRIG_DATA_READY, .chan = SENSOR_CHAN_ROTATION}, \ + .config = &configs[idx], .sensor_index = idx \ + } +#define SENSOR_ITEM(idx, _i) _SENSOR_ITEM(idx, ZMK_KEYMAP_SENSORS_BY_IDX(idx)) + +#define PLUS_ONE(n) +1 +#define ZMK_KEYMAP_SENSORS_CHILD_COUNT (0 DT_FOREACH_CHILD(ZMK_KEYMAP_SENSORS_NODE, PLUS_ONE)) +#define SENSOR_CHILD_ITEM(node) \ + { \ + .triggers_per_rotation = \ + DT_PROP_OR(node, triggers_per_rotation, \ + DT_PROP_OR(ZMK_KEYMAP_SENSORS_NODE, triggers_per_rotation, \ + CONFIG_ZMK_KEYMAP_SENSORS_DEFAULT_TRIGGERS_PER_ROTATION)) \ + } +#define SENSOR_CHILD_DEFAULTS(idx, arg) \ + { \ + .triggers_per_rotation = \ + DT_PROP_OR(ZMK_KEYMAP_SENSORS_NODE, triggers_per_rotation, \ + CONFIG_ZMK_KEYMAP_SENSORS_DEFAULT_TRIGGERS_PER_ROTATION) \ + } + +static struct zmk_sensor_config configs[] = { +#if ZMK_KEYMAP_SENSORS_CHILD_COUNT > 0 + DT_FOREACH_CHILD_SEP(ZMK_KEYMAP_SENSORS_NODE, SENSOR_CHILD_ITEM, (, )) +#else + LISTIFY(ZMK_KEYMAP_SENSORS_LEN, SENSOR_CHILD_DEFAULTS, (, ), 0) +#endif +}; + +static struct sensors_item_cfg sensors[] = {LISTIFY(ZMK_KEYMAP_SENSORS_LEN, SENSOR_ITEM, (, ), 0)}; + +static ATOMIC_DEFINE(pending_sensors, ZMK_KEYMAP_SENSORS_LEN); + +const struct zmk_sensor_config *zmk_sensors_get_config_at_index(uint8_t sensor_index) { + if (sensor_index > ARRAY_SIZE(configs)) { + return NULL; + } + + return &configs[sensor_index]; +} + +static void trigger_sensor_data_for_position(uint32_t sensor_index) { + int err; + const struct sensors_item_cfg *item = &sensors[sensor_index]; + + err = sensor_sample_fetch(item->dev); + if (err) { + LOG_WRN("Failed to fetch sample from device %d", err); + return; + } + + struct sensor_value value; + err = sensor_channel_get(item->dev, item->trigger.chan, &value); + + if (err) { + LOG_WRN("Failed to get channel data from device %d", err); + return; + } + + ZMK_EVENT_RAISE(new_zmk_sensor_event( + (struct zmk_sensor_event){.sensor_index = item->sensor_index, + .channel_data_size = 1, + .channel_data = {(struct zmk_sensor_channel_data){ + .value = value, .channel = item->trigger.chan}}, + .timestamp = k_uptime_get()})); +} + +static void run_sensors_data_trigger(struct k_work *work) { + for (int i = 0; i < ARRAY_SIZE(sensors); i++) { + if (atomic_test_and_clear_bit(pending_sensors, i)) { + trigger_sensor_data_for_position(i); + } + } +} + +K_WORK_DEFINE(sensor_data_work, run_sensors_data_trigger); + +static void zmk_sensors_trigger_handler(const struct device *dev, + const struct sensor_trigger *trigger) { + const struct sensors_item_cfg *test_item = + CONTAINER_OF(trigger, struct sensors_item_cfg, trigger); + int sensor_index = test_item - sensors; + + if (sensor_index < 0 || sensor_index >= ARRAY_SIZE(sensors)) { + LOG_ERR("Invalid sensor item triggered our callback (%d)", sensor_index); + return; + } + + if (k_is_in_isr()) { + atomic_set_bit(pending_sensors, sensor_index); + k_work_submit(&sensor_data_work); + } else { + trigger_sensor_data_for_position(sensor_index); + } +} + +static void zmk_sensors_init_item(uint8_t i) { + LOG_DBG("Init sensor at index %d", i); + + if (!sensors[i].dev) { + LOG_DBG("No local device for %d", i); + return; + } + + int err = sensor_trigger_set(sensors[i].dev, &sensors[i].trigger, zmk_sensors_trigger_handler); + if (err) { + LOG_WRN("Failed to set sensor trigger (%d)", err); + } +} + +#define SENSOR_INIT(idx, _t) zmk_sensors_init_item(idx); + +static int zmk_sensors_init(const struct device *_arg) { + LISTIFY(ZMK_KEYMAP_SENSORS_LEN, SENSOR_INIT, (), 0) + + return 0; +} + +SYS_INIT(zmk_sensors_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); + +#endif /* ZMK_KEYMAP_HAS_SENSORS */ diff --git a/app/src/split/CMakeLists.txt b/app/src/split/CMakeLists.txt new file mode 100644 index 000000000000..27abb82ad064 --- /dev/null +++ b/app/src/split/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if (CONFIG_ZMK_SPLIT_BLE) + add_subdirectory(bluetooth) +endif() \ No newline at end of file diff --git a/app/src/split/Kconfig b/app/src/split/Kconfig new file mode 100644 index 000000000000..1134937056f1 --- /dev/null +++ b/app/src/split/Kconfig @@ -0,0 +1,32 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +menuconfig ZMK_SPLIT + bool "Split keyboard support" + +if ZMK_SPLIT + +config ZMK_SPLIT_ROLE_CENTRAL + bool "Split central device" + +choice ZMK_SPLIT_TRANSPORT + prompt "Split transport" + +config ZMK_SPLIT_BLE + bool "BLE" + depends on ZMK_BLE + select BT_USER_PHY_UPDATE + select BT_AUTO_PHY_UPDATE + +endchoice + +config ZMK_SPLIT_PERIPHERAL_HID_INDICATORS + bool "Peripheral HID Indicators" + depends on ZMK_HID_INDICATORS + help + Enable propogating the HID (LED) Indicator state to the split peripheral(s). + +#ZMK_SPLIT +endif + +rsource "bluetooth/Kconfig" diff --git a/app/src/split/bluetooth/CMakeLists.txt b/app/src/split/bluetooth/CMakeLists.txt new file mode 100644 index 000000000000..241a9b8d8c09 --- /dev/null +++ b/app/src/split/bluetooth/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if (NOT CONFIG_ZMK_SPLIT_ROLE_CENTRAL) + target_sources(app PRIVATE split_listener.c) + target_sources(app PRIVATE service.c) + target_sources(app PRIVATE peripheral.c) +endif() +if (CONFIG_ZMK_SPLIT_ROLE_CENTRAL) + target_sources(app PRIVATE central.c) +endif() \ No newline at end of file diff --git a/app/src/split/bluetooth/Kconfig b/app/src/split/bluetooth/Kconfig new file mode 100644 index 000000000000..858e7308fefc --- /dev/null +++ b/app/src/split/bluetooth/Kconfig @@ -0,0 +1,110 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if ZMK_SPLIT && ZMK_SPLIT_BLE + +menu "BLE Transport" + +# Added for backwards compatibility. New shields/board should set `ZMK_SPLIT_ROLE_CENTRAL` only. +config ZMK_SPLIT_BLE_ROLE_CENTRAL + bool + select ZMK_SPLIT_ROLE_CENTRAL + +config ZMK_SPLIT_ROLE_CENTRAL + select BT_CENTRAL + select BT_GATT_CLIENT + select BT_GATT_AUTO_DISCOVER_CCC + select BT_SCAN_WITH_IDENTITY + +if ZMK_SPLIT_ROLE_CENTRAL + +config ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS + int "Number of peripherals that will connect to the central." + default 1 + +config ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE + int "Max number of key position state events to queue when received from peripherals" + default 5 + +config ZMK_SPLIT_BLE_CENTRAL_SPLIT_RUN_STACK_SIZE + int "BLE split central write thread stack size" + default 512 + +config ZMK_SPLIT_BLE_CENTRAL_SPLIT_RUN_QUEUE_SIZE + int "Max number of behavior run events to queue to send to the peripheral(s)" + default 5 + +config ZMK_SPLIT_BLE_PREF_INT + int "Connection interval to use for split central/peripheral connection" + default 6 + +config ZMK_SPLIT_BLE_PREF_LATENCY + int "Latency to use for split central/peripheral connection" + default 30 + +config ZMK_SPLIT_BLE_PREF_TIMEOUT + int "Supervision timeout to use for split central/peripheral connection" + default 400 + +endif # ZMK_SPLIT_ROLE_CENTRAL + +if !ZMK_SPLIT_ROLE_CENTRAL + +config ZMK_SPLIT_BLE_PERIPHERAL_STACK_SIZE + int "BLE split peripheral notify thread stack size" + default 650 + +config ZMK_SPLIT_BLE_PERIPHERAL_PRIORITY + int "BLE split peripheral notify thread priority" + default 5 + +config ZMK_SPLIT_BLE_PERIPHERAL_POSITION_QUEUE_SIZE + int "Max number of key position state events to queue to send to the central" + default 10 + +config BT_MAX_PAIRED + default 1 + +config BT_MAX_CONN + default 1 + +# Allow central to specify connection parameters. +config BT_GAP_AUTO_UPDATE_CONN_PARAMS + default n + +#!ZMK_SPLIT_ROLE_CENTRAL +endif + +endmenu + +#ZMK_SPLIT_BLE +endif + + +if ZMK_BLE + +if ZMK_SPLIT_BLE && ZMK_SPLIT_ROLE_CENTRAL + +config BT_MAX_CONN + default 6 + +config BT_MAX_PAIRED + default 6 + +#ZMK_SPLIT_BLE && ZMK_SPLIT_ROLE_CENTRAL +endif + +if !ZMK_SPLIT_BLE + +config BT_MAX_CONN + default 5 + +config BT_MAX_PAIRED + default 5 + +#!ZMK_SPLIT_BLE +endif + +#ZMK_BLE +endif + diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c new file mode 100644 index 000000000000..3635322431c2 --- /dev/null +++ b/app/src/split/bluetooth/central.c @@ -0,0 +1,753 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int start_scanning(void); + +#define POSITION_STATE_DATA_LEN 16 + +enum peripheral_slot_state { + PERIPHERAL_SLOT_STATE_OPEN, + PERIPHERAL_SLOT_STATE_CONNECTING, + PERIPHERAL_SLOT_STATE_CONNECTED, +}; + +struct peripheral_slot { + enum peripheral_slot_state state; + struct bt_conn *conn; + struct bt_gatt_discover_params discover_params; + struct bt_gatt_subscribe_params subscribe_params; + struct bt_gatt_subscribe_params sensor_subscribe_params; + struct bt_gatt_discover_params sub_discover_params; + uint16_t run_behavior_handle; +#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) + uint16_t update_hid_indicators; +#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) + uint8_t position_state[POSITION_STATE_DATA_LEN]; + uint8_t changed_positions[POSITION_STATE_DATA_LEN]; +}; + +static struct peripheral_slot peripherals[ZMK_SPLIT_BLE_PERIPHERAL_COUNT]; + +static bool is_scanning = false; + +static const struct bt_uuid_128 split_service_uuid = BT_UUID_INIT_128(ZMK_SPLIT_BT_SERVICE_UUID); + +K_MSGQ_DEFINE(peripheral_event_msgq, sizeof(struct zmk_position_state_changed), + CONFIG_ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE, 4); + +void peripheral_event_work_callback(struct k_work *work) { + struct zmk_position_state_changed ev; + while (k_msgq_get(&peripheral_event_msgq, &ev, K_NO_WAIT) == 0) { + LOG_DBG("Trigger key position state change for %d", ev.position); + ZMK_EVENT_RAISE(new_zmk_position_state_changed(ev)); + } +} + +K_WORK_DEFINE(peripheral_event_work, peripheral_event_work_callback); + +int peripheral_slot_index_for_conn(struct bt_conn *conn) { + for (int i = 0; i < ZMK_SPLIT_BLE_PERIPHERAL_COUNT; i++) { + if (peripherals[i].conn == conn) { + return i; + } + } + + return -EINVAL; +} + +struct peripheral_slot *peripheral_slot_for_conn(struct bt_conn *conn) { + int idx = peripheral_slot_index_for_conn(conn); + if (idx < 0) { + return NULL; + } + + return &peripherals[idx]; +} + +int release_peripheral_slot(int index) { + if (index < 0 || index >= ZMK_SPLIT_BLE_PERIPHERAL_COUNT) { + return -EINVAL; + } + + struct peripheral_slot *slot = &peripherals[index]; + + if (slot->state == PERIPHERAL_SLOT_STATE_OPEN) { + return -EINVAL; + } + + LOG_DBG("Releasing peripheral slot at %d", index); + + if (slot->conn != NULL) { + bt_conn_unref(slot->conn); + slot->conn = NULL; + } + slot->state = PERIPHERAL_SLOT_STATE_OPEN; + + // Raise events releasing any active positions from this peripheral + for (int i = 0; i < POSITION_STATE_DATA_LEN; i++) { + for (int j = 0; j < 8; j++) { + if (slot->position_state[i] & BIT(j)) { + uint32_t position = (i * 8) + j; + struct zmk_position_state_changed ev = {.source = index, + .position = position, + .state = false, + .timestamp = k_uptime_get()}; + + k_msgq_put(&peripheral_event_msgq, &ev, K_NO_WAIT); + k_work_submit(&peripheral_event_work); + } + } + } + + for (int i = 0; i < POSITION_STATE_DATA_LEN; i++) { + slot->position_state[i] = 0U; + slot->changed_positions[i] = 0U; + } + + // Clean up previously discovered handles; + slot->subscribe_params.value_handle = 0; + slot->run_behavior_handle = 0; +#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) + slot->update_hid_indicators = 0; +#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) + + return 0; +} + +int reserve_peripheral_slot(const bt_addr_le_t *addr) { + int i = zmk_ble_put_peripheral_addr(addr); + if (i >= 0) { + if (peripherals[i].state == PERIPHERAL_SLOT_STATE_OPEN) { + // Be sure the slot is fully reinitialized. + release_peripheral_slot(i); + peripherals[i].state = PERIPHERAL_SLOT_STATE_CONNECTING; + return i; + } + } + + return -ENOMEM; +} + +int release_peripheral_slot_for_conn(struct bt_conn *conn) { + int idx = peripheral_slot_index_for_conn(conn); + if (idx < 0) { + return idx; + } + + return release_peripheral_slot(idx); +} + +int confirm_peripheral_slot_conn(struct bt_conn *conn) { + int idx = peripheral_slot_index_for_conn(conn); + if (idx < 0) { + return idx; + } + + peripherals[idx].state = PERIPHERAL_SLOT_STATE_CONNECTED; + return 0; +} + +#if ZMK_KEYMAP_HAS_SENSORS +K_MSGQ_DEFINE(peripheral_sensor_event_msgq, sizeof(struct zmk_sensor_event), + CONFIG_ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE, 4); + +void peripheral_sensor_event_work_callback(struct k_work *work) { + struct zmk_sensor_event ev; + while (k_msgq_get(&peripheral_sensor_event_msgq, &ev, K_NO_WAIT) == 0) { + LOG_DBG("Trigger sensor change for %d", ev.sensor_index); + ZMK_EVENT_RAISE(new_zmk_sensor_event(ev)); + } +} + +K_WORK_DEFINE(peripheral_sensor_event_work, peripheral_sensor_event_work_callback); + +static uint8_t split_central_sensor_notify_func(struct bt_conn *conn, + struct bt_gatt_subscribe_params *params, + const void *data, uint16_t length) { + if (!data) { + LOG_DBG("[UNSUBSCRIBED]"); + params->value_handle = 0U; + return BT_GATT_ITER_STOP; + } + + LOG_DBG("[SENSOR NOTIFICATION] data %p length %u", data, length); + + if (length < offsetof(struct sensor_event, channel_data)) { + LOG_WRN("Ignoring sensor notify with insufficient data length (%d)", length); + return BT_GATT_ITER_STOP; + } + + struct sensor_event sensor_event; + memcpy(&sensor_event, data, MIN(length, sizeof(sensor_event))); + struct zmk_sensor_event ev = { + .sensor_index = sensor_event.sensor_index, + .channel_data_size = MIN(sensor_event.channel_data_size, ZMK_SENSOR_EVENT_MAX_CHANNELS), + .timestamp = k_uptime_get()}; + + memcpy(ev.channel_data, sensor_event.channel_data, + sizeof(struct zmk_sensor_channel_data) * sensor_event.channel_data_size); + k_msgq_put(&peripheral_sensor_event_msgq, &ev, K_NO_WAIT); + k_work_submit(&peripheral_sensor_event_work); + + return BT_GATT_ITER_CONTINUE; +} +#endif /* ZMK_KEYMAP_HAS_SENSORS */ + +static uint8_t split_central_notify_func(struct bt_conn *conn, + struct bt_gatt_subscribe_params *params, const void *data, + uint16_t length) { + struct peripheral_slot *slot = peripheral_slot_for_conn(conn); + + if (slot == NULL) { + LOG_ERR("No peripheral state found for connection"); + return BT_GATT_ITER_CONTINUE; + } + + if (!data) { + LOG_DBG("[UNSUBSCRIBED]"); + params->value_handle = 0U; + return BT_GATT_ITER_STOP; + } + + LOG_DBG("[NOTIFICATION] data %p length %u", data, length); + + for (int i = 0; i < POSITION_STATE_DATA_LEN; i++) { + slot->changed_positions[i] = ((uint8_t *)data)[i] ^ slot->position_state[i]; + slot->position_state[i] = ((uint8_t *)data)[i]; + LOG_DBG("data: %d", slot->position_state[i]); + } + + for (int i = 0; i < POSITION_STATE_DATA_LEN; i++) { + for (int j = 0; j < 8; j++) { + if (slot->changed_positions[i] & BIT(j)) { + uint32_t position = (i * 8) + j; + bool pressed = slot->position_state[i] & BIT(j); + struct zmk_position_state_changed ev = {.source = + peripheral_slot_index_for_conn(conn), + .position = position, + .state = pressed, + .timestamp = k_uptime_get()}; + + k_msgq_put(&peripheral_event_msgq, &ev, K_NO_WAIT); + k_work_submit(&peripheral_event_work); + } + } + } + + return BT_GATT_ITER_CONTINUE; +} + +static int split_central_subscribe(struct bt_conn *conn, struct bt_gatt_subscribe_params *params) { + int err = bt_gatt_subscribe(conn, params); + switch (err) { + case -EALREADY: + LOG_DBG("[ALREADY SUBSCRIBED]"); + break; + case 0: + LOG_DBG("[SUBSCRIBED]"); + break; + default: + LOG_ERR("Subscribe failed (err %d)", err); + break; + } + + return err; +} + +static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { + if (!attr) { + LOG_DBG("Discover complete"); + return BT_GATT_ITER_STOP; + } + + if (!attr->user_data) { + LOG_ERR("Required user data not passed to discovery"); + return BT_GATT_ITER_STOP; + } + + struct peripheral_slot *slot = peripheral_slot_for_conn(conn); + if (slot == NULL) { + LOG_ERR("No peripheral state found for connection"); + return BT_GATT_ITER_STOP; + } + + LOG_DBG("[ATTRIBUTE] handle %u", attr->handle); + const struct bt_uuid *chrc_uuid = ((struct bt_gatt_chrc *)attr->user_data)->uuid; + + if (bt_uuid_cmp(chrc_uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID)) == 0) { + LOG_DBG("Found position state characteristic"); + slot->discover_params.uuid = NULL; + slot->discover_params.start_handle = attr->handle + 2; + slot->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; + + slot->subscribe_params.disc_params = &slot->sub_discover_params; + slot->subscribe_params.end_handle = slot->discover_params.end_handle; + slot->subscribe_params.value_handle = bt_gatt_attr_value_handle(attr); + slot->subscribe_params.notify = split_central_notify_func; + slot->subscribe_params.value = BT_GATT_CCC_NOTIFY; + split_central_subscribe(conn, &slot->subscribe_params); +#if ZMK_KEYMAP_HAS_SENSORS + } else if (bt_uuid_cmp(chrc_uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_SENSOR_STATE_UUID)) == + 0) { + slot->discover_params.uuid = NULL; + slot->discover_params.start_handle = attr->handle + 2; + slot->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; + + slot->sensor_subscribe_params.disc_params = &slot->sub_discover_params; + slot->sensor_subscribe_params.end_handle = slot->discover_params.end_handle; + slot->sensor_subscribe_params.value_handle = bt_gatt_attr_value_handle(attr); + slot->sensor_subscribe_params.notify = split_central_sensor_notify_func; + slot->sensor_subscribe_params.value = BT_GATT_CCC_NOTIFY; + split_central_subscribe(conn, &slot->sensor_subscribe_params); +#endif /* ZMK_KEYMAP_HAS_SENSORS */ + } else if (bt_uuid_cmp(chrc_uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID)) == + 0) { + LOG_DBG("Found run behavior handle"); + slot->discover_params.uuid = NULL; + slot->discover_params.start_handle = attr->handle + 2; + slot->run_behavior_handle = bt_gatt_attr_value_handle(attr); +#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) + } else if (!bt_uuid_cmp(((struct bt_gatt_chrc *)attr->user_data)->uuid, + BT_UUID_DECLARE_128(ZMK_SPLIT_BT_UPDATE_HID_INDICATORS_UUID))) { + LOG_DBG("Found update HID indicators handle"); + slot->update_hid_indicators = bt_gatt_attr_value_handle(attr); +#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) + } + + bool subscribed = (slot->run_behavior_handle && slot->subscribe_params.value_handle); +#if ZMK_KEYMAP_HAS_SENSORS + subscribed = subscribed && slot->sensor_subscribe_params.value_handle; +#endif /* ZMK_KEYMAP_HAS_SENSORS */ + +#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) + subscribed = subscribed && slot->update_hid_indicators; +#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) + + return subscribed ? BT_GATT_ITER_STOP : BT_GATT_ITER_CONTINUE; +} + +static uint8_t split_central_service_discovery_func(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { + if (!attr) { + LOG_DBG("Discover complete"); + (void)memset(params, 0, sizeof(*params)); + return BT_GATT_ITER_STOP; + } + + LOG_DBG("[ATTRIBUTE] handle %u", attr->handle); + + struct peripheral_slot *slot = peripheral_slot_for_conn(conn); + if (slot == NULL) { + LOG_ERR("No peripheral state found for connection"); + return BT_GATT_ITER_STOP; + } + + if (bt_uuid_cmp(slot->discover_params.uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID)) != + 0) { + LOG_DBG("Found other service"); + return BT_GATT_ITER_CONTINUE; + } + + LOG_DBG("Found split service"); + slot->discover_params.uuid = NULL; + slot->discover_params.func = split_central_chrc_discovery_func; + slot->discover_params.start_handle = attr->handle + 1; + slot->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; + + int err = bt_gatt_discover(conn, &slot->discover_params); + if (err) { + LOG_ERR("Failed to start discovering split service characteristics (err %d)", err); + } + return BT_GATT_ITER_STOP; +} + +static void split_central_process_connection(struct bt_conn *conn) { + int err; + + LOG_DBG("Current security for connection: %d", bt_conn_get_security(conn)); + +#if !IS_ENABLED(CONFIG_BT_GATT_AUTO_SEC_REQ) + err = bt_conn_set_security(conn, BT_SECURITY_L2); + if (err) { + LOG_ERR("Failed to set security (reason %d)", err); + return; + } +#endif // !IS_ENABLED(CONFIG_BT_GATT_AUTO_SEC_REQ) + + struct peripheral_slot *slot = peripheral_slot_for_conn(conn); + if (slot == NULL) { + LOG_ERR("No peripheral state found for connection"); + return; + } + + if (!slot->subscribe_params.value_handle) { + slot->discover_params.uuid = &split_service_uuid.uuid; + slot->discover_params.func = split_central_service_discovery_func; + slot->discover_params.start_handle = 0x0001; + slot->discover_params.end_handle = 0xffff; + slot->discover_params.type = BT_GATT_DISCOVER_PRIMARY; + + err = bt_gatt_discover(slot->conn, &slot->discover_params); + if (err) { + LOG_ERR("Discover failed(err %d)", err); + return; + } + } + + struct bt_conn_info info; + + bt_conn_get_info(conn, &info); + + LOG_DBG("New connection params: Interval: %d, Latency: %d, PHY: %d", info.le.interval, + info.le.latency, info.le.phy->rx_phy); + + // Restart scanning if necessary. + start_scanning(); +} + +static int stop_scanning() { + LOG_DBG("Stopping peripheral scanning"); + is_scanning = false; + + int err = bt_le_scan_stop(); + if (err < 0) { + LOG_ERR("Stop LE scan failed (err %d)", err); + return err; + } + + return 0; +} + +static bool split_central_eir_found(const bt_addr_le_t *addr) { + LOG_DBG("Found the split service"); + + // Reserve peripheral slot. Once the central has bonded to its peripherals, + // the peripheral MAC addresses will be validated internally and the slot + // reservation will fail if there is a mismatch. + int slot_idx = reserve_peripheral_slot(addr); + if (slot_idx < 0) { + LOG_INF("Unable to reserve peripheral slot (err %d)", slot_idx); + return false; + } + struct peripheral_slot *slot = &peripherals[slot_idx]; + + // Stop scanning so we can connect to the peripheral device. + int err = stop_scanning(); + if (err < 0) { + return false; + } + + LOG_DBG("Initiating new connnection"); + struct bt_le_conn_param *param = + BT_LE_CONN_PARAM(CONFIG_ZMK_SPLIT_BLE_PREF_INT, CONFIG_ZMK_SPLIT_BLE_PREF_INT, + CONFIG_ZMK_SPLIT_BLE_PREF_LATENCY, CONFIG_ZMK_SPLIT_BLE_PREF_TIMEOUT); + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &slot->conn); + if (err < 0) { + LOG_ERR("Create conn failed (err %d) (create conn? 0x%04x)", err, BT_HCI_OP_LE_CREATE_CONN); + release_peripheral_slot(slot_idx); + start_scanning(); + } + + return false; +} + +static bool split_central_eir_parse(struct bt_data *data, void *user_data) { + bt_addr_le_t *addr = user_data; + int i; + + LOG_DBG("[AD]: %u data_len %u", data->type, data->data_len); + + switch (data->type) { + case BT_DATA_UUID128_SOME: + case BT_DATA_UUID128_ALL: + if (data->data_len % 16 != 0U) { + LOG_ERR("AD malformed"); + return true; + } + + for (i = 0; i < data->data_len; i += 16) { + struct bt_uuid_128 uuid; + + if (!bt_uuid_create(&uuid.uuid, &data->data[i], 16)) { + LOG_ERR("Unable to load UUID"); + continue; + } + + if (bt_uuid_cmp(&uuid.uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID)) != 0) { + char uuid_str[BT_UUID_STR_LEN]; + char service_uuid_str[BT_UUID_STR_LEN]; + + bt_uuid_to_str(&uuid.uuid, uuid_str, sizeof(uuid_str)); + bt_uuid_to_str(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID), service_uuid_str, + sizeof(service_uuid_str)); + LOG_DBG("UUID %s does not match split UUID: %s", uuid_str, service_uuid_str); + continue; + } + + return split_central_eir_found(addr); + } + } + + return true; +} + +static void split_central_device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, + struct net_buf_simple *ad) { + char dev[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(addr, dev, sizeof(dev)); + LOG_DBG("[DEVICE]: %s, AD evt type %u, AD data len %u, RSSI %i", dev, type, ad->len, rssi); + + /* We're only interested in connectable events */ + if (type == BT_GAP_ADV_TYPE_ADV_IND) { + bt_data_parse(ad, split_central_eir_parse, (void *)addr); + } else if (type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { + split_central_eir_found(addr); + } +} + +static int start_scanning(void) { + // No action is necessary if central is already scanning. + if (is_scanning) { + LOG_DBG("Scanning already running"); + return 0; + } + + // If all the devices are connected, there is no need to scan. + bool has_unconnected = false; + for (int i = 0; i < CONFIG_ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS; i++) { + if (peripherals[i].conn == NULL) { + has_unconnected = true; + break; + } + } + if (!has_unconnected) { + LOG_DBG("All devices are connected, scanning is unnecessary"); + return 0; + } + + // Start scanning otherwise. + is_scanning = true; + int err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, split_central_device_found); + if (err < 0) { + LOG_ERR("Scanning failed to start (err %d)", err); + return err; + } + + LOG_DBG("Scanning successfully started"); + return 0; +} + +static void split_central_connected(struct bt_conn *conn, uint8_t conn_err) { + char addr[BT_ADDR_LE_STR_LEN]; + struct bt_conn_info info; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + bt_conn_get_info(conn, &info); + + if (info.role != BT_CONN_ROLE_CENTRAL) { + LOG_DBG("SKIPPING FOR ROLE %d", info.role); + return; + } + + if (conn_err) { + LOG_ERR("Failed to connect to %s (%u)", addr, conn_err); + + release_peripheral_slot_for_conn(conn); + + start_scanning(); + return; + } + + LOG_DBG("Connected: %s", addr); + + confirm_peripheral_slot_conn(conn); + split_central_process_connection(conn); +} + +static void split_central_disconnected(struct bt_conn *conn, uint8_t reason) { + char addr[BT_ADDR_LE_STR_LEN]; + int err; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + LOG_DBG("Disconnected: %s (reason %d)", addr, reason); + + err = release_peripheral_slot_for_conn(conn); + + if (err < 0) { + return; + } + + start_scanning(); +} + +static struct bt_conn_cb conn_callbacks = { + .connected = split_central_connected, + .disconnected = split_central_disconnected, +}; + +K_THREAD_STACK_DEFINE(split_central_split_run_q_stack, + CONFIG_ZMK_SPLIT_BLE_CENTRAL_SPLIT_RUN_STACK_SIZE); + +struct k_work_q split_central_split_run_q; + +struct zmk_split_run_behavior_payload_wrapper { + uint8_t source; + struct zmk_split_run_behavior_payload payload; +}; + +K_MSGQ_DEFINE(zmk_split_central_split_run_msgq, + sizeof(struct zmk_split_run_behavior_payload_wrapper), + CONFIG_ZMK_SPLIT_BLE_CENTRAL_SPLIT_RUN_QUEUE_SIZE, 4); + +void split_central_split_run_callback(struct k_work *work) { + struct zmk_split_run_behavior_payload_wrapper payload_wrapper; + + LOG_DBG(""); + + while (k_msgq_get(&zmk_split_central_split_run_msgq, &payload_wrapper, K_NO_WAIT) == 0) { + if (peripherals[payload_wrapper.source].state != PERIPHERAL_SLOT_STATE_CONNECTED) { + LOG_ERR("Source not connected"); + continue; + } + if (!peripherals[payload_wrapper.source].run_behavior_handle) { + LOG_ERR("Run behavior handle not found"); + continue; + } + + int err = bt_gatt_write_without_response( + peripherals[payload_wrapper.source].conn, + peripherals[payload_wrapper.source].run_behavior_handle, &payload_wrapper.payload, + sizeof(struct zmk_split_run_behavior_payload), true); + + if (err) { + LOG_ERR("Failed to write the behavior characteristic (err %d)", err); + } + } +} + +K_WORK_DEFINE(split_central_split_run_work, split_central_split_run_callback); + +static int +split_bt_invoke_behavior_payload(struct zmk_split_run_behavior_payload_wrapper payload_wrapper) { + LOG_DBG(""); + + int err = k_msgq_put(&zmk_split_central_split_run_msgq, &payload_wrapper, K_MSEC(100)); + if (err) { + switch (err) { + case -EAGAIN: { + LOG_WRN("Consumer message queue full, popping first message and queueing again"); + struct zmk_split_run_behavior_payload_wrapper discarded_report; + k_msgq_get(&zmk_split_central_split_run_msgq, &discarded_report, K_NO_WAIT); + return split_bt_invoke_behavior_payload(payload_wrapper); + } + default: + LOG_WRN("Failed to queue behavior to send (%d)", err); + return err; + } + } + + k_work_submit_to_queue(&split_central_split_run_q, &split_central_split_run_work); + + return 0; +}; + +int zmk_split_bt_invoke_behavior(uint8_t source, struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event, bool state) { + struct zmk_split_run_behavior_payload payload = {.data = { + .param1 = binding->param1, + .param2 = binding->param2, + .position = event.position, + .state = state ? 1 : 0, + }}; + const size_t payload_dev_size = sizeof(payload.behavior_dev); + if (strlcpy(payload.behavior_dev, binding->behavior_dev, payload_dev_size) >= + payload_dev_size) { + LOG_ERR("Truncated behavior label %s to %s before invoking peripheral behavior", + binding->behavior_dev, payload.behavior_dev); + } + + struct zmk_split_run_behavior_payload_wrapper wrapper = {.source = source, .payload = payload}; + return split_bt_invoke_behavior_payload(wrapper); +} + +#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) + +static zmk_hid_indicators_t hid_indicators = 0; + +static void split_central_update_indicators_callback(struct k_work *work) { + zmk_hid_indicators_t indicators = hid_indicators; + for (int i = 0; i < ZMK_SPLIT_BLE_PERIPHERAL_COUNT; i++) { + if (peripherals[i].state != PERIPHERAL_SLOT_STATE_CONNECTED) { + continue; + } + + if (peripherals[i].update_hid_indicators == 0) { + // It appears that sometimes the peripheral is considered connected + // before the GATT characteristics have been discovered. If this is + // the case, the update_hid_indicators handle will not yet be set. + continue; + } + + int err = bt_gatt_write_without_response(peripherals[i].conn, + peripherals[i].update_hid_indicators, &indicators, + sizeof(indicators), true); + + if (err) { + LOG_ERR("Failed to write HID indicator characteristic (err %d)", err); + } + } +} + +static K_WORK_DEFINE(split_central_update_indicators, split_central_update_indicators_callback); + +int zmk_split_bt_update_hid_indicator(zmk_hid_indicators_t indicators) { + hid_indicators = indicators; + return k_work_submit_to_queue(&split_central_split_run_q, &split_central_update_indicators); +} + +#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) + +int zmk_split_bt_central_init(const struct device *_arg) { + k_work_queue_start(&split_central_split_run_q, split_central_split_run_q_stack, + K_THREAD_STACK_SIZEOF(split_central_split_run_q_stack), + CONFIG_ZMK_BLE_THREAD_PRIORITY, NULL); + bt_conn_cb_register(&conn_callbacks); + + return IS_ENABLED(CONFIG_ZMK_BLE_CLEAR_BONDS_ON_START) ? 0 : start_scanning(); +} + +SYS_INIT(zmk_split_bt_central_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY); diff --git a/app/src/split/bluetooth/peripheral.c b/app/src/split/bluetooth/peripheral.c new file mode 100644 index 000000000000..704e2eed4087 --- /dev/null +++ b/app/src/split/bluetooth/peripheral.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#if IS_ENABLED(CONFIG_SETTINGS) + +#include + +#endif + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include + +static const struct bt_data zmk_ble_ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA_BYTES(BT_DATA_UUID16_SOME, 0x0f, 0x18 /* Battery Service */ + ), + BT_DATA_BYTES(BT_DATA_UUID128_ALL, ZMK_SPLIT_BT_SERVICE_UUID)}; + +static bool is_connected = false; + +static bool is_bonded = false; + +static void each_bond(const struct bt_bond_info *info, void *user_data) { + bt_addr_le_t *addr = (bt_addr_le_t *)user_data; + + if (bt_addr_le_cmp(&info->addr, BT_ADDR_LE_NONE) != 0) { + bt_addr_le_copy(addr, &info->addr); + } +} + +static int start_advertising(bool low_duty) { + bt_addr_le_t central_addr = bt_addr_le_none; + + bt_foreach_bond(BT_ID_DEFAULT, each_bond, ¢ral_addr); + + if (bt_addr_le_cmp(¢ral_addr, BT_ADDR_LE_NONE) != 0) { + is_bonded = true; + struct bt_le_adv_param adv_param = low_duty ? *BT_LE_ADV_CONN_DIR_LOW_DUTY(¢ral_addr) + : *BT_LE_ADV_CONN_DIR(¢ral_addr); + return bt_le_adv_start(&adv_param, NULL, 0, NULL, 0); + } else { + is_bonded = false; + return bt_le_adv_start(BT_LE_ADV_CONN, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0); + } +}; + +static bool low_duty_advertising = false; + +static void advertising_cb(struct k_work *work) { + const int err = start_advertising(low_duty_advertising); + if (err < 0) { + LOG_ERR("Failed to start advertising (%d)", err); + } +} + +K_WORK_DEFINE(advertising_work, advertising_cb); + +static void connected(struct bt_conn *conn, uint8_t err) { + is_connected = (err == 0); + + ZMK_EVENT_RAISE(new_zmk_split_peripheral_status_changed( + (struct zmk_split_peripheral_status_changed){.connected = is_connected})); + + if (err == BT_HCI_ERR_ADV_TIMEOUT) { + low_duty_advertising = true; + k_work_submit(&advertising_work); + } +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) { + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + LOG_DBG("Disconnected from %s (reason 0x%02x)", addr, reason); + + is_connected = false; + + ZMK_EVENT_RAISE(new_zmk_split_peripheral_status_changed( + (struct zmk_split_peripheral_status_changed){.connected = is_connected})); + + low_duty_advertising = false; + k_work_submit(&advertising_work); +} + +static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) { + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (!err) { + LOG_DBG("Security changed: %s level %u", addr, level); + } else { + LOG_ERR("Security failed: %s level %u err %d", addr, level, err); + } +} + +static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency, + uint16_t timeout) { + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + LOG_DBG("%s: interval %d latency %d timeout %d", addr, interval, latency, timeout); +} + +static struct bt_conn_cb conn_callbacks = { + .connected = connected, + .disconnected = disconnected, + .security_changed = security_changed, + .le_param_updated = le_param_updated, +}; + +static void auth_pairing_complete(struct bt_conn *conn, bool bonded) { is_bonded = bonded; } + +static struct bt_conn_auth_info_cb zmk_peripheral_ble_auth_info_cb = { + .pairing_complete = auth_pairing_complete, +}; + +bool zmk_split_bt_peripheral_is_connected() { return is_connected; } + +bool zmk_split_bt_peripheral_is_bonded() { return is_bonded; } + +static int zmk_peripheral_ble_init(const struct device *_arg) { + int err = bt_enable(NULL); + + if (err) { + LOG_ERR("BLUETOOTH FAILED (%d)", err); + return err; + } + +#if IS_ENABLED(CONFIG_SETTINGS) + settings_subsys_init(); + + settings_load_subtree("ble"); + settings_load_subtree("bt"); +#endif + +#if IS_ENABLED(CONFIG_ZMK_BLE_CLEAR_BONDS_ON_START) + LOG_WRN("Clearing all existing BLE bond information from the keyboard"); + + bt_unpair(BT_ID_DEFAULT, NULL); +#else + bt_conn_cb_register(&conn_callbacks); + bt_conn_auth_info_cb_register(&zmk_peripheral_ble_auth_info_cb); + + low_duty_advertising = false; + k_work_submit(&advertising_work); +#endif + + return 0; +} + +SYS_INIT(zmk_peripheral_ble_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY); diff --git a/app/src/split/bluetooth/service.c b/app/src/split/bluetooth/service.c new file mode 100644 index 000000000000..0072cf8c8357 --- /dev/null +++ b/app/src/split/bluetooth/service.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include + +#include +#include +#include +#include +#include + +#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) +#include +#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) + +#include +#include + +#if ZMK_KEYMAP_HAS_SENSORS +static struct sensor_event last_sensor_event; + +static ssize_t split_svc_sensor_state(struct bt_conn *conn, const struct bt_gatt_attr *attrs, + void *buf, uint16_t len, uint16_t offset) { + return bt_gatt_attr_read(conn, attrs, buf, len, offset, &last_sensor_event, + sizeof(last_sensor_event)); +} + +static void split_svc_sensor_state_ccc(const struct bt_gatt_attr *attr, uint16_t value) { + LOG_DBG("value %d", value); +} +#endif /* ZMK_KEYMAP_HAS_SENSORS */ + +#define POS_STATE_LEN 16 + +static uint8_t num_of_positions = ZMK_KEYMAP_LEN; +static uint8_t position_state[POS_STATE_LEN]; + +static struct zmk_split_run_behavior_payload behavior_run_payload; + +static ssize_t split_svc_pos_state(struct bt_conn *conn, const struct bt_gatt_attr *attrs, + void *buf, uint16_t len, uint16_t offset) { + return bt_gatt_attr_read(conn, attrs, buf, len, offset, &position_state, + sizeof(position_state)); +} + +static ssize_t split_svc_run_behavior(struct bt_conn *conn, const struct bt_gatt_attr *attrs, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) { + struct zmk_split_run_behavior_payload *payload = attrs->user_data; + uint16_t end_addr = offset + len; + + LOG_DBG("offset %d len %d", offset, len); + + if (end_addr > sizeof(struct zmk_split_run_behavior_payload)) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + memcpy(payload + offset, buf, len); + + // We run if: + // 1: We've gotten all the position/state/param data. + // 2: We have a null terminated string for the behavior device label. + const size_t behavior_dev_offset = + offsetof(struct zmk_split_run_behavior_payload, behavior_dev); + if ((end_addr > sizeof(struct zmk_split_run_behavior_data)) && + payload->behavior_dev[end_addr - behavior_dev_offset - 1] == '\0') { + struct zmk_behavior_binding binding = { + .param1 = payload->data.param1, + .param2 = payload->data.param2, + .behavior_dev = payload->behavior_dev, + }; + LOG_DBG("%s with params %d %d: pressed? %d", binding.behavior_dev, binding.param1, + binding.param2, payload->data.state); + struct zmk_behavior_binding_event event = {.position = payload->data.position, + .timestamp = k_uptime_get()}; + int err; + if (payload->data.state > 0) { + err = behavior_keymap_binding_pressed(&binding, event); + } else { + err = behavior_keymap_binding_released(&binding, event); + } + + if (err) { + LOG_ERR("Failed to invoke behavior %s: %d", binding.behavior_dev, err); + } + } + + return len; +} + +static ssize_t split_svc_num_of_positions(struct bt_conn *conn, const struct bt_gatt_attr *attrs, + void *buf, uint16_t len, uint16_t offset) { + return bt_gatt_attr_read(conn, attrs, buf, len, offset, attrs->user_data, sizeof(uint8_t)); +} + +static void split_svc_pos_state_ccc(const struct bt_gatt_attr *attr, uint16_t value) { + LOG_DBG("value %d", value); +} + +#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) + +static zmk_hid_indicators_t hid_indicators = 0; + +static void split_svc_update_indicators_callback(struct k_work *work) { + LOG_DBG("Raising HID indicators changed event: %x", hid_indicators); + ZMK_EVENT_RAISE(new_zmk_hid_indicators_changed( + (struct zmk_hid_indicators_changed){.indicators = hid_indicators})); +} + +static K_WORK_DEFINE(split_svc_update_indicators_work, split_svc_update_indicators_callback); + +static ssize_t split_svc_update_indicators(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) { + if (offset + len > sizeof(zmk_hid_indicators_t)) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + memcpy((uint8_t *)&hid_indicators + offset, buf, len); + + k_work_submit(&split_svc_update_indicators_work); + + return len; +} + +#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) + +BT_GATT_SERVICE_DEFINE( + split_svc, BT_GATT_PRIMARY_SERVICE(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID)), + BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID), + BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ_ENCRYPT, + split_svc_pos_state, NULL, &position_state), + BT_GATT_CCC(split_svc_pos_state_ccc, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID), + BT_GATT_CHRC_WRITE_WITHOUT_RESP, BT_GATT_PERM_WRITE_ENCRYPT, NULL, + split_svc_run_behavior, &behavior_run_payload), + BT_GATT_DESCRIPTOR(BT_UUID_NUM_OF_DIGITALS, BT_GATT_PERM_READ, split_svc_num_of_positions, NULL, + &num_of_positions), +#if ZMK_KEYMAP_HAS_SENSORS + BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_SENSOR_STATE_UUID), + BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ_ENCRYPT, + split_svc_sensor_state, NULL, &last_sensor_event), + BT_GATT_CCC(split_svc_sensor_state_ccc, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), +#endif /* ZMK_KEYMAP_HAS_SENSORS */ +#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) + BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_UPDATE_HID_INDICATORS_UUID), + BT_GATT_CHRC_WRITE_WITHOUT_RESP, BT_GATT_PERM_WRITE_ENCRYPT, NULL, + split_svc_update_indicators, NULL), +#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) +); + +K_THREAD_STACK_DEFINE(service_q_stack, CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_STACK_SIZE); + +struct k_work_q service_work_q; + +K_MSGQ_DEFINE(position_state_msgq, sizeof(char[POS_STATE_LEN]), + CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_POSITION_QUEUE_SIZE, 4); + +void send_position_state_callback(struct k_work *work) { + uint8_t state[POS_STATE_LEN]; + + while (k_msgq_get(&position_state_msgq, &state, K_NO_WAIT) == 0) { + int err = bt_gatt_notify(NULL, &split_svc.attrs[1], &state, sizeof(state)); + if (err) { + LOG_DBG("Error notifying %d", err); + } + } +}; + +K_WORK_DEFINE(service_position_notify_work, send_position_state_callback); + +int send_position_state() { + int err = k_msgq_put(&position_state_msgq, position_state, K_MSEC(100)); + if (err) { + switch (err) { + case -EAGAIN: { + LOG_WRN("Position state message queue full, popping first message and queueing again"); + uint8_t discarded_state[POS_STATE_LEN]; + k_msgq_get(&position_state_msgq, &discarded_state, K_NO_WAIT); + return send_position_state(); + } + default: + LOG_WRN("Failed to queue position state to send (%d)", err); + return err; + } + } + + k_work_submit_to_queue(&service_work_q, &service_position_notify_work); + + return 0; +} + +int zmk_split_bt_position_pressed(uint8_t position) { + WRITE_BIT(position_state[position / 8], position % 8, true); + return send_position_state(); +} + +int zmk_split_bt_position_released(uint8_t position) { + WRITE_BIT(position_state[position / 8], position % 8, false); + return send_position_state(); +} + +#if ZMK_KEYMAP_HAS_SENSORS +K_MSGQ_DEFINE(sensor_state_msgq, sizeof(struct sensor_event), + CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_POSITION_QUEUE_SIZE, 4); + +void send_sensor_state_callback(struct k_work *work) { + while (k_msgq_get(&sensor_state_msgq, &last_sensor_event, K_NO_WAIT) == 0) { + int err = bt_gatt_notify(NULL, &split_svc.attrs[8], &last_sensor_event, + sizeof(last_sensor_event)); + if (err) { + LOG_DBG("Error notifying %d", err); + } + } +}; + +K_WORK_DEFINE(service_sensor_notify_work, send_sensor_state_callback); + +int send_sensor_state(struct sensor_event ev) { + int err = k_msgq_put(&sensor_state_msgq, &ev, K_MSEC(100)); + if (err) { + // retry... + switch (err) { + case -EAGAIN: { + LOG_WRN("Sensor state message queue full, popping first message and queueing again"); + struct sensor_event discarded_state; + k_msgq_get(&sensor_state_msgq, &discarded_state, K_NO_WAIT); + return send_sensor_state(ev); + } + default: + LOG_WRN("Failed to queue sensor state to send (%d)", err); + return err; + } + } + + k_work_submit_to_queue(&service_work_q, &service_sensor_notify_work); + return 0; +} + +int zmk_split_bt_sensor_triggered(uint8_t sensor_index, + const struct zmk_sensor_channel_data channel_data[], + size_t channel_data_size) { + if (channel_data_size > ZMK_SENSOR_EVENT_MAX_CHANNELS) { + return -EINVAL; + } + + struct sensor_event ev = + (struct sensor_event){.sensor_index = sensor_index, .channel_data_size = channel_data_size}; + memcpy(ev.channel_data, channel_data, + channel_data_size * sizeof(struct zmk_sensor_channel_data)); + return send_sensor_state(ev); +} +#endif /* ZMK_KEYMAP_HAS_SENSORS */ + +int service_init(const struct device *_arg) { + static const struct k_work_queue_config queue_config = { + .name = "Split Peripheral Notification Queue"}; + k_work_queue_start(&service_work_q, service_q_stack, K_THREAD_STACK_SIZEOF(service_q_stack), + CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_PRIORITY, &queue_config); + + return 0; +} + +SYS_INIT(service_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY); diff --git a/app/src/split/bluetooth/split_listener.c b/app/src/split/bluetooth/split_listener.c new file mode 100644 index 000000000000..9b680d2c89cd --- /dev/null +++ b/app/src/split/bluetooth/split_listener.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include +#include +#include + +int split_listener(const zmk_event_t *eh) { + LOG_DBG(""); + const struct zmk_position_state_changed *pos_ev; + if ((pos_ev = as_zmk_position_state_changed(eh)) != NULL) { + if (pos_ev->state) { + return zmk_split_bt_position_pressed(pos_ev->position); + } else { + return zmk_split_bt_position_released(pos_ev->position); + } + } + +#if ZMK_KEYMAP_HAS_SENSORS + const struct zmk_sensor_event *sensor_ev; + if ((sensor_ev = as_zmk_sensor_event(eh)) != NULL) { + return zmk_split_bt_sensor_triggered(sensor_ev->sensor_index, sensor_ev->channel_data, + sensor_ev->channel_data_size); + } +#endif /* ZMK_KEYMAP_HAS_SENSORS */ + return ZMK_EV_EVENT_BUBBLE; +} + +ZMK_LISTENER(split_listener, split_listener); +ZMK_SUBSCRIPTION(split_listener, zmk_position_state_changed); + +#if ZMK_KEYMAP_HAS_SENSORS +ZMK_SUBSCRIPTION(split_listener, zmk_sensor_event); +#endif /* ZMK_KEYMAP_HAS_SENSORS */ diff --git a/app/src/stdlib.c b/app/src/stdlib.c new file mode 100644 index 000000000000..5bca1696c8d3 --- /dev/null +++ b/app/src/stdlib.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +/* + * ANSI C version of strlcpy + * Based on the NetBSD strlcpy man page. + * + * Nathan Myers , 2003/06/03 + * Placed in the public domain. + */ + +size_t strlcpy(char *dst, const char *src, size_t size) { + const size_t len = strlen(src); + if (size != 0) { + memcpy(dst, src, (len > size - 1) ? size - 1 : len); + dst[size - 1] = 0; + } + return len; +} diff --git a/app/src/usb.c b/app/src/usb.c new file mode 100644 index 000000000000..9d27900c3c6e --- /dev/null +++ b/app/src/usb.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +static enum usb_dc_status_code usb_status = USB_DC_UNKNOWN; + +static void raise_usb_status_changed_event(struct k_work *_work) { + ZMK_EVENT_RAISE(new_zmk_usb_conn_state_changed( + (struct zmk_usb_conn_state_changed){.conn_state = zmk_usb_get_conn_state()})); +} + +K_WORK_DEFINE(usb_status_notifier_work, raise_usb_status_changed_event); + +enum usb_dc_status_code zmk_usb_get_status() { return usb_status; } + +enum zmk_usb_conn_state zmk_usb_get_conn_state() { + LOG_DBG("state: %d", usb_status); + switch (usb_status) { + case USB_DC_SUSPEND: + case USB_DC_CONFIGURED: + case USB_DC_RESUME: + case USB_DC_CLEAR_HALT: + case USB_DC_SOF: + return ZMK_USB_CONN_HID; + + case USB_DC_DISCONNECTED: + case USB_DC_UNKNOWN: + return ZMK_USB_CONN_NONE; + + default: + return ZMK_USB_CONN_POWERED; + } +} + +void usb_status_cb(enum usb_dc_status_code status, const uint8_t *params) { + // Start-of-frame events are too frequent and noisy to notify, and they're + // not used within ZMK + if (status == USB_DC_SOF) { + return; + } + +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + if (status == USB_DC_RESET) { + zmk_usb_hid_set_protocol(HID_PROTOCOL_REPORT); + } +#endif + usb_status = status; + k_work_submit(&usb_status_notifier_work); +}; + +static int zmk_usb_init(const struct device *_arg) { + int usb_enable_ret; + + usb_enable_ret = usb_enable(usb_status_cb); + + if (usb_enable_ret != 0) { + LOG_ERR("Unable to enable USB"); + return -EINVAL; + } + + return 0; +} + +SYS_INIT(zmk_usb_init, APPLICATION, CONFIG_ZMK_USB_INIT_PRIORITY); diff --git a/app/src/usb_hid.c b/app/src/usb_hid.c new file mode 100644 index 000000000000..3412314086fd --- /dev/null +++ b/app/src/usb_hid.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#include +#include + +#include +#include +#include +#if IS_ENABLED(CONFIG_ZMK_HID_INDICATORS) +#include +#endif // IS_ENABLED(CONFIG_ZMK_HID_INDICATORS) +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +static const struct device *hid_dev; + +static K_SEM_DEFINE(hid_sem, 1, 1); + +static void in_ready_cb(const struct device *dev) { k_sem_give(&hid_sem); } + +#define HID_GET_REPORT_TYPE_MASK 0xff00 +#define HID_GET_REPORT_ID_MASK 0x00ff + +#define HID_REPORT_TYPE_INPUT 0x100 +#define HID_REPORT_TYPE_OUTPUT 0x200 +#define HID_REPORT_TYPE_FEATURE 0x300 + +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) +static uint8_t hid_protocol = HID_PROTOCOL_REPORT; + +static void set_proto_cb(const struct device *dev, uint8_t protocol) { hid_protocol = protocol; } + +void zmk_usb_hid_set_protocol(uint8_t protocol) { hid_protocol = protocol; } +#endif /* IS_ENABLED(CONFIG_ZMK_USB_BOOT) */ + +static uint8_t *get_keyboard_report(size_t *len) { +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + if (hid_protocol != HID_PROTOCOL_REPORT) { + zmk_hid_boot_report_t *boot_report = zmk_hid_get_boot_report(); + *len = sizeof(*boot_report); + return (uint8_t *)boot_report; + } +#endif + struct zmk_hid_keyboard_report *report = zmk_hid_get_keyboard_report(); + *len = sizeof(*report); + return (uint8_t *)report; +} + +static int get_report_cb(const struct device *dev, struct usb_setup_packet *setup, int32_t *len, + uint8_t **data) { + + /* + * 7.2.1 of the HID v1.11 spec is unclear about handling requests for reports that do not exist + * For requested reports that aren't input reports, return -ENOTSUP like the Zephyr subsys does + */ + if ((setup->wValue & HID_GET_REPORT_TYPE_MASK) != HID_REPORT_TYPE_INPUT) { + LOG_ERR("Unsupported report type %d requested", (setup->wValue & HID_GET_REPORT_TYPE_MASK) + << 8); + return -ENOTSUP; + } + + switch (setup->wValue & HID_GET_REPORT_ID_MASK) { + case ZMK_HID_REPORT_ID_KEYBOARD: { + *data = get_keyboard_report(len); + break; + } + case ZMK_HID_REPORT_ID_CONSUMER: { + struct zmk_hid_consumer_report *report = zmk_hid_get_consumer_report(); + *data = (uint8_t *)report; + *len = sizeof(*report); + break; + } + default: + LOG_ERR("Invalid report ID %d requested", setup->wValue & HID_GET_REPORT_ID_MASK); + return -EINVAL; + } + + return 0; +} + +static int set_report_cb(const struct device *dev, struct usb_setup_packet *setup, int32_t *len, + uint8_t **data) { + if ((setup->wValue & HID_GET_REPORT_TYPE_MASK) != HID_REPORT_TYPE_OUTPUT) { + LOG_ERR("Unsupported report type %d requested", + (setup->wValue & HID_GET_REPORT_TYPE_MASK) >> 8); + return -ENOTSUP; + } + + switch (setup->wValue & HID_GET_REPORT_ID_MASK) { +#if IS_ENABLED(CONFIG_ZMK_HID_INDICATORS) + case ZMK_HID_REPORT_ID_LEDS: + if (*len != sizeof(struct zmk_hid_led_report)) { + LOG_ERR("LED set report is malformed: length=%d", *len); + return -EINVAL; + } else { + struct zmk_hid_led_report *report = (struct zmk_hid_led_report *)*data; + struct zmk_endpoint_instance endpoint = { + .transport = ZMK_TRANSPORT_USB, + }; + zmk_hid_indicators_process_report(&report->body, endpoint); + } + break; +#endif // IS_ENABLED(CONFIG_ZMK_HID_INDICATORS) + default: + LOG_ERR("Invalid report ID %d requested", setup->wValue & HID_GET_REPORT_ID_MASK); + return -EINVAL; + } + + return 0; +} + +static const struct hid_ops ops = { +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + .protocol_change = set_proto_cb, +#endif + .int_in_ready = in_ready_cb, + .get_report = get_report_cb, + .set_report = set_report_cb, +}; + +static int zmk_usb_hid_send_report(const uint8_t *report, size_t len) { + switch (zmk_usb_get_status()) { + case USB_DC_SUSPEND: + return usb_wakeup_request(); + case USB_DC_ERROR: + case USB_DC_RESET: + case USB_DC_DISCONNECTED: + case USB_DC_UNKNOWN: + return -ENODEV; + default: + k_sem_take(&hid_sem, K_MSEC(30)); + int err = hid_int_ep_write(hid_dev, report, len, NULL); + + if (err) { + k_sem_give(&hid_sem); + } + + return err; + } +} + +int zmk_usb_hid_send_keyboard_report() { + size_t len; + uint8_t *report = get_keyboard_report(&len); + return zmk_usb_hid_send_report(report, len); +} + +int zmk_usb_hid_send_consumer_report() { +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + if (hid_protocol == HID_PROTOCOL_BOOT) { + return -ENOTSUP; + } +#endif /* IS_ENABLED(CONFIG_ZMK_USB_BOOT) */ + + struct zmk_hid_consumer_report *report = zmk_hid_get_consumer_report(); + return zmk_usb_hid_send_report((uint8_t *)report, sizeof(*report)); +} + +#if IS_ENABLED(CONFIG_ZMK_MOUSE) +int zmk_usb_hid_send_mouse_report() { +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + if (hid_protocol == HID_PROTOCOL_BOOT) { + return -ENOTSUP; + } +#endif /* IS_ENABLED(CONFIG_ZMK_USB_BOOT) */ + + struct zmk_hid_mouse_report *report = zmk_hid_get_mouse_report(); + return zmk_usb_hid_send_report((uint8_t *)report, sizeof(*report)); +} +#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) + +static int zmk_usb_hid_init(const struct device *_arg) { + hid_dev = device_get_binding("HID_0"); + if (hid_dev == NULL) { + LOG_ERR("Unable to locate HID device"); + return -EINVAL; + } + + usb_hid_register_device(hid_dev, zmk_hid_report_desc, sizeof(zmk_hid_report_desc), &ops); + +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + usb_hid_set_proto_code(hid_dev, HID_BOOT_IFACE_CODE_KEYBOARD); +#endif /* IS_ENABLED(CONFIG_ZMK_USB_BOOT) */ + + usb_hid_init(hid_dev); + + return 0; +} + +SYS_INIT(zmk_usb_hid_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/app/src/workqueue.c b/app/src/workqueue.c new file mode 100644 index 000000000000..a9a8bce52028 --- /dev/null +++ b/app/src/workqueue.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#include + +K_THREAD_STACK_DEFINE(lowprio_q_stack, CONFIG_ZMK_LOW_PRIORITY_THREAD_STACK_SIZE); + +static struct k_work_q lowprio_work_q; + +struct k_work_q *zmk_workqueue_lowprio_work_q() { + return &lowprio_work_q; +} + +static int workqueue_init() { + static const struct k_work_queue_config queue_config = {.name = "Low Priority Work Queue"}; + k_work_queue_start(&lowprio_work_q, lowprio_q_stack, K_THREAD_STACK_SIZEOF(lowprio_q_stack), + CONFIG_ZMK_LOW_PRIORITY_THREAD_PRIORITY, &queue_config); + return 0; +} + +SYS_INIT(workqueue_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/app/src/wpm.c b/app/src/wpm.c new file mode 100644 index 000000000000..00a5942ecb8b --- /dev/null +++ b/app/src/wpm.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include + +#include + +#define WPM_UPDATE_INTERVAL_SECONDS 1 +#define WPM_RESET_INTERVAL_SECONDS 5 + +// See https://en.wikipedia.org/wiki/Words_per_minute +// "Since the length or duration of words is clearly variable, for the purpose of measurement of +// text entry, the definition of each "word" is often standardized to be five characters or +// keystrokes long in English" +#define CHARS_PER_WORD 5.0 + +static uint8_t wpm_state = -1; +static uint8_t last_wpm_state; +static uint8_t wpm_update_counter; +static uint32_t key_pressed_count; + +int zmk_wpm_get_state() { return wpm_state; } + +int wpm_event_listener(const zmk_event_t *eh) { + const struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh); + if (ev) { + // count only key up events + if (!ev->state) { + key_pressed_count++; + LOG_DBG("key_pressed_count %d keycode %d", key_pressed_count, ev->keycode); + } + } + return 0; +} + +void wpm_work_handler(struct k_work *work) { + wpm_update_counter++; + wpm_state = (key_pressed_count / CHARS_PER_WORD) / + (wpm_update_counter * WPM_UPDATE_INTERVAL_SECONDS / 60.0); + + if (last_wpm_state != wpm_state) { + LOG_DBG("Raised WPM state changed %d wpm_update_counter %d", wpm_state, wpm_update_counter); + + ZMK_EVENT_RAISE( + new_zmk_wpm_state_changed((struct zmk_wpm_state_changed){.state = wpm_state})); + + last_wpm_state = wpm_state; + } + + if (wpm_update_counter >= WPM_RESET_INTERVAL_SECONDS) { + wpm_update_counter = 0; + key_pressed_count = 0; + } +} + +K_WORK_DEFINE(wpm_work, wpm_work_handler); + +void wpm_expiry_function() { k_work_submit(&wpm_work); } + +K_TIMER_DEFINE(wpm_timer, wpm_expiry_function, NULL); + +int wpm_init() { + wpm_state = 0; + wpm_update_counter = 0; + k_timer_start(&wpm_timer, K_SECONDS(WPM_UPDATE_INTERVAL_SECONDS), + K_SECONDS(WPM_UPDATE_INTERVAL_SECONDS)); + return 0; +} + +ZMK_LISTENER(wpm, wpm_event_listener); +ZMK_SUBSCRIPTION(wpm, zmk_keycode_state_changed); + +SYS_INIT(wpm_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/app/tests/backlight/basic/events.patterns b/app/tests/backlight/basic/events.patterns new file mode 100644 index 000000000000..bb11bc15e5b2 --- /dev/null +++ b/app/tests/backlight/basic/events.patterns @@ -0,0 +1 @@ +s/.*zmk_backlight_update: //p diff --git a/app/tests/backlight/basic/keycode_events.snapshot b/app/tests/backlight/basic/keycode_events.snapshot new file mode 100644 index 000000000000..4aa184cd33a3 --- /dev/null +++ b/app/tests/backlight/basic/keycode_events.snapshot @@ -0,0 +1,9 @@ +Update backlight brightness: 40% +Update backlight brightness: 60% +Update backlight brightness: 80% +Update backlight brightness: 60% +Update backlight brightness: 40% +Update backlight brightness: 0% +Update backlight brightness: 0% +Update backlight brightness: 40% +Update backlight brightness: 40% diff --git a/app/tests/backlight/basic/native_posix_64.conf b/app/tests/backlight/basic/native_posix_64.conf new file mode 100644 index 000000000000..bd29a072c9c9 --- /dev/null +++ b/app/tests/backlight/basic/native_posix_64.conf @@ -0,0 +1,11 @@ +CONFIG_GPIO=y +CONFIG_GPIO_EMUL=y +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_DEBUG=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + +CONFIG_LED_GPIO=y +CONFIG_ZMK_BACKLIGHT=y diff --git a/app/tests/backlight/basic/native_posix_64.keymap b/app/tests/backlight/basic/native_posix_64.keymap new file mode 100644 index 000000000000..dfb08fef51bc --- /dev/null +++ b/app/tests/backlight/basic/native_posix_64.keymap @@ -0,0 +1,30 @@ +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_OFF */ + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + /* BL_OFF */ + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + /* BL_ON */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + /* BL_ON */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; diff --git a/app/tests/backlight/behavior_keymap.dtsi b/app/tests/backlight/behavior_keymap.dtsi new file mode 100644 index 000000000000..4433f28ce06d --- /dev/null +++ b/app/tests/backlight/behavior_keymap.dtsi @@ -0,0 +1,31 @@ +#include +#include +#include +#include + +/ { + chosen { + zmk,backlight = &backlight; + }; + + backlight: leds { + compatible = "gpio-leds"; + led_0 { + gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; + }; + led_1 { + gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &bl BL_INC &bl BL_DEC + &bl BL_ON &bl BL_OFF + >; + }; + }; +}; diff --git a/app/tests/backlight/config-brt/events.patterns b/app/tests/backlight/config-brt/events.patterns new file mode 100644 index 000000000000..bb11bc15e5b2 --- /dev/null +++ b/app/tests/backlight/config-brt/events.patterns @@ -0,0 +1 @@ +s/.*zmk_backlight_update: //p diff --git a/app/tests/backlight/config-brt/keycode_events.snapshot b/app/tests/backlight/config-brt/keycode_events.snapshot new file mode 100644 index 000000000000..3297a7cd6805 --- /dev/null +++ b/app/tests/backlight/config-brt/keycode_events.snapshot @@ -0,0 +1,3 @@ +Update backlight brightness: 60% +Update backlight brightness: 80% +Update backlight brightness: 60% diff --git a/app/tests/backlight/config-brt/native_posix_64.conf b/app/tests/backlight/config-brt/native_posix_64.conf new file mode 100644 index 000000000000..65cdd3263d9d --- /dev/null +++ b/app/tests/backlight/config-brt/native_posix_64.conf @@ -0,0 +1,12 @@ +CONFIG_GPIO=y +CONFIG_GPIO_EMUL=y +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_DEBUG=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + +CONFIG_LED_GPIO=y +CONFIG_ZMK_BACKLIGHT=y +CONFIG_ZMK_BACKLIGHT_BRT_START=60 diff --git a/app/tests/backlight/config-brt/native_posix_64.keymap b/app/tests/backlight/config-brt/native_posix_64.keymap new file mode 100644 index 000000000000..cbb6c93fcae0 --- /dev/null +++ b/app/tests/backlight/config-brt/native_posix_64.keymap @@ -0,0 +1,12 @@ +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; diff --git a/app/tests/backlight/config-on/events.patterns b/app/tests/backlight/config-on/events.patterns new file mode 100644 index 000000000000..bb11bc15e5b2 --- /dev/null +++ b/app/tests/backlight/config-on/events.patterns @@ -0,0 +1 @@ +s/.*zmk_backlight_update: //p diff --git a/app/tests/backlight/config-on/keycode_events.snapshot b/app/tests/backlight/config-on/keycode_events.snapshot new file mode 100644 index 000000000000..8797af58132d --- /dev/null +++ b/app/tests/backlight/config-on/keycode_events.snapshot @@ -0,0 +1,3 @@ +Update backlight brightness: 0% +Update backlight brightness: 40% +Update backlight brightness: 0% diff --git a/app/tests/backlight/config-on/native_posix_64.conf b/app/tests/backlight/config-on/native_posix_64.conf new file mode 100644 index 000000000000..eb9e7c8a1b2d --- /dev/null +++ b/app/tests/backlight/config-on/native_posix_64.conf @@ -0,0 +1,12 @@ +CONFIG_GPIO=y +CONFIG_GPIO_EMUL=y +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_DEBUG=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + +CONFIG_LED_GPIO=y +CONFIG_ZMK_BACKLIGHT=y +CONFIG_ZMK_BACKLIGHT_ON_START=n diff --git a/app/tests/backlight/config-on/native_posix_64.keymap b/app/tests/backlight/config-on/native_posix_64.keymap new file mode 100644 index 000000000000..1a8de92884b3 --- /dev/null +++ b/app/tests/backlight/config-on/native_posix_64.keymap @@ -0,0 +1,12 @@ +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + /* BL_ON */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + /* BL_OFF */ + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + >; +}; diff --git a/app/tests/backlight/config-step/events.patterns b/app/tests/backlight/config-step/events.patterns new file mode 100644 index 000000000000..bb11bc15e5b2 --- /dev/null +++ b/app/tests/backlight/config-step/events.patterns @@ -0,0 +1 @@ +s/.*zmk_backlight_update: //p diff --git a/app/tests/backlight/config-step/keycode_events.snapshot b/app/tests/backlight/config-step/keycode_events.snapshot new file mode 100644 index 000000000000..4532fed49b3d --- /dev/null +++ b/app/tests/backlight/config-step/keycode_events.snapshot @@ -0,0 +1,11 @@ +Update backlight brightness: 60% +Update backlight brightness: 90% +Update backlight brightness: 100% +Update backlight brightness: 100% +Update backlight brightness: 70% +Update backlight brightness: 40% +Update backlight brightness: 10% +Update backlight brightness: 0% +Update backlight brightness: 0% +Update backlight brightness: 30% +Update backlight brightness: 60% diff --git a/app/tests/backlight/config-step/native_posix_64.conf b/app/tests/backlight/config-step/native_posix_64.conf new file mode 100644 index 000000000000..c03eb7b01a67 --- /dev/null +++ b/app/tests/backlight/config-step/native_posix_64.conf @@ -0,0 +1,13 @@ +CONFIG_GPIO=y +CONFIG_GPIO_EMUL=y +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_DEBUG=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + +CONFIG_LED_GPIO=y +CONFIG_ZMK_BACKLIGHT=y +CONFIG_ZMK_BACKLIGHT_BRT_START=60 +CONFIG_ZMK_BACKLIGHT_BRT_STEP=30 diff --git a/app/tests/backlight/config-step/native_posix_64.keymap b/app/tests/backlight/config-step/native_posix_64.keymap new file mode 100644 index 000000000000..706144597a32 --- /dev/null +++ b/app/tests/backlight/config-step/native_posix_64.keymap @@ -0,0 +1,36 @@ +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/app/tests/backlight/cycle/events.patterns b/app/tests/backlight/cycle/events.patterns new file mode 100644 index 000000000000..bb11bc15e5b2 --- /dev/null +++ b/app/tests/backlight/cycle/events.patterns @@ -0,0 +1 @@ +s/.*zmk_backlight_update: //p diff --git a/app/tests/backlight/cycle/keycode_events.snapshot b/app/tests/backlight/cycle/keycode_events.snapshot new file mode 100644 index 000000000000..70d0988c14a7 --- /dev/null +++ b/app/tests/backlight/cycle/keycode_events.snapshot @@ -0,0 +1,14 @@ +Update backlight brightness: 40% +Update backlight brightness: 60% +Update backlight brightness: 80% +Update backlight brightness: 100% +Update backlight brightness: 0% +Update backlight brightness: 20% +Update backlight brightness: 40% +Update backlight brightness: 60% +Update backlight brightness: 80% +Update backlight brightness: 100% +Update backlight brightness: 0% +Update backlight brightness: 20% +Update backlight brightness: 40% +Update backlight brightness: 60% diff --git a/app/tests/backlight/cycle/native_posix_64.conf b/app/tests/backlight/cycle/native_posix_64.conf new file mode 100644 index 000000000000..bd29a072c9c9 --- /dev/null +++ b/app/tests/backlight/cycle/native_posix_64.conf @@ -0,0 +1,11 @@ +CONFIG_GPIO=y +CONFIG_GPIO_EMUL=y +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_DEBUG=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + +CONFIG_LED_GPIO=y +CONFIG_ZMK_BACKLIGHT=y diff --git a/app/tests/backlight/cycle/native_posix_64.keymap b/app/tests/backlight/cycle/native_posix_64.keymap new file mode 100644 index 000000000000..dcc23aa5f6d2 --- /dev/null +++ b/app/tests/backlight/cycle/native_posix_64.keymap @@ -0,0 +1,75 @@ +#include +#include +#include +#include + +/ { + chosen { + zmk,backlight = &backlight; + }; + + backlight: leds { + compatible = "gpio-leds"; + led_0 { + gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; + }; + led_1 { + gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &bl BL_CYCLE &none + &none &none + >; + }; + }; +}; + +&kscan { + events = < + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_CYCLE */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/app/tests/backlight/low-brightness/events.patterns b/app/tests/backlight/low-brightness/events.patterns new file mode 100644 index 000000000000..bb11bc15e5b2 --- /dev/null +++ b/app/tests/backlight/low-brightness/events.patterns @@ -0,0 +1 @@ +s/.*zmk_backlight_update: //p diff --git a/app/tests/backlight/low-brightness/keycode_events.snapshot b/app/tests/backlight/low-brightness/keycode_events.snapshot new file mode 100644 index 000000000000..9fee324784ff --- /dev/null +++ b/app/tests/backlight/low-brightness/keycode_events.snapshot @@ -0,0 +1,12 @@ +Update backlight brightness: 40% +Update backlight brightness: 20% +Update backlight brightness: 0% +Update backlight brightness: 20% +Update backlight brightness: 0% +Update backlight brightness: 40% +Update backlight brightness: 60% +Update backlight brightness: 0% +Update backlight brightness: 40% +Update backlight brightness: 20% +Update backlight brightness: 0% +Update backlight brightness: 20% diff --git a/app/tests/backlight/low-brightness/native_posix_64.conf b/app/tests/backlight/low-brightness/native_posix_64.conf new file mode 100644 index 000000000000..bd29a072c9c9 --- /dev/null +++ b/app/tests/backlight/low-brightness/native_posix_64.conf @@ -0,0 +1,11 @@ +CONFIG_GPIO=y +CONFIG_GPIO_EMUL=y +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_DEBUG=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + +CONFIG_LED_GPIO=y +CONFIG_ZMK_BACKLIGHT=y diff --git a/app/tests/backlight/low-brightness/native_posix_64.keymap b/app/tests/backlight/low-brightness/native_posix_64.keymap new file mode 100644 index 000000000000..a151e0f6b960 --- /dev/null +++ b/app/tests/backlight/low-brightness/native_posix_64.keymap @@ -0,0 +1,39 @@ +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_ON */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + /* BL_OFF */ + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* BL_OFF */ + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_DEC */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* BL_INC */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/app/tests/ble/central/CMakeLists.txt b/app/tests/ble/central/CMakeLists.txt new file mode 100644 index 000000000000..020bef3813cc --- /dev/null +++ b/app/tests/ble/central/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(ble_test_central) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) + +# zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth) diff --git a/app/tests/ble/central/prj.conf b/app/tests/ble/central/prj.conf new file mode 100644 index 000000000000..735d4ac5bbf5 --- /dev/null +++ b/app/tests/ble/central/prj.conf @@ -0,0 +1,9 @@ +CONFIG_BT=y +CONFIG_LOG=y +CONFIG_BOOT_BANNER=n +CONFIG_BT_LOG_LEVEL_WRN=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_BT_CENTRAL=y +CONFIG_BT_SMP=y +CONFIG_BT_SCAN_WITH_IDENTITY=y +CONFIG_BT_GATT_CLIENT=y diff --git a/app/tests/ble/central/src/main.c b/app/tests/ble/central/src/main.c new file mode 100644 index 000000000000..67521e60da0b --- /dev/null +++ b/app/tests/ble/central/src/main.c @@ -0,0 +1,369 @@ +/* main.c - Application main entry point */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include + +LOG_MODULE_REGISTER(ble_central, 4); + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_ARCH_POSIX + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cmdline.h" +#include "soc.h" + +static bool disconnect_and_reconnect = false; +static bool clear_bond_on_disconnect = false; +static bool halt_after_bonding = false; +static int32_t wait_on_start = 0; + +static void ble_central_native_posix_options(void) { + static struct args_struct_t options[] = { + {.is_switch = true, + .option = "disconnect_and_reconnect", + .type = 'b', + .dest = (void *)&disconnect_and_reconnect, + .descript = "Disconnect and reconnect after the initial connection"}, + {.is_switch = true, + .option = "halt_after_bonding", + .type = 'b', + .dest = (void *)&halt_after_bonding, + .descript = "Halt any further logic after bonding the first time"}, + {.is_switch = true, + .option = "clear_bond_on_disconnect", + .type = 'b', + .dest = (void *)&clear_bond_on_disconnect, + .descript = "Clear bonds on disconnect and reconnect"}, + {.option = "wait_on_start", + .name = "milliseconds", + .type = 'u', + .dest = (void *)&wait_on_start, + .descript = "Time in milliseconds to wait before starting the test process"}, + ARG_TABLE_ENDMARKER}; + + native_add_command_line_opts(options); +} + +NATIVE_TASK(ble_central_native_posix_options, PRE_BOOT_1, 1); + +#endif + +static void start_scan(void); + +static struct bt_conn *default_conn; + +static struct bt_uuid_16 uuid = BT_UUID_INIT_16(0); +static struct bt_gatt_discover_params discover_params; +static struct bt_gatt_subscribe_params subscribe_params; + +static uint8_t notify_func(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, + const void *data, uint16_t length) { + if (!data) { + LOG_DBG("[UNSUBSCRIBED]"); + params->value_handle = 0U; + return BT_GATT_ITER_STOP; + } + + LOG_HEXDUMP_DBG(data, length, "payload"); + + return BT_GATT_ITER_CONTINUE; +} + +static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { + int err; + + if (!attr) { + LOG_DBG("[Discover complete]"); + (void)memset(params, 0, sizeof(*params)); + return BT_GATT_ITER_STOP; + } + + LOG_DBG("[ATTRIBUTE] handle %u", attr->handle); + + if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_HIDS)) { + memcpy(&uuid, BT_UUID_HIDS_REPORT, sizeof(uuid)); + discover_params.uuid = &uuid.uuid; + discover_params.start_handle = attr->handle + 1; + discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; + + err = bt_gatt_discover(conn, &discover_params); + if (err) { + LOG_DBG("[Discover failed] (err %d)", err); + } + } else if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_HIDS_REPORT)) { + memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid)); + discover_params.uuid = &uuid.uuid; + discover_params.start_handle = attr->handle + 2; + discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR; + subscribe_params.value_handle = bt_gatt_attr_value_handle(attr); + + err = bt_gatt_discover(conn, &discover_params); + if (err) { + LOG_DBG("[Discover failed] (err %d)", err); + } + } else { + subscribe_params.notify = notify_func; + subscribe_params.value = BT_GATT_CCC_NOTIFY; + subscribe_params.ccc_handle = attr->handle; + + err = bt_gatt_subscribe(conn, &subscribe_params); + if (err && err != -EALREADY) { + LOG_DBG("[Subscribe failed] (err %d)", err); + } else { + LOG_DBG("[SUBSCRIBED]"); + } + + return BT_GATT_ITER_STOP; + } + + return BT_GATT_ITER_STOP; +} + +static void reconnect(const bt_addr_le_t *addr) { + struct bt_le_conn_param *param; + int err = bt_le_scan_stop(); + if (err < 0) { + LOG_DBG("Stop LE scan failed (err %d)", err); + } + + param = BT_LE_CONN_PARAM_DEFAULT; + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &default_conn); + if (err < 0) { + LOG_DBG("Create conn failed (err %d)", err); + start_scan(); + } +} + +static bool eir_found(struct bt_data *data, void *user_data) { + bt_addr_le_t *addr = user_data; + int i; + + LOG_DBG("[AD]: %u data_len %u", data->type, data->data_len); + + switch (data->type) { + case BT_DATA_UUID16_SOME: + case BT_DATA_UUID16_ALL: + if (data->data_len % sizeof(uint16_t) != 0U) { + LOG_DBG("[AD malformed]"); + return true; + } + + for (i = 0; i < data->data_len; i += sizeof(uint16_t)) { + struct bt_le_conn_param *param; + struct bt_uuid *uuid; + uint16_t u16; + int err; + + memcpy(&u16, &data->data[i], sizeof(u16)); + uuid = BT_UUID_DECLARE_16(sys_le16_to_cpu(u16)); + if (bt_uuid_cmp(uuid, BT_UUID_HIDS)) { + continue; + } + + err = bt_le_scan_stop(); + if (err) { + LOG_DBG("[Stop LE scan failed] (err %d)", err); + continue; + } + + param = BT_LE_CONN_PARAM_DEFAULT; + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &default_conn); + if (err) { + LOG_DBG("[Create conn failed] (err %d)", err); + start_scan(); + } + + return false; + } + } + + return true; +} + +static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, + struct net_buf_simple *ad) { + char dev[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(addr, dev, sizeof(dev)); + LOG_DBG("[DEVICE]: %s, AD evt type %u, AD data len %u, RSSI %i", dev, type, ad->len, rssi); + + /* We're only interested in connectable events */ + if (type == BT_GAP_ADV_TYPE_ADV_IND) { + bt_data_parse(ad, eir_found, (void *)addr); + } else if (type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { + reconnect(addr); + } +} + +static void start_scan(void) { + int err; + + /* Use active scanning and disable duplicate filtering to handle any + * devices that might update their advertising data at runtime. */ + struct bt_le_scan_param scan_param = { + .type = BT_LE_SCAN_TYPE_ACTIVE, + .options = BT_LE_SCAN_OPT_NONE, + .interval = BT_GAP_SCAN_FAST_INTERVAL, + .window = BT_GAP_SCAN_FAST_WINDOW, + }; + + err = bt_le_scan_start(&scan_param, device_found); + if (err) { + LOG_DBG("[Scanning failed to start] (err %d)", err); + return; + } + + LOG_DBG("[Scanning successfully started]"); +} + +static void discover_conn(struct bt_conn *conn) { + int err; + + LOG_DBG("[Discovery started for conn]"); + memcpy(&uuid, BT_UUID_HIDS, sizeof(uuid)); + discover_params.uuid = &uuid.uuid; + discover_params.func = discover_func; + discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + discover_params.type = BT_GATT_DISCOVER_PRIMARY; + + err = bt_gatt_discover(default_conn, &discover_params); + if (err) { + LOG_DBG("[Discover failed] (err %d)", err); + return; + } +} + +static void connected(struct bt_conn *conn, uint8_t conn_err) { + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (conn_err) { + LOG_DBG("[Failed to connect to %s] (%u)", addr, conn_err); + + bt_conn_unref(default_conn); + default_conn = NULL; + + start_scan(); + return; + } + + LOG_DBG("[Connected]: %s", addr); + + if (conn == default_conn) { + if (bt_conn_get_security(conn) >= BT_SECURITY_L2) { + discover_conn(conn); + } else { + LOG_DBG("[Setting the security for the connection]"); + bt_conn_set_security(conn, BT_SECURITY_L2); + } + } +} + +static bool first_connect = true; +static void pairing_complete(struct bt_conn *conn, bool bonded) { LOG_DBG("Pairing complete"); } + +static void do_disconnect_of_active(struct k_work *work) { + bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + if (clear_bond_on_disconnect) { + bt_unpair(BT_ID_DEFAULT, bt_conn_get_dst(default_conn)); + } +} + +static K_WORK_DELAYABLE_DEFINE(disconnect_work, do_disconnect_of_active); + +static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) { + if (err > BT_SECURITY_ERR_SUCCESS) { + LOG_DBG("[Security Change Failed]"); + exit(1); + } + + if (halt_after_bonding) { + exit(1); + } + + bool do_disconnect = first_connect && disconnect_and_reconnect; + first_connect = false; + if (do_disconnect) { + k_work_reschedule(&disconnect_work, K_MSEC(500)); + } else { + discover_conn(conn); + } +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) { + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + LOG_DBG("[Disconnected]: %s (reason 0x%02x)", addr, reason); + + if (default_conn != conn) { + return; + } + + bt_conn_unref(default_conn); + default_conn = NULL; + + if (!halt_after_bonding) { + start_scan(); + } +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, + .security_changed = security_changed, +}; + +struct bt_conn_auth_info_cb auth_info_cb = { + .pairing_complete = pairing_complete, +}; + +void main(void) { + int err; + + if (wait_on_start > 0) { + k_sleep(K_MSEC(wait_on_start)); + } + + err = bt_conn_auth_info_cb_register(&auth_info_cb); + + err = bt_enable(NULL); + + if (err) { + LOG_DBG("[Bluetooth init failed] (err %d)", err); + return; + } + + LOG_DBG("[Bluetooth initialized]"); + + start_scan(); +} diff --git a/app/tests/ble/profiles/bond-clear-then-bond-second-client/centrals.txt b/app/tests/ble/profiles/bond-clear-then-bond-second-client/centrals.txt new file mode 100644 index 000000000000..80601bad8bc6 --- /dev/null +++ b/app/tests/ble/profiles/bond-clear-then-bond-second-client/centrals.txt @@ -0,0 +1,2 @@ +./ble_test_central.exe -d=2 -halt_after_bonding +./ble_test_central.exe -d=3 -wait_on_start=1300 diff --git a/app/tests/ble/profiles/bond-clear-then-bond-second-client/events.patterns b/app/tests/ble/profiles/bond-clear-then-bond-second-client/events.patterns new file mode 100644 index 000000000000..dbfe5627ecf6 --- /dev/null +++ b/app/tests/ble/profiles/bond-clear-then-bond-second-client/events.patterns @@ -0,0 +1,2 @@ +s/^d_02: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9] .{19}/profile 0 /p +s/^d_03: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9] .{19}/profile 1 /p diff --git a/app/tests/ble/profiles/bond-clear-then-bond-second-client/nrf52_bsim.keymap b/app/tests/ble/profiles/bond-clear-then-bond-second-client/nrf52_bsim.keymap new file mode 100644 index 000000000000..36eba046e037 --- /dev/null +++ b/app/tests/ble/profiles/bond-clear-then-bond-second-client/nrf52_bsim.keymap @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +&kscan { + events = + ; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &bt BT_SEL 0 &bt BT_CLR>; + }; + }; +}; diff --git a/app/tests/ble/profiles/bond-clear-then-bond-second-client/snapshot.log b/app/tests/ble/profiles/bond-clear-then-bond-second-client/snapshot.log new file mode 100644 index 000000000000..4939c0d76a88 --- /dev/null +++ b/app/tests/ble/profiles/bond-clear-then-bond-second-client/snapshot.log @@ -0,0 +1,33 @@ +profile 0 bt_id: No static addresses stored in controller +profile 0 ble_central: _posix_zephyr_main: [Bluetooth initialized] +profile 0 ble_central: start_scan: [Scanning successfully started] +profile 0 ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59 +profile 0 ble_central: eir_found: [AD]: 9 data_len 0 +profile 0 ble_central: eir_found: [AD]: 25 data_len 2 +profile 0 ble_central: eir_found: [AD]: 1 data_len 1 +profile 0 ble_central: eir_found: [AD]: 2 data_len 4 +profile 0 ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random) +profile 0 ble_central: connected: [Setting the security for the connection] +profile 0 ble_central: pairing_complete: Pairing complete +profile 1 bt_id: No static addresses stored in controller +profile 1 ble_central: _posix_zephyr_main: [Bluetooth initialized] +profile 1 ble_central: start_scan: [Scanning successfully started] +profile 1 ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59 +profile 1 ble_central: eir_found: [AD]: 9 data_len 0 +profile 1 ble_central: eir_found: [AD]: 25 data_len 2 +profile 1 ble_central: eir_found: [AD]: 1 data_len 1 +profile 1 ble_central: eir_found: [AD]: 2 data_len 4 +profile 1 ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random) +profile 1 ble_central: connected: [Setting the security for the connection] +profile 1 ble_central: pairing_complete: Pairing complete +profile 1 ble_central: discover_conn: [Discovery started for conn] +profile 1 ble_central: discover_func: [ATTRIBUTE] handle 23 +profile 1 ble_central: discover_func: [ATTRIBUTE] handle 28 +profile 1 ble_central: discover_func: [ATTRIBUTE] handle 30 +profile 1 ble_central: discover_func: [SUBSCRIBED] +profile 1 ble_central: notify_func: payload +profile 1 00 00 04 00 00 00 00 00 |........ +profile 1 ble_central: notify_func: payload +profile 1 00 00 00 00 00 00 00 00 |........ +profile 1 ble_central: notify_func: payload +profile 1 00 00 00 00 00 00 00 00 |........ diff --git a/app/tests/ble/profiles/bond-to-cleared-profile/centrals.txt b/app/tests/ble/profiles/bond-to-cleared-profile/centrals.txt new file mode 100644 index 000000000000..80601bad8bc6 --- /dev/null +++ b/app/tests/ble/profiles/bond-to-cleared-profile/centrals.txt @@ -0,0 +1,2 @@ +./ble_test_central.exe -d=2 -halt_after_bonding +./ble_test_central.exe -d=3 -wait_on_start=1300 diff --git a/app/tests/ble/profiles/bond-to-cleared-profile/events.patterns b/app/tests/ble/profiles/bond-to-cleared-profile/events.patterns new file mode 100644 index 000000000000..dbfe5627ecf6 --- /dev/null +++ b/app/tests/ble/profiles/bond-to-cleared-profile/events.patterns @@ -0,0 +1,2 @@ +s/^d_02: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9] .{19}/profile 0 /p +s/^d_03: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9] .{19}/profile 1 /p diff --git a/app/tests/ble/profiles/bond-to-cleared-profile/nrf52_bsim.keymap b/app/tests/ble/profiles/bond-to-cleared-profile/nrf52_bsim.keymap new file mode 100644 index 000000000000..45e2aea0b1ee --- /dev/null +++ b/app/tests/ble/profiles/bond-to-cleared-profile/nrf52_bsim.keymap @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +&kscan { + events = + ; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &bt BT_SEL 0 &bt BT_CLR>; + }; + }; +}; diff --git a/app/tests/ble/profiles/bond-to-cleared-profile/snapshot.log b/app/tests/ble/profiles/bond-to-cleared-profile/snapshot.log new file mode 100644 index 000000000000..4939c0d76a88 --- /dev/null +++ b/app/tests/ble/profiles/bond-to-cleared-profile/snapshot.log @@ -0,0 +1,33 @@ +profile 0 bt_id: No static addresses stored in controller +profile 0 ble_central: _posix_zephyr_main: [Bluetooth initialized] +profile 0 ble_central: start_scan: [Scanning successfully started] +profile 0 ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59 +profile 0 ble_central: eir_found: [AD]: 9 data_len 0 +profile 0 ble_central: eir_found: [AD]: 25 data_len 2 +profile 0 ble_central: eir_found: [AD]: 1 data_len 1 +profile 0 ble_central: eir_found: [AD]: 2 data_len 4 +profile 0 ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random) +profile 0 ble_central: connected: [Setting the security for the connection] +profile 0 ble_central: pairing_complete: Pairing complete +profile 1 bt_id: No static addresses stored in controller +profile 1 ble_central: _posix_zephyr_main: [Bluetooth initialized] +profile 1 ble_central: start_scan: [Scanning successfully started] +profile 1 ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59 +profile 1 ble_central: eir_found: [AD]: 9 data_len 0 +profile 1 ble_central: eir_found: [AD]: 25 data_len 2 +profile 1 ble_central: eir_found: [AD]: 1 data_len 1 +profile 1 ble_central: eir_found: [AD]: 2 data_len 4 +profile 1 ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random) +profile 1 ble_central: connected: [Setting the security for the connection] +profile 1 ble_central: pairing_complete: Pairing complete +profile 1 ble_central: discover_conn: [Discovery started for conn] +profile 1 ble_central: discover_func: [ATTRIBUTE] handle 23 +profile 1 ble_central: discover_func: [ATTRIBUTE] handle 28 +profile 1 ble_central: discover_func: [ATTRIBUTE] handle 30 +profile 1 ble_central: discover_func: [SUBSCRIBED] +profile 1 ble_central: notify_func: payload +profile 1 00 00 04 00 00 00 00 00 |........ +profile 1 ble_central: notify_func: payload +profile 1 00 00 00 00 00 00 00 00 |........ +profile 1 ble_central: notify_func: payload +profile 1 00 00 00 00 00 00 00 00 |........ diff --git a/app/tests/ble/profiles/connnect-and-output-to-selection/centrals.txt b/app/tests/ble/profiles/connnect-and-output-to-selection/centrals.txt new file mode 100644 index 000000000000..110e617d4b74 --- /dev/null +++ b/app/tests/ble/profiles/connnect-and-output-to-selection/centrals.txt @@ -0,0 +1 @@ +./ble_test_central.exe -d=2 diff --git a/app/tests/ble/profiles/connnect-and-output-to-selection/events.patterns b/app/tests/ble/profiles/connnect-and-output-to-selection/events.patterns new file mode 100644 index 000000000000..cca5a2d4ed3f --- /dev/null +++ b/app/tests/ble/profiles/connnect-and-output-to-selection/events.patterns @@ -0,0 +1 @@ +s/^d_02: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9] .{19}//p diff --git a/app/tests/ble/profiles/connnect-and-output-to-selection/nrf52_bsim.keymap b/app/tests/ble/profiles/connnect-and-output-to-selection/nrf52_bsim.keymap new file mode 100644 index 000000000000..7c67425e6a25 --- /dev/null +++ b/app/tests/ble/profiles/connnect-and-output-to-selection/nrf52_bsim.keymap @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +&kscan { + events = + ; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &bt BT_SEL 0 &bt BT_SEL 1>; + }; + }; +}; diff --git a/app/tests/ble/profiles/connnect-and-output-to-selection/snapshot.log b/app/tests/ble/profiles/connnect-and-output-to-selection/snapshot.log new file mode 100644 index 000000000000..092bb034f872 --- /dev/null +++ b/app/tests/ble/profiles/connnect-and-output-to-selection/snapshot.log @@ -0,0 +1,26 @@ + bt_id: No static addresses stored in controller + ble_central: _posix_zephyr_main: [Bluetooth initialized] + ble_central: start_scan: [Scanning successfully started] + ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59 + ble_central: eir_found: [AD]: 9 data_len 0 + ble_central: eir_found: [AD]: 25 data_len 2 + ble_central: eir_found: [AD]: 1 data_len 1 + ble_central: eir_found: [AD]: 2 data_len 4 + ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random) + ble_central: connected: [Setting the security for the connection] + ble_central: pairing_complete: Pairing complete + ble_central: discover_conn: [Discovery started for conn] + ble_central: discover_func: [ATTRIBUTE] handle 23 + ble_central: discover_func: [ATTRIBUTE] handle 28 + ble_central: discover_func: [ATTRIBUTE] handle 30 + ble_central: discover_func: [SUBSCRIBED] + ble_central: notify_func: payload + 00 00 04 00 00 00 00 00 |........ + ble_central: notify_func: payload + 00 00 00 00 00 00 00 00 |........ + ble_central: notify_func: payload + 00 00 05 00 00 00 00 00 |........ + ble_central: notify_func: payload + 00 00 00 00 00 00 00 00 |........ + ble_central: notify_func: payload + 00 00 00 00 00 00 00 00 |........ diff --git a/app/tests/ble/profiles/dont-bond-to-taken-profile/centrals.txt b/app/tests/ble/profiles/dont-bond-to-taken-profile/centrals.txt new file mode 100644 index 000000000000..80601bad8bc6 --- /dev/null +++ b/app/tests/ble/profiles/dont-bond-to-taken-profile/centrals.txt @@ -0,0 +1,2 @@ +./ble_test_central.exe -d=2 -halt_after_bonding +./ble_test_central.exe -d=3 -wait_on_start=1300 diff --git a/app/tests/ble/profiles/dont-bond-to-taken-profile/events.patterns b/app/tests/ble/profiles/dont-bond-to-taken-profile/events.patterns new file mode 100644 index 000000000000..dbfe5627ecf6 --- /dev/null +++ b/app/tests/ble/profiles/dont-bond-to-taken-profile/events.patterns @@ -0,0 +1,2 @@ +s/^d_02: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9] .{19}/profile 0 /p +s/^d_03: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9] .{19}/profile 1 /p diff --git a/app/tests/ble/profiles/dont-bond-to-taken-profile/nrf52_bsim.keymap b/app/tests/ble/profiles/dont-bond-to-taken-profile/nrf52_bsim.keymap new file mode 100644 index 000000000000..7c67425e6a25 --- /dev/null +++ b/app/tests/ble/profiles/dont-bond-to-taken-profile/nrf52_bsim.keymap @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +&kscan { + events = + ; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &bt BT_SEL 0 &bt BT_SEL 1>; + }; + }; +}; diff --git a/app/tests/ble/profiles/dont-bond-to-taken-profile/snapshot.log b/app/tests/ble/profiles/dont-bond-to-taken-profile/snapshot.log new file mode 100644 index 000000000000..d41eae797dfc --- /dev/null +++ b/app/tests/ble/profiles/dont-bond-to-taken-profile/snapshot.log @@ -0,0 +1,23 @@ +profile 0 bt_id: No static addresses stored in controller +profile 0 ble_central: _posix_zephyr_main: [Bluetooth initialized] +profile 0 ble_central: start_scan: [Scanning successfully started] +profile 0 ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59 +profile 0 ble_central: eir_found: [AD]: 9 data_len 0 +profile 0 ble_central: eir_found: [AD]: 25 data_len 2 +profile 0 ble_central: eir_found: [AD]: 1 data_len 1 +profile 0 ble_central: eir_found: [AD]: 2 data_len 4 +profile 0 ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random) +profile 0 ble_central: connected: [Setting the security for the connection] +profile 0 ble_central: pairing_complete: Pairing complete +profile 1 bt_id: No static addresses stored in controller +profile 1 ble_central: _posix_zephyr_main: [Bluetooth initialized] +profile 1 ble_central: start_scan: [Scanning successfully started] +profile 1 ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59 +profile 1 ble_central: eir_found: [AD]: 9 data_len 0 +profile 1 ble_central: eir_found: [AD]: 25 data_len 2 +profile 1 ble_central: eir_found: [AD]: 1 data_len 1 +profile 1 ble_central: eir_found: [AD]: 2 data_len 4 +profile 1 ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random) +profile 1 ble_central: connected: [Setting the security for the connection] +profile 1 bt_smp: reason 0x8 +profile 1 ble_central: security_changed: [Security Change Failed] diff --git a/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/centrals.txt b/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/centrals.txt new file mode 100644 index 000000000000..e60cdec044b1 --- /dev/null +++ b/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/centrals.txt @@ -0,0 +1,2 @@ +./ble_test_central.exe -d=2 +./ble_test_central.exe -d=3 -wait_on_start=1300 diff --git a/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/events.patterns b/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/events.patterns new file mode 100644 index 000000000000..dbfe5627ecf6 --- /dev/null +++ b/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/events.patterns @@ -0,0 +1,2 @@ +s/^d_02: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9] .{19}/profile 0 /p +s/^d_03: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9] .{19}/profile 1 /p diff --git a/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/nrf52_bsim.keymap b/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/nrf52_bsim.keymap new file mode 100644 index 000000000000..de6884ae11d6 --- /dev/null +++ b/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/nrf52_bsim.keymap @@ -0,0 +1,26 @@ +#include +#include +#include +#include + +&kscan { + events = + ; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &bt BT_SEL 0 &bt BT_SEL 1>; + }; + }; +}; diff --git a/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/snapshot.log b/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/snapshot.log new file mode 100644 index 000000000000..a03bbb095089 --- /dev/null +++ b/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/snapshot.log @@ -0,0 +1,42 @@ +profile 0 bt_id: No static addresses stored in controller +profile 0 ble_central: _posix_zephyr_main: [Bluetooth initialized] +profile 0 ble_central: start_scan: [Scanning successfully started] +profile 0 ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59 +profile 0 ble_central: eir_found: [AD]: 9 data_len 0 +profile 0 ble_central: eir_found: [AD]: 25 data_len 2 +profile 0 ble_central: eir_found: [AD]: 1 data_len 1 +profile 0 ble_central: eir_found: [AD]: 2 data_len 4 +profile 0 ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random) +profile 0 ble_central: connected: [Setting the security for the connection] +profile 0 ble_central: pairing_complete: Pairing complete +profile 0 ble_central: discover_conn: [Discovery started for conn] +profile 0 ble_central: discover_func: [ATTRIBUTE] handle 23 +profile 1 bt_id: No static addresses stored in controller +profile 1 ble_central: _posix_zephyr_main: [Bluetooth initialized] +profile 1 ble_central: start_scan: [Scanning successfully started] +profile 0 ble_central: discover_func: [ATTRIBUTE] handle 28 +profile 0 ble_central: discover_func: [ATTRIBUTE] handle 30 +profile 0 ble_central: discover_func: [SUBSCRIBED] +profile 0 ble_central: notify_func: payload +profile 0 00 00 04 00 00 00 00 00 |........ +profile 0 ble_central: notify_func: payload +profile 0 00 00 00 00 00 00 00 00 |........ +profile 1 ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59 +profile 1 ble_central: eir_found: [AD]: 9 data_len 0 +profile 1 ble_central: eir_found: [AD]: 25 data_len 2 +profile 1 ble_central: eir_found: [AD]: 1 data_len 1 +profile 1 ble_central: eir_found: [AD]: 2 data_len 4 +profile 1 ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random) +profile 1 ble_central: connected: [Setting the security for the connection] +profile 1 ble_central: pairing_complete: Pairing complete +profile 1 ble_central: discover_conn: [Discovery started for conn] +profile 1 ble_central: discover_func: [ATTRIBUTE] handle 23 +profile 1 ble_central: discover_func: [ATTRIBUTE] handle 28 +profile 1 ble_central: discover_func: [ATTRIBUTE] handle 30 +profile 1 ble_central: discover_func: [SUBSCRIBED] +profile 1 ble_central: notify_func: payload +profile 1 00 00 05 00 00 00 00 00 |........ +profile 1 ble_central: notify_func: payload +profile 1 00 00 00 00 00 00 00 00 |........ +profile 1 ble_central: notify_func: payload +profile 1 00 00 00 00 00 00 00 00 |........ diff --git a/app/tests/ble/profiles/reconnect-then-output-to-selection/centrals.txt b/app/tests/ble/profiles/reconnect-then-output-to-selection/centrals.txt new file mode 100644 index 000000000000..2478118532e1 --- /dev/null +++ b/app/tests/ble/profiles/reconnect-then-output-to-selection/centrals.txt @@ -0,0 +1 @@ +./ble_test_central.exe -d=2 -disconnect_and_reconnect diff --git a/app/tests/ble/profiles/reconnect-then-output-to-selection/events.patterns b/app/tests/ble/profiles/reconnect-then-output-to-selection/events.patterns new file mode 100644 index 000000000000..cca5a2d4ed3f --- /dev/null +++ b/app/tests/ble/profiles/reconnect-then-output-to-selection/events.patterns @@ -0,0 +1 @@ +s/^d_02: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9] .{19}//p diff --git a/app/tests/ble/profiles/reconnect-then-output-to-selection/nrf52_bsim.keymap b/app/tests/ble/profiles/reconnect-then-output-to-selection/nrf52_bsim.keymap new file mode 100644 index 000000000000..7c67425e6a25 --- /dev/null +++ b/app/tests/ble/profiles/reconnect-then-output-to-selection/nrf52_bsim.keymap @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +&kscan { + events = + ; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &bt BT_SEL 0 &bt BT_SEL 1>; + }; + }; +}; diff --git a/app/tests/ble/profiles/reconnect-then-output-to-selection/snapshot.log b/app/tests/ble/profiles/reconnect-then-output-to-selection/snapshot.log new file mode 100644 index 000000000000..bf6cc49ea0f4 --- /dev/null +++ b/app/tests/ble/profiles/reconnect-then-output-to-selection/snapshot.log @@ -0,0 +1,35 @@ + bt_id: No static addresses stored in controller + ble_central: _posix_zephyr_main: [Bluetooth initialized] + ble_central: start_scan: [Scanning successfully started] + ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59 + ble_central: eir_found: [AD]: 9 data_len 0 + ble_central: eir_found: [AD]: 25 data_len 2 + ble_central: eir_found: [AD]: 1 data_len 1 + ble_central: eir_found: [AD]: 2 data_len 4 + ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random) + ble_central: connected: [Setting the security for the connection] + ble_central: pairing_complete: Pairing complete + ble_central: disconnected: [Disconnected]: ED:3B:20:15:18:12 (random) (reason 0x16) + ble_central: start_scan: [Scanning successfully started] + ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59 + ble_central: eir_found: [AD]: 9 data_len 0 + ble_central: eir_found: [AD]: 25 data_len 2 + ble_central: eir_found: [AD]: 1 data_len 1 + ble_central: eir_found: [AD]: 2 data_len 4 + ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random) + ble_central: connected: [Setting the security for the connection] + ble_central: discover_conn: [Discovery started for conn] + ble_central: discover_func: [ATTRIBUTE] handle 23 + ble_central: discover_func: [ATTRIBUTE] handle 28 + ble_central: discover_func: [ATTRIBUTE] handle 30 + ble_central: discover_func: [SUBSCRIBED] + ble_central: notify_func: payload + 00 00 04 00 00 00 00 00 |........ + ble_central: notify_func: payload + 00 00 00 00 00 00 00 00 |........ + ble_central: notify_func: payload + 00 00 05 00 00 00 00 00 |........ + ble_central: notify_func: payload + 00 00 00 00 00 00 00 00 |........ + ble_central: notify_func: payload + 00 00 00 00 00 00 00 00 |........ diff --git a/app/tests/caps-word/behavior_keymap.dtsi b/app/tests/caps-word/behavior_keymap.dtsi new file mode 100644 index 000000000000..2e404afbfe3c --- /dev/null +++ b/app/tests/caps-word/behavior_keymap.dtsi @@ -0,0 +1,16 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &caps_word &kp A + &kp N6 &kp MINUS + >; + }; + }; +}; diff --git a/app/tests/caps-word/continue-with-modifiers/events.patterns b/app/tests/caps-word/continue-with-modifiers/events.patterns new file mode 100644 index 000000000000..dd4d3d3f7008 --- /dev/null +++ b/app/tests/caps-word/continue-with-modifiers/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode_//p +s/.*hid_implicit_modifiers_//p +s/.*caps_word_enhance_usage/enhance_usage/p +s/.*caps_word_is_caps_includelist/caps_includelist/p \ No newline at end of file diff --git a/app/tests/caps-word/continue-with-modifiers/keycode_events.snapshot b/app/tests/caps-word/continue-with-modifiers/keycode_events.snapshot new file mode 100644 index 000000000000..b4752fd416e0 --- /dev/null +++ b/app/tests/caps-word/continue-with-modifiers/keycode_events.snapshot @@ -0,0 +1,20 @@ +enhance_usage: Enhancing usage 0x04 with modifiers: 0x02 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x02 explicit_mods 0x00 +press: Modifiers set to 0x02 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 +pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x02 +caps_includelist: Comparing with 0x07 - 0x2D (with implicit mods: 0x02) +caps_includelist: Continuing capsword, found included usage: 0x07 - 0x2D +pressed: usage_page 0x07 keycode 0x2D implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x02 +released: usage_page 0x07 keycode 0x2D implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x02 +released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 +enhance_usage: Enhancing usage 0x04 with modifiers: 0x02 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x02 explicit_mods 0x00 +press: Modifiers set to 0x02 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 diff --git a/app/tests/caps-word/continue-with-modifiers/native_posix_64.keymap b/app/tests/caps-word/continue-with-modifiers/native_posix_64.keymap new file mode 100644 index 000000000000..fe5360e69897 --- /dev/null +++ b/app/tests/caps-word/continue-with-modifiers/native_posix_64.keymap @@ -0,0 +1,32 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &caps_word &kp A + &kp LSHFT &kp MINUS + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/caps-word/continue-with-non-alpha-continue-list-item/events.patterns b/app/tests/caps-word/continue-with-non-alpha-continue-list-item/events.patterns new file mode 100644 index 000000000000..dd4d3d3f7008 --- /dev/null +++ b/app/tests/caps-word/continue-with-non-alpha-continue-list-item/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode_//p +s/.*hid_implicit_modifiers_//p +s/.*caps_word_enhance_usage/enhance_usage/p +s/.*caps_word_is_caps_includelist/caps_includelist/p \ No newline at end of file diff --git a/app/tests/caps-word/continue-with-non-alpha-continue-list-item/keycode_events.snapshot b/app/tests/caps-word/continue-with-non-alpha-continue-list-item/keycode_events.snapshot new file mode 100644 index 000000000000..8910db99690b --- /dev/null +++ b/app/tests/caps-word/continue-with-non-alpha-continue-list-item/keycode_events.snapshot @@ -0,0 +1,17 @@ +enhance_usage: Enhancing usage 0x04 with modifiers: 0x02 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x02 explicit_mods 0x00 +press: Modifiers set to 0x02 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 +caps_includelist: Comparing with 0x07 - 0x2D (with implicit mods: 0x02) +caps_includelist: Comparing with 0x07 - 0x2D (with implicit mods: 0x00) +caps_includelist: Continuing capsword, found included usage: 0x07 - 0x2D +pressed: usage_page 0x07 keycode 0x2D implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x2D implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 +enhance_usage: Enhancing usage 0x04 with modifiers: 0x02 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x02 explicit_mods 0x00 +press: Modifiers set to 0x02 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 diff --git a/app/tests/caps-word/continue-with-non-alpha-continue-list-item/native_posix_64.keymap b/app/tests/caps-word/continue-with-non-alpha-continue-list-item/native_posix_64.keymap new file mode 100644 index 000000000000..08b173bd771d --- /dev/null +++ b/app/tests/caps-word/continue-with-non-alpha-continue-list-item/native_posix_64.keymap @@ -0,0 +1,21 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&caps_word { + continue-list = ; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/caps-word/continue-with-non-modified-numeric-usage-id/events.patterns b/app/tests/caps-word/continue-with-non-modified-numeric-usage-id/events.patterns new file mode 100644 index 000000000000..dd4d3d3f7008 --- /dev/null +++ b/app/tests/caps-word/continue-with-non-modified-numeric-usage-id/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode_//p +s/.*hid_implicit_modifiers_//p +s/.*caps_word_enhance_usage/enhance_usage/p +s/.*caps_word_is_caps_includelist/caps_includelist/p \ No newline at end of file diff --git a/app/tests/caps-word/continue-with-non-modified-numeric-usage-id/keycode_events.snapshot b/app/tests/caps-word/continue-with-non-modified-numeric-usage-id/keycode_events.snapshot new file mode 100644 index 000000000000..23ddbe1b1906 --- /dev/null +++ b/app/tests/caps-word/continue-with-non-modified-numeric-usage-id/keycode_events.snapshot @@ -0,0 +1,14 @@ +enhance_usage: Enhancing usage 0x04 with modifiers: 0x02 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x02 explicit_mods 0x00 +press: Modifiers set to 0x02 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 +pressed: usage_page 0x07 keycode 0x23 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x23 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 +enhance_usage: Enhancing usage 0x04 with modifiers: 0x02 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x02 explicit_mods 0x00 +press: Modifiers set to 0x02 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 diff --git a/app/tests/caps-word/continue-with-non-modified-numeric-usage-id/native_posix_64.keymap b/app/tests/caps-word/continue-with-non-modified-numeric-usage-id/native_posix_64.keymap new file mode 100644 index 000000000000..cde97c846f37 --- /dev/null +++ b/app/tests/caps-word/continue-with-non-modified-numeric-usage-id/native_posix_64.keymap @@ -0,0 +1,21 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&caps_word { + continue-list = ; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/caps-word/deactivate-by-non-alpha-non-continuation/events.patterns b/app/tests/caps-word/deactivate-by-non-alpha-non-continuation/events.patterns new file mode 100644 index 000000000000..fa75ab0c7df8 --- /dev/null +++ b/app/tests/caps-word/deactivate-by-non-alpha-non-continuation/events.patterns @@ -0,0 +1,3 @@ +s/.*hid_listener_keycode_//p +s/.*hid_implicit_modifiers_//p +s/.*caps_word_enhance_usage/enhance_usage/p \ No newline at end of file diff --git a/app/tests/caps-word/deactivate-by-non-alpha-non-continuation/keycode_events.snapshot b/app/tests/caps-word/deactivate-by-non-alpha-non-continuation/keycode_events.snapshot new file mode 100644 index 000000000000..f479db1219ab --- /dev/null +++ b/app/tests/caps-word/deactivate-by-non-alpha-non-continuation/keycode_events.snapshot @@ -0,0 +1,13 @@ +enhance_usage: Enhancing usage 0x04 with modifiers: 0x02 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x02 explicit_mods 0x00 +press: Modifiers set to 0x02 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 +pressed: usage_page 0x07 keycode 0x2D implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x2D implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 diff --git a/app/tests/caps-word/deactivate-by-non-alpha-non-continuation/native_posix_64.keymap b/app/tests/caps-word/deactivate-by-non-alpha-non-continuation/native_posix_64.keymap new file mode 100644 index 000000000000..3fbb020b5cfb --- /dev/null +++ b/app/tests/caps-word/deactivate-by-non-alpha-non-continuation/native_posix_64.keymap @@ -0,0 +1,17 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/caps-word/deactivate-by-second-press/events.patterns b/app/tests/caps-word/deactivate-by-second-press/events.patterns new file mode 100644 index 000000000000..fa75ab0c7df8 --- /dev/null +++ b/app/tests/caps-word/deactivate-by-second-press/events.patterns @@ -0,0 +1,3 @@ +s/.*hid_listener_keycode_//p +s/.*hid_implicit_modifiers_//p +s/.*caps_word_enhance_usage/enhance_usage/p \ No newline at end of file diff --git a/app/tests/caps-word/deactivate-by-second-press/keycode_events.snapshot b/app/tests/caps-word/deactivate-by-second-press/keycode_events.snapshot new file mode 100644 index 000000000000..5181f75b1f84 --- /dev/null +++ b/app/tests/caps-word/deactivate-by-second-press/keycode_events.snapshot @@ -0,0 +1,9 @@ +enhance_usage: Enhancing usage 0x04 with modifiers: 0x02 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x02 explicit_mods 0x00 +press: Modifiers set to 0x02 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 diff --git a/app/tests/caps-word/deactivate-by-second-press/native_posix.keymap b/app/tests/caps-word/deactivate-by-second-press/native_posix.keymap new file mode 100644 index 000000000000..121a827cce6c --- /dev/null +++ b/app/tests/caps-word/deactivate-by-second-press/native_posix.keymap @@ -0,0 +1,17 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/caps-word/deactivate-by-second-press/native_posix_64.keymap b/app/tests/caps-word/deactivate-by-second-press/native_posix_64.keymap new file mode 100644 index 000000000000..b8ae4ee02eb2 --- /dev/null +++ b/app/tests/caps-word/deactivate-by-second-press/native_posix_64.keymap @@ -0,0 +1,17 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10000) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,1,30) + ZMK_MOCK_RELEASE(0,1,30) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,30) + ZMK_MOCK_PRESS(0,1,30) + ZMK_MOCK_RELEASE(0,1,1000) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/combos-and-holdtaps-0/events.patterns b/app/tests/combo/combos-and-holdtaps-0/events.patterns new file mode 100644 index 000000000000..b1342af4d971 --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-0/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p diff --git a/app/tests/combo/combos-and-holdtaps-0/keycode_events.snapshot b/app/tests/combo/combos-and-holdtaps-0/keycode_events.snapshot new file mode 100644 index 000000000000..16e8744e25ae --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-0/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/combos-and-holdtaps-0/native_posix_64.keymap b/app/tests/combo/combos-and-holdtaps-0/native_posix_64.keymap new file mode 100644 index 000000000000..6f9f9860f273 --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-0/native_posix_64.keymap @@ -0,0 +1,46 @@ +#include +#include +#include + +&mt { + flavor = "hold-preferred"; +}; + +/* +This test fails if the order of event handlers for hold-taps +and combos is wrong. Hold-taps need to process key position events +first so the decision to hold or tap can be made. +*/ +/ { + combos { + compatible = "zmk,combos"; + + combo_two { + timeout-ms = <100>; + key-positions = <1 2>; + bindings = <&kp Y>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &mt LEFT_CONTROL A &kp B + &kp C &none + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,2,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,2,10) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/combos-and-holdtaps-1/events.patterns b/app/tests/combo/combos-and-holdtaps-1/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-1/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/combo/combos-and-holdtaps-1/keycode_events.snapshot b/app/tests/combo/combos-and-holdtaps-1/keycode_events.snapshot new file mode 100644 index 000000000000..257d7e344249 --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-1/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/combos-and-holdtaps-1/native_posix_64.keymap b/app/tests/combo/combos-and-holdtaps-1/native_posix_64.keymap new file mode 100644 index 000000000000..0982d34befa0 --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-1/native_posix_64.keymap @@ -0,0 +1,41 @@ +#include +#include +#include + +&mt { + flavor = "hold-preferred"; +}; + +/* this test checks if hold-taps can be part of a combo */ +/ { + combos { + compatible = "zmk,combos"; + combo_two { + timeout-ms = <100>; + key-positions = <0 1>; + bindings = <&kp Y>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &mt LEFT_CONTROL A &kp B + &kp C &none + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,2,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,2,10) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/combos-and-holdtaps-2/events.patterns b/app/tests/combo/combos-and-holdtaps-2/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-2/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/combo/combos-and-holdtaps-2/keycode_events.snapshot b/app/tests/combo/combos-and-holdtaps-2/keycode_events.snapshot new file mode 100644 index 000000000000..7a2ec83f1505 --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-2/keycode_events.snapshot @@ -0,0 +1,2 @@ +pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0xE4 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/combos-and-holdtaps-2/native_posix_64.keymap b/app/tests/combo/combos-and-holdtaps-2/native_posix_64.keymap new file mode 100644 index 000000000000..6feebf2f76fa --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-2/native_posix_64.keymap @@ -0,0 +1,44 @@ +#include +#include +#include + +&mt { + flavor = "hold-preferred"; +}; + +/* This test verifies that hold-tap keys can observe + * events which were released from combos. + */ +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = <100>; + key-positions = <0 2>; + bindings = <&kp Y>; + }; + combo_two { + timeout-ms = <100>; + key-positions = <1 3>; + bindings = <&kp Z>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &mt LEFT_CONTROL A &mt RIGHT_CONTROL B + &none &none + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,0) + ZMK_MOCK_PRESS(0,1,300) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/combos-and-holdtaps-3/events.patterns b/app/tests/combo/combos-and-holdtaps-3/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-3/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/combo/combos-and-holdtaps-3/keycode_events.snapshot b/app/tests/combo/combos-and-holdtaps-3/keycode_events.snapshot new file mode 100644 index 000000000000..843832ddbc14 --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-3/keycode_events.snapshot @@ -0,0 +1,5 @@ +pressed: usage_page 0x07 keycode 0xE5 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/combos-and-holdtaps-3/native_posix_64.keymap b/app/tests/combo/combos-and-holdtaps-3/native_posix_64.keymap new file mode 100644 index 000000000000..fbbd7a9e501a --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-3/native_posix_64.keymap @@ -0,0 +1,39 @@ +#include +#include +#include + +&mt { + flavor = "hold-preferred"; +}; + +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = <40>; + key-positions = <0 1>; + bindings = <&kp X>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &mt RSHFT RET &kp C + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(0,1,50) + ZMK_MOCK_RELEASE(1,1,50) + >; +}; diff --git a/app/tests/combo/combos-and-holdtaps-4/events.patterns b/app/tests/combo/combos-and-holdtaps-4/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-4/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/combo/combos-and-holdtaps-4/keycode_events.snapshot b/app/tests/combo/combos-and-holdtaps-4/keycode_events.snapshot new file mode 100644 index 000000000000..f84bc761b332 --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-4/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/combos-and-holdtaps-4/native_posix_64.keymap b/app/tests/combo/combos-and-holdtaps-4/native_posix_64.keymap new file mode 100644 index 000000000000..b3e987cf277b --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-4/native_posix_64.keymap @@ -0,0 +1,45 @@ +#include +#include +#include + + +#define ZMK_COMBO(name, combo_bindings, keypos, combo_term) \ +/ { \ + combos { \ + compatible = "zmk,combos"; \ + combo_ ## name { \ + key-positions = ; \ + bindings = ; \ + timeout-ms = ; \ + }; \ + }; \ +}; + +ZMK_COMBO(qmark, &kp QMARK, 0 3, 30) +ZMK_COMBO(dllr, &kp DLLR, 1 3, 50) +ZMK_COMBO(tilde, &kp TILDE, 3 4, 50) + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &none &none + &kp A &mt LSHFT T + &none + >; + }; + }; +}; + +&kscan { + rows = <3>; + columns = <2>; + events = < + ZMK_MOCK_PRESS(1,1,500) + ZMK_MOCK_PRESS(1,0,100) + ZMK_MOCK_RELEASE(1,0,500) + ZMK_MOCK_RELEASE(1,1,0) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/layer-filter-0/events.patterns b/app/tests/combo/layer-filter-0/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/combo/layer-filter-0/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/combo/layer-filter-0/keycode_events.snapshot b/app/tests/combo/layer-filter-0/keycode_events.snapshot new file mode 100644 index 000000000000..21bf0c3ffdbb --- /dev/null +++ b/app/tests/combo/layer-filter-0/keycode_events.snapshot @@ -0,0 +1,8 @@ +pressed: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/layer-filter-0/native_posix_64.keymap b/app/tests/combo/layer-filter-0/native_posix_64.keymap new file mode 100644 index 000000000000..12946183249f --- /dev/null +++ b/app/tests/combo/layer-filter-0/native_posix_64.keymap @@ -0,0 +1,77 @@ +#include +#include +#include + +/* it is useful to set timeout to a large value when attaching a debugger. */ +#define TIMEOUT (60*60*1000) + +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = ; + key-positions = <0 1>; + bindings = <&kp X>; + layers = <0>; + }; + + combo_two { + timeout-ms = ; + key-positions = <0 1>; + bindings = <&kp Y>; + layers = <1>; + }; + + combo_three { + timeout-ms = ; + key-positions = <0 2>; + bindings = <&kp Z>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &kp C &tog 1 + >; + }; + + filtered_layer { + bindings = < + &kp A &kp B + &kp C &tog 0 + >; + }; + }; +}; + +&kscan { + events = < + /* Combo One */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + /* Combo Three */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(1,1,10) + /* Toggle Layer */ + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + /* Combo Two */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + /* Combo Three */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(1,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/layer-filter-1/events.patterns b/app/tests/combo/layer-filter-1/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/combo/layer-filter-1/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/combo/layer-filter-1/keycode_events.snapshot b/app/tests/combo/layer-filter-1/keycode_events.snapshot new file mode 100644 index 000000000000..bb47d85203c5 --- /dev/null +++ b/app/tests/combo/layer-filter-1/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/layer-filter-1/native_posix_64.keymap b/app/tests/combo/layer-filter-1/native_posix_64.keymap new file mode 100644 index 000000000000..6d4a30212781 --- /dev/null +++ b/app/tests/combo/layer-filter-1/native_posix_64.keymap @@ -0,0 +1,39 @@ +#include +#include +#include + +/* it is useful to set timeout to a large value when attaching a debugger. */ +#define TIMEOUT (60*60*1000) + +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = ; + key-positions = <0 1>; + bindings = <&kp X>; + layers = <1>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &kp C &tog 1 + >; + }; + }; +}; + +&kscan { + events = < + /* Combo One */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/multiple-timeouts/events.patterns b/app/tests/combo/multiple-timeouts/events.patterns new file mode 100644 index 000000000000..b1342af4d971 --- /dev/null +++ b/app/tests/combo/multiple-timeouts/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p diff --git a/app/tests/combo/multiple-timeouts/keycode_events.snapshot b/app/tests/combo/multiple-timeouts/keycode_events.snapshot new file mode 100644 index 000000000000..bb47d85203c5 --- /dev/null +++ b/app/tests/combo/multiple-timeouts/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/multiple-timeouts/native_posix_64.keymap b/app/tests/combo/multiple-timeouts/native_posix_64.keymap new file mode 100644 index 000000000000..0e3ae996a191 --- /dev/null +++ b/app/tests/combo/multiple-timeouts/native_posix_64.keymap @@ -0,0 +1,39 @@ +#include +#include +#include + +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = <30>; + key-positions = <0 1>; + bindings = <&kp C>; + }; + combo_two { + timeout-ms = <120>; + key-positions = <0 1 2>; + bindings = <&kp C>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &none &none + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,100) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/overlapping-combos-0/events.patterns b/app/tests/combo/overlapping-combos-0/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/combo/overlapping-combos-0/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/combo/overlapping-combos-0/keycode_events.snapshot b/app/tests/combo/overlapping-combos-0/keycode_events.snapshot new file mode 100644 index 000000000000..9e87293a69ca --- /dev/null +++ b/app/tests/combo/overlapping-combos-0/keycode_events.snapshot @@ -0,0 +1,20 @@ +pressed: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/overlapping-combos-0/native_posix_64.keymap b/app/tests/combo/overlapping-combos-0/native_posix_64.keymap new file mode 100644 index 000000000000..a9a229fb3a22 --- /dev/null +++ b/app/tests/combo/overlapping-combos-0/native_posix_64.keymap @@ -0,0 +1,116 @@ +#include +#include +#include + +/* + combo 0 timeout inf + combo 01 timeout inf + combo 0123 timeout inf + press 012 in any combination, release any of those keys + expected: combo 012 on key-release + */ + +/* it is useful to set timeout to a large value when attaching a debugger. */ +#define TIMEOUT (60*60*1000) + +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = ; + key-positions = <0 1 2>; + bindings = <&kp X>; + }; + + combo_two { + timeout-ms = ; + key-positions = <0 2>; + bindings = <&kp Y>; + }; + + combo_three { + timeout-ms = ; + key-positions = <1>; + bindings = <&kp Z>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &kp C &none + >; + }; + }; +}; +&kscan { + events = < + /* all permutations of combo one press, combo triggered by release */ + /* while debugging these, you may want to set the release_timer to a high number */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,2,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,2,10) + + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,2,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,2,10) + ZMK_MOCK_RELEASE(0,1,10) + + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,2,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,2,10) + + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,2,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,2,10) + ZMK_MOCK_RELEASE(0,0,10) + + ZMK_MOCK_PRESS(0,2,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,2,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + + ZMK_MOCK_PRESS(0,2,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,2,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + + /* all permutations of combo two press and release, combo triggered by release */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,2,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,2,10) + + ZMK_MOCK_PRESS(0,2,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,2,10) + ZMK_MOCK_RELEASE(0,0,10) + + ZMK_MOCK_PRESS(0,2,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,2,10) + + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,2,10) + ZMK_MOCK_RELEASE(0,2,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/overlapping-combos-1/events.patterns b/app/tests/combo/overlapping-combos-1/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/combo/overlapping-combos-1/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/combo/overlapping-combos-1/keycode_events.snapshot b/app/tests/combo/overlapping-combos-1/keycode_events.snapshot new file mode 100644 index 000000000000..e69112369fb5 --- /dev/null +++ b/app/tests/combo/overlapping-combos-1/keycode_events.snapshot @@ -0,0 +1,8 @@ +pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/overlapping-combos-1/native_posix_64.keymap b/app/tests/combo/overlapping-combos-1/native_posix_64.keymap new file mode 100644 index 000000000000..f3b0ab975b11 --- /dev/null +++ b/app/tests/combo/overlapping-combos-1/native_posix_64.keymap @@ -0,0 +1,64 @@ +#include +#include +#include + +/* + combo 01 timeout 50 + combo 012 timeout 100 + AB is pressed within 50ms, C is never pressed. + expected outcome: AB after 100ms +*/ +/ { + combos { + compatible = "zmk,combos"; + combo_two { + timeout-ms = <50>; + key-positions = <0 1>; + bindings = <&kp Y>; + }; + + combo_three { + timeout-ms = <100>; + key-positions = <0 1 2>; + bindings = <&kp X>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &kp C &none + >; + }; + }; +}; + +&kscan { + events = < + /* if you're debugging these, remember that the timer can be triggered between + events while stepping through code. */ + /* all permutations of combo two press and release, combo triggered by timeout */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,100) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,0,100) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,0,100) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,100) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/overlapping-combos-2/events.patterns b/app/tests/combo/overlapping-combos-2/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/combo/overlapping-combos-2/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/combo/overlapping-combos-2/keycode_events.snapshot b/app/tests/combo/overlapping-combos-2/keycode_events.snapshot new file mode 100644 index 000000000000..257d7e344249 --- /dev/null +++ b/app/tests/combo/overlapping-combos-2/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/overlapping-combos-2/native_posix_64.keymap b/app/tests/combo/overlapping-combos-2/native_posix_64.keymap new file mode 100644 index 000000000000..beed222e8906 --- /dev/null +++ b/app/tests/combo/overlapping-combos-2/native_posix_64.keymap @@ -0,0 +1,51 @@ +#include +#include +#include + +/* + combo 01 timeout 100 + combo 0123 timeout 100 + press 012, wait until timeout runs out + expected: combo 01 after 100ms, immediately followed by key 2. + */ +/ { + combos { + compatible = "zmk,combos"; + combo_two { + timeout-ms = <100>; + key-positions = <0 1>; + bindings = <&kp Y>; + }; + + combo_four { + timeout-ms = <100>; + key-positions = <0 1 2 3>; + bindings = <&kp W>; + }; + + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &kp C &none + >; + }; + }; +}; + +&kscan { + events = < + /* if you're debugging these, remember that the timer can be triggered between + events while stepping through code. */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,2,100) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,2,100) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/overlapping-combos-3/events.patterns b/app/tests/combo/overlapping-combos-3/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/combo/overlapping-combos-3/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/combo/overlapping-combos-3/keycode_events.snapshot b/app/tests/combo/overlapping-combos-3/keycode_events.snapshot new file mode 100644 index 000000000000..38513aabade9 --- /dev/null +++ b/app/tests/combo/overlapping-combos-3/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/overlapping-combos-3/native_posix_64.keymap b/app/tests/combo/overlapping-combos-3/native_posix_64.keymap new file mode 100644 index 000000000000..2e7e4225bb25 --- /dev/null +++ b/app/tests/combo/overlapping-combos-3/native_posix_64.keymap @@ -0,0 +1,52 @@ +#include +#include +#include + +/* + combo 12 timeout 100 + combo 0123 timeout 100 + press 012, release 2 + expected: key pos 0 followed by combo 12 + */ +/ { + combos { + compatible = "zmk,combos"; + combo_two { + timeout-ms = <100>; + key-positions = <1 2>; + bindings = <&kp Y>; + }; + + + combo_four { + timeout-ms = <100>; + key-positions = <0 1 2 3>; + bindings = <&kp W>; + }; + + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &kp C &none + >; + }; + }; +}; + +&kscan { + events = < + /* if you're debugging these, remember that the timer can be triggered between + events while stepping through code. */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,2,100) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,2,100) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/overlapping-combos-4-different-timeouts/events.patterns b/app/tests/combo/overlapping-combos-4-different-timeouts/events.patterns new file mode 100644 index 000000000000..89015deee067 --- /dev/null +++ b/app/tests/combo/overlapping-combos-4-different-timeouts/events.patterns @@ -0,0 +1 @@ +s/.*\(hid_listener_keycode_pressed\|filter_timed_out_candidates\): //p \ No newline at end of file diff --git a/app/tests/combo/overlapping-combos-4-different-timeouts/keycode_events.snapshot b/app/tests/combo/overlapping-combos-4-different-timeouts/keycode_events.snapshot new file mode 100644 index 000000000000..8fe441ff46e3 --- /dev/null +++ b/app/tests/combo/overlapping-combos-4-different-timeouts/keycode_events.snapshot @@ -0,0 +1,8 @@ +after filtering out timed out combo candidates: remaining_candidates=2 timestamp=71 +after filtering out timed out combo candidates: remaining_candidates=1 timestamp=81 +after filtering out timed out combo candidates: remaining_candidates=0 timestamp=91 +usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +after filtering out timed out combo candidates: remaining_candidates=2 timestamp=143 +after filtering out timed out combo candidates: remaining_candidates=1 timestamp=153 +after filtering out timed out combo candidates: remaining_candidates=1 timestamp=159 +usage_page 0x07 keycode 0x1D implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/overlapping-combos-4-different-timeouts/native_posix_64.keymap b/app/tests/combo/overlapping-combos-4-different-timeouts/native_posix_64.keymap new file mode 100644 index 000000000000..06a67b881340 --- /dev/null +++ b/app/tests/combo/overlapping-combos-4-different-timeouts/native_posix_64.keymap @@ -0,0 +1,97 @@ +#include +#include +#include + +#define kA 0 +#define kB 1 +#define kC 2 +#define kD 3 + +/ { + combos { + compatible = "zmk,combos"; + + // Intentionally out of order in the config, to make sure 'combo.c' handles it properly + combo_40 { + timeout-ms = <40>; + key-positions = ; + bindings = <&kp Z>; + }; + combo_20 { + timeout-ms = <20>; + key-positions = ; + bindings = <&kp X>; + }; + combo_30 { + timeout-ms = <30>; + key-positions = ; + bindings = <&kp Y>; + }; + + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &kp C &kp D + >; + }; + }; +}; + +#define press_A_and_wait(delay_next) \ + ZMK_MOCK_PRESS(0,0,delay_next) +#define press_B_and_wait(delay_next) \ + ZMK_MOCK_PRESS(0,1,delay_next) +#define press_C_and_wait(delay_next) \ + ZMK_MOCK_PRESS(1,0,delay_next) +#define press_D_and_wait(delay_next) \ + ZMK_MOCK_PRESS(1,1,delay_next) + +#define release_A_and_wait(delay_next) \ + ZMK_MOCK_RELEASE(0,0,delay_next) +#define release_D_and_wait(delay_next) \ + ZMK_MOCK_RELEASE(1,1,delay_next) + +&kscan { + events = < + /* Note: This starts at T+50 because the ZMK_MOCK_PRESS seems to launch the first event at T+(first wait duration). So in our case T+50 */ + + + + /*** First Phase: All 3 combos expire ***/ + + /* T+50+0= T+50: Press A and wait 50ms */ + press_A_and_wait(50) + + /* T+50+20= T+70: 'combo_20' should expire */ + /* T+50+30= T+80: 'combo_30' should expire */ + /* T+50+40= T+90: 'combo_40' should expire, and we should send the keycode 'A' */ + + /* T+50+50= T+100: We release A and wait 20ms */ + release_A_and_wait(20) + + + + /*** Second Phase: 2 combo expire, 1 combo triggers ***/ + + /* T+120+0= T+120: Press A and wait 35ms */ + press_A_and_wait(35) + + /* T+120+20= T+140: 'combo_20' should expire */ + /* T+120+30= T+150: 'combo_30' should expire */ + + /* T+120+35= T+155: We press 'D', this should trigger 'combo_40' and send the keycode 'Z'. We wait 15ms */ + press_D_and_wait(15) + + + + /*** Cleanup ***/ + /* T+120+50= T+170: We release both keys */ + release_A_and_wait(20) + release_D_and_wait(0) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/partially-overlapping-combos/events.patterns b/app/tests/combo/partially-overlapping-combos/events.patterns new file mode 100644 index 000000000000..b1342af4d971 --- /dev/null +++ b/app/tests/combo/partially-overlapping-combos/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p diff --git a/app/tests/combo/partially-overlapping-combos/keycode_events.snapshot b/app/tests/combo/partially-overlapping-combos/keycode_events.snapshot new file mode 100644 index 000000000000..cca612440378 --- /dev/null +++ b/app/tests/combo/partially-overlapping-combos/keycode_events.snapshot @@ -0,0 +1,16 @@ +pressed: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/partially-overlapping-combos/native_posix_64.keymap b/app/tests/combo/partially-overlapping-combos/native_posix_64.keymap new file mode 100644 index 000000000000..d3151382ecec --- /dev/null +++ b/app/tests/combo/partially-overlapping-combos/native_posix_64.keymap @@ -0,0 +1,83 @@ +#include +#include +#include + +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = <30>; + key-positions = <0 1>; + bindings = <&kp X>; + }; + + combo_two { + timeout-ms = <30>; + key-positions = <0 2>; + bindings = <&kp Y>; + }; + + combo_three { + timeout-ms = <30>; + key-positions = <3>; + bindings = <&kp Z>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &kp C &none + >; + }; + }; +}; + +&kscan { + events = < + /* all permutations of combo one press and release */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + + /* all permutations of combo two press and release */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,2,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,2,10) + + ZMK_MOCK_PRESS(0,2,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,2,10) + ZMK_MOCK_RELEASE(0,0,10) + + ZMK_MOCK_PRESS(0,2,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,2,10) + + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,2,10) + ZMK_MOCK_RELEASE(0,2,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/app/tests/combo/press-release-long-combo-complete/events.patterns b/app/tests/combo/press-release-long-combo-complete/events.patterns new file mode 100644 index 000000000000..b1342af4d971 --- /dev/null +++ b/app/tests/combo/press-release-long-combo-complete/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p diff --git a/app/tests/combo/press-release-long-combo-complete/keycode_events.snapshot b/app/tests/combo/press-release-long-combo-complete/keycode_events.snapshot new file mode 100644 index 000000000000..cc6fa00e9a28 --- /dev/null +++ b/app/tests/combo/press-release-long-combo-complete/keycode_events.snapshot @@ -0,0 +1,2 @@ +pressed: usage_page 0x07 keycode 0x1D implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1D implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/press-release-long-combo-complete/native_posix_64.keymap b/app/tests/combo/press-release-long-combo-complete/native_posix_64.keymap new file mode 100644 index 000000000000..85cb6475caeb --- /dev/null +++ b/app/tests/combo/press-release-long-combo-complete/native_posix_64.keymap @@ -0,0 +1,38 @@ +#include +#include +#include + +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = <80>; + key-positions = <0 1 2 3>; + bindings = <&kp Z>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &kp C &kp D + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,100) + ZMK_MOCK_RELEASE(1,0,100) + ZMK_MOCK_RELEASE(0,1,100) + ZMK_MOCK_RELEASE(1,1,100) + >; +}; diff --git a/app/tests/combo/press-release-long-combo-incomplete/events.patterns b/app/tests/combo/press-release-long-combo-incomplete/events.patterns new file mode 100644 index 000000000000..b1342af4d971 --- /dev/null +++ b/app/tests/combo/press-release-long-combo-incomplete/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p diff --git a/app/tests/combo/press-release-long-combo-incomplete/keycode_events.snapshot b/app/tests/combo/press-release-long-combo-incomplete/keycode_events.snapshot new file mode 100644 index 000000000000..e7c0cb124acc --- /dev/null +++ b/app/tests/combo/press-release-long-combo-incomplete/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/press-release-long-combo-incomplete/native_posix_64.keymap b/app/tests/combo/press-release-long-combo-incomplete/native_posix_64.keymap new file mode 100644 index 000000000000..49b929686026 --- /dev/null +++ b/app/tests/combo/press-release-long-combo-incomplete/native_posix_64.keymap @@ -0,0 +1,34 @@ +#include +#include +#include + +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = <80>; + key-positions = <0 1 2 3>; + bindings = <&kp Z>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &kp C &kp D + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,100) + ZMK_MOCK_RELEASE(1,1,100) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/press-release-long-combo-wrong-last-key/events.patterns b/app/tests/combo/press-release-long-combo-wrong-last-key/events.patterns new file mode 100644 index 000000000000..b1342af4d971 --- /dev/null +++ b/app/tests/combo/press-release-long-combo-wrong-last-key/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p diff --git a/app/tests/combo/press-release-long-combo-wrong-last-key/keycode_events.snapshot b/app/tests/combo/press-release-long-combo-wrong-last-key/keycode_events.snapshot new file mode 100644 index 000000000000..d1b9db96fdd3 --- /dev/null +++ b/app/tests/combo/press-release-long-combo-wrong-last-key/keycode_events.snapshot @@ -0,0 +1,6 @@ +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/press-release-long-combo-wrong-last-key/native_posix_64.keymap b/app/tests/combo/press-release-long-combo-wrong-last-key/native_posix_64.keymap new file mode 100644 index 000000000000..61787322cf57 --- /dev/null +++ b/app/tests/combo/press-release-long-combo-wrong-last-key/native_posix_64.keymap @@ -0,0 +1,36 @@ +#include +#include +#include + +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = <80>; + key-positions = <0 1 2>; + bindings = <&kp Z>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &kp C &kp D + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,100) + ZMK_MOCK_RELEASE(0,1,100) + ZMK_MOCK_RELEASE(0,0,100) + >; +}; diff --git a/app/tests/combo/press-release/events.patterns b/app/tests/combo/press-release/events.patterns new file mode 100644 index 000000000000..b1342af4d971 --- /dev/null +++ b/app/tests/combo/press-release/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p diff --git a/app/tests/combo/press-release/keycode_events.snapshot b/app/tests/combo/press-release/keycode_events.snapshot new file mode 100644 index 000000000000..d0767ca4fa7c --- /dev/null +++ b/app/tests/combo/press-release/keycode_events.snapshot @@ -0,0 +1,8 @@ +pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/press-release/native_posix_64.keymap b/app/tests/combo/press-release/native_posix_64.keymap new file mode 100644 index 000000000000..783dcf00437e --- /dev/null +++ b/app/tests/combo/press-release/native_posix_64.keymap @@ -0,0 +1,50 @@ +#include +#include +#include + +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = <30>; + key-positions = <0 1>; + bindings = <&kp C>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &none &none + >; + }; + }; +}; + +&kscan { + events = < + /* all different combinations of press and release order */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/press-timeout/events.patterns b/app/tests/combo/press-timeout/events.patterns new file mode 100644 index 000000000000..b1342af4d971 --- /dev/null +++ b/app/tests/combo/press-timeout/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p diff --git a/app/tests/combo/press-timeout/keycode_events.snapshot b/app/tests/combo/press-timeout/keycode_events.snapshot new file mode 100644 index 000000000000..bb47d85203c5 --- /dev/null +++ b/app/tests/combo/press-timeout/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/press-timeout/native_posix_64.keymap b/app/tests/combo/press-timeout/native_posix_64.keymap new file mode 100644 index 000000000000..c9cd2331e343 --- /dev/null +++ b/app/tests/combo/press-timeout/native_posix_64.keymap @@ -0,0 +1,34 @@ +#include +#include +#include + +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = <30>; + key-positions = <0 1>; + bindings = <&kp C>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &none &none + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,100) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/press1-press2-release1-release2/events.patterns b/app/tests/combo/press1-press2-release1-release2/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/combo/press1-press2-release1-release2/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/combo/press1-press2-release1-release2/keycode_events.snapshot b/app/tests/combo/press1-press2-release1-release2/keycode_events.snapshot new file mode 100644 index 000000000000..0539a7ca4943 --- /dev/null +++ b/app/tests/combo/press1-press2-release1-release2/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/press1-press2-release1-release2/native_posix_64.keymap b/app/tests/combo/press1-press2-release1-release2/native_posix_64.keymap new file mode 100644 index 000000000000..55d93823dfe3 --- /dev/null +++ b/app/tests/combo/press1-press2-release1-release2/native_posix_64.keymap @@ -0,0 +1,44 @@ +#include +#include +#include + +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = <30>; + key-positions = <0 1>; + bindings = <&kp C>; + }; + + combo_two { + timeout-ms = <30>; + key-positions = <2 3>; + bindings = <&kp D>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &kp Z &kp Y + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(1,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/press1-press2-release2-release1/events.patterns b/app/tests/combo/press1-press2-release2-release1/events.patterns new file mode 100644 index 000000000000..b1342af4d971 --- /dev/null +++ b/app/tests/combo/press1-press2-release2-release1/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p diff --git a/app/tests/combo/press1-press2-release2-release1/keycode_events.snapshot b/app/tests/combo/press1-press2-release2-release1/keycode_events.snapshot new file mode 100644 index 000000000000..c473ece05525 --- /dev/null +++ b/app/tests/combo/press1-press2-release2-release1/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/press1-press2-release2-release1/native_posix_64.keymap b/app/tests/combo/press1-press2-release2-release1/native_posix_64.keymap new file mode 100644 index 000000000000..ace63a16a805 --- /dev/null +++ b/app/tests/combo/press1-press2-release2-release1/native_posix_64.keymap @@ -0,0 +1,45 @@ +#include +#include +#include + +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = <30>; + key-positions = <0 1>; + bindings = <&kp C>; + }; + + combo_two { + timeout-ms = <30>; + key-positions = <2 3>; + bindings = <&kp D>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &kp Z &kp Y + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/press1-release1-press2-release2/events.patterns b/app/tests/combo/press1-release1-press2-release2/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/combo/press1-release1-press2-release2/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/combo/press1-release1-press2-release2/keycode_events.snapshot b/app/tests/combo/press1-release1-press2-release2/keycode_events.snapshot new file mode 100644 index 000000000000..3c8dc1381b13 --- /dev/null +++ b/app/tests/combo/press1-release1-press2-release2/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/press1-release1-press2-release2/native_posix_64.keymap b/app/tests/combo/press1-release1-press2-release2/native_posix_64.keymap new file mode 100644 index 000000000000..8b59792b047e --- /dev/null +++ b/app/tests/combo/press1-release1-press2-release2/native_posix_64.keymap @@ -0,0 +1,45 @@ +#include +#include +#include + +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = <30>; + key-positions = <0 1>; + bindings = <&kp C>; + }; + + combo_two { + timeout-ms = <30>; + key-positions = <2 3>; + bindings = <&kp D>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &kp Z &kp Y + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(1,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/require-prior-idle/events.patterns b/app/tests/combo/require-prior-idle/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/combo/require-prior-idle/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/combo/require-prior-idle/keycode_events.snapshot b/app/tests/combo/require-prior-idle/keycode_events.snapshot new file mode 100644 index 000000000000..ee4dd064c617 --- /dev/null +++ b/app/tests/combo/require-prior-idle/keycode_events.snapshot @@ -0,0 +1,14 @@ +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/require-prior-idle/native_posix_64.keymap b/app/tests/combo/require-prior-idle/native_posix_64.keymap new file mode 100644 index 000000000000..72801f74950f --- /dev/null +++ b/app/tests/combo/require-prior-idle/native_posix_64.keymap @@ -0,0 +1,63 @@ +#include +#include +#include + +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = <50>; + key-positions = <0 1>; + bindings = <&kp X>; + require-prior-idle-ms = <100>; + }; + + combo_two { + timeout-ms = <50>; + key-positions = <0 2>; + bindings = <&kp Y>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &kp C &kp D + >; + }; + }; +}; + +&kscan { + events = < + /* Tap A */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,60) + /* Quick Tap A and B */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,200) + /* Combo One */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + /* Combo One Again (shouldn't quick tap) */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + /* Tap A */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,60) + /* Combo 2 */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; diff --git a/app/tests/combo/slowrelease-disabled/events.patterns b/app/tests/combo/slowrelease-disabled/events.patterns new file mode 100644 index 000000000000..b1342af4d971 --- /dev/null +++ b/app/tests/combo/slowrelease-disabled/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p diff --git a/app/tests/combo/slowrelease-disabled/keycode_events.snapshot b/app/tests/combo/slowrelease-disabled/keycode_events.snapshot new file mode 100644 index 000000000000..3c8dc1381b13 --- /dev/null +++ b/app/tests/combo/slowrelease-disabled/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/slowrelease-disabled/native_posix_64.keymap b/app/tests/combo/slowrelease-disabled/native_posix_64.keymap new file mode 100644 index 000000000000..cfea0cd60e40 --- /dev/null +++ b/app/tests/combo/slowrelease-disabled/native_posix_64.keymap @@ -0,0 +1,37 @@ +#include +#include +#include + +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = <30>; + key-positions = <0 1>; + bindings = <&kp C>; + /* no slow-release! */ + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &kp D &none + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) /* this should release the combo */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/slowrelease-enabled/events.patterns b/app/tests/combo/slowrelease-enabled/events.patterns new file mode 100644 index 000000000000..b1342af4d971 --- /dev/null +++ b/app/tests/combo/slowrelease-enabled/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p diff --git a/app/tests/combo/slowrelease-enabled/keycode_events.snapshot b/app/tests/combo/slowrelease-enabled/keycode_events.snapshot new file mode 100644 index 000000000000..0539a7ca4943 --- /dev/null +++ b/app/tests/combo/slowrelease-enabled/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/slowrelease-enabled/native_posix_64.keymap b/app/tests/combo/slowrelease-enabled/native_posix_64.keymap new file mode 100644 index 000000000000..e57bae60c886 --- /dev/null +++ b/app/tests/combo/slowrelease-enabled/native_posix_64.keymap @@ -0,0 +1,37 @@ +#include +#include +#include + +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = <30>; + key-positions = <0 1>; + bindings = <&kp C>; + slow-release; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp A &kp B + &kp D &none + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) /* this should not release the combo yet */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/conditional-layer/chained-activation/events.patterns b/app/tests/conditional-layer/chained-activation/events.patterns new file mode 100644 index 000000000000..14ded7959fd8 --- /dev/null +++ b/app/tests/conditional-layer/chained-activation/events.patterns @@ -0,0 +1,3 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*conditional_layer/cl/p diff --git a/app/tests/conditional-layer/chained-activation/keycode_events.snapshot b/app/tests/conditional-layer/chained-activation/keycode_events.snapshot new file mode 100644 index 000000000000..f847391faad3 --- /dev/null +++ b/app/tests/conditional-layer/chained-activation/keycode_events.snapshot @@ -0,0 +1,10 @@ +mo_pressed: position 2 layer 1 +mo_pressed: position 3 layer 2 +cl_activate: layer 3 +cl_activate: layer 4 +kp_pressed: usage_page 0x07 keycode 0x0C implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x0C implicit_mods 0x00 explicit_mods 0x00 +mo_released: position 3 layer 2 +cl_deactivate: layer 3 +cl_deactivate: layer 4 +mo_released: position 2 layer 1 diff --git a/app/tests/conditional-layer/chained-activation/native_posix_64.keymap b/app/tests/conditional-layer/chained-activation/native_posix_64.keymap new file mode 100644 index 000000000000..d799cc5e5e63 --- /dev/null +++ b/app/tests/conditional-layer/chained-activation/native_posix_64.keymap @@ -0,0 +1,62 @@ +#include +#include +#include + +/ { + conditional_layers { + compatible = "zmk,conditional-layers"; + conditional_layer_1 { + if-layers = <1 2>; + then-layer = <3>; + }; + conditional_layer_2 { + if-layers = <1 3>; + then-layer = <4>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + default_layer { + bindings = < + &kp A &kp B + &mo 1 &mo 2 + >; + }; + layer_1 { + bindings = < + &kp C &kp D + &trans &trans + >; + }; + layer_2 { + bindings = < + &kp E &kp F + &trans &trans + >; + }; + layer_3 { + bindings = < + &kp G &kp H + &trans &trans + >; + }; + layer_4 { + bindings = < + &kp I &kp J + &trans &trans + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; diff --git a/app/tests/conditional-layer/mo-overlap/events.patterns b/app/tests/conditional-layer/mo-overlap/events.patterns new file mode 100644 index 000000000000..14ded7959fd8 --- /dev/null +++ b/app/tests/conditional-layer/mo-overlap/events.patterns @@ -0,0 +1,3 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*conditional_layer/cl/p diff --git a/app/tests/conditional-layer/mo-overlap/keycode_events.snapshot b/app/tests/conditional-layer/mo-overlap/keycode_events.snapshot new file mode 100644 index 000000000000..0200d8de9687 --- /dev/null +++ b/app/tests/conditional-layer/mo-overlap/keycode_events.snapshot @@ -0,0 +1,17 @@ +mo_pressed: position 1 layer 3 +cl_deactivate: layer 3 +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +mo_pressed: position 2 layer 1 +mo_pressed: position 3 layer 2 +cl_activate: layer 3 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +mo_released: position 3 layer 2 +cl_deactivate: layer 3 +mo_released: position 2 layer 1 +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +mo_released: position 1 layer 3 +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/conditional-layer/mo-overlap/native_posix_64.keymap b/app/tests/conditional-layer/mo-overlap/native_posix_64.keymap new file mode 100644 index 000000000000..1518fc8a078a --- /dev/null +++ b/app/tests/conditional-layer/mo-overlap/native_posix_64.keymap @@ -0,0 +1,60 @@ +#include +#include +#include + +/ { + conditional_layers { + compatible = "zmk,conditional-layers"; + tri_layer { + if-layers = <1 2>; + then-layer = <3>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + default_layer { + bindings = < + &kp A &mo 3 + &mo 1 &mo 2 + >; + }; + layer_1 { + bindings = < + &kp B &trans + &trans &trans + >; + }; + layer_2 { + bindings = < + &kp C &trans + &trans &trans + >; + }; + layer_3 { + bindings = < + &kp D &trans + &trans &trans + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/app/tests/conditional-layer/multiple-configs/events.patterns b/app/tests/conditional-layer/multiple-configs/events.patterns new file mode 100644 index 000000000000..14ded7959fd8 --- /dev/null +++ b/app/tests/conditional-layer/multiple-configs/events.patterns @@ -0,0 +1,3 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*conditional_layer/cl/p diff --git a/app/tests/conditional-layer/multiple-configs/keycode_events.snapshot b/app/tests/conditional-layer/multiple-configs/keycode_events.snapshot new file mode 100644 index 000000000000..a076a639e067 --- /dev/null +++ b/app/tests/conditional-layer/multiple-configs/keycode_events.snapshot @@ -0,0 +1,16 @@ +mo_pressed: position 2 layer 1 +mo_pressed: position 3 layer 2 +cl_activate: layer 4 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +mo_pressed: position 1 layer 3 +cl_activate: layer 5 +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +mo_released: position 1 layer 3 +cl_deactivate: layer 5 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +mo_released: position 3 layer 2 +cl_deactivate: layer 4 +mo_released: position 2 layer 1 diff --git a/app/tests/conditional-layer/multiple-configs/native_posix_64.keymap b/app/tests/conditional-layer/multiple-configs/native_posix_64.keymap new file mode 100644 index 000000000000..8290649f9e43 --- /dev/null +++ b/app/tests/conditional-layer/multiple-configs/native_posix_64.keymap @@ -0,0 +1,74 @@ +#include +#include +#include + +/ { + conditional_layers { + compatible = "zmk,conditional-layers"; + tri_layer { + if-layers = <1 2>; + then-layer = <4>; + }; + quad_layer { + if-layers = <1 2 3>; + then-layer = <5>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + default_layer { + bindings = < + &kp A &mo 3 + &mo 1 &mo 2 + >; + }; + layer_1 { + bindings = < + &kp B &trans + &trans &trans + >; + }; + layer_2 { + bindings = < + &kp C &trans + &trans &trans + >; + }; + layer_3 { + bindings = < + &kp D &trans + &trans &trans + >; + }; + layer_4 { + bindings = < + &kp E &trans + &trans &trans + >; + }; + layer_5 { + bindings = < + &kp F &trans + &trans &trans + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; diff --git a/app/tests/conditional-layer/quad-layer/events.patterns b/app/tests/conditional-layer/quad-layer/events.patterns new file mode 100644 index 000000000000..14ded7959fd8 --- /dev/null +++ b/app/tests/conditional-layer/quad-layer/events.patterns @@ -0,0 +1,3 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*conditional_layer/cl/p diff --git a/app/tests/conditional-layer/quad-layer/keycode_events.snapshot b/app/tests/conditional-layer/quad-layer/keycode_events.snapshot new file mode 100644 index 000000000000..fb54a6caa3e2 --- /dev/null +++ b/app/tests/conditional-layer/quad-layer/keycode_events.snapshot @@ -0,0 +1,10 @@ +mo_pressed: position 2 layer 1 +mo_pressed: position 3 layer 2 +mo_pressed: position 1 layer 3 +cl_activate: layer 4 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +mo_released: position 1 layer 3 +cl_deactivate: layer 4 +mo_released: position 3 layer 2 +mo_released: position 2 layer 1 diff --git a/app/tests/conditional-layer/quad-layer/native_posix_64.keymap b/app/tests/conditional-layer/quad-layer/native_posix_64.keymap new file mode 100644 index 000000000000..300b1f75f24e --- /dev/null +++ b/app/tests/conditional-layer/quad-layer/native_posix_64.keymap @@ -0,0 +1,60 @@ +#include +#include +#include + +/ { + conditional_layers { + compatible = "zmk,conditional-layers"; + quad_layer { + if-layers = <1 2 3>; + then-layer = <4>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + default_layer { + bindings = < + &kp A &mo 3 + &mo 1 &mo 2 + >; + }; + layer_1 { + bindings = < + &kp B &trans + &trans &trans + >; + }; + layer_2 { + bindings = < + &kp C &trans + &trans &trans + >; + }; + layer_3 { + bindings = < + &kp D &trans + &trans &trans + >; + }; + layer_4 { + bindings = < + &kp E &trans + &trans &trans + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; diff --git a/app/tests/conditional-layer/same-layer-reached-both-ways/events.patterns b/app/tests/conditional-layer/same-layer-reached-both-ways/events.patterns new file mode 100644 index 000000000000..14ded7959fd8 --- /dev/null +++ b/app/tests/conditional-layer/same-layer-reached-both-ways/events.patterns @@ -0,0 +1,3 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*conditional_layer/cl/p diff --git a/app/tests/conditional-layer/same-layer-reached-both-ways/keycode_events.snapshot b/app/tests/conditional-layer/same-layer-reached-both-ways/keycode_events.snapshot new file mode 100644 index 000000000000..49fc0f873a3a --- /dev/null +++ b/app/tests/conditional-layer/same-layer-reached-both-ways/keycode_events.snapshot @@ -0,0 +1,20 @@ +mo_pressed: position 2 layer 1 +mo_pressed: position 3 layer 2 +cl_activate: layer 4 +mo_pressed: position 1 layer 3 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +mo_released: position 1 layer 3 +mo_released: position 3 layer 2 +cl_deactivate: layer 4 +mo_released: position 2 layer 1 +mo_pressed: position 1 layer 3 +mo_pressed: position 2 layer 1 +cl_activate: layer 4 +mo_pressed: position 3 layer 2 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +mo_released: position 3 layer 2 +mo_released: position 2 layer 1 +cl_deactivate: layer 4 +mo_released: position 1 layer 3 diff --git a/app/tests/conditional-layer/same-layer-reached-both-ways/native_posix_64.keymap b/app/tests/conditional-layer/same-layer-reached-both-ways/native_posix_64.keymap new file mode 100644 index 000000000000..c94dcef21903 --- /dev/null +++ b/app/tests/conditional-layer/same-layer-reached-both-ways/native_posix_64.keymap @@ -0,0 +1,73 @@ +#include +#include +#include + +/ { + conditional_layers { + compatible = "zmk,conditional-layers"; + conditional_layer_1 { + if-layers = <1 2>; + then-layer = <4>; + }; + conditional_layer_2 { + if-layers = <1 3>; + then-layer = <4>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + default_layer { + bindings = < + &kp A &mo 3 + &mo 1 &mo 2 + >; + }; + layer_1 { + bindings = < + &kp B &trans + &trans &trans + >; + }; + layer_2 { + bindings = < + &kp C &trans + &trans &trans + >; + }; + layer_3 { + bindings = < + &kp D &trans + &trans &trans + >; + }; + layer_4 { + bindings = < + &kp E &trans + &trans &trans + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(1,0,10) + + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; diff --git a/app/tests/conditional-layer/same-layer-reached-differently/events.patterns b/app/tests/conditional-layer/same-layer-reached-differently/events.patterns new file mode 100644 index 000000000000..14ded7959fd8 --- /dev/null +++ b/app/tests/conditional-layer/same-layer-reached-differently/events.patterns @@ -0,0 +1,3 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*conditional_layer/cl/p diff --git a/app/tests/conditional-layer/same-layer-reached-differently/keycode_events.snapshot b/app/tests/conditional-layer/same-layer-reached-differently/keycode_events.snapshot new file mode 100644 index 000000000000..86371d2fb432 --- /dev/null +++ b/app/tests/conditional-layer/same-layer-reached-differently/keycode_events.snapshot @@ -0,0 +1,16 @@ +mo_pressed: position 2 layer 1 +mo_pressed: position 3 layer 2 +cl_activate: layer 4 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +mo_released: position 3 layer 2 +cl_deactivate: layer 4 +mo_released: position 2 layer 1 +mo_pressed: position 1 layer 3 +mo_pressed: position 2 layer 1 +cl_activate: layer 4 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +mo_released: position 2 layer 1 +cl_deactivate: layer 4 +mo_released: position 1 layer 3 diff --git a/app/tests/conditional-layer/same-layer-reached-differently/native_posix_64.keymap b/app/tests/conditional-layer/same-layer-reached-differently/native_posix_64.keymap new file mode 100644 index 000000000000..fd127d0529fe --- /dev/null +++ b/app/tests/conditional-layer/same-layer-reached-differently/native_posix_64.keymap @@ -0,0 +1,69 @@ +#include +#include +#include + +/ { + conditional_layers { + compatible = "zmk,conditional-layers"; + conditional_layer_1 { + if-layers = <1 2>; + then-layer = <4>; + }; + conditional_layer_2 { + if-layers = <1 3>; + then-layer = <4>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + default_layer { + bindings = < + &kp A &mo 3 + &mo 1 &mo 2 + >; + }; + layer_1 { + bindings = < + &kp B &trans + &trans &trans + >; + }; + layer_2 { + bindings = < + &kp C &trans + &trans &trans + >; + }; + layer_3 { + bindings = < + &kp D &trans + &trans &trans + >; + }; + layer_4 { + bindings = < + &kp E &trans + &trans &trans + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(1,0,10) + + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; diff --git a/app/tests/conditional-layer/tri-layer-alt-order/events.patterns b/app/tests/conditional-layer/tri-layer-alt-order/events.patterns new file mode 100644 index 000000000000..14ded7959fd8 --- /dev/null +++ b/app/tests/conditional-layer/tri-layer-alt-order/events.patterns @@ -0,0 +1,3 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*conditional_layer/cl/p diff --git a/app/tests/conditional-layer/tri-layer-alt-order/keycode_events.snapshot b/app/tests/conditional-layer/tri-layer-alt-order/keycode_events.snapshot new file mode 100644 index 000000000000..46d6c03a60e1 --- /dev/null +++ b/app/tests/conditional-layer/tri-layer-alt-order/keycode_events.snapshot @@ -0,0 +1,8 @@ +mo_pressed: position 3 layer 2 +mo_pressed: position 2 layer 1 +cl_activate: layer 3 +kp_pressed: usage_page 0x07 keycode 0x0A implicit_mods 0x00 explicit_mods 0x00 +mo_released: position 3 layer 2 +cl_deactivate: layer 3 +mo_released: position 2 layer 1 +kp_released: usage_page 0x07 keycode 0x0A implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/conditional-layer/tri-layer-alt-order/native_posix_64.keymap b/app/tests/conditional-layer/tri-layer-alt-order/native_posix_64.keymap new file mode 100644 index 000000000000..a31540380bcd --- /dev/null +++ b/app/tests/conditional-layer/tri-layer-alt-order/native_posix_64.keymap @@ -0,0 +1,52 @@ +#include +#include +#include + +/ { + conditional_layers { + compatible = "zmk,conditional-layers"; + tri_layer { + if-layers = <1 2>; + then-layer = <3>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + default_layer { + bindings = < + &kp A &kp B + &mo 1 &mo 2 + >; + }; + layer_1 { + bindings = < + &kp C &kp D + &trans &trans + >; + }; + layer_2 { + bindings = < + &kp E &kp F + &trans &trans + >; + }; + layer_3 { + bindings = < + &kp G &kp H + &trans &trans + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/app/tests/conditional-layer/tri-layer-lt/events.patterns b/app/tests/conditional-layer/tri-layer-lt/events.patterns new file mode 100644 index 000000000000..6a0e3bdc34f1 --- /dev/null +++ b/app/tests/conditional-layer/tri-layer-lt/events.patterns @@ -0,0 +1,3 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*conditional_layer/cl/p \ No newline at end of file diff --git a/app/tests/conditional-layer/tri-layer-lt/keycode_events.snapshot b/app/tests/conditional-layer/tri-layer-lt/keycode_events.snapshot new file mode 100644 index 000000000000..cb452df5453e --- /dev/null +++ b/app/tests/conditional-layer/tri-layer-lt/keycode_events.snapshot @@ -0,0 +1,8 @@ +mo_pressed: position 2 layer 1 +mo_pressed: position 3 layer 2 +cl_activate: layer 3 +kp_pressed: usage_page 0x07 keycode 0x0A implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x0A implicit_mods 0x00 explicit_mods 0x00 +mo_released: position 3 layer 2 +cl_deactivate: layer 3 +mo_released: position 2 layer 1 diff --git a/app/tests/conditional-layer/tri-layer-lt/native_posix_64.keymap b/app/tests/conditional-layer/tri-layer-lt/native_posix_64.keymap new file mode 100644 index 000000000000..7a091609a9fe --- /dev/null +++ b/app/tests/conditional-layer/tri-layer-lt/native_posix_64.keymap @@ -0,0 +1,56 @@ +#include +#include +#include + +< { + flavor = "balanced"; +}; + +/ { + conditional_layers { + compatible = "zmk,conditional-layers"; + tri_layer { + if-layers = <1 2>; + then-layer = <3>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + default_layer { + bindings = < + &kp A &kp B + < 1 I < 2 J + >; + }; + layer_1 { + bindings = < + &kp C &kp D + &trans &trans + >; + }; + layer_2 { + bindings = < + &kp E &kp F + &trans &trans + >; + }; + layer_3 { + bindings = < + &kp G &kp H + &trans &trans + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; diff --git a/app/tests/conditional-layer/tri-layer/events.patterns b/app/tests/conditional-layer/tri-layer/events.patterns new file mode 100644 index 000000000000..14ded7959fd8 --- /dev/null +++ b/app/tests/conditional-layer/tri-layer/events.patterns @@ -0,0 +1,3 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*conditional_layer/cl/p diff --git a/app/tests/conditional-layer/tri-layer/keycode_events.snapshot b/app/tests/conditional-layer/tri-layer/keycode_events.snapshot new file mode 100644 index 000000000000..cb452df5453e --- /dev/null +++ b/app/tests/conditional-layer/tri-layer/keycode_events.snapshot @@ -0,0 +1,8 @@ +mo_pressed: position 2 layer 1 +mo_pressed: position 3 layer 2 +cl_activate: layer 3 +kp_pressed: usage_page 0x07 keycode 0x0A implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x0A implicit_mods 0x00 explicit_mods 0x00 +mo_released: position 3 layer 2 +cl_deactivate: layer 3 +mo_released: position 2 layer 1 diff --git a/app/tests/conditional-layer/tri-layer/native_posix_64.keymap b/app/tests/conditional-layer/tri-layer/native_posix_64.keymap new file mode 100644 index 000000000000..150d6dd1ad65 --- /dev/null +++ b/app/tests/conditional-layer/tri-layer/native_posix_64.keymap @@ -0,0 +1,52 @@ +#include +#include +#include + +/ { + conditional_layers { + compatible = "zmk,conditional-layers"; + tri_layer { + if-layers = <1 2>; + then-layer = <3>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + default_layer { + bindings = < + &kp A &kp B + &mo 1 &mo 2 + >; + }; + layer_1 { + bindings = < + &kp C &kp D + &trans &trans + >; + }; + layer_2 { + bindings = < + &kp E &kp F + &trans &trans + >; + }; + layer_3 { + bindings = < + &kp G &kp H + &trans &trans + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; diff --git a/app/tests/gresc/gresc-press-release/events.patterns b/app/tests/gresc/gresc-press-release/events.patterns new file mode 100644 index 000000000000..b1342af4d971 --- /dev/null +++ b/app/tests/gresc/gresc-press-release/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p diff --git a/app/tests/gresc/gresc-press-release/keycode_events.snapshot b/app/tests/gresc/gresc-press-release/keycode_events.snapshot new file mode 100644 index 000000000000..061149ee08f8 --- /dev/null +++ b/app/tests/gresc/gresc-press-release/keycode_events.snapshot @@ -0,0 +1,18 @@ +pressed: usage_page 0x07 keycode 0x29 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x29 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x35 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x35 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0xE3 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x35 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x35 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0xE3 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x35 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x35 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0xE3 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x35 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0xE3 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x35 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/gresc/gresc-press-release/native_posix_64.keymap b/app/tests/gresc/gresc-press-release/native_posix_64.keymap new file mode 100644 index 000000000000..5280543d9e3d --- /dev/null +++ b/app/tests/gresc/gresc-press-release/native_posix_64.keymap @@ -0,0 +1,48 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &gresc &none + &kp LEFT_SHIFT &kp LEFT_GUI + >; + }; + }; +}; + +&kscan { + events = < + /* esc */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + + /* ~ */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(1,0,10) + + /* LGUI+` */ + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(1,1,10) + + /* ~ */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + + /* LGUI+` */ + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/gresc/gresc-two-instances/events.patterns b/app/tests/gresc/gresc-two-instances/events.patterns new file mode 100644 index 000000000000..ef7b795571b4 --- /dev/null +++ b/app/tests/gresc/gresc-two-instances/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode_//p +s/.*on_mod_morph_binding_/morph_binding_/p \ No newline at end of file diff --git a/app/tests/gresc/gresc-two-instances/keycode_events.snapshot b/app/tests/gresc/gresc-two-instances/keycode_events.snapshot new file mode 100644 index 000000000000..b33232abdc16 --- /dev/null +++ b/app/tests/gresc/gresc-two-instances/keycode_events.snapshot @@ -0,0 +1,6 @@ +pressed: usage_page 0x07 keycode 0x29 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x29 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x35 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x35 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/gresc/gresc-two-instances/native_posix_64.keymap b/app/tests/gresc/gresc-two-instances/native_posix_64.keymap new file mode 100644 index 000000000000..5cb0695c7bca --- /dev/null +++ b/app/tests/gresc/gresc-two-instances/native_posix_64.keymap @@ -0,0 +1,42 @@ +#include +#include +#include + +/* +This test checks nothing breaks if two grave-escapes are pressed at the same time. +If someone ever really needs two, they can make a second behavior definition. + +The second gresc that is pressed is ignored. +The first gresc that is released releases the key. +*/ + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &gresc &gresc + &kp LEFT_SHIFT &kp LEFT_GUI + >; + }; + }; +}; + +&kscan { + events = < + /* esc */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) /* the second gresc is ignored */ + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) /* the second gresc is ignored */ + + /* ~ */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,0,10) /* the second gresc is ignored */ + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) /* the second gresc is ignored */ + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/README.md b/app/tests/hold-tap/README.md new file mode 100644 index 000000000000..0630132d3db3 --- /dev/null +++ b/app/tests/hold-tap/README.md @@ -0,0 +1 @@ +Refer to the pdf/open document "zmk-modtap-proposal.{pdf,odt}" in this directory for a visual representation of the numbered tests for hold-tap. diff --git a/app/tests/hold-tap/balanced/1-dn-up/events.patterns b/app/tests/hold-tap/balanced/1-dn-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/balanced/1-dn-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/1-dn-up/keycode_events.snapshot b/app/tests/hold-tap/balanced/1-dn-up/keycode_events.snapshot new file mode 100644 index 000000000000..76a8ee5f8b31 --- /dev/null +++ b/app/tests/hold-tap/balanced/1-dn-up/keycode_events.snapshot @@ -0,0 +1,5 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (balanced decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/1-dn-up/native_posix_64.keymap b/app/tests/hold-tap/balanced/1-dn-up/native_posix_64.keymap new file mode 100644 index 000000000000..5b725bb15361 --- /dev/null +++ b/app/tests/hold-tap/balanced/1-dn-up/native_posix_64.keymap @@ -0,0 +1,11 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/2-dn-timer-up/events.patterns b/app/tests/hold-tap/balanced/2-dn-timer-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/balanced/2-dn-timer-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/2-dn-timer-up/keycode_events.snapshot b/app/tests/hold-tap/balanced/2-dn-timer-up/keycode_events.snapshot new file mode 100644 index 000000000000..9b8860673ce9 --- /dev/null +++ b/app/tests/hold-tap/balanced/2-dn-timer-up/keycode_events.snapshot @@ -0,0 +1,5 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (balanced decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/2-dn-timer-up/native_posix_64.keymap b/app/tests/hold-tap/balanced/2-dn-timer-up/native_posix_64.keymap new file mode 100644 index 000000000000..bb20a323fdeb --- /dev/null +++ b/app/tests/hold-tap/balanced/2-dn-timer-up/native_posix_64.keymap @@ -0,0 +1,11 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,500) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/3a-moddn-dn-modup-up/events.patterns b/app/tests/hold-tap/balanced/3a-moddn-dn-modup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/balanced/3a-moddn-dn-modup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/3a-moddn-dn-modup-up/keycode_events.snapshot b/app/tests/hold-tap/balanced/3a-moddn-dn-modup-up/keycode_events.snapshot new file mode 100644 index 000000000000..b9f928229550 --- /dev/null +++ b/app/tests/hold-tap/balanced/3a-moddn-dn-modup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +kp_pressed: usage_page 0x07 keycode 0xE4 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (balanced decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE4 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/3a-moddn-dn-modup-up/native_posix_64.keymap b/app/tests/hold-tap/balanced/3a-moddn-dn-modup-up/native_posix_64.keymap new file mode 100644 index 000000000000..3a696af79b3e --- /dev/null +++ b/app/tests/hold-tap/balanced/3a-moddn-dn-modup-up/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,1,10) /*ctrl*/ + ZMK_MOCK_PRESS(0,0,100) /*mt f-shift */ + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/3b-moddn-dn-modup-timer-up/events.patterns b/app/tests/hold-tap/balanced/3b-moddn-dn-modup-timer-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/balanced/3b-moddn-dn-modup-timer-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/3b-moddn-dn-modup-timer-up/keycode_events.snapshot b/app/tests/hold-tap/balanced/3b-moddn-dn-modup-timer-up/keycode_events.snapshot new file mode 100644 index 000000000000..0f2edc79d95a --- /dev/null +++ b/app/tests/hold-tap/balanced/3b-moddn-dn-modup-timer-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +kp_pressed: usage_page 0x07 keycode 0xE4 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (balanced decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE4 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/3b-moddn-dn-modup-timer-up/native_posix_64.keymap b/app/tests/hold-tap/balanced/3b-moddn-dn-modup-timer-up/native_posix_64.keymap new file mode 100644 index 000000000000..5704ca4b529b --- /dev/null +++ b/app/tests/hold-tap/balanced/3b-moddn-dn-modup-timer-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,1,10) /*ctrl*/ + ZMK_MOCK_PRESS(0,0,50) /*mt f-shift */ + ZMK_MOCK_RELEASE(1,1,300) + /*timer*/ + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/3c-kcdn-dn-kcup-up/events.patterns b/app/tests/hold-tap/balanced/3c-kcdn-dn-kcup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/balanced/3c-kcdn-dn-kcup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/3c-kcdn-dn-kcup-up/keycode_events.snapshot b/app/tests/hold-tap/balanced/3c-kcdn-dn-kcup-up/keycode_events.snapshot new file mode 100644 index 000000000000..38bceb97be2c --- /dev/null +++ b/app/tests/hold-tap/balanced/3c-kcdn-dn-kcup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_decide: 0 decided tap (balanced decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/3c-kcdn-dn-kcup-up/native_posix_64.keymap b/app/tests/hold-tap/balanced/3c-kcdn-dn-kcup-up/native_posix_64.keymap new file mode 100644 index 000000000000..df066fb0c496 --- /dev/null +++ b/app/tests/hold-tap/balanced/3c-kcdn-dn-kcup-up/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) /*d*/ + ZMK_MOCK_PRESS(0,0,100) /*mt f-shift */ + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/3d-kcdn-dn-kcup-timer-up/events.patterns b/app/tests/hold-tap/balanced/3d-kcdn-dn-kcup-timer-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/balanced/3d-kcdn-dn-kcup-timer-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/3d-kcdn-dn-kcup-timer-up/keycode_events.snapshot b/app/tests/hold-tap/balanced/3d-kcdn-dn-kcup-timer-up/keycode_events.snapshot new file mode 100644 index 000000000000..d56fe18dcffd --- /dev/null +++ b/app/tests/hold-tap/balanced/3d-kcdn-dn-kcup-timer-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_decide: 0 decided hold-timer (balanced decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/3d-kcdn-dn-kcup-timer-up/native_posix_64.keymap b/app/tests/hold-tap/balanced/3d-kcdn-dn-kcup-timer-up/native_posix_64.keymap new file mode 100644 index 000000000000..34645ad4a433 --- /dev/null +++ b/app/tests/hold-tap/balanced/3d-kcdn-dn-kcup-timer-up/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) /* d */ + ZMK_MOCK_PRESS(0,0,100) /* mt f-shift */ + ZMK_MOCK_RELEASE(1,0,400) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/4a-dn-htdn-timer-htup-up/events.patterns b/app/tests/hold-tap/balanced/4a-dn-htdn-timer-htup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/balanced/4a-dn-htdn-timer-htup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/4a-dn-htdn-timer-htup-up/keycode_events.snapshot b/app/tests/hold-tap/balanced/4a-dn-htdn-timer-htup-up/keycode_events.snapshot new file mode 100644 index 000000000000..7fb953862601 --- /dev/null +++ b/app/tests/hold-tap/balanced/4a-dn-htdn-timer-htup-up/keycode_events.snapshot @@ -0,0 +1,10 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (balanced decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 1 new undecided hold_tap +ht_decide: 1 decided tap (balanced decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x0D implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x0D implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 1 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/4a-dn-htdn-timer-htup-up/native_posix_64.keymap b/app/tests/hold-tap/balanced/4a-dn-htdn-timer-htup-up/native_posix_64.keymap new file mode 100644 index 000000000000..9c108d32ff57 --- /dev/null +++ b/app/tests/hold-tap/balanced/4a-dn-htdn-timer-htup-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,200) + ZMK_MOCK_PRESS(0,1,200) + /* timer fires */ + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/4a-dn-kcdn-timer-kcup-up/events.patterns b/app/tests/hold-tap/balanced/4a-dn-kcdn-timer-kcup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/balanced/4a-dn-kcdn-timer-kcup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/4a-dn-kcdn-timer-kcup-up/keycode_events.snapshot b/app/tests/hold-tap/balanced/4a-dn-kcdn-timer-kcup-up/keycode_events.snapshot new file mode 100644 index 000000000000..b5b5886df858 --- /dev/null +++ b/app/tests/hold-tap/balanced/4a-dn-kcdn-timer-kcup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (balanced decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/4a-dn-kcdn-timer-kcup-up/native_posix_64.keymap b/app/tests/hold-tap/balanced/4a-dn-kcdn-timer-kcup-up/native_posix_64.keymap new file mode 100644 index 000000000000..9fd7cbf09e65 --- /dev/null +++ b/app/tests/hold-tap/balanced/4a-dn-kcdn-timer-kcup-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,200) + ZMK_MOCK_PRESS(1,0,200) + /* timer fires */ + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/4b-dn-kcdn-kcup-timer-up/events.patterns b/app/tests/hold-tap/balanced/4b-dn-kcdn-kcup-timer-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/balanced/4b-dn-kcdn-kcup-timer-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/4b-dn-kcdn-kcup-timer-up/keycode_events.snapshot b/app/tests/hold-tap/balanced/4b-dn-kcdn-kcup-timer-up/keycode_events.snapshot new file mode 100644 index 000000000000..55a620a81f6b --- /dev/null +++ b/app/tests/hold-tap/balanced/4b-dn-kcdn-kcup-timer-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-interrupt (balanced decision moment other-key-up) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/4b-dn-kcdn-kcup-timer-up/native_posix_64.keymap b/app/tests/hold-tap/balanced/4b-dn-kcdn-kcup-timer-up/native_posix_64.keymap new file mode 100644 index 000000000000..f586b97862f2 --- /dev/null +++ b/app/tests/hold-tap/balanced/4b-dn-kcdn-kcup-timer-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,100) + ZMK_MOCK_PRESS(1,0,100) + ZMK_MOCK_RELEASE(1,0,200) + /* timer fires */ + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/4c-dn-kcdn-kcup-up/events.patterns b/app/tests/hold-tap/balanced/4c-dn-kcdn-kcup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/balanced/4c-dn-kcdn-kcup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/4c-dn-kcdn-kcup-up/keycode_events.snapshot b/app/tests/hold-tap/balanced/4c-dn-kcdn-kcup-up/keycode_events.snapshot new file mode 100644 index 000000000000..55a620a81f6b --- /dev/null +++ b/app/tests/hold-tap/balanced/4c-dn-kcdn-kcup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-interrupt (balanced decision moment other-key-up) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/4c-dn-kcdn-kcup-up/native_posix_64.keymap b/app/tests/hold-tap/balanced/4c-dn-kcdn-kcup-up/native_posix_64.keymap new file mode 100644 index 000000000000..3a5eab10c4fe --- /dev/null +++ b/app/tests/hold-tap/balanced/4c-dn-kcdn-kcup-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* timer */ + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/4d-dn-kcdn-timer-up-kcup/events.patterns b/app/tests/hold-tap/balanced/4d-dn-kcdn-timer-up-kcup/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/balanced/4d-dn-kcdn-timer-up-kcup/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/4d-dn-kcdn-timer-up-kcup/keycode_events.snapshot b/app/tests/hold-tap/balanced/4d-dn-kcdn-timer-up-kcup/keycode_events.snapshot new file mode 100644 index 000000000000..d06cd1cacb82 --- /dev/null +++ b/app/tests/hold-tap/balanced/4d-dn-kcdn-timer-up-kcup/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (balanced decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/hold-tap/balanced/4d-dn-kcdn-timer-up-kcup/native_posix_64.keymap b/app/tests/hold-tap/balanced/4d-dn-kcdn-timer-up-kcup/native_posix_64.keymap new file mode 100644 index 000000000000..cc7412f7f373 --- /dev/null +++ b/app/tests/hold-tap/balanced/4d-dn-kcdn-timer-up-kcup/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,100) + ZMK_MOCK_PRESS(1,0,100) + ZMK_MOCK_RELEASE(0,0,200) + /* timer fires */ + ZMK_MOCK_RELEASE(1,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/5-quick-tap/events.patterns b/app/tests/hold-tap/balanced/5-quick-tap/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/balanced/5-quick-tap/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/5-quick-tap/keycode_events.snapshot b/app/tests/hold-tap/balanced/5-quick-tap/keycode_events.snapshot new file mode 100644 index 000000000000..4d0cdd8300c9 --- /dev/null +++ b/app/tests/hold-tap/balanced/5-quick-tap/keycode_events.snapshot @@ -0,0 +1,10 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (balanced decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (balanced decision moment quick-tap) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/5-quick-tap/native_posix_64.keymap b/app/tests/hold-tap/balanced/5-quick-tap/native_posix_64.keymap new file mode 100644 index 000000000000..bd431ceb095a --- /dev/null +++ b/app/tests/hold-tap/balanced/5-quick-tap/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/6-retro-tap/events.patterns b/app/tests/hold-tap/balanced/6-retro-tap/events.patterns new file mode 100644 index 000000000000..4db21917caf4 --- /dev/null +++ b/app/tests/hold-tap/balanced/6-retro-tap/events.patterns @@ -0,0 +1,6 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p +s/.*update_hold_status_for_retro_tap/update_hold_status_for_retro_tap/p +s/.*decide_retro_tap/decide_retro_tap/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/6-retro-tap/keycode_events.snapshot b/app/tests/hold-tap/balanced/6-retro-tap/keycode_events.snapshot new file mode 100644 index 000000000000..8cc506ab5b44 --- /dev/null +++ b/app/tests/hold-tap/balanced/6-retro-tap/keycode_events.snapshot @@ -0,0 +1,19 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (balanced decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (balanced decision moment timer) +decide_retro_tap: 0 retro tap +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (balanced decision moment timer) +update_hold_status_for_retro_tap: Update hold tap 0 status to hold-interrupt +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/6-retro-tap/native_posix_64.keymap b/app/tests/hold-tap/balanced/6-retro-tap/native_posix_64.keymap new file mode 100644 index 000000000000..f9bda1cfd999 --- /dev/null +++ b/app/tests/hold-tap/balanced/6-retro-tap/native_posix_64.keymap @@ -0,0 +1,43 @@ +#include +#include +#include + +/ { + behaviors { + ht_bal: behavior_balanced { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "balanced"; + tapping_term_ms = <300>; + bindings = <&kp>, <&kp>; + retro-tap; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &ht_bal LEFT_SHIFT F &none + &kp D &none>; + }; + }; +}; + + +&kscan { + events = < + /* tap */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* retro tap */ + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(0,0,10) + /* hold */ + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/events.patterns b/app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/keycode_events.snapshot b/app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/keycode_events.snapshot new file mode 100644 index 000000000000..9b8860673ce9 --- /dev/null +++ b/app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/keycode_events.snapshot @@ -0,0 +1,5 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (balanced decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/native_posix_64.keymap b/app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/native_posix_64.keymap new file mode 100644 index 000000000000..bb20a323fdeb --- /dev/null +++ b/app/tests/hold-tap/balanced/7-positional/2-dn-timer-up/native_posix_64.keymap @@ -0,0 +1,11 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,500) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/events.patterns b/app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot b/app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot new file mode 100644 index 000000000000..1b5cc8f233f5 --- /dev/null +++ b/app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (balanced decision moment timer) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix_64.keymap b/app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix_64.keymap new file mode 100644 index 000000000000..9ee237d3a994 --- /dev/null +++ b/app/tests/hold-tap/balanced/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,200) + ZMK_MOCK_PRESS(1,1,200) // non trigger key + /* timer fires */ + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/events.patterns b/app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot b/app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot new file mode 100644 index 000000000000..b5b5886df858 --- /dev/null +++ b/app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (balanced decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix_64.keymap b/app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix_64.keymap new file mode 100644 index 000000000000..f2f2f8bd068c --- /dev/null +++ b/app/tests/hold-tap/balanced/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,200) + ZMK_MOCK_PRESS(1,0,200) // trigger key + /* timer fires */ + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/7-positional/behavior_keymap.dtsi b/app/tests/hold-tap/balanced/7-positional/behavior_keymap.dtsi new file mode 100644 index 000000000000..9acf5a1b58d4 --- /dev/null +++ b/app/tests/hold-tap/balanced/7-positional/behavior_keymap.dtsi @@ -0,0 +1,27 @@ +#include +#include +#include + +/ { + behaviors { + ht_bal: behavior_hold_tap_balanced { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "balanced"; + tapping-term-ms = <300>; + quick-tap-ms = <200>; + bindings = <&kp>, <&kp>; + hold-trigger-key-positions = <2>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &ht_bal LEFT_SHIFT F &ht_bal LEFT_CONTROL J + &kp D &kp E>; + }; + }; +}; diff --git a/app/tests/hold-tap/balanced/7-positional/on-release-no-trigger/events.patterns b/app/tests/hold-tap/balanced/7-positional/on-release-no-trigger/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/balanced/7-positional/on-release-no-trigger/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/7-positional/on-release-no-trigger/keycode_events.snapshot b/app/tests/hold-tap/balanced/7-positional/on-release-no-trigger/keycode_events.snapshot new file mode 100644 index 000000000000..24a8b033a558 --- /dev/null +++ b/app/tests/hold-tap/balanced/7-positional/on-release-no-trigger/keycode_events.snapshot @@ -0,0 +1,12 @@ +ht_binding_pressed: 0 new undecided hold_tap +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_decide: 0 decided hold-interrupt (balanced decision moment other-key-up) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 1 new undecided hold_tap +ht_decide: 1 decided tap (balanced decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x0D implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x0D implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 1 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/7-positional/on-release-no-trigger/native_posix_64.keymap b/app/tests/hold-tap/balanced/7-positional/on-release-no-trigger/native_posix_64.keymap new file mode 100644 index 000000000000..8c24dc34f8a5 --- /dev/null +++ b/app/tests/hold-tap/balanced/7-positional/on-release-no-trigger/native_posix_64.keymap @@ -0,0 +1,17 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&ht_bal { hold-trigger-on-release; }; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) // mod 1 + ZMK_MOCK_PRESS(0,1,10) // mod 2 + ZMK_MOCK_PRESS(1,1,10) // not trigger position + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/app/tests/hold-tap/balanced/7-positional/on-release-trigger/events.patterns b/app/tests/hold-tap/balanced/7-positional/on-release-trigger/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/balanced/7-positional/on-release-trigger/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/7-positional/on-release-trigger/keycode_events.snapshot b/app/tests/hold-tap/balanced/7-positional/on-release-trigger/keycode_events.snapshot new file mode 100644 index 000000000000..fb5587b1c126 --- /dev/null +++ b/app/tests/hold-tap/balanced/7-positional/on-release-trigger/keycode_events.snapshot @@ -0,0 +1,12 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-interrupt (balanced decision moment other-key-up) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 1 new undecided hold_tap +ht_decide: 1 decided hold-interrupt (balanced decision moment other-key-up) +kp_pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 1 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/7-positional/on-release-trigger/native_posix_64.keymap b/app/tests/hold-tap/balanced/7-positional/on-release-trigger/native_posix_64.keymap new file mode 100644 index 000000000000..1db5f20e386f --- /dev/null +++ b/app/tests/hold-tap/balanced/7-positional/on-release-trigger/native_posix_64.keymap @@ -0,0 +1,17 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&ht_bal { hold-trigger-on-release; }; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) // mod 1 + ZMK_MOCK_PRESS(0,1,10) // mod 2 + ZMK_MOCK_PRESS(1,0,10) // trigger position + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/events.patterns b/app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot b/app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot new file mode 100644 index 000000000000..1e1ea6b90726 --- /dev/null +++ b/app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot @@ -0,0 +1,9 @@ +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (balanced decision moment timer) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix_64.keymap b/app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix_64.keymap new file mode 100644 index 000000000000..78404536bed7 --- /dev/null +++ b/app/tests/hold-tap/balanced/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix_64.keymap @@ -0,0 +1,16 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) // trigger key + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,1,400) // not trigger key + /* timer fires */ + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/8-require-prior-idle/1-basic/events.patterns b/app/tests/hold-tap/balanced/8-require-prior-idle/1-basic/events.patterns new file mode 100644 index 000000000000..4db21917caf4 --- /dev/null +++ b/app/tests/hold-tap/balanced/8-require-prior-idle/1-basic/events.patterns @@ -0,0 +1,6 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p +s/.*update_hold_status_for_retro_tap/update_hold_status_for_retro_tap/p +s/.*decide_retro_tap/decide_retro_tap/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/8-require-prior-idle/1-basic/keycode_events.snapshot b/app/tests/hold-tap/balanced/8-require-prior-idle/1-basic/keycode_events.snapshot new file mode 100644 index 000000000000..4c4b3296b027 --- /dev/null +++ b/app/tests/hold-tap/balanced/8-require-prior-idle/1-basic/keycode_events.snapshot @@ -0,0 +1,24 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (balanced decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (balanced decision moment quick-tap) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (balanced decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (balanced decision moment quick-tap) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/8-require-prior-idle/1-basic/native_posix_64.keymap b/app/tests/hold-tap/balanced/8-require-prior-idle/1-basic/native_posix_64.keymap new file mode 100644 index 000000000000..aa6294980730 --- /dev/null +++ b/app/tests/hold-tap/balanced/8-require-prior-idle/1-basic/native_posix_64.keymap @@ -0,0 +1,25 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + /* tap */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,250) + /* normal quick tap */ + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(0,0,400) + /* hold */ + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,400) + /* require-prior-idle */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/app/tests/hold-tap/balanced/8-require-prior-idle/2-double-hold/events.patterns b/app/tests/hold-tap/balanced/8-require-prior-idle/2-double-hold/events.patterns new file mode 100644 index 000000000000..4db21917caf4 --- /dev/null +++ b/app/tests/hold-tap/balanced/8-require-prior-idle/2-double-hold/events.patterns @@ -0,0 +1,6 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p +s/.*update_hold_status_for_retro_tap/update_hold_status_for_retro_tap/p +s/.*decide_retro_tap/decide_retro_tap/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/8-require-prior-idle/2-double-hold/keycode_events.snapshot b/app/tests/hold-tap/balanced/8-require-prior-idle/2-double-hold/keycode_events.snapshot new file mode 100644 index 000000000000..0528e2137e97 --- /dev/null +++ b/app/tests/hold-tap/balanced/8-require-prior-idle/2-double-hold/keycode_events.snapshot @@ -0,0 +1,12 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (balanced decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 1 new undecided hold_tap +ht_decide: 1 decided hold-timer (balanced decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 1 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/8-require-prior-idle/2-double-hold/native_posix_64.keymap b/app/tests/hold-tap/balanced/8-require-prior-idle/2-double-hold/native_posix_64.keymap new file mode 100644 index 000000000000..69d691cee8ea --- /dev/null +++ b/app/tests/hold-tap/balanced/8-require-prior-idle/2-double-hold/native_posix_64.keymap @@ -0,0 +1,20 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + /* hold the first mod tap */ + ZMK_MOCK_PRESS(0,0,400) + /* hold the second mod tap */ + ZMK_MOCK_PRESS(0,1,400) + /* press the normal key */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + + /* release the hold taps */ + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; diff --git a/app/tests/hold-tap/balanced/8-require-prior-idle/behavior_keymap.dtsi b/app/tests/hold-tap/balanced/8-require-prior-idle/behavior_keymap.dtsi new file mode 100644 index 000000000000..0bcb27c5d9fa --- /dev/null +++ b/app/tests/hold-tap/balanced/8-require-prior-idle/behavior_keymap.dtsi @@ -0,0 +1,27 @@ +#include +#include +#include + +/ { + behaviors { + ht_bal: behavior_balanced { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "balanced"; + tapping-term-ms = <300>; + quick-tap-ms = <300>; + require-prior-idle-ms = <100>; + bindings = <&kp>, <&kp>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &ht_bal LEFT_SHIFT F &ht_bal LEFT_CONTROL C + &kp D &none>; + }; + }; +}; diff --git a/app/tests/hold-tap/balanced/behavior_keymap.dtsi b/app/tests/hold-tap/balanced/behavior_keymap.dtsi new file mode 100644 index 000000000000..350dfaf32663 --- /dev/null +++ b/app/tests/hold-tap/balanced/behavior_keymap.dtsi @@ -0,0 +1,26 @@ +#include +#include +#include + +/ { + behaviors { + ht_bal: behavior_hold_tap_balanced { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "balanced"; + tapping-term-ms = <300>; + quick-tap-ms = <200>; + bindings = <&kp>, <&kp>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &ht_bal LEFT_SHIFT F &ht_bal LEFT_CONTROL J + &kp D &kp RIGHT_CONTROL>; + }; + }; +}; diff --git a/app/tests/hold-tap/balanced/many-nested/events.patterns b/app/tests/hold-tap/balanced/many-nested/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/balanced/many-nested/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/many-nested/keycode_events.snapshot b/app/tests/hold-tap/balanced/many-nested/keycode_events.snapshot new file mode 100644 index 000000000000..b2d708b8a19c --- /dev/null +++ b/app/tests/hold-tap/balanced/many-nested/keycode_events.snapshot @@ -0,0 +1,20 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (balanced decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 1 new undecided hold_tap +ht_decide: 1 decided hold-timer (balanced decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 2 new undecided hold_tap +ht_binding_released: 0 cleaning up hold-tap +ht_decide: 2 decided hold-timer (balanced decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE3 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 3 new undecided hold_tap +ht_binding_released: 1 cleaning up hold-tap +ht_decide: 3 decided hold-timer (balanced decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE2 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE3 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 2 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0xE2 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 3 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/many-nested/native_posix_64.keymap b/app/tests/hold-tap/balanced/many-nested/native_posix_64.keymap new file mode 100644 index 000000000000..cfbb128fadfc --- /dev/null +++ b/app/tests/hold-tap/balanced/many-nested/native_posix_64.keymap @@ -0,0 +1,39 @@ +#include +#include +#include + +/ { + behaviors { + ht_bal: behavior_hold_tap_balanced { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "balanced"; + tapping-term-ms = <300>; + bindings = <&kp>, <&kp>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &ht_bal LEFT_SHIFT F &ht_bal LEFT_CONTROL J + &ht_bal LEFT_GUI H &ht_bal LEFT_ALT L + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,100) + ZMK_MOCK_PRESS(0,1,100) + ZMK_MOCK_PRESS(1,0,100) + ZMK_MOCK_PRESS(1,1,100) + ZMK_MOCK_RELEASE(0,0,100) + ZMK_MOCK_RELEASE(0,1,100) + ZMK_MOCK_RELEASE(1,0,100) + ZMK_MOCK_RELEASE(1,1,100) + >; +}; diff --git a/app/tests/hold-tap/hold-preferred/1-dn-up/events.patterns b/app/tests/hold-tap/hold-preferred/1-dn-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/1-dn-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/1-dn-up/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/1-dn-up/keycode_events.snapshot new file mode 100644 index 000000000000..36dc281a212e --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/1-dn-up/keycode_events.snapshot @@ -0,0 +1,5 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (hold-preferred decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/hold-preferred/1-dn-up/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/1-dn-up/native_posix_64.keymap new file mode 100644 index 000000000000..5b725bb15361 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/1-dn-up/native_posix_64.keymap @@ -0,0 +1,11 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/2-dn-timer-up/events.patterns b/app/tests/hold-tap/hold-preferred/2-dn-timer-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/2-dn-timer-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/2-dn-timer-up/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/2-dn-timer-up/keycode_events.snapshot new file mode 100644 index 000000000000..7298dc106164 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/2-dn-timer-up/keycode_events.snapshot @@ -0,0 +1,5 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (hold-preferred decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/hold-preferred/2-dn-timer-up/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/2-dn-timer-up/native_posix_64.keymap new file mode 100644 index 000000000000..bb20a323fdeb --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/2-dn-timer-up/native_posix_64.keymap @@ -0,0 +1,11 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,500) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/3a-moddn-dn-modup-up/events.patterns b/app/tests/hold-tap/hold-preferred/3a-moddn-dn-modup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/3a-moddn-dn-modup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/3a-moddn-dn-modup-up/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/3a-moddn-dn-modup-up/keycode_events.snapshot new file mode 100644 index 000000000000..83e2182cb0fe --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/3a-moddn-dn-modup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +kp_pressed: usage_page 0x07 keycode 0xE4 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (hold-preferred decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE4 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/hold-preferred/3a-moddn-dn-modup-up/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/3a-moddn-dn-modup-up/native_posix_64.keymap new file mode 100644 index 000000000000..3a696af79b3e --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/3a-moddn-dn-modup-up/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,1,10) /*ctrl*/ + ZMK_MOCK_PRESS(0,0,100) /*mt f-shift */ + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/3b-moddn-dn-modup-timer-up/events.patterns b/app/tests/hold-tap/hold-preferred/3b-moddn-dn-modup-timer-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/3b-moddn-dn-modup-timer-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/3b-moddn-dn-modup-timer-up/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/3b-moddn-dn-modup-timer-up/keycode_events.snapshot new file mode 100644 index 000000000000..fd0adb586313 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/3b-moddn-dn-modup-timer-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +kp_pressed: usage_page 0x07 keycode 0xE4 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (hold-preferred decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE4 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/hold-preferred/3b-moddn-dn-modup-timer-up/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/3b-moddn-dn-modup-timer-up/native_posix_64.keymap new file mode 100644 index 000000000000..5704ca4b529b --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/3b-moddn-dn-modup-timer-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,1,10) /*ctrl*/ + ZMK_MOCK_PRESS(0,0,50) /*mt f-shift */ + ZMK_MOCK_RELEASE(1,1,300) + /*timer*/ + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/3c-kcdn-dn-kcup-up/events.patterns b/app/tests/hold-tap/hold-preferred/3c-kcdn-dn-kcup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/3c-kcdn-dn-kcup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/3c-kcdn-dn-kcup-up/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/3c-kcdn-dn-kcup-up/keycode_events.snapshot new file mode 100644 index 000000000000..a5b9f1345918 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/3c-kcdn-dn-kcup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_decide: 0 decided tap (hold-preferred decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/hold-preferred/3c-kcdn-dn-kcup-up/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/3c-kcdn-dn-kcup-up/native_posix_64.keymap new file mode 100644 index 000000000000..df066fb0c496 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/3c-kcdn-dn-kcup-up/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) /*d*/ + ZMK_MOCK_PRESS(0,0,100) /*mt f-shift */ + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/3d-kcdn-dn-kcup-timer-up/events.patterns b/app/tests/hold-tap/hold-preferred/3d-kcdn-dn-kcup-timer-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/3d-kcdn-dn-kcup-timer-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/3d-kcdn-dn-kcup-timer-up/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/3d-kcdn-dn-kcup-timer-up/keycode_events.snapshot new file mode 100644 index 000000000000..7afa3fe95e61 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/3d-kcdn-dn-kcup-timer-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_decide: 0 decided hold-timer (hold-preferred decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/hold-preferred/3d-kcdn-dn-kcup-timer-up/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/3d-kcdn-dn-kcup-timer-up/native_posix_64.keymap new file mode 100644 index 000000000000..34645ad4a433 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/3d-kcdn-dn-kcup-timer-up/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) /* d */ + ZMK_MOCK_PRESS(0,0,100) /* mt f-shift */ + ZMK_MOCK_RELEASE(1,0,400) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/4a-dn-htdn-timer-htup-up/events.patterns b/app/tests/hold-tap/hold-preferred/4a-dn-htdn-timer-htup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/4a-dn-htdn-timer-htup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/4a-dn-htdn-timer-htup-up/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/4a-dn-htdn-timer-htup-up/keycode_events.snapshot new file mode 100644 index 000000000000..fcae0aac2842 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/4a-dn-htdn-timer-htup-up/keycode_events.snapshot @@ -0,0 +1,10 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-interrupt (hold-preferred decision moment other-key-down) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 1 new undecided hold_tap +ht_decide: 1 decided tap (hold-preferred decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x0D implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x0D implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 1 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/hold-preferred/4a-dn-htdn-timer-htup-up/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/4a-dn-htdn-timer-htup-up/native_posix_64.keymap new file mode 100644 index 000000000000..9c108d32ff57 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/4a-dn-htdn-timer-htup-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,200) + ZMK_MOCK_PRESS(0,1,200) + /* timer fires */ + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/4a-dn-kcdn-timer-kcup-up/events.patterns b/app/tests/hold-tap/hold-preferred/4a-dn-kcdn-timer-kcup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/4a-dn-kcdn-timer-kcup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/4a-dn-kcdn-timer-kcup-up/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/4a-dn-kcdn-timer-kcup-up/keycode_events.snapshot new file mode 100644 index 000000000000..026646cc7931 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/4a-dn-kcdn-timer-kcup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-interrupt (hold-preferred decision moment other-key-down) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/hold-preferred/4a-dn-kcdn-timer-kcup-up/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/4a-dn-kcdn-timer-kcup-up/native_posix_64.keymap new file mode 100644 index 000000000000..9fd7cbf09e65 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/4a-dn-kcdn-timer-kcup-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,200) + ZMK_MOCK_PRESS(1,0,200) + /* timer fires */ + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/4b-dn-kcdn-kcup-timer-up/events.patterns b/app/tests/hold-tap/hold-preferred/4b-dn-kcdn-kcup-timer-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/4b-dn-kcdn-kcup-timer-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/4b-dn-kcdn-kcup-timer-up/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/4b-dn-kcdn-kcup-timer-up/keycode_events.snapshot new file mode 100644 index 000000000000..026646cc7931 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/4b-dn-kcdn-kcup-timer-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-interrupt (hold-preferred decision moment other-key-down) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/hold-preferred/4b-dn-kcdn-kcup-timer-up/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/4b-dn-kcdn-kcup-timer-up/native_posix_64.keymap new file mode 100644 index 000000000000..f586b97862f2 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/4b-dn-kcdn-kcup-timer-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,100) + ZMK_MOCK_PRESS(1,0,100) + ZMK_MOCK_RELEASE(1,0,200) + /* timer fires */ + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/4c-dn-kcdn-kcup-up/events.patterns b/app/tests/hold-tap/hold-preferred/4c-dn-kcdn-kcup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/4c-dn-kcdn-kcup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/4c-dn-kcdn-kcup-up/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/4c-dn-kcdn-kcup-up/keycode_events.snapshot new file mode 100644 index 000000000000..026646cc7931 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/4c-dn-kcdn-kcup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-interrupt (hold-preferred decision moment other-key-down) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/hold-preferred/4c-dn-kcdn-kcup-up/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/4c-dn-kcdn-kcup-up/native_posix_64.keymap new file mode 100644 index 000000000000..3a5eab10c4fe --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/4c-dn-kcdn-kcup-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* timer */ + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/4d-dn-kcdn-timer-up-kcup/events.patterns b/app/tests/hold-tap/hold-preferred/4d-dn-kcdn-timer-up-kcup/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/4d-dn-kcdn-timer-up-kcup/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/4d-dn-kcdn-timer-up-kcup/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/4d-dn-kcdn-timer-up-kcup/keycode_events.snapshot new file mode 100644 index 000000000000..ad3ead5bd9c0 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/4d-dn-kcdn-timer-up-kcup/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-interrupt (hold-preferred decision moment other-key-down) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/hold-tap/hold-preferred/4d-dn-kcdn-timer-up-kcup/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/4d-dn-kcdn-timer-up-kcup/native_posix_64.keymap new file mode 100644 index 000000000000..cc7412f7f373 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/4d-dn-kcdn-timer-up-kcup/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,100) + ZMK_MOCK_PRESS(1,0,100) + ZMK_MOCK_RELEASE(0,0,200) + /* timer fires */ + ZMK_MOCK_RELEASE(1,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/5-quick-tap/events.patterns b/app/tests/hold-tap/hold-preferred/5-quick-tap/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/5-quick-tap/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/5-quick-tap/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/5-quick-tap/keycode_events.snapshot new file mode 100644 index 000000000000..704cf41c9d62 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/5-quick-tap/keycode_events.snapshot @@ -0,0 +1,10 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (hold-preferred decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (hold-preferred decision moment quick-tap) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/hold-preferred/5-quick-tap/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/5-quick-tap/native_posix_64.keymap new file mode 100644 index 000000000000..bd431ceb095a --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/5-quick-tap/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/6-retro-tap/events.patterns b/app/tests/hold-tap/hold-preferred/6-retro-tap/events.patterns new file mode 100644 index 000000000000..4db21917caf4 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/6-retro-tap/events.patterns @@ -0,0 +1,6 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p +s/.*update_hold_status_for_retro_tap/update_hold_status_for_retro_tap/p +s/.*decide_retro_tap/decide_retro_tap/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/6-retro-tap/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/6-retro-tap/keycode_events.snapshot new file mode 100644 index 000000000000..a0d44794d5b6 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/6-retro-tap/keycode_events.snapshot @@ -0,0 +1,19 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (hold-preferred decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (hold-preferred decision moment timer) +decide_retro_tap: 0 retro tap +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (hold-preferred decision moment timer) +update_hold_status_for_retro_tap: Update hold tap 0 status to hold-interrupt +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/hold-preferred/6-retro-tap/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/6-retro-tap/native_posix_64.keymap new file mode 100644 index 000000000000..8aa29dec4439 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/6-retro-tap/native_posix_64.keymap @@ -0,0 +1,43 @@ +#include +#include +#include + +/ { + behaviors { + hp: behavior_hold_preferred { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "hold-preferred"; + tapping_term_ms = <300>; + bindings = <&kp>, <&kp>; + retro-tap; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &hp LEFT_SHIFT F &none + &kp D &none>; + }; + }; +}; + + +&kscan { + events = < + /* tap */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* retro tap */ + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(0,0,10) + /* hold */ + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/events.patterns b/app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/keycode_events.snapshot new file mode 100644 index 000000000000..7298dc106164 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/keycode_events.snapshot @@ -0,0 +1,5 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (hold-preferred decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/native_posix_64.keymap new file mode 100644 index 000000000000..bb20a323fdeb --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/7-positional/2-dn-timer-up/native_posix_64.keymap @@ -0,0 +1,11 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,500) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/events.patterns b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot new file mode 100644 index 000000000000..964cbafe45a6 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (hold-preferred decision moment other-key-down) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix_64.keymap new file mode 100644 index 000000000000..9ee237d3a994 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,200) + ZMK_MOCK_PRESS(1,1,200) // non trigger key + /* timer fires */ + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/events.patterns b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot new file mode 100644 index 000000000000..026646cc7931 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-interrupt (hold-preferred decision moment other-key-down) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix_64.keymap new file mode 100644 index 000000000000..f2f2f8bd068c --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,200) + ZMK_MOCK_PRESS(1,0,200) // trigger key + /* timer fires */ + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/7-positional/behavior_keymap.dtsi b/app/tests/hold-tap/hold-preferred/7-positional/behavior_keymap.dtsi new file mode 100644 index 000000000000..65e7f9aa217d --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/7-positional/behavior_keymap.dtsi @@ -0,0 +1,27 @@ +#include +#include +#include + +/ { + behaviors { + ht_hold: behavior_hold_hold_tap { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "hold-preferred"; + tapping-term-ms = <300>; + quick-tap-ms = <200>; + bindings = <&kp>, <&kp>; + hold-trigger-key-positions = <2>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &ht_hold LEFT_SHIFT F &ht_hold LEFT_CONTROL J + &kp D &kp E>; + }; + }; +}; diff --git a/app/tests/hold-tap/hold-preferred/7-positional/on-release-no-trigger/events.patterns b/app/tests/hold-tap/hold-preferred/7-positional/on-release-no-trigger/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/7-positional/on-release-no-trigger/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/7-positional/on-release-no-trigger/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/7-positional/on-release-no-trigger/keycode_events.snapshot new file mode 100644 index 000000000000..1df24b0c26cd --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/7-positional/on-release-no-trigger/keycode_events.snapshot @@ -0,0 +1,12 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-interrupt (hold-preferred decision moment other-key-down) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 1 new undecided hold_tap +ht_decide: 1 decided hold-interrupt (hold-preferred decision moment other-key-down) +kp_pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 1 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/hold-preferred/7-positional/on-release-no-trigger/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/7-positional/on-release-no-trigger/native_posix_64.keymap new file mode 100644 index 000000000000..f35b73ba7014 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/7-positional/on-release-no-trigger/native_posix_64.keymap @@ -0,0 +1,17 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&ht_hold { hold-trigger-on-release; }; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) // mod 1 + ZMK_MOCK_PRESS(0,1,10) // mod 2 + ZMK_MOCK_PRESS(1,1,10) // not trigger position + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/app/tests/hold-tap/hold-preferred/7-positional/on-release-trigger/events.patterns b/app/tests/hold-tap/hold-preferred/7-positional/on-release-trigger/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/7-positional/on-release-trigger/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/7-positional/on-release-trigger/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/7-positional/on-release-trigger/keycode_events.snapshot new file mode 100644 index 000000000000..e35848cdc527 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/7-positional/on-release-trigger/keycode_events.snapshot @@ -0,0 +1,12 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-interrupt (hold-preferred decision moment other-key-down) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 1 new undecided hold_tap +ht_decide: 1 decided hold-interrupt (hold-preferred decision moment other-key-down) +kp_pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 1 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/hold-preferred/7-positional/on-release-trigger/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/7-positional/on-release-trigger/native_posix_64.keymap new file mode 100644 index 000000000000..0b4eb32094dc --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/7-positional/on-release-trigger/native_posix_64.keymap @@ -0,0 +1,17 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&ht_hold { hold-trigger-on-release; }; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) // mod 1 + ZMK_MOCK_PRESS(0,1,10) // mod 2 + ZMK_MOCK_PRESS(1,0,10) // trigger position + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/events.patterns b/app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot new file mode 100644 index 000000000000..2838194d498f --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot @@ -0,0 +1,9 @@ +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (hold-preferred decision moment other-key-down) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix_64.keymap new file mode 100644 index 000000000000..78404536bed7 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix_64.keymap @@ -0,0 +1,16 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) // trigger key + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,1,400) // not trigger key + /* timer fires */ + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/8-require-prior-idle/1-basic/events.patterns b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/1-basic/events.patterns new file mode 100644 index 000000000000..4db21917caf4 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/1-basic/events.patterns @@ -0,0 +1,6 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p +s/.*update_hold_status_for_retro_tap/update_hold_status_for_retro_tap/p +s/.*decide_retro_tap/decide_retro_tap/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/8-require-prior-idle/1-basic/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/1-basic/keycode_events.snapshot new file mode 100644 index 000000000000..22c7f64b20a8 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/1-basic/keycode_events.snapshot @@ -0,0 +1,24 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (hold-preferred decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (hold-preferred decision moment quick-tap) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-interrupt (hold-preferred decision moment other-key-down) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (hold-preferred decision moment quick-tap) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/hold-preferred/8-require-prior-idle/1-basic/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/1-basic/native_posix_64.keymap new file mode 100644 index 000000000000..6db79abc3815 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/1-basic/native_posix_64.keymap @@ -0,0 +1,25 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + /* tap */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,250) + /* normal quick tap */ + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(0,0,400) + /* hold */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,400) + /* require-prior-idle */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/app/tests/hold-tap/hold-preferred/8-require-prior-idle/2-double-hold/events.patterns b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/2-double-hold/events.patterns new file mode 100644 index 000000000000..4db21917caf4 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/2-double-hold/events.patterns @@ -0,0 +1,6 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p +s/.*update_hold_status_for_retro_tap/update_hold_status_for_retro_tap/p +s/.*decide_retro_tap/decide_retro_tap/p \ No newline at end of file diff --git a/app/tests/hold-tap/hold-preferred/8-require-prior-idle/2-double-hold/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/2-double-hold/keycode_events.snapshot new file mode 100644 index 000000000000..fb65b8cee48d --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/2-double-hold/keycode_events.snapshot @@ -0,0 +1,12 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (hold-preferred decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 1 new undecided hold_tap +ht_decide: 1 decided hold-timer (hold-preferred decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 1 cleaning up hold-tap diff --git a/app/tests/hold-tap/hold-preferred/8-require-prior-idle/2-double-hold/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/2-double-hold/native_posix_64.keymap new file mode 100644 index 000000000000..69d691cee8ea --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/2-double-hold/native_posix_64.keymap @@ -0,0 +1,20 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + /* hold the first mod tap */ + ZMK_MOCK_PRESS(0,0,400) + /* hold the second mod tap */ + ZMK_MOCK_PRESS(0,1,400) + /* press the normal key */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + + /* release the hold taps */ + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; diff --git a/app/tests/hold-tap/hold-preferred/8-require-prior-idle/behavior_keymap.dtsi b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/behavior_keymap.dtsi new file mode 100644 index 000000000000..bdc6838ae872 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/behavior_keymap.dtsi @@ -0,0 +1,27 @@ +#include +#include +#include + +/ { + behaviors { + hp: behavior_hold_preferred { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "hold-preferred"; + tapping-term-ms = <300>; + quick-tap-ms = <300>; + require-prior-idle-ms = <100>; + bindings = <&kp>, <&kp>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &hp LEFT_SHIFT F &hp LEFT_CONTROL G + &kp D &none>; + }; + }; +}; diff --git a/app/tests/hold-tap/hold-preferred/behavior_keymap.dtsi b/app/tests/hold-tap/hold-preferred/behavior_keymap.dtsi new file mode 100644 index 000000000000..702a96b4ef31 --- /dev/null +++ b/app/tests/hold-tap/hold-preferred/behavior_keymap.dtsi @@ -0,0 +1,28 @@ +#include +#include +#include + + + +/ { + behaviors { + ht_hold: behavior_hold_hold_tap { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "hold-preferred"; + tapping-term-ms = <300>; + quick-tap-ms = <200>; + bindings = <&kp>, <&kp>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &ht_hold LEFT_SHIFT F &ht_hold LEFT_CONTROL J + &kp D &kp RIGHT_CONTROL>; + }; + }; +}; diff --git a/app/tests/hold-tap/tap-preferred/1-dn-up/events.patterns b/app/tests/hold-tap/tap-preferred/1-dn-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/1-dn-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/1-dn-up/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/1-dn-up/keycode_events.snapshot new file mode 100644 index 000000000000..d1f01261c81a --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/1-dn-up/keycode_events.snapshot @@ -0,0 +1,5 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-preferred decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-preferred/1-dn-up/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/1-dn-up/native_posix_64.keymap new file mode 100644 index 000000000000..5b725bb15361 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/1-dn-up/native_posix_64.keymap @@ -0,0 +1,11 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/2-dn-timer-up/events.patterns b/app/tests/hold-tap/tap-preferred/2-dn-timer-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/2-dn-timer-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/2-dn-timer-up/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/2-dn-timer-up/keycode_events.snapshot new file mode 100644 index 000000000000..a8d82ae692f0 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/2-dn-timer-up/keycode_events.snapshot @@ -0,0 +1,5 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (tap-preferred decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-preferred/2-dn-timer-up/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/2-dn-timer-up/native_posix_64.keymap new file mode 100644 index 000000000000..bb20a323fdeb --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/2-dn-timer-up/native_posix_64.keymap @@ -0,0 +1,11 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,500) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/3a-moddn-dn-modup-up/events.patterns b/app/tests/hold-tap/tap-preferred/3a-moddn-dn-modup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/3a-moddn-dn-modup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/3a-moddn-dn-modup-up/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/3a-moddn-dn-modup-up/keycode_events.snapshot new file mode 100644 index 000000000000..ace1f88b7b57 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/3a-moddn-dn-modup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +kp_pressed: usage_page 0x07 keycode 0xE4 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-preferred decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE4 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-preferred/3a-moddn-dn-modup-up/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/3a-moddn-dn-modup-up/native_posix_64.keymap new file mode 100644 index 000000000000..3a696af79b3e --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/3a-moddn-dn-modup-up/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,1,10) /*ctrl*/ + ZMK_MOCK_PRESS(0,0,100) /*mt f-shift */ + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/3b-moddn-dn-modup-timer-up/events.patterns b/app/tests/hold-tap/tap-preferred/3b-moddn-dn-modup-timer-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/3b-moddn-dn-modup-timer-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/3b-moddn-dn-modup-timer-up/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/3b-moddn-dn-modup-timer-up/keycode_events.snapshot new file mode 100644 index 000000000000..2ea80bcdfe68 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/3b-moddn-dn-modup-timer-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +kp_pressed: usage_page 0x07 keycode 0xE4 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (tap-preferred decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE4 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-preferred/3b-moddn-dn-modup-timer-up/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/3b-moddn-dn-modup-timer-up/native_posix_64.keymap new file mode 100644 index 000000000000..5704ca4b529b --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/3b-moddn-dn-modup-timer-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,1,10) /*ctrl*/ + ZMK_MOCK_PRESS(0,0,50) /*mt f-shift */ + ZMK_MOCK_RELEASE(1,1,300) + /*timer*/ + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/3c-kcdn-dn-kcup-up/events.patterns b/app/tests/hold-tap/tap-preferred/3c-kcdn-dn-kcup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/3c-kcdn-dn-kcup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/3c-kcdn-dn-kcup-up/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/3c-kcdn-dn-kcup-up/keycode_events.snapshot new file mode 100644 index 000000000000..72e3755a1151 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/3c-kcdn-dn-kcup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_decide: 0 decided tap (tap-preferred decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-preferred/3c-kcdn-dn-kcup-up/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/3c-kcdn-dn-kcup-up/native_posix_64.keymap new file mode 100644 index 000000000000..df066fb0c496 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/3c-kcdn-dn-kcup-up/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) /*d*/ + ZMK_MOCK_PRESS(0,0,100) /*mt f-shift */ + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/3d-kcdn-dn-kcup-timer-up/events.patterns b/app/tests/hold-tap/tap-preferred/3d-kcdn-dn-kcup-timer-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/3d-kcdn-dn-kcup-timer-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/3d-kcdn-dn-kcup-timer-up/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/3d-kcdn-dn-kcup-timer-up/keycode_events.snapshot new file mode 100644 index 000000000000..ef6ab73b0ca7 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/3d-kcdn-dn-kcup-timer-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_decide: 0 decided hold-timer (tap-preferred decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-preferred/3d-kcdn-dn-kcup-timer-up/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/3d-kcdn-dn-kcup-timer-up/native_posix_64.keymap new file mode 100644 index 000000000000..34645ad4a433 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/3d-kcdn-dn-kcup-timer-up/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) /* d */ + ZMK_MOCK_PRESS(0,0,100) /* mt f-shift */ + ZMK_MOCK_RELEASE(1,0,400) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/4a-dn-htdn-timer-htup-up/events.patterns b/app/tests/hold-tap/tap-preferred/4a-dn-htdn-timer-htup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/4a-dn-htdn-timer-htup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/4a-dn-htdn-timer-htup-up/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/4a-dn-htdn-timer-htup-up/keycode_events.snapshot new file mode 100644 index 000000000000..11ab645187df --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/4a-dn-htdn-timer-htup-up/keycode_events.snapshot @@ -0,0 +1,10 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (tap-preferred decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 1 new undecided hold_tap +ht_decide: 1 decided tap (tap-preferred decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x0D implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x0D implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 1 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-preferred/4a-dn-htdn-timer-htup-up/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/4a-dn-htdn-timer-htup-up/native_posix_64.keymap new file mode 100644 index 000000000000..9c108d32ff57 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/4a-dn-htdn-timer-htup-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,200) + ZMK_MOCK_PRESS(0,1,200) + /* timer fires */ + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/4a-dn-kcdn-timer-kcup-up/events.patterns b/app/tests/hold-tap/tap-preferred/4a-dn-kcdn-timer-kcup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/4a-dn-kcdn-timer-kcup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/4a-dn-kcdn-timer-kcup-up/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/4a-dn-kcdn-timer-kcup-up/keycode_events.snapshot new file mode 100644 index 000000000000..a0a2e232f730 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/4a-dn-kcdn-timer-kcup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (tap-preferred decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-preferred/4a-dn-kcdn-timer-kcup-up/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/4a-dn-kcdn-timer-kcup-up/native_posix_64.keymap new file mode 100644 index 000000000000..9fd7cbf09e65 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/4a-dn-kcdn-timer-kcup-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,200) + ZMK_MOCK_PRESS(1,0,200) + /* timer fires */ + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/4b-dn-kcdn-kcup-timer-up/events.patterns b/app/tests/hold-tap/tap-preferred/4b-dn-kcdn-kcup-timer-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/4b-dn-kcdn-kcup-timer-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/4b-dn-kcdn-kcup-timer-up/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/4b-dn-kcdn-kcup-timer-up/keycode_events.snapshot new file mode 100644 index 000000000000..a0a2e232f730 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/4b-dn-kcdn-kcup-timer-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (tap-preferred decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-preferred/4b-dn-kcdn-kcup-timer-up/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/4b-dn-kcdn-kcup-timer-up/native_posix_64.keymap new file mode 100644 index 000000000000..f586b97862f2 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/4b-dn-kcdn-kcup-timer-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,100) + ZMK_MOCK_PRESS(1,0,100) + ZMK_MOCK_RELEASE(1,0,200) + /* timer fires */ + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/4c-dn-kcdn-kcup-up/events.patterns b/app/tests/hold-tap/tap-preferred/4c-dn-kcdn-kcup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/4c-dn-kcdn-kcup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/4c-dn-kcdn-kcup-up/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/4c-dn-kcdn-kcup-up/keycode_events.snapshot new file mode 100644 index 000000000000..93fa43be6d22 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/4c-dn-kcdn-kcup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-preferred decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-preferred/4c-dn-kcdn-kcup-up/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/4c-dn-kcdn-kcup-up/native_posix_64.keymap new file mode 100644 index 000000000000..3a5eab10c4fe --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/4c-dn-kcdn-kcup-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* timer */ + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/4d-dn-kcdn-timer-up-kcup/events.patterns b/app/tests/hold-tap/tap-preferred/4d-dn-kcdn-timer-up-kcup/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/4d-dn-kcdn-timer-up-kcup/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/4d-dn-kcdn-timer-up-kcup/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/4d-dn-kcdn-timer-up-kcup/keycode_events.snapshot new file mode 100644 index 000000000000..e10f263eb156 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/4d-dn-kcdn-timer-up-kcup/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-preferred decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/hold-tap/tap-preferred/4d-dn-kcdn-timer-up-kcup/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/4d-dn-kcdn-timer-up-kcup/native_posix_64.keymap new file mode 100644 index 000000000000..cc7412f7f373 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/4d-dn-kcdn-timer-up-kcup/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,100) + ZMK_MOCK_PRESS(1,0,100) + ZMK_MOCK_RELEASE(0,0,200) + /* timer fires */ + ZMK_MOCK_RELEASE(1,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/5-quick-tap/events.patterns b/app/tests/hold-tap/tap-preferred/5-quick-tap/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/5-quick-tap/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/5-quick-tap/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/5-quick-tap/keycode_events.snapshot new file mode 100644 index 000000000000..3e8ec42b520e --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/5-quick-tap/keycode_events.snapshot @@ -0,0 +1,10 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-preferred decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-preferred decision moment quick-tap) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-preferred/5-quick-tap/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/5-quick-tap/native_posix_64.keymap new file mode 100644 index 000000000000..bd431ceb095a --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/5-quick-tap/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/6-nested-timeouts/events.patterns b/app/tests/hold-tap/tap-preferred/6-nested-timeouts/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/6-nested-timeouts/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/6-nested-timeouts/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/6-nested-timeouts/keycode_events.snapshot new file mode 100644 index 000000000000..11ab645187df --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/6-nested-timeouts/keycode_events.snapshot @@ -0,0 +1,10 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (tap-preferred decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 1 new undecided hold_tap +ht_decide: 1 decided tap (tap-preferred decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x0D implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x0D implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 1 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-preferred/6-nested-timeouts/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/6-nested-timeouts/native_posix_64.keymap new file mode 100644 index 000000000000..85c9a9590b77 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/6-nested-timeouts/native_posix_64.keymap @@ -0,0 +1,50 @@ +#include +#include +#include + +/* +* A hold-tap with long tapping term is pressed first. +* A hold-tap with short tapping term is quickly tapped. +* The short tapping term hold-tap should 'tap', not 'hold'. +*/ + +/ { + behaviors { + tp_short: short_tap { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <100>; + quick-tap-ms = <200>; + bindings = <&kp>, <&kp>; + }; + tp_long: long_tap { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <200>; + quick-tap-ms = <200>; + bindings = <&kp>, <&kp>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &tp_long LEFT_SHIFT F &tp_short LEFT_CONTROL J + &kp D &kp RIGHT_CONTROL>; + }; + }; +}; + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,20) + ZMK_MOCK_PRESS(0,1,20) + ZMK_MOCK_RELEASE(0,1,200) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/events.patterns b/app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/keycode_events.snapshot new file mode 100644 index 000000000000..a8d82ae692f0 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/keycode_events.snapshot @@ -0,0 +1,5 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (tap-preferred decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/native_posix_64.keymap new file mode 100644 index 000000000000..bb20a323fdeb --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/7-positional/2-dn-timer-up/native_posix_64.keymap @@ -0,0 +1,11 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,500) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/events.patterns b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot new file mode 100644 index 000000000000..337af3e9f200 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-preferred decision moment timer) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix_64.keymap new file mode 100644 index 000000000000..9ee237d3a994 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-ntgdn-timer-ntgup-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,200) + ZMK_MOCK_PRESS(1,1,200) // non trigger key + /* timer fires */ + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/events.patterns b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot new file mode 100644 index 000000000000..a0a2e232f730 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (tap-preferred decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix_64.keymap new file mode 100644 index 000000000000..f2f2f8bd068c --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/7-positional/4a-dn-tgdn-timer-tgup-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,200) + ZMK_MOCK_PRESS(1,0,200) // trigger key + /* timer fires */ + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/7-positional/behavior_keymap.dtsi b/app/tests/hold-tap/tap-preferred/7-positional/behavior_keymap.dtsi new file mode 100644 index 000000000000..3e891f2c2cc6 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/7-positional/behavior_keymap.dtsi @@ -0,0 +1,27 @@ +#include +#include +#include + +/ { + behaviors { + tp: behavior_tap_preferred { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <300>; + quick-tap-ms = <200>; + bindings = <&kp>, <&kp>; + hold-trigger-key-positions = <2>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &tp LEFT_SHIFT F &tp LEFT_CONTROL J + &kp D &kp E>; + }; + }; +}; diff --git a/app/tests/hold-tap/tap-preferred/7-positional/on-release-no-trigger/events.patterns b/app/tests/hold-tap/tap-preferred/7-positional/on-release-no-trigger/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/7-positional/on-release-no-trigger/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/7-positional/on-release-no-trigger/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/7-positional/on-release-no-trigger/keycode_events.snapshot new file mode 100644 index 000000000000..d72f20d61e0b --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/7-positional/on-release-no-trigger/keycode_events.snapshot @@ -0,0 +1,12 @@ +ht_binding_pressed: 0 new undecided hold_tap +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_decide: 0 decided tap (tap-preferred decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 1 new undecided hold_tap +ht_decide: 1 decided tap (tap-preferred decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x0D implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x0D implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 1 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-preferred/7-positional/on-release-no-trigger/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/7-positional/on-release-no-trigger/native_posix_64.keymap new file mode 100644 index 000000000000..179b64ee2d8f --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/7-positional/on-release-no-trigger/native_posix_64.keymap @@ -0,0 +1,17 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&tp { hold-trigger-on-release; }; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) // mod 1 + ZMK_MOCK_PRESS(0,1,10) // mod 2 + ZMK_MOCK_PRESS(1,1,10) // not trigger position + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/app/tests/hold-tap/tap-preferred/7-positional/on-release-trigger/events.patterns b/app/tests/hold-tap/tap-preferred/7-positional/on-release-trigger/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/7-positional/on-release-trigger/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/7-positional/on-release-trigger/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/7-positional/on-release-trigger/keycode_events.snapshot new file mode 100644 index 000000000000..a330a93c147c --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/7-positional/on-release-trigger/keycode_events.snapshot @@ -0,0 +1,12 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-preferred decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 1 new undecided hold_tap +ht_decide: 1 decided tap (tap-preferred decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x0D implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x0D implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 1 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-preferred/7-positional/on-release-trigger/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/7-positional/on-release-trigger/native_posix_64.keymap new file mode 100644 index 000000000000..e926b45c4fe5 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/7-positional/on-release-trigger/native_posix_64.keymap @@ -0,0 +1,17 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&tp { hold-trigger-on-release; }; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) // mod 1 + ZMK_MOCK_PRESS(0,1,10) // mod 2 + ZMK_MOCK_PRESS(1,0,10) // trigger position + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/events.patterns b/app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot new file mode 100644 index 000000000000..4ecb1b8e08ad --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/keycode_events.snapshot @@ -0,0 +1,9 @@ +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-preferred decision moment timer) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix_64.keymap new file mode 100644 index 000000000000..78404536bed7 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/7-positional/tgdn-dn-ntgdn-timer-ntgup-tgup-up/native_posix_64.keymap @@ -0,0 +1,16 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) // trigger key + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,1,400) // not trigger key + /* timer fires */ + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/8-require-prior-idle/1-basic/events.patterns b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/1-basic/events.patterns new file mode 100644 index 000000000000..4db21917caf4 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/1-basic/events.patterns @@ -0,0 +1,6 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p +s/.*update_hold_status_for_retro_tap/update_hold_status_for_retro_tap/p +s/.*decide_retro_tap/decide_retro_tap/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/8-require-prior-idle/1-basic/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/1-basic/keycode_events.snapshot new file mode 100644 index 000000000000..84522da3d678 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/1-basic/keycode_events.snapshot @@ -0,0 +1,24 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-preferred decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-preferred decision moment quick-tap) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (tap-preferred decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-preferred decision moment quick-tap) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-preferred/8-require-prior-idle/1-basic/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/1-basic/native_posix_64.keymap new file mode 100644 index 000000000000..aa6294980730 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/1-basic/native_posix_64.keymap @@ -0,0 +1,25 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + /* tap */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,250) + /* normal quick tap */ + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(0,0,400) + /* hold */ + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,400) + /* require-prior-idle */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/app/tests/hold-tap/tap-preferred/8-require-prior-idle/2-double-hold/events.patterns b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/2-double-hold/events.patterns new file mode 100644 index 000000000000..4db21917caf4 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/2-double-hold/events.patterns @@ -0,0 +1,6 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p +s/.*update_hold_status_for_retro_tap/update_hold_status_for_retro_tap/p +s/.*decide_retro_tap/decide_retro_tap/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-preferred/8-require-prior-idle/2-double-hold/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/2-double-hold/keycode_events.snapshot new file mode 100644 index 000000000000..756dcf2e838a --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/2-double-hold/keycode_events.snapshot @@ -0,0 +1,12 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-timer (tap-preferred decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 1 new undecided hold_tap +ht_decide: 1 decided hold-timer (tap-preferred decision moment timer) +kp_pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 1 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-preferred/8-require-prior-idle/2-double-hold/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/2-double-hold/native_posix_64.keymap new file mode 100644 index 000000000000..068ae81a8c69 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/2-double-hold/native_posix_64.keymap @@ -0,0 +1,20 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + /* hold the first mod tap */ + ZMK_MOCK_PRESS(0,0,10) + /* hold the second mod tap */ + ZMK_MOCK_PRESS(0,1,400) + /* press the normal key */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + + /* release the hold taps */ + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; diff --git a/app/tests/hold-tap/tap-preferred/8-require-prior-idle/behavior_keymap.dtsi b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/behavior_keymap.dtsi new file mode 100644 index 000000000000..23ecd2df53ed --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/behavior_keymap.dtsi @@ -0,0 +1,27 @@ +#include +#include +#include + +/ { + behaviors { + tp: behavior_tap_preferred { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <300>; + quick-tap-ms = <300>; + require-prior-idle-ms = <100>; + bindings = <&kp>, <&kp>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &tp LEFT_SHIFT F &tp LEFT_CONTROL C + &kp D &none>; + }; + }; +}; diff --git a/app/tests/hold-tap/tap-preferred/behavior_keymap.dtsi b/app/tests/hold-tap/tap-preferred/behavior_keymap.dtsi new file mode 100644 index 000000000000..fbe6c95da9a3 --- /dev/null +++ b/app/tests/hold-tap/tap-preferred/behavior_keymap.dtsi @@ -0,0 +1,26 @@ +#include +#include +#include + +/ { + behaviors { + tp: behavior_tap_preferred { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <300>; + quick-tap-ms = <200>; + bindings = <&kp>, <&kp>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &tp LEFT_SHIFT F &tp LEFT_CONTROL J + &kp D &kp RIGHT_CONTROL>; + }; + }; +}; diff --git a/app/tests/hold-tap/tap-unless-interrupted/1-dn-up/events.patterns b/app/tests/hold-tap/tap-unless-interrupted/1-dn-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/1-dn-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/1-dn-up/keycode_events.snapshot b/app/tests/hold-tap/tap-unless-interrupted/1-dn-up/keycode_events.snapshot new file mode 100644 index 000000000000..1eb2d1e32469 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/1-dn-up/keycode_events.snapshot @@ -0,0 +1,5 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-unless-interrupted decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-unless-interrupted/1-dn-up/native_posix_64.keymap b/app/tests/hold-tap/tap-unless-interrupted/1-dn-up/native_posix_64.keymap new file mode 100644 index 000000000000..5b725bb15361 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/1-dn-up/native_posix_64.keymap @@ -0,0 +1,11 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/2-dn-timer-up/events.patterns b/app/tests/hold-tap/tap-unless-interrupted/2-dn-timer-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/2-dn-timer-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/2-dn-timer-up/keycode_events.snapshot b/app/tests/hold-tap/tap-unless-interrupted/2-dn-timer-up/keycode_events.snapshot new file mode 100644 index 000000000000..e036acb9d283 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/2-dn-timer-up/keycode_events.snapshot @@ -0,0 +1,5 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-unless-interrupted decision moment timer) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-unless-interrupted/2-dn-timer-up/native_posix_64.keymap b/app/tests/hold-tap/tap-unless-interrupted/2-dn-timer-up/native_posix_64.keymap new file mode 100644 index 000000000000..bb20a323fdeb --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/2-dn-timer-up/native_posix_64.keymap @@ -0,0 +1,11 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,500) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/3a-moddn-dn-modup-up/events.patterns b/app/tests/hold-tap/tap-unless-interrupted/3a-moddn-dn-modup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/3a-moddn-dn-modup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/3a-moddn-dn-modup-up/keycode_events.snapshot b/app/tests/hold-tap/tap-unless-interrupted/3a-moddn-dn-modup-up/keycode_events.snapshot new file mode 100644 index 000000000000..ad1b0911ad51 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/3a-moddn-dn-modup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +kp_pressed: usage_page 0x07 keycode 0xE4 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-unless-interrupted decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE4 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-unless-interrupted/3a-moddn-dn-modup-up/native_posix_64.keymap b/app/tests/hold-tap/tap-unless-interrupted/3a-moddn-dn-modup-up/native_posix_64.keymap new file mode 100644 index 000000000000..3a696af79b3e --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/3a-moddn-dn-modup-up/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,1,10) /*ctrl*/ + ZMK_MOCK_PRESS(0,0,100) /*mt f-shift */ + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/3b-moddn-dn-modup-timer-up/events.patterns b/app/tests/hold-tap/tap-unless-interrupted/3b-moddn-dn-modup-timer-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/3b-moddn-dn-modup-timer-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/3b-moddn-dn-modup-timer-up/keycode_events.snapshot b/app/tests/hold-tap/tap-unless-interrupted/3b-moddn-dn-modup-timer-up/keycode_events.snapshot new file mode 100644 index 000000000000..7922ade455e1 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/3b-moddn-dn-modup-timer-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +kp_pressed: usage_page 0x07 keycode 0xE4 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-unless-interrupted decision moment timer) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE4 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-unless-interrupted/3b-moddn-dn-modup-timer-up/native_posix_64.keymap b/app/tests/hold-tap/tap-unless-interrupted/3b-moddn-dn-modup-timer-up/native_posix_64.keymap new file mode 100644 index 000000000000..5704ca4b529b --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/3b-moddn-dn-modup-timer-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,1,10) /*ctrl*/ + ZMK_MOCK_PRESS(0,0,50) /*mt f-shift */ + ZMK_MOCK_RELEASE(1,1,300) + /*timer*/ + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/3c-kcdn-dn-kcup-up/events.patterns b/app/tests/hold-tap/tap-unless-interrupted/3c-kcdn-dn-kcup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/3c-kcdn-dn-kcup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/3c-kcdn-dn-kcup-up/keycode_events.snapshot b/app/tests/hold-tap/tap-unless-interrupted/3c-kcdn-dn-kcup-up/keycode_events.snapshot new file mode 100644 index 000000000000..3a9b3dcb5023 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/3c-kcdn-dn-kcup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_decide: 0 decided tap (tap-unless-interrupted decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-unless-interrupted/3c-kcdn-dn-kcup-up/native_posix_64.keymap b/app/tests/hold-tap/tap-unless-interrupted/3c-kcdn-dn-kcup-up/native_posix_64.keymap new file mode 100644 index 000000000000..df066fb0c496 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/3c-kcdn-dn-kcup-up/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) /*d*/ + ZMK_MOCK_PRESS(0,0,100) /*mt f-shift */ + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/3d-kcdn-dn-kcup-timer-up/events.patterns b/app/tests/hold-tap/tap-unless-interrupted/3d-kcdn-dn-kcup-timer-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/3d-kcdn-dn-kcup-timer-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/3d-kcdn-dn-kcup-timer-up/keycode_events.snapshot b/app/tests/hold-tap/tap-unless-interrupted/3d-kcdn-dn-kcup-timer-up/keycode_events.snapshot new file mode 100644 index 000000000000..0a72c83a3a04 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/3d-kcdn-dn-kcup-timer-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_decide: 0 decided tap (tap-unless-interrupted decision moment timer) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-unless-interrupted/3d-kcdn-dn-kcup-timer-up/native_posix_64.keymap b/app/tests/hold-tap/tap-unless-interrupted/3d-kcdn-dn-kcup-timer-up/native_posix_64.keymap new file mode 100644 index 000000000000..34645ad4a433 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/3d-kcdn-dn-kcup-timer-up/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) /* d */ + ZMK_MOCK_PRESS(0,0,100) /* mt f-shift */ + ZMK_MOCK_RELEASE(1,0,400) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/4a-dn-htdn-timer-htup-up/events.patterns b/app/tests/hold-tap/tap-unless-interrupted/4a-dn-htdn-timer-htup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/4a-dn-htdn-timer-htup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/4a-dn-htdn-timer-htup-up/keycode_events.snapshot b/app/tests/hold-tap/tap-unless-interrupted/4a-dn-htdn-timer-htup-up/keycode_events.snapshot new file mode 100644 index 000000000000..311a7a70ce03 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/4a-dn-htdn-timer-htup-up/keycode_events.snapshot @@ -0,0 +1,10 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-interrupt (tap-unless-interrupted decision moment other-key-down) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 1 new undecided hold_tap +ht_decide: 1 decided tap (tap-unless-interrupted decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x0D implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x0D implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 1 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-unless-interrupted/4a-dn-htdn-timer-htup-up/native_posix_64.keymap b/app/tests/hold-tap/tap-unless-interrupted/4a-dn-htdn-timer-htup-up/native_posix_64.keymap new file mode 100644 index 000000000000..9c108d32ff57 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/4a-dn-htdn-timer-htup-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,200) + ZMK_MOCK_PRESS(0,1,200) + /* timer fires */ + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/4a-dn-kcdn-timer-kcup-up/events.patterns b/app/tests/hold-tap/tap-unless-interrupted/4a-dn-kcdn-timer-kcup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/4a-dn-kcdn-timer-kcup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/4a-dn-kcdn-timer-kcup-up/keycode_events.snapshot b/app/tests/hold-tap/tap-unless-interrupted/4a-dn-kcdn-timer-kcup-up/keycode_events.snapshot new file mode 100644 index 000000000000..2f3484256dfe --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/4a-dn-kcdn-timer-kcup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-interrupt (tap-unless-interrupted decision moment other-key-down) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-unless-interrupted/4a-dn-kcdn-timer-kcup-up/native_posix_64.keymap b/app/tests/hold-tap/tap-unless-interrupted/4a-dn-kcdn-timer-kcup-up/native_posix_64.keymap new file mode 100644 index 000000000000..9fd7cbf09e65 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/4a-dn-kcdn-timer-kcup-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,200) + ZMK_MOCK_PRESS(1,0,200) + /* timer fires */ + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/4b-dn-kcdn-kcup-timer-up/events.patterns b/app/tests/hold-tap/tap-unless-interrupted/4b-dn-kcdn-kcup-timer-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/4b-dn-kcdn-kcup-timer-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/4b-dn-kcdn-kcup-timer-up/keycode_events.snapshot b/app/tests/hold-tap/tap-unless-interrupted/4b-dn-kcdn-kcup-timer-up/keycode_events.snapshot new file mode 100644 index 000000000000..2f3484256dfe --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/4b-dn-kcdn-kcup-timer-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-interrupt (tap-unless-interrupted decision moment other-key-down) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-unless-interrupted/4b-dn-kcdn-kcup-timer-up/native_posix_64.keymap b/app/tests/hold-tap/tap-unless-interrupted/4b-dn-kcdn-kcup-timer-up/native_posix_64.keymap new file mode 100644 index 000000000000..f586b97862f2 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/4b-dn-kcdn-kcup-timer-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,100) + ZMK_MOCK_PRESS(1,0,100) + ZMK_MOCK_RELEASE(1,0,200) + /* timer fires */ + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/4c-dn-kcdn-kcup-up/events.patterns b/app/tests/hold-tap/tap-unless-interrupted/4c-dn-kcdn-kcup-up/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/4c-dn-kcdn-kcup-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/4c-dn-kcdn-kcup-up/keycode_events.snapshot b/app/tests/hold-tap/tap-unless-interrupted/4c-dn-kcdn-kcup-up/keycode_events.snapshot new file mode 100644 index 000000000000..2f3484256dfe --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/4c-dn-kcdn-kcup-up/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-interrupt (tap-unless-interrupted decision moment other-key-down) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-unless-interrupted/4c-dn-kcdn-kcup-up/native_posix_64.keymap b/app/tests/hold-tap/tap-unless-interrupted/4c-dn-kcdn-kcup-up/native_posix_64.keymap new file mode 100644 index 000000000000..3a5eab10c4fe --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/4c-dn-kcdn-kcup-up/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* timer */ + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/4d-dn-kcdn-timer-up-kcup/events.patterns b/app/tests/hold-tap/tap-unless-interrupted/4d-dn-kcdn-timer-up-kcup/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/4d-dn-kcdn-timer-up-kcup/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/4d-dn-kcdn-timer-up-kcup/keycode_events.snapshot b/app/tests/hold-tap/tap-unless-interrupted/4d-dn-kcdn-timer-up-kcup/keycode_events.snapshot new file mode 100644 index 000000000000..ae7c79466dd6 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/4d-dn-kcdn-timer-up-kcup/keycode_events.snapshot @@ -0,0 +1,7 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold-interrupt (tap-unless-interrupted decision moment other-key-down) +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/hold-tap/tap-unless-interrupted/4d-dn-kcdn-timer-up-kcup/native_posix_64.keymap b/app/tests/hold-tap/tap-unless-interrupted/4d-dn-kcdn-timer-up-kcup/native_posix_64.keymap new file mode 100644 index 000000000000..cc7412f7f373 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/4d-dn-kcdn-timer-up-kcup/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,100) + ZMK_MOCK_PRESS(1,0,100) + ZMK_MOCK_RELEASE(0,0,200) + /* timer fires */ + ZMK_MOCK_RELEASE(1,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/5-quick-tap/events.patterns b/app/tests/hold-tap/tap-unless-interrupted/5-quick-tap/events.patterns new file mode 100644 index 000000000000..fdf2b15cf258 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/5-quick-tap/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/5-quick-tap/keycode_events.snapshot b/app/tests/hold-tap/tap-unless-interrupted/5-quick-tap/keycode_events.snapshot new file mode 100644 index 000000000000..070b9938b183 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/5-quick-tap/keycode_events.snapshot @@ -0,0 +1,10 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-unless-interrupted decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-unless-interrupted decision moment quick-tap) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-unless-interrupted/5-quick-tap/native_posix_64.keymap b/app/tests/hold-tap/tap-unless-interrupted/5-quick-tap/native_posix_64.keymap new file mode 100644 index 000000000000..bd431ceb095a --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/5-quick-tap/native_posix_64.keymap @@ -0,0 +1,14 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/1-basic/events.patterns b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/1-basic/events.patterns new file mode 100644 index 000000000000..4db21917caf4 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/1-basic/events.patterns @@ -0,0 +1,6 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p +s/.*update_hold_status_for_retro_tap/update_hold_status_for_retro_tap/p +s/.*decide_retro_tap/decide_retro_tap/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/1-basic/keycode_events.snapshot b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/1-basic/keycode_events.snapshot new file mode 100644 index 000000000000..03bc028906d8 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/1-basic/keycode_events.snapshot @@ -0,0 +1,24 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-unless-interrupted decision moment key-up) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-unless-interrupted decision moment quick-tap) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-unless-interrupted decision moment timer) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-unless-interrupted decision moment quick-tap) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/1-basic/native_posix_64.keymap b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/1-basic/native_posix_64.keymap new file mode 100644 index 000000000000..aa6294980730 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/1-basic/native_posix_64.keymap @@ -0,0 +1,25 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + /* tap */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,250) + /* normal quick tap */ + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(0,0,400) + /* hold */ + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,400) + /* require-prior-idle */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/2-double-hold/events.patterns b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/2-double-hold/events.patterns new file mode 100644 index 000000000000..4db21917caf4 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/2-double-hold/events.patterns @@ -0,0 +1,6 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p +s/.*update_hold_status_for_retro_tap/update_hold_status_for_retro_tap/p +s/.*decide_retro_tap/decide_retro_tap/p \ No newline at end of file diff --git a/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/2-double-hold/keycode_events.snapshot b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/2-double-hold/keycode_events.snapshot new file mode 100644 index 000000000000..bf3ab9c05869 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/2-double-hold/keycode_events.snapshot @@ -0,0 +1,12 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided tap (tap-unless-interrupted decision moment timer) +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_pressed: 1 new undecided hold_tap +ht_decide: 1 decided tap (tap-unless-interrupted decision moment timer) +kp_pressed: usage_page 0x07 keycode 0x0D implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 0 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0x0D implicit_mods 0x00 explicit_mods 0x00 +ht_binding_released: 1 cleaning up hold-tap diff --git a/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/2-double-hold/native_posix_64.keymap b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/2-double-hold/native_posix_64.keymap new file mode 100644 index 000000000000..69d691cee8ea --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/2-double-hold/native_posix_64.keymap @@ -0,0 +1,20 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + /* hold the first mod tap */ + ZMK_MOCK_PRESS(0,0,400) + /* hold the second mod tap */ + ZMK_MOCK_PRESS(0,1,400) + /* press the normal key */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + + /* release the hold taps */ + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; diff --git a/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/behavior_keymap.dtsi b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/behavior_keymap.dtsi new file mode 100644 index 000000000000..6a78d588248d --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/behavior_keymap.dtsi @@ -0,0 +1,27 @@ +#include +#include +#include + +/ { + behaviors { + ht_tui: behavior_hold_tap_tap_unless_interrupted { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "tap-unless-interrupted"; + tapping-term-ms = <300>; + quick-tap-ms = <300>; + require-prior-idle-ms = <100>; + bindings = <&kp>, <&kp>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &ht_tui LEFT_SHIFT F &ht_tui LEFT_CONTROL J + &kp D &kp RIGHT_CONTROL>; + }; + }; +}; diff --git a/app/tests/hold-tap/tap-unless-interrupted/behavior_keymap.dtsi b/app/tests/hold-tap/tap-unless-interrupted/behavior_keymap.dtsi new file mode 100644 index 000000000000..7616c46287f4 --- /dev/null +++ b/app/tests/hold-tap/tap-unless-interrupted/behavior_keymap.dtsi @@ -0,0 +1,28 @@ +#include +#include +#include + + + +/ { + behaviors { + ht_tui: behavior_hold_tap_tap_unless_interrupted { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "tap-unless-interrupted"; + tapping-term-ms = <300>; + quick-tap-ms = <200>; + bindings = <&kp>, <&kp>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &ht_tui LEFT_SHIFT F &ht_tui LEFT_CONTROL J + &kp D &kp RIGHT_CONTROL>; + }; + }; +}; diff --git a/app/tests/hold-tap/zmk-modtap-proposal.odg b/app/tests/hold-tap/zmk-modtap-proposal.odg new file mode 100644 index 000000000000..82f84369d4cb Binary files /dev/null and b/app/tests/hold-tap/zmk-modtap-proposal.odg differ diff --git a/app/tests/hold-tap/zmk-modtap-proposal.pdf b/app/tests/hold-tap/zmk-modtap-proposal.pdf new file mode 100644 index 000000000000..33048ca1d64e Binary files /dev/null and b/app/tests/hold-tap/zmk-modtap-proposal.pdf differ diff --git a/app/tests/key-repeat/behavior_keymap.dtsi b/app/tests/key-repeat/behavior_keymap.dtsi new file mode 100644 index 000000000000..a0e5c8f9849c --- /dev/null +++ b/app/tests/key-repeat/behavior_keymap.dtsi @@ -0,0 +1,16 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &key_repeat &kp A + &kp LCTRL &kp C_VOL_UP + >; + }; + }; +}; diff --git a/app/tests/key-repeat/ignore-other-usage-page-events/events.patterns b/app/tests/key-repeat/ignore-other-usage-page-events/events.patterns new file mode 100644 index 000000000000..794719239fc5 --- /dev/null +++ b/app/tests/key-repeat/ignore-other-usage-page-events/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode_//p +s/.*hid_implicit_modifiers_//p \ No newline at end of file diff --git a/app/tests/key-repeat/ignore-other-usage-page-events/keycode_events.snapshot b/app/tests/key-repeat/ignore-other-usage-page-events/keycode_events.snapshot new file mode 100644 index 000000000000..26830981d83b --- /dev/null +++ b/app/tests/key-repeat/ignore-other-usage-page-events/keycode_events.snapshot @@ -0,0 +1,12 @@ +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 +pressed: usage_page 0x0C keycode 0xE9 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +released: usage_page 0x0C keycode 0xE9 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 diff --git a/app/tests/key-repeat/ignore-other-usage-page-events/native_posix_64.keymap b/app/tests/key-repeat/ignore-other-usage-page-events/native_posix_64.keymap new file mode 100644 index 000000000000..e4687573944e --- /dev/null +++ b/app/tests/key-repeat/ignore-other-usage-page-events/native_posix_64.keymap @@ -0,0 +1,15 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/key-repeat/press-and-release-after-key-usage/events.patterns b/app/tests/key-repeat/press-and-release-after-key-usage/events.patterns new file mode 100644 index 000000000000..794719239fc5 --- /dev/null +++ b/app/tests/key-repeat/press-and-release-after-key-usage/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode_//p +s/.*hid_implicit_modifiers_//p \ No newline at end of file diff --git a/app/tests/key-repeat/press-and-release-after-key-usage/keycode_events.snapshot b/app/tests/key-repeat/press-and-release-after-key-usage/keycode_events.snapshot new file mode 100644 index 000000000000..d568d378d835 --- /dev/null +++ b/app/tests/key-repeat/press-and-release-after-key-usage/keycode_events.snapshot @@ -0,0 +1,8 @@ +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 diff --git a/app/tests/key-repeat/press-and-release-after-key-usage/native_posix.keymap b/app/tests/key-repeat/press-and-release-after-key-usage/native_posix.keymap new file mode 100644 index 000000000000..9078f304d58a --- /dev/null +++ b/app/tests/key-repeat/press-and-release-after-key-usage/native_posix.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/key-repeat/press-and-release-after-key-usage/native_posix_64.keymap b/app/tests/key-repeat/press-and-release-after-key-usage/native_posix_64.keymap new file mode 100644 index 000000000000..1d27770b240a --- /dev/null +++ b/app/tests/key-repeat/press-and-release-after-key-usage/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,1,9000) + ZMK_MOCK_RELEASE(0,1,30) + ZMK_MOCK_PRESS(0,0,30) + ZMK_MOCK_RELEASE(0,0,3000) + >; +}; \ No newline at end of file diff --git a/app/tests/key-repeat/press-and-release-with-explicit-modifiers/events.patterns b/app/tests/key-repeat/press-and-release-with-explicit-modifiers/events.patterns new file mode 100644 index 000000000000..794719239fc5 --- /dev/null +++ b/app/tests/key-repeat/press-and-release-with-explicit-modifiers/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode_//p +s/.*hid_implicit_modifiers_//p \ No newline at end of file diff --git a/app/tests/key-repeat/press-and-release-with-explicit-modifiers/keycode_events.snapshot b/app/tests/key-repeat/press-and-release-with-explicit-modifiers/keycode_events.snapshot new file mode 100644 index 000000000000..08f9e5583584 --- /dev/null +++ b/app/tests/key-repeat/press-and-release-with-explicit-modifiers/keycode_events.snapshot @@ -0,0 +1,12 @@ +pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x01 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x01 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x01 +released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x01 explicit_mods 0x00 +press: Modifiers set to 0x01 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x01 explicit_mods 0x00 +release: Modifiers set to 0x00 diff --git a/app/tests/key-repeat/press-and-release-with-explicit-modifiers/native_posix_64.keymap b/app/tests/key-repeat/press-and-release-with-explicit-modifiers/native_posix_64.keymap new file mode 100644 index 000000000000..109aed5ac3dd --- /dev/null +++ b/app/tests/key-repeat/press-and-release-with-explicit-modifiers/native_posix_64.keymap @@ -0,0 +1,15 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/events.patterns b/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/events.patterns new file mode 100644 index 000000000000..794719239fc5 --- /dev/null +++ b/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode_//p +s/.*hid_implicit_modifiers_//p \ No newline at end of file diff --git a/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/keycode_events.snapshot b/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/keycode_events.snapshot new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/native_posix_64.keymap b/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/native_posix_64.keymap new file mode 100644 index 000000000000..0d2d0f6c65ba --- /dev/null +++ b/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/native_posix_64.keymap @@ -0,0 +1,11 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/key-repeat/tap-when-rolling/events.patterns b/app/tests/key-repeat/tap-when-rolling/events.patterns new file mode 100644 index 000000000000..794719239fc5 --- /dev/null +++ b/app/tests/key-repeat/tap-when-rolling/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode_//p +s/.*hid_implicit_modifiers_//p \ No newline at end of file diff --git a/app/tests/key-repeat/tap-when-rolling/keycode_events.snapshot b/app/tests/key-repeat/tap-when-rolling/keycode_events.snapshot new file mode 100644 index 000000000000..7d54e9de9b20 --- /dev/null +++ b/app/tests/key-repeat/tap-when-rolling/keycode_events.snapshot @@ -0,0 +1,9 @@ +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +pressed: unregistering usage_page 0x07 keycode 0x04 since it was already pressed +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 diff --git a/app/tests/key-repeat/tap-when-rolling/native_posix.keymap b/app/tests/key-repeat/tap-when-rolling/native_posix.keymap new file mode 100644 index 000000000000..bb129d14c7ad --- /dev/null +++ b/app/tests/key-repeat/tap-when-rolling/native_posix.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/app/tests/key-repeat/tap-when-rolling/native_posix_64.keymap b/app/tests/key-repeat/tap-when-rolling/native_posix_64.keymap new file mode 100644 index 000000000000..a947f7ab0ed1 --- /dev/null +++ b/app/tests/key-repeat/tap-when-rolling/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,1,9000) + ZMK_MOCK_PRESS(0,0,30) + ZMK_MOCK_RELEASE(0,1,30) + ZMK_MOCK_RELEASE(0,0,3000) + >; +}; diff --git a/app/tests/keypress/behavior_keymap.dtsi b/app/tests/keypress/behavior_keymap.dtsi new file mode 100644 index 000000000000..5f7cfd2dfeb6 --- /dev/null +++ b/app/tests/keypress/behavior_keymap.dtsi @@ -0,0 +1,16 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp B &none + &none &none + >; + }; + }; +}; diff --git a/app/tests/keypress/kp-press-release/events.patterns b/app/tests/keypress/kp-press-release/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/keypress/kp-press-release/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/keypress/kp-press-release/keycode_events.snapshot b/app/tests/keypress/kp-press-release/keycode_events.snapshot new file mode 100644 index 000000000000..259501ba3d96 --- /dev/null +++ b/app/tests/keypress/kp-press-release/keycode_events.snapshot @@ -0,0 +1,2 @@ +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/keypress/kp-press-release/native_posix_64.keymap b/app/tests/keypress/kp-press-release/native_posix_64.keymap new file mode 100644 index 000000000000..a414f34ba631 --- /dev/null +++ b/app/tests/keypress/kp-press-release/native_posix_64.keymap @@ -0,0 +1,8 @@ +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/keytoggle/behavior_keymap.dtsi b/app/tests/keytoggle/behavior_keymap.dtsi new file mode 100644 index 000000000000..a8e751364e33 --- /dev/null +++ b/app/tests/keytoggle/behavior_keymap.dtsi @@ -0,0 +1,16 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kt B &none + &none &none + >; + }; + }; +}; diff --git a/app/tests/keytoggle/kt-alt-tab/events.patterns b/app/tests/keytoggle/kt-alt-tab/events.patterns new file mode 100644 index 000000000000..69eeca5afd6c --- /dev/null +++ b/app/tests/keytoggle/kt-alt-tab/events.patterns @@ -0,0 +1 @@ +s/.*\(hid_listener_keycode_\|hid_implicit_modifiers_\)//p diff --git a/app/tests/keytoggle/kt-alt-tab/keycode_events.snapshot b/app/tests/keytoggle/kt-alt-tab/keycode_events.snapshot new file mode 100644 index 000000000000..3318db423641 --- /dev/null +++ b/app/tests/keytoggle/kt-alt-tab/keycode_events.snapshot @@ -0,0 +1,28 @@ +pressed: usage_page 0x07 keycode 0xE2 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x04 +pressed: usage_page 0x07 keycode 0x2B implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x04 +released: usage_page 0x07 keycode 0x2B implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x04 +pressed: usage_page 0x07 keycode 0x2B implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x04 +released: usage_page 0x07 keycode 0x2B implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x04 +pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x06 +pressed: usage_page 0x07 keycode 0x2B implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x06 +released: usage_page 0x07 keycode 0x2B implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x06 +released: usage_page 0x07 keycode 0xE2 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x02 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x02 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x02 +released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 diff --git a/app/tests/keytoggle/kt-alt-tab/native_posix_64.keymap b/app/tests/keytoggle/kt-alt-tab/native_posix_64.keymap new file mode 100644 index 000000000000..78b4e4554766 --- /dev/null +++ b/app/tests/keytoggle/kt-alt-tab/native_posix_64.keymap @@ -0,0 +1,47 @@ +#include +#include +#include + +&kscan { + events = < + /* Toggle LALT on */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* Tap TAB twice */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* Toggle LSHFT on */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + /* Tap TAB once */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* Toggle LALT off */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* Tap A */ + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + /* Toggle LSHFT off */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + /* Tap A */ + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + >; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kt LALT &kp TAB + &kt LSHFT &kp A + >; + }; + }; +}; \ No newline at end of file diff --git a/app/tests/keytoggle/kt-modded-alpha/events.patterns b/app/tests/keytoggle/kt-modded-alpha/events.patterns new file mode 100644 index 000000000000..69eeca5afd6c --- /dev/null +++ b/app/tests/keytoggle/kt-modded-alpha/events.patterns @@ -0,0 +1 @@ +s/.*\(hid_listener_keycode_\|hid_implicit_modifiers_\)//p diff --git a/app/tests/keytoggle/kt-modded-alpha/keycode_events.snapshot b/app/tests/keytoggle/kt-modded-alpha/keycode_events.snapshot new file mode 100644 index 000000000000..6fd41cb21683 --- /dev/null +++ b/app/tests/keytoggle/kt-modded-alpha/keycode_events.snapshot @@ -0,0 +1,12 @@ +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x02 explicit_mods 0x00 +press: Modifiers set to 0x02 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x02 explicit_mods 0x00 +release: Modifiers set to 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x02 explicit_mods 0x00 +release: Modifiers set to 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x02 explicit_mods 0x00 +press: Modifiers set to 0x02 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 diff --git a/app/tests/keytoggle/kt-modded-alpha/native_posix_64.keymap b/app/tests/keytoggle/kt-modded-alpha/native_posix_64.keymap new file mode 100644 index 000000000000..0621b33ad63a --- /dev/null +++ b/app/tests/keytoggle/kt-modded-alpha/native_posix_64.keymap @@ -0,0 +1,37 @@ +#include +#include +#include + +&kscan { + events = < + /* Toggle LS(A) on */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* Toggle LS(A) off */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* Press A */ + ZMK_MOCK_PRESS(1,0,10) + /* Toggle LS(A) on */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* Toggle LS(A) off */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* Release A */ + ZMK_MOCK_RELEASE(1,0,10) + >; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kt LS(A) &trans + &kp A &trans + >; + }; + }; +}; \ No newline at end of file diff --git a/app/tests/keytoggle/kt-press-release-nkro/events.patterns b/app/tests/keytoggle/kt-press-release-nkro/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/keytoggle/kt-press-release-nkro/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/keytoggle/kt-press-release-nkro/keycode_events.snapshot b/app/tests/keytoggle/kt-press-release-nkro/keycode_events.snapshot new file mode 100644 index 000000000000..259501ba3d96 --- /dev/null +++ b/app/tests/keytoggle/kt-press-release-nkro/keycode_events.snapshot @@ -0,0 +1,2 @@ +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/keytoggle/kt-press-release-nkro/native_posix_64.conf b/app/tests/keytoggle/kt-press-release-nkro/native_posix_64.conf new file mode 100644 index 000000000000..01abac5ee198 --- /dev/null +++ b/app/tests/keytoggle/kt-press-release-nkro/native_posix_64.conf @@ -0,0 +1,7 @@ +CONFIG_GPIO=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_DEBUG=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_ZMK_HID_REPORT_TYPE_NKRO=y \ No newline at end of file diff --git a/app/tests/keytoggle/kt-press-release-nkro/native_posix_64.keymap b/app/tests/keytoggle/kt-press-release-nkro/native_posix_64.keymap new file mode 100644 index 000000000000..5c2d202850b1 --- /dev/null +++ b/app/tests/keytoggle/kt-press-release-nkro/native_posix_64.keymap @@ -0,0 +1,10 @@ +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/keytoggle/kt-press-release/events.patterns b/app/tests/keytoggle/kt-press-release/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/keytoggle/kt-press-release/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/keytoggle/kt-press-release/keycode_events.snapshot b/app/tests/keytoggle/kt-press-release/keycode_events.snapshot new file mode 100644 index 000000000000..259501ba3d96 --- /dev/null +++ b/app/tests/keytoggle/kt-press-release/keycode_events.snapshot @@ -0,0 +1,2 @@ +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/keytoggle/kt-press-release/native_posix_64.keymap b/app/tests/keytoggle/kt-press-release/native_posix_64.keymap new file mode 100644 index 000000000000..5c2d202850b1 --- /dev/null +++ b/app/tests/keytoggle/kt-press-release/native_posix_64.keymap @@ -0,0 +1,10 @@ +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/macros/basic/events.patterns b/app/tests/macros/basic/events.patterns new file mode 100644 index 000000000000..0a5f25ca647c --- /dev/null +++ b/app/tests/macros/basic/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*behavior_queue_process_next/queue_process_next/p \ No newline at end of file diff --git a/app/tests/macros/basic/keycode_events.snapshot b/app/tests/macros/basic/keycode_events.snapshot new file mode 100644 index 000000000000..5639f1d73b02 --- /dev/null +++ b/app/tests/macros/basic/keycode_events.snapshot @@ -0,0 +1,18 @@ +queue_process_next: Invoking key_press: 0x70004 0x00 +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 50ms +queue_process_next: Invoking key_press: 0x70004 0x00 +kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 10ms +queue_process_next: Invoking key_press: 0x70005 0x00 +kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 50ms +queue_process_next: Invoking key_press: 0x70005 0x00 +kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 10ms +queue_process_next: Invoking key_press: 0x70006 0x00 +kp_pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 50ms +queue_process_next: Invoking key_press: 0x70006 0x00 +kp_released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 10ms diff --git a/app/tests/macros/basic/native_posix_64.keymap b/app/tests/macros/basic/native_posix_64.keymap new file mode 100644 index 000000000000..a34ba99f72eb --- /dev/null +++ b/app/tests/macros/basic/native_posix_64.keymap @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/macros/behavior_keymap.dtsi b/app/tests/macros/behavior_keymap.dtsi new file mode 100644 index 000000000000..25414216af2e --- /dev/null +++ b/app/tests/macros/behavior_keymap.dtsi @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + macros { + ZMK_MACRO(abc_macro, + wait-ms = <10>; + tap-ms = <50>; + bindings = <&kp A &kp B &kp C>; + ) + + ZMK_MACRO(hold_shift_macro, + bindings + = <¯o_press &kp LSHFT> + , <¯o_tap> + , <&kp D &kp O &kp G> + , <¯o_release &kp LSHFT> + ; + ) + + ZMK_MACRO(custom_timing, + bindings + = <¯o_wait_time 50> + , <&kp A> + , <¯o_tap_time 20> + , <&kp B &kp C> + ; + ) + + ZMK_MACRO(dual_sequence_macro, + wait-ms = <10>; + tap-ms = <40>; + bindings + = <¯o_press &kp LALT> + , <¯o_tap> + , <&kp TAB> + , <¯o_pause_for_release> + , <¯o_release &kp LALT> + ; + ) + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &abc_macro &mo 1 + &hold_shift_macro &custom_timing>; + }; + + extra_layer { + bindings = < + &dual_sequence_macro &trans + &kp TAB &none>; + + }; + + }; +}; diff --git a/app/tests/macros/mo-plus-modifier-from-hold-tap/events.patterns b/app/tests/macros/mo-plus-modifier-from-hold-tap/events.patterns new file mode 100644 index 000000000000..3c9d3f838c62 --- /dev/null +++ b/app/tests/macros/mo-plus-modifier-from-hold-tap/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode/kp/p \ No newline at end of file diff --git a/app/tests/macros/mo-plus-modifier-from-hold-tap/keycode_events.snapshot b/app/tests/macros/mo-plus-modifier-from-hold-tap/keycode_events.snapshot new file mode 100644 index 000000000000..6e1257c6026a --- /dev/null +++ b/app/tests/macros/mo-plus-modifier-from-hold-tap/keycode_events.snapshot @@ -0,0 +1,4 @@ +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/macros/mo-plus-modifier-from-hold-tap/native_posix_64.keymap b/app/tests/macros/mo-plus-modifier-from-hold-tap/native_posix_64.keymap new file mode 100644 index 000000000000..d9d186ce2fc2 --- /dev/null +++ b/app/tests/macros/mo-plus-modifier-from-hold-tap/native_posix_64.keymap @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + macros { + ZMK_MACRO( + mo_mod_macro, + wait-ms = <0>; + tap-ms = <20>; + bindings + = <¯o_press &mo 1 &kp LSHFT> + , <¯o_pause_for_release> + , <¯o_release &mo 1 &kp LSHFT>; + ) + }; + + behaviors { + mth: macro_tap_hold { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "tap-unless-interrupted"; + tapping-term-ms = <200>; + bindings = <&mo_mod_macro>, <&kp>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &mth 0 TAB &kp A + &kp B &kp C>; + }; + + extra_layer { + bindings = < + &kp D &kp E + &kp F &kp G>; + + }; + + }; +}; + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/macros/mo-plus-modifier-macro/events.patterns b/app/tests/macros/mo-plus-modifier-macro/events.patterns new file mode 100644 index 000000000000..3c9d3f838c62 --- /dev/null +++ b/app/tests/macros/mo-plus-modifier-macro/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode/kp/p \ No newline at end of file diff --git a/app/tests/macros/mo-plus-modifier-macro/keycode_events.snapshot b/app/tests/macros/mo-plus-modifier-macro/keycode_events.snapshot new file mode 100644 index 000000000000..6e1257c6026a --- /dev/null +++ b/app/tests/macros/mo-plus-modifier-macro/keycode_events.snapshot @@ -0,0 +1,4 @@ +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/macros/mo-plus-modifier-macro/native_posix_64.keymap b/app/tests/macros/mo-plus-modifier-macro/native_posix_64.keymap new file mode 100644 index 000000000000..bb06d2c37545 --- /dev/null +++ b/app/tests/macros/mo-plus-modifier-macro/native_posix_64.keymap @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + macros { + ZMK_MACRO( + mo_mod_macro, + wait-ms = <0>; + tap-ms = <20>; + bindings + = <¯o_press &mo 1 &kp LSHFT> + , <¯o_pause_for_release> + , <¯o_release &mo 1 &kp LSHFT>; + ) + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &mo_mod_macro &kp A + &kp B &kp C>; + }; + + extra_layer { + bindings = < + &kp D &kp E + &kp F &kp G>; + + }; + + }; +}; + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/macros/place-holder-parameters/events.patterns b/app/tests/macros/place-holder-parameters/events.patterns new file mode 100644 index 000000000000..3c9d3f838c62 --- /dev/null +++ b/app/tests/macros/place-holder-parameters/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode/kp/p \ No newline at end of file diff --git a/app/tests/macros/place-holder-parameters/keycode_events.snapshot b/app/tests/macros/place-holder-parameters/keycode_events.snapshot new file mode 100644 index 000000000000..f198a49b81ee --- /dev/null +++ b/app/tests/macros/place-holder-parameters/keycode_events.snapshot @@ -0,0 +1,16 @@ +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x38 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x38 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x34 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x34 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x34 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x34 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/macros/place-holder-parameters/native_posix_64.keymap b/app/tests/macros/place-holder-parameters/native_posix_64.keymap new file mode 100644 index 000000000000..c6fcd5c6b867 --- /dev/null +++ b/app/tests/macros/place-holder-parameters/native_posix_64.keymap @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + macros { + slash_macro: slash_macro { + #binding-cells = <2>; + compatible = "zmk,behavior-macro-two-param"; + wait-ms = <40>; + tap-ms = <40>; + bindings = < + ¯o_param_1to1 &kp MACRO_PLACEHOLDER + &kp SLASH + ¯o_param_2to1 &kp MACRO_PLACEHOLDER>; + }; + + to_second_macro: to_second_macro { + #binding-cells = <2>; + compatible = "zmk,behavior-macro-two-param"; + wait-ms = <40>; + tap-ms = <40>; + bindings = < + ¯o_param_1to2 &mt LSHIFT MACRO_PLACEHOLDER + ¯o_param_2to2 &mt RSHIFT MACRO_PLACEHOLDER>; + }; + + quote_letter_macro: quote_letter_macro { + #binding-cells = <1>; + compatible = "zmk,behavior-macro-one-param"; + wait-ms = <40>; + tap-ms = <40>; + bindings = < + &kp QUOT + ¯o_param_1to1 &kp MACRO_PLACEHOLDER + &kp QUOT>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &slash_macro A B "e_letter_macro B + &to_second_macro E F &kp C>; + }; + }; +}; + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/macros/press-mid-macro/events.patterns b/app/tests/macros/press-mid-macro/events.patterns new file mode 100644 index 000000000000..cedbda8bc6db --- /dev/null +++ b/app/tests/macros/press-mid-macro/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*keymap_apply_position_state/pos_state/p \ No newline at end of file diff --git a/app/tests/macros/press-mid-macro/keycode_events.snapshot b/app/tests/macros/press-mid-macro/keycode_events.snapshot new file mode 100644 index 000000000000..0ec7ccb3cd65 --- /dev/null +++ b/app/tests/macros/press-mid-macro/keycode_events.snapshot @@ -0,0 +1,10 @@ +pos_state: layer: 0 position: 0, binding name: abc_macro +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pos_state: layer: 0 position: 0, binding name: abc_macro +pos_state: layer: 0 position: 1, binding name: momentary_layer +pos_state: layer: 0 position: 1, binding name: momentary_layer +kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/macros/press-mid-macro/native_posix_64.keymap b/app/tests/macros/press-mid-macro/native_posix_64.keymap new file mode 100644 index 000000000000..8010a8e79dc3 --- /dev/null +++ b/app/tests/macros/press-mid-macro/native_posix_64.keymap @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/macros/press-release/events.patterns b/app/tests/macros/press-release/events.patterns new file mode 100644 index 000000000000..3c9d3f838c62 --- /dev/null +++ b/app/tests/macros/press-release/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode/kp/p \ No newline at end of file diff --git a/app/tests/macros/press-release/keycode_events.snapshot b/app/tests/macros/press-release/keycode_events.snapshot new file mode 100644 index 000000000000..d40cfb65a86a --- /dev/null +++ b/app/tests/macros/press-release/keycode_events.snapshot @@ -0,0 +1,8 @@ +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x12 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x12 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x0A implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x0A implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/macros/press-release/native_posix_64.keymap b/app/tests/macros/press-release/native_posix_64.keymap new file mode 100644 index 000000000000..75333333783a --- /dev/null +++ b/app/tests/macros/press-release/native_posix_64.keymap @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/macros/timing-override/events.patterns b/app/tests/macros/timing-override/events.patterns new file mode 100644 index 000000000000..0a5f25ca647c --- /dev/null +++ b/app/tests/macros/timing-override/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*behavior_queue_process_next/queue_process_next/p \ No newline at end of file diff --git a/app/tests/macros/timing-override/keycode_events.snapshot b/app/tests/macros/timing-override/keycode_events.snapshot new file mode 100644 index 000000000000..e275cf9b39f0 --- /dev/null +++ b/app/tests/macros/timing-override/keycode_events.snapshot @@ -0,0 +1,18 @@ +queue_process_next: Invoking key_press: 0x70004 0x00 +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 30ms +queue_process_next: Invoking key_press: 0x70004 0x00 +kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 50ms +queue_process_next: Invoking key_press: 0x70005 0x00 +kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 20ms +queue_process_next: Invoking key_press: 0x70005 0x00 +kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 50ms +queue_process_next: Invoking key_press: 0x70006 0x00 +kp_pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 20ms +queue_process_next: Invoking key_press: 0x70006 0x00 +kp_released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 50ms diff --git a/app/tests/macros/timing-override/native_posix_64.keymap b/app/tests/macros/timing-override/native_posix_64.keymap new file mode 100644 index 000000000000..e5d35e88de45 --- /dev/null +++ b/app/tests/macros/timing-override/native_posix_64.keymap @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/macros/wait-macro-release/events.patterns b/app/tests/macros/wait-macro-release/events.patterns new file mode 100644 index 000000000000..02e0c505c122 --- /dev/null +++ b/app/tests/macros/wait-macro-release/events.patterns @@ -0,0 +1,3 @@ +s/.*hid_listener_keycode/kp/p +s/.*behavior_queue_process_next/queue_process_next/p +s/.*queue_macro/qm/p \ No newline at end of file diff --git a/app/tests/macros/wait-macro-release/keycode_events.snapshot b/app/tests/macros/wait-macro-release/keycode_events.snapshot new file mode 100644 index 000000000000..abe9791f701d --- /dev/null +++ b/app/tests/macros/wait-macro-release/keycode_events.snapshot @@ -0,0 +1,16 @@ +qm: Iterating macro bindings - starting: 0, count: 4 +queue_process_next: Invoking key_press: 0x700e2 0x00 +kp_pressed: usage_page 0x07 keycode 0xE2 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 10ms +queue_process_next: Invoking key_press: 0x7002b 0x00 +kp_pressed: usage_page 0x07 keycode 0x2B implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 40ms +queue_process_next: Invoking key_press: 0x7002b 0x00 +kp_released: usage_page 0x07 keycode 0x2B implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 10ms +kp_pressed: usage_page 0x07 keycode 0x2B implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x2B implicit_mods 0x00 explicit_mods 0x00 +qm: Iterating macro bindings - starting: 5, count: 2 +queue_process_next: Invoking key_press: 0x700e2 0x00 +kp_released: usage_page 0x07 keycode 0xE2 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 0ms diff --git a/app/tests/macros/wait-macro-release/native_posix_64.keymap b/app/tests/macros/wait-macro-release/native_posix_64.keymap new file mode 100644 index 000000000000..394e4a88a4fb --- /dev/null +++ b/app/tests/macros/wait-macro-release/native_posix_64.keymap @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/mod-morph/1-no-morph/events.patterns b/app/tests/mod-morph/1-no-morph/events.patterns new file mode 100644 index 000000000000..f1a41fcf2c33 --- /dev/null +++ b/app/tests/mod-morph/1-no-morph/events.patterns @@ -0,0 +1,8 @@ +s/.*hid_listener_keycode_pressed.*keycode/pressed: keycode/p +s/.*hid_listener_keycode_released.*keycode/released: keycode/p +s/.*hid_register_mod.*Modifiers set to /reg explicit: Modifiers set to /p +s/.*hid_unregister_mod.*Modifiers set to /unreg explicit: Modifiers set to /p +s/.*hid_implicit_modifiers_press.*Modifiers set to /reg implicit: Modifiers set to /p +s/.*hid_implicit_modifiers_release.*Modifiers set to /unreg implicit: Modifiers set to /p +s/.*hid_masked_modifiers_set.*Modifiers set to /mask mods: Modifiers set to /p +s/.*hid_masked_modifiers_clear.*Modifiers set to /unmask mods: Modifiers set to /p diff --git a/app/tests/mod-morph/1-no-morph/keycode_events.snapshot b/app/tests/mod-morph/1-no-morph/keycode_events.snapshot new file mode 100644 index 000000000000..3a2d70febebf --- /dev/null +++ b/app/tests/mod-morph/1-no-morph/keycode_events.snapshot @@ -0,0 +1,5 @@ +pressed: keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +reg implicit: Modifiers set to 0x00 +released: keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +unreg implicit: Modifiers set to 0x00 +unmask mods: Modifiers set to 0x00 diff --git a/app/tests/mod-morph/1-no-morph/native_posix_64.keymap b/app/tests/mod-morph/1-no-morph/native_posix_64.keymap new file mode 100644 index 000000000000..916aa5696522 --- /dev/null +++ b/app/tests/mod-morph/1-no-morph/native_posix_64.keymap @@ -0,0 +1,11 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; diff --git a/app/tests/mod-morph/2a-masked-morph/events.patterns b/app/tests/mod-morph/2a-masked-morph/events.patterns new file mode 100644 index 000000000000..f1a41fcf2c33 --- /dev/null +++ b/app/tests/mod-morph/2a-masked-morph/events.patterns @@ -0,0 +1,8 @@ +s/.*hid_listener_keycode_pressed.*keycode/pressed: keycode/p +s/.*hid_listener_keycode_released.*keycode/released: keycode/p +s/.*hid_register_mod.*Modifiers set to /reg explicit: Modifiers set to /p +s/.*hid_unregister_mod.*Modifiers set to /unreg explicit: Modifiers set to /p +s/.*hid_implicit_modifiers_press.*Modifiers set to /reg implicit: Modifiers set to /p +s/.*hid_implicit_modifiers_release.*Modifiers set to /unreg implicit: Modifiers set to /p +s/.*hid_masked_modifiers_set.*Modifiers set to /mask mods: Modifiers set to /p +s/.*hid_masked_modifiers_clear.*Modifiers set to /unmask mods: Modifiers set to /p diff --git a/app/tests/mod-morph/2a-masked-morph/keycode_events.snapshot b/app/tests/mod-morph/2a-masked-morph/keycode_events.snapshot new file mode 100644 index 000000000000..dcf2aae6384d --- /dev/null +++ b/app/tests/mod-morph/2a-masked-morph/keycode_events.snapshot @@ -0,0 +1,12 @@ +pressed: keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +reg explicit: Modifiers set to 0x02 +reg implicit: Modifiers set to 0x02 +mask mods: Modifiers set to 0x00 +pressed: keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +reg implicit: Modifiers set to 0x00 +released: keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +unreg implicit: Modifiers set to 0x00 +unmask mods: Modifiers set to 0x02 +released: keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +unreg explicit: Modifiers set to 0x00 +unreg implicit: Modifiers set to 0x00 diff --git a/app/tests/mod-morph/2a-masked-morph/native_posix_64.keymap b/app/tests/mod-morph/2a-masked-morph/native_posix_64.keymap new file mode 100644 index 000000000000..ec0591e5a075 --- /dev/null +++ b/app/tests/mod-morph/2a-masked-morph/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; diff --git a/app/tests/mod-morph/2b-masked-morph-implicit-overwrite/events.patterns b/app/tests/mod-morph/2b-masked-morph-implicit-overwrite/events.patterns new file mode 100644 index 000000000000..f1a41fcf2c33 --- /dev/null +++ b/app/tests/mod-morph/2b-masked-morph-implicit-overwrite/events.patterns @@ -0,0 +1,8 @@ +s/.*hid_listener_keycode_pressed.*keycode/pressed: keycode/p +s/.*hid_listener_keycode_released.*keycode/released: keycode/p +s/.*hid_register_mod.*Modifiers set to /reg explicit: Modifiers set to /p +s/.*hid_unregister_mod.*Modifiers set to /unreg explicit: Modifiers set to /p +s/.*hid_implicit_modifiers_press.*Modifiers set to /reg implicit: Modifiers set to /p +s/.*hid_implicit_modifiers_release.*Modifiers set to /unreg implicit: Modifiers set to /p +s/.*hid_masked_modifiers_set.*Modifiers set to /mask mods: Modifiers set to /p +s/.*hid_masked_modifiers_clear.*Modifiers set to /unmask mods: Modifiers set to /p diff --git a/app/tests/mod-morph/2b-masked-morph-implicit-overwrite/keycode_events.snapshot b/app/tests/mod-morph/2b-masked-morph-implicit-overwrite/keycode_events.snapshot new file mode 100644 index 000000000000..ce85f25db6c8 --- /dev/null +++ b/app/tests/mod-morph/2b-masked-morph-implicit-overwrite/keycode_events.snapshot @@ -0,0 +1,12 @@ +pressed: keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +reg explicit: Modifiers set to 0x02 +reg implicit: Modifiers set to 0x02 +mask mods: Modifiers set to 0x00 +pressed: keycode 0x05 implicit_mods 0x02 explicit_mods 0x00 +reg implicit: Modifiers set to 0x02 +released: keycode 0x05 implicit_mods 0x02 explicit_mods 0x00 +unreg implicit: Modifiers set to 0x00 +unmask mods: Modifiers set to 0x02 +released: keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +unreg explicit: Modifiers set to 0x00 +unreg implicit: Modifiers set to 0x00 diff --git a/app/tests/mod-morph/2b-masked-morph-implicit-overwrite/native_posix_64.keymap b/app/tests/mod-morph/2b-masked-morph-implicit-overwrite/native_posix_64.keymap new file mode 100644 index 000000000000..8f7b2cdb02a5 --- /dev/null +++ b/app/tests/mod-morph/2b-masked-morph-implicit-overwrite/native_posix_64.keymap @@ -0,0 +1,35 @@ +#include +#include +#include + +/ { + behaviors { + mod_morph: mod_morph { + compatible = "zmk,behavior-mod-morph"; + #binding-cells = <0>; + bindings = <&kp A>, <&kp LS(B)>; // implict mod overwrite + mods = <(MOD_LSFT|MOD_RSFT)>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp LEFT_ALT &mod_morph + &kp LEFT_SHIFT &kp RIGHT_SHIFT + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; + diff --git a/app/tests/mod-morph/2c-masked-morph-and-explicit-mods/events.patterns b/app/tests/mod-morph/2c-masked-morph-and-explicit-mods/events.patterns new file mode 100644 index 000000000000..f1a41fcf2c33 --- /dev/null +++ b/app/tests/mod-morph/2c-masked-morph-and-explicit-mods/events.patterns @@ -0,0 +1,8 @@ +s/.*hid_listener_keycode_pressed.*keycode/pressed: keycode/p +s/.*hid_listener_keycode_released.*keycode/released: keycode/p +s/.*hid_register_mod.*Modifiers set to /reg explicit: Modifiers set to /p +s/.*hid_unregister_mod.*Modifiers set to /unreg explicit: Modifiers set to /p +s/.*hid_implicit_modifiers_press.*Modifiers set to /reg implicit: Modifiers set to /p +s/.*hid_implicit_modifiers_release.*Modifiers set to /unreg implicit: Modifiers set to /p +s/.*hid_masked_modifiers_set.*Modifiers set to /mask mods: Modifiers set to /p +s/.*hid_masked_modifiers_clear.*Modifiers set to /unmask mods: Modifiers set to /p diff --git a/app/tests/mod-morph/2c-masked-morph-and-explicit-mods/keycode_events.snapshot b/app/tests/mod-morph/2c-masked-morph-and-explicit-mods/keycode_events.snapshot new file mode 100644 index 000000000000..561f88a9297a --- /dev/null +++ b/app/tests/mod-morph/2c-masked-morph-and-explicit-mods/keycode_events.snapshot @@ -0,0 +1,18 @@ +pressed: keycode 0xE2 implicit_mods 0x00 explicit_mods 0x00 +reg explicit: Modifiers set to 0x04 +reg implicit: Modifiers set to 0x04 +pressed: keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +reg explicit: Modifiers set to 0x06 +reg implicit: Modifiers set to 0x06 +mask mods: Modifiers set to 0x04 +pressed: keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +reg implicit: Modifiers set to 0x04 +released: keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +unreg implicit: Modifiers set to 0x04 +unmask mods: Modifiers set to 0x06 +released: keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +unreg explicit: Modifiers set to 0x04 +unreg implicit: Modifiers set to 0x04 +released: keycode 0xE2 implicit_mods 0x00 explicit_mods 0x00 +unreg explicit: Modifiers set to 0x00 +unreg implicit: Modifiers set to 0x00 diff --git a/app/tests/mod-morph/2c-masked-morph-and-explicit-mods/native_posix_64.keymap b/app/tests/mod-morph/2c-masked-morph-and-explicit-mods/native_posix_64.keymap new file mode 100644 index 000000000000..de1368bdafa3 --- /dev/null +++ b/app/tests/mod-morph/2c-masked-morph-and-explicit-mods/native_posix_64.keymap @@ -0,0 +1,15 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/app/tests/mod-morph/2d-masked-morph-into-hold-tap-tap/events.patterns b/app/tests/mod-morph/2d-masked-morph-into-hold-tap-tap/events.patterns new file mode 100644 index 000000000000..f1a41fcf2c33 --- /dev/null +++ b/app/tests/mod-morph/2d-masked-morph-into-hold-tap-tap/events.patterns @@ -0,0 +1,8 @@ +s/.*hid_listener_keycode_pressed.*keycode/pressed: keycode/p +s/.*hid_listener_keycode_released.*keycode/released: keycode/p +s/.*hid_register_mod.*Modifiers set to /reg explicit: Modifiers set to /p +s/.*hid_unregister_mod.*Modifiers set to /unreg explicit: Modifiers set to /p +s/.*hid_implicit_modifiers_press.*Modifiers set to /reg implicit: Modifiers set to /p +s/.*hid_implicit_modifiers_release.*Modifiers set to /unreg implicit: Modifiers set to /p +s/.*hid_masked_modifiers_set.*Modifiers set to /mask mods: Modifiers set to /p +s/.*hid_masked_modifiers_clear.*Modifiers set to /unmask mods: Modifiers set to /p diff --git a/app/tests/mod-morph/2d-masked-morph-into-hold-tap-tap/keycode_events.snapshot b/app/tests/mod-morph/2d-masked-morph-into-hold-tap-tap/keycode_events.snapshot new file mode 100644 index 000000000000..dcf2aae6384d --- /dev/null +++ b/app/tests/mod-morph/2d-masked-morph-into-hold-tap-tap/keycode_events.snapshot @@ -0,0 +1,12 @@ +pressed: keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +reg explicit: Modifiers set to 0x02 +reg implicit: Modifiers set to 0x02 +mask mods: Modifiers set to 0x00 +pressed: keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +reg implicit: Modifiers set to 0x00 +released: keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +unreg implicit: Modifiers set to 0x00 +unmask mods: Modifiers set to 0x02 +released: keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +unreg explicit: Modifiers set to 0x00 +unreg implicit: Modifiers set to 0x00 diff --git a/app/tests/mod-morph/2d-masked-morph-into-hold-tap-tap/native_posix_64.keymap b/app/tests/mod-morph/2d-masked-morph-into-hold-tap-tap/native_posix_64.keymap new file mode 100644 index 000000000000..4f9f491086a4 --- /dev/null +++ b/app/tests/mod-morph/2d-masked-morph-into-hold-tap-tap/native_posix_64.keymap @@ -0,0 +1,43 @@ +#include +#include +#include + +&kscan { + events = < + /* Shift + tap &mod_morph --> expect B (but get Shift + B) */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; + +/ { + behaviors { + mod_morph: mod_morph { + compatible = "zmk,behavior-mod-morph"; + #binding-cells = <0>; + bindings = <&kp A>, << 1 B>; + mods = <(MOD_LSFT|MOD_RSFT)>; + }; + + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp LEFT_SHIFT &mod_morph + &kp C &none + >; + }; + + second_layer { + bindings = < + &trans &trans + &kp D &trans + >; + }; + }; +}; diff --git a/app/tests/mod-morph/2e-masked-morph-into-hold-tap-hold/events.patterns b/app/tests/mod-morph/2e-masked-morph-into-hold-tap-hold/events.patterns new file mode 100644 index 000000000000..f1a41fcf2c33 --- /dev/null +++ b/app/tests/mod-morph/2e-masked-morph-into-hold-tap-hold/events.patterns @@ -0,0 +1,8 @@ +s/.*hid_listener_keycode_pressed.*keycode/pressed: keycode/p +s/.*hid_listener_keycode_released.*keycode/released: keycode/p +s/.*hid_register_mod.*Modifiers set to /reg explicit: Modifiers set to /p +s/.*hid_unregister_mod.*Modifiers set to /unreg explicit: Modifiers set to /p +s/.*hid_implicit_modifiers_press.*Modifiers set to /reg implicit: Modifiers set to /p +s/.*hid_implicit_modifiers_release.*Modifiers set to /unreg implicit: Modifiers set to /p +s/.*hid_masked_modifiers_set.*Modifiers set to /mask mods: Modifiers set to /p +s/.*hid_masked_modifiers_clear.*Modifiers set to /unmask mods: Modifiers set to /p diff --git a/app/tests/mod-morph/2e-masked-morph-into-hold-tap-hold/keycode_events.snapshot b/app/tests/mod-morph/2e-masked-morph-into-hold-tap-hold/keycode_events.snapshot new file mode 100644 index 000000000000..ba70ee981777 --- /dev/null +++ b/app/tests/mod-morph/2e-masked-morph-into-hold-tap-hold/keycode_events.snapshot @@ -0,0 +1,12 @@ +pressed: keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +reg explicit: Modifiers set to 0x02 +reg implicit: Modifiers set to 0x02 +mask mods: Modifiers set to 0x00 +pressed: keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +reg implicit: Modifiers set to 0x00 +released: keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +unreg implicit: Modifiers set to 0x00 +unmask mods: Modifiers set to 0x02 +released: keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +unreg explicit: Modifiers set to 0x00 +unreg implicit: Modifiers set to 0x00 diff --git a/app/tests/mod-morph/2e-masked-morph-into-hold-tap-hold/native_posix_64.keymap b/app/tests/mod-morph/2e-masked-morph-into-hold-tap-hold/native_posix_64.keymap new file mode 100644 index 000000000000..77067f341bc1 --- /dev/null +++ b/app/tests/mod-morph/2e-masked-morph-into-hold-tap-hold/native_posix_64.keymap @@ -0,0 +1,45 @@ +#include +#include +#include + +&kscan { + events = < + /* Shift + hold &mod_morph --> expect and get D (no shift) */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,200) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; + +/ { + behaviors { + mod_morph: mod_morph { + compatible = "zmk,behavior-mod-morph"; + #binding-cells = <0>; + bindings = <&kp A>, << 1 B>; + mods = <(MOD_LSFT|MOD_RSFT)>; + }; + + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp LEFT_SHIFT &mod_morph + &kp C &none + >; + }; + + second_layer { + bindings = < + &trans &trans + &kp D &trans + >; + }; + }; +}; diff --git a/app/tests/mod-morph/3-unmasked-morph/events.patterns b/app/tests/mod-morph/3-unmasked-morph/events.patterns new file mode 100644 index 000000000000..f1a41fcf2c33 --- /dev/null +++ b/app/tests/mod-morph/3-unmasked-morph/events.patterns @@ -0,0 +1,8 @@ +s/.*hid_listener_keycode_pressed.*keycode/pressed: keycode/p +s/.*hid_listener_keycode_released.*keycode/released: keycode/p +s/.*hid_register_mod.*Modifiers set to /reg explicit: Modifiers set to /p +s/.*hid_unregister_mod.*Modifiers set to /unreg explicit: Modifiers set to /p +s/.*hid_implicit_modifiers_press.*Modifiers set to /reg implicit: Modifiers set to /p +s/.*hid_implicit_modifiers_release.*Modifiers set to /unreg implicit: Modifiers set to /p +s/.*hid_masked_modifiers_set.*Modifiers set to /mask mods: Modifiers set to /p +s/.*hid_masked_modifiers_clear.*Modifiers set to /unmask mods: Modifiers set to /p diff --git a/app/tests/mod-morph/3-unmasked-morph/keycode_events.snapshot b/app/tests/mod-morph/3-unmasked-morph/keycode_events.snapshot new file mode 100644 index 000000000000..424242d599ea --- /dev/null +++ b/app/tests/mod-morph/3-unmasked-morph/keycode_events.snapshot @@ -0,0 +1,12 @@ +pressed: keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +reg explicit: Modifiers set to 0x02 +reg implicit: Modifiers set to 0x02 +mask mods: Modifiers set to 0x02 +pressed: keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +reg implicit: Modifiers set to 0x02 +released: keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +unreg implicit: Modifiers set to 0x02 +unmask mods: Modifiers set to 0x02 +released: keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +unreg explicit: Modifiers set to 0x00 +unreg implicit: Modifiers set to 0x00 diff --git a/app/tests/mod-morph/3-unmasked-morph/native_posix_64.keymap b/app/tests/mod-morph/3-unmasked-morph/native_posix_64.keymap new file mode 100644 index 000000000000..d2ad5670c035 --- /dev/null +++ b/app/tests/mod-morph/3-unmasked-morph/native_posix_64.keymap @@ -0,0 +1,35 @@ +#include +#include +#include + +/ { + behaviors { + mod_morph: mod_morph { + compatible = "zmk,behavior-mod-morph"; + #binding-cells = <0>; + bindings = <&kp A>, <&kp B>; + mods = <(MOD_LSFT|MOD_RSFT)>; + keep-mods = <(MOD_LSFT|MOD_RSFT)>; // no masking + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp LEFT_ALT &mod_morph + &kp LEFT_SHIFT &kp RIGHT_SHIFT + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; diff --git a/app/tests/mod-morph/behavior_keymap.dtsi b/app/tests/mod-morph/behavior_keymap.dtsi new file mode 100644 index 000000000000..86150307762d --- /dev/null +++ b/app/tests/mod-morph/behavior_keymap.dtsi @@ -0,0 +1,21 @@ +/ { + behaviors { + mod_morph: mod_morph { + compatible = "zmk,behavior-mod-morph"; + #binding-cells = <0>; + bindings = <&kp A>, <&kp B>; + mods = <(MOD_LSFT|MOD_RSFT)>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp LEFT_ALT &mod_morph + &kp LEFT_SHIFT &kp RIGHT_SHIFT + >; + }; + }; +}; diff --git a/app/tests/modifiers/explicit/kp-hyper-dn-a-dn-a-up-hyper-up/events.patterns b/app/tests/modifiers/explicit/kp-hyper-dn-a-dn-a-up-hyper-up/events.patterns new file mode 100644 index 000000000000..cbf21aff278f --- /dev/null +++ b/app/tests/modifiers/explicit/kp-hyper-dn-a-dn-a-up-hyper-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode_//p +s/.*hid_register_mod/reg/p +s/.*hid_unregister_mod/unreg/p +s/.*zmk_hid_.*Modifiers set to /mods: Modifiers set to /p \ No newline at end of file diff --git a/app/tests/modifiers/explicit/kp-hyper-dn-a-dn-a-up-hyper-up/keycode_events.snapshot b/app/tests/modifiers/explicit/kp-hyper-dn-a-dn-a-up-hyper-up/keycode_events.snapshot new file mode 100644 index 000000000000..ab200cbf11f4 --- /dev/null +++ b/app/tests/modifiers/explicit/kp-hyper-dn-a-dn-a-up-hyper-up/keycode_events.snapshot @@ -0,0 +1,28 @@ +pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x0E +reg: Modifier 0 count 1 +reg: Modifiers set to 0x01 +reg: Modifier 1 count 1 +reg: Modifiers set to 0x03 +reg: Modifier 2 count 1 +reg: Modifiers set to 0x07 +reg: Modifier 3 count 1 +reg: Modifiers set to 0x0F +mods: Modifiers set to 0x0F +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +mods: Modifiers set to 0x0F +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +mods: Modifiers set to 0x0F +released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x0E +unreg: Modifier 0 count: 0 +unreg: Modifier 0 released +unreg: Modifiers set to 0x0E +unreg: Modifier 1 count: 0 +unreg: Modifier 1 released +unreg: Modifiers set to 0x0C +unreg: Modifier 2 count: 0 +unreg: Modifier 2 released +unreg: Modifiers set to 0x08 +unreg: Modifier 3 count: 0 +unreg: Modifier 3 released +unreg: Modifiers set to 0x00 +mods: Modifiers set to 0x00 diff --git a/app/tests/modifiers/explicit/kp-hyper-dn-a-dn-a-up-hyper-up/native_posix_64.keymap b/app/tests/modifiers/explicit/kp-hyper-dn-a-dn-a-up-hyper-up/native_posix_64.keymap new file mode 100644 index 000000000000..8060f18f611a --- /dev/null +++ b/app/tests/modifiers/explicit/kp-hyper-dn-a-dn-a-up-hyper-up/native_posix_64.keymap @@ -0,0 +1,27 @@ +#include +#include +#include + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + + >; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp LS(LA(LG(LEFT_CONTROL))) &kp LEFT_CONTROL + &kp A &none + >; + }; + }; +}; diff --git a/app/tests/modifiers/explicit/kp-lctl-dn-lctl-dn-lctl-up-lctl-up/events.patterns b/app/tests/modifiers/explicit/kp-lctl-dn-lctl-dn-lctl-up-lctl-up/events.patterns new file mode 100644 index 000000000000..cbf21aff278f --- /dev/null +++ b/app/tests/modifiers/explicit/kp-lctl-dn-lctl-dn-lctl-up-lctl-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode_//p +s/.*hid_register_mod/reg/p +s/.*hid_unregister_mod/unreg/p +s/.*zmk_hid_.*Modifiers set to /mods: Modifiers set to /p \ No newline at end of file diff --git a/app/tests/modifiers/explicit/kp-lctl-dn-lctl-dn-lctl-up-lctl-up/keycode_events.snapshot b/app/tests/modifiers/explicit/kp-lctl-dn-lctl-dn-lctl-up-lctl-up/keycode_events.snapshot new file mode 100644 index 000000000000..1cbbf91bf281 --- /dev/null +++ b/app/tests/modifiers/explicit/kp-lctl-dn-lctl-dn-lctl-up-lctl-up/keycode_events.snapshot @@ -0,0 +1,17 @@ +pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +reg: Modifier 0 count 1 +reg: Modifiers set to 0x01 +mods: Modifiers set to 0x01 +pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +reg: Modifier 0 count 2 +reg: Modifiers set to 0x01 +mods: Modifiers set to 0x01 +released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +unreg: Modifier 0 count: 1 +unreg: Modifiers set to 0x01 +mods: Modifiers set to 0x01 +released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +unreg: Modifier 0 count: 0 +unreg: Modifier 0 released +unreg: Modifiers set to 0x00 +mods: Modifiers set to 0x00 diff --git a/app/tests/modifiers/explicit/kp-lctl-dn-lctl-dn-lctl-up-lctl-up/native_posix_64.keymap b/app/tests/modifiers/explicit/kp-lctl-dn-lctl-dn-lctl-up-lctl-up/native_posix_64.keymap new file mode 100644 index 000000000000..503c3519960e --- /dev/null +++ b/app/tests/modifiers/explicit/kp-lctl-dn-lctl-dn-lctl-up-lctl-up/native_posix_64.keymap @@ -0,0 +1,26 @@ +#include +#include +#include + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp LEFT_CONTROL &kp LEFT_CONTROL + &kp LEFT_SHIFT &none + >; + }; + }; +}; diff --git a/app/tests/modifiers/explicit/kp-lctl-dn-lctl-up/events.patterns b/app/tests/modifiers/explicit/kp-lctl-dn-lctl-up/events.patterns new file mode 100644 index 000000000000..cbf21aff278f --- /dev/null +++ b/app/tests/modifiers/explicit/kp-lctl-dn-lctl-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode_//p +s/.*hid_register_mod/reg/p +s/.*hid_unregister_mod/unreg/p +s/.*zmk_hid_.*Modifiers set to /mods: Modifiers set to /p \ No newline at end of file diff --git a/app/tests/modifiers/explicit/kp-lctl-dn-lctl-up/keycode_events.snapshot b/app/tests/modifiers/explicit/kp-lctl-dn-lctl-up/keycode_events.snapshot new file mode 100644 index 000000000000..478320941969 --- /dev/null +++ b/app/tests/modifiers/explicit/kp-lctl-dn-lctl-up/keycode_events.snapshot @@ -0,0 +1,9 @@ +pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +reg: Modifier 0 count 1 +reg: Modifiers set to 0x01 +mods: Modifiers set to 0x01 +released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +unreg: Modifier 0 count: 0 +unreg: Modifier 0 released +unreg: Modifiers set to 0x00 +mods: Modifiers set to 0x00 diff --git a/app/tests/modifiers/explicit/kp-lctl-dn-lctl-up/native_posix_64.keymap b/app/tests/modifiers/explicit/kp-lctl-dn-lctl-up/native_posix_64.keymap new file mode 100644 index 000000000000..362754c83538 --- /dev/null +++ b/app/tests/modifiers/explicit/kp-lctl-dn-lctl-up/native_posix_64.keymap @@ -0,0 +1,24 @@ +#include +#include +#include + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp LEFT_CONTROL &kp LEFT_CONTROL + &kp LEFT_SHIFT &none + >; + }; + }; +}; diff --git a/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lctl-up-lsft-up/events.patterns b/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lctl-up-lsft-up/events.patterns new file mode 100644 index 000000000000..cbf21aff278f --- /dev/null +++ b/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lctl-up-lsft-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode_//p +s/.*hid_register_mod/reg/p +s/.*hid_unregister_mod/unreg/p +s/.*zmk_hid_.*Modifiers set to /mods: Modifiers set to /p \ No newline at end of file diff --git a/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lctl-up-lsft-up/keycode_events.snapshot b/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lctl-up-lsft-up/keycode_events.snapshot new file mode 100644 index 000000000000..85c14ca201e5 --- /dev/null +++ b/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lctl-up-lsft-up/keycode_events.snapshot @@ -0,0 +1,18 @@ +pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +reg: Modifier 0 count 1 +reg: Modifiers set to 0x01 +mods: Modifiers set to 0x01 +pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +reg: Modifier 1 count 1 +reg: Modifiers set to 0x03 +mods: Modifiers set to 0x03 +released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +unreg: Modifier 0 count: 0 +unreg: Modifier 0 released +unreg: Modifiers set to 0x02 +mods: Modifiers set to 0x02 +released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +unreg: Modifier 1 count: 0 +unreg: Modifier 1 released +unreg: Modifiers set to 0x00 +mods: Modifiers set to 0x00 diff --git a/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lctl-up-lsft-up/native_posix_64.keymap b/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lctl-up-lsft-up/native_posix_64.keymap new file mode 100644 index 000000000000..f25996f6670d --- /dev/null +++ b/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lctl-up-lsft-up/native_posix_64.keymap @@ -0,0 +1,26 @@ +#include +#include +#include + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp LEFT_CONTROL &kp LEFT_CONTROL + &kp LEFT_SHIFT &none + >; + }; + }; +}; diff --git a/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lsft-up-lctl-up/events.patterns b/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lsft-up-lctl-up/events.patterns new file mode 100644 index 000000000000..cbf21aff278f --- /dev/null +++ b/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lsft-up-lctl-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode_//p +s/.*hid_register_mod/reg/p +s/.*hid_unregister_mod/unreg/p +s/.*zmk_hid_.*Modifiers set to /mods: Modifiers set to /p \ No newline at end of file diff --git a/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lsft-up-lctl-up/keycode_events.snapshot b/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lsft-up-lctl-up/keycode_events.snapshot new file mode 100644 index 000000000000..80b246763b3e --- /dev/null +++ b/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lsft-up-lctl-up/keycode_events.snapshot @@ -0,0 +1,18 @@ +pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +reg: Modifier 0 count 1 +reg: Modifiers set to 0x01 +mods: Modifiers set to 0x01 +pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +reg: Modifier 1 count 1 +reg: Modifiers set to 0x03 +mods: Modifiers set to 0x03 +released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +unreg: Modifier 1 count: 0 +unreg: Modifier 1 released +unreg: Modifiers set to 0x01 +mods: Modifiers set to 0x01 +released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +unreg: Modifier 0 count: 0 +unreg: Modifier 0 released +unreg: Modifiers set to 0x00 +mods: Modifiers set to 0x00 diff --git a/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lsft-up-lctl-up/native_posix_64.keymap b/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lsft-up-lctl-up/native_posix_64.keymap new file mode 100644 index 000000000000..15cdc5c9d9e9 --- /dev/null +++ b/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lsft-up-lctl-up/native_posix_64.keymap @@ -0,0 +1,27 @@ +#include +#include +#include + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + + >; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp LEFT_CONTROL &kp LEFT_CONTROL + &kp LEFT_SHIFT &none + >; + }; + }; +}; diff --git a/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod1-up-mod2-up/events.patterns b/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod1-up-mod2-up/events.patterns new file mode 100644 index 000000000000..cbf21aff278f --- /dev/null +++ b/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod1-up-mod2-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode_//p +s/.*hid_register_mod/reg/p +s/.*hid_unregister_mod/unreg/p +s/.*zmk_hid_.*Modifiers set to /mods: Modifiers set to /p \ No newline at end of file diff --git a/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod1-up-mod2-up/keycode_events.snapshot b/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod1-up-mod2-up/keycode_events.snapshot new file mode 100644 index 000000000000..6dad3dea4265 --- /dev/null +++ b/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod1-up-mod2-up/keycode_events.snapshot @@ -0,0 +1,8 @@ +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x02 explicit_mods 0x00 +mods: Modifiers set to 0x02 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x01 explicit_mods 0x00 +mods: Modifiers set to 0x01 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x02 explicit_mods 0x00 +mods: Modifiers set to 0x01 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x01 explicit_mods 0x00 +mods: Modifiers set to 0x00 diff --git a/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod1-up-mod2-up/native_posix_64.keymap b/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod1-up-mod2-up/native_posix_64.keymap new file mode 100644 index 000000000000..17d949e73082 --- /dev/null +++ b/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod1-up-mod2-up/native_posix_64.keymap @@ -0,0 +1,26 @@ +#include +#include +#include + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp LC(A) &kp LS(B) + &kp LEFT_CONTROL &none + >; + }; + }; +}; diff --git a/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod1-up-mod2-up/pending b/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod1-up-mod2-up/pending new file mode 100644 index 000000000000..f3df27cabd54 --- /dev/null +++ b/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod1-up-mod2-up/pending @@ -0,0 +1,9 @@ +This test fails because the hid_listener_keycode_released function +releases implicit modifiers always, even if they were not set by the +key that's going up. Also see the comment in that function: + + If LC(A) is pressed, then LS(B), then LC(A) is released, the shift for B will be released + prematurely. This causes if LS(B) to repeat like Bbbbbbbb when pressed for a long time. + Solving this would require keeping track of which key's implicit modifiers are currently + active and only releasing modifiers at that time. + diff --git a/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod2-up-mod1-up/events.patterns b/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod2-up-mod1-up/events.patterns new file mode 100644 index 000000000000..cbf21aff278f --- /dev/null +++ b/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod2-up-mod1-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode_//p +s/.*hid_register_mod/reg/p +s/.*hid_unregister_mod/unreg/p +s/.*zmk_hid_.*Modifiers set to /mods: Modifiers set to /p \ No newline at end of file diff --git a/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod2-up-mod1-up/keycode_events.snapshot b/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod2-up-mod1-up/keycode_events.snapshot new file mode 100644 index 000000000000..723b03e58a60 --- /dev/null +++ b/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod2-up-mod1-up/keycode_events.snapshot @@ -0,0 +1,8 @@ +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x01 explicit_mods 0x00 +mods: Modifiers set to 0x01 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x02 explicit_mods 0x00 +mods: Modifiers set to 0x02 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x02 explicit_mods 0x00 +mods: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x01 explicit_mods 0x00 +mods: Modifiers set to 0x00 diff --git a/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod2-up-mod1-up/native_posix_64.keymap b/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod2-up-mod1-up/native_posix_64.keymap new file mode 100644 index 000000000000..fa34be426b3e --- /dev/null +++ b/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod2-up-mod1-up/native_posix_64.keymap @@ -0,0 +1,26 @@ +#include +#include +#include + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp LC(A) &kp LS(B) + &none &none + >; + }; + }; +}; diff --git a/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/events.patterns b/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/events.patterns new file mode 100644 index 000000000000..cbf21aff278f --- /dev/null +++ b/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode_//p +s/.*hid_register_mod/reg/p +s/.*hid_unregister_mod/unreg/p +s/.*zmk_hid_.*Modifiers set to /mods: Modifiers set to /p \ No newline at end of file diff --git a/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/keycode_events.snapshot b/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/keycode_events.snapshot new file mode 100644 index 000000000000..0b06bd91d885 --- /dev/null +++ b/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/keycode_events.snapshot @@ -0,0 +1,9 @@ +pressed: usage_page 0x07 keycode 0x2E implicit_mods 0x02 explicit_mods 0x00 +mods: Modifiers set to 0x02 +pressed: unregistering usage_page 0x07 keycode 0x2E since it was already pressed +pressed: usage_page 0x07 keycode 0x2E implicit_mods 0x00 explicit_mods 0x00 +mods: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x2E implicit_mods 0x02 explicit_mods 0x00 +mods: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x2E implicit_mods 0x00 explicit_mods 0x00 +mods: Modifiers set to 0x00 diff --git a/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/native_posix_64.keymap b/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/native_posix_64.keymap new file mode 100644 index 000000000000..214cff496426 --- /dev/null +++ b/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/native_posix_64.keymap @@ -0,0 +1,26 @@ +#include +#include +#include + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp PLUS &kp EQUAL + &none &none + >; + }; + }; +}; diff --git a/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-lctl-up-mod-up/events.patterns b/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-lctl-up-mod-up/events.patterns new file mode 100644 index 000000000000..cbf21aff278f --- /dev/null +++ b/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-lctl-up-mod-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode_//p +s/.*hid_register_mod/reg/p +s/.*hid_unregister_mod/unreg/p +s/.*zmk_hid_.*Modifiers set to /mods: Modifiers set to /p \ No newline at end of file diff --git a/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-lctl-up-mod-up/keycode_events.snapshot b/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-lctl-up-mod-up/keycode_events.snapshot new file mode 100644 index 000000000000..45719679dfb9 --- /dev/null +++ b/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-lctl-up-mod-up/keycode_events.snapshot @@ -0,0 +1,13 @@ +pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +reg: Modifier 0 count 1 +reg: Modifiers set to 0x01 +mods: Modifiers set to 0x01 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x02 explicit_mods 0x00 +mods: Modifiers set to 0x03 +released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +unreg: Modifier 0 count: 0 +unreg: Modifier 0 released +unreg: Modifiers set to 0x02 +mods: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x02 explicit_mods 0x00 +mods: Modifiers set to 0x00 diff --git a/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-lctl-up-mod-up/native_posix_64.keymap b/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-lctl-up-mod-up/native_posix_64.keymap new file mode 100644 index 000000000000..01387e54f11d --- /dev/null +++ b/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-lctl-up-mod-up/native_posix_64.keymap @@ -0,0 +1,26 @@ +#include +#include +#include + + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp LC(A) &kp LS(B) + &kp LEFT_CONTROL &none + >; + }; + }; +}; diff --git a/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-mod-up-lctl-up/events.patterns b/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-mod-up-lctl-up/events.patterns new file mode 100644 index 000000000000..cbf21aff278f --- /dev/null +++ b/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-mod-up-lctl-up/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode_//p +s/.*hid_register_mod/reg/p +s/.*hid_unregister_mod/unreg/p +s/.*zmk_hid_.*Modifiers set to /mods: Modifiers set to /p \ No newline at end of file diff --git a/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-mod-up-lctl-up/keycode_events.snapshot b/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-mod-up-lctl-up/keycode_events.snapshot new file mode 100644 index 000000000000..fdc7aec446d6 --- /dev/null +++ b/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-mod-up-lctl-up/keycode_events.snapshot @@ -0,0 +1,13 @@ +pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +reg: Modifier 0 count 1 +reg: Modifiers set to 0x01 +mods: Modifiers set to 0x01 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x02 explicit_mods 0x00 +mods: Modifiers set to 0x03 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x02 explicit_mods 0x00 +mods: Modifiers set to 0x01 +released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +unreg: Modifier 0 count: 0 +unreg: Modifier 0 released +unreg: Modifiers set to 0x00 +mods: Modifiers set to 0x00 diff --git a/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-mod-up-lctl-up/native_posix_64.keymap b/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-mod-up-lctl-up/native_posix_64.keymap new file mode 100644 index 000000000000..113fc488ee18 --- /dev/null +++ b/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-mod-up-lctl-up/native_posix_64.keymap @@ -0,0 +1,26 @@ +#include +#include +#include + + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp LC(A) &kp LS(B) + &kp LEFT_CONTROL &none + >; + }; + }; +}; diff --git a/app/tests/momentary-layer/1-normal/events.patterns b/app/tests/momentary-layer/1-normal/events.patterns new file mode 100644 index 000000000000..bd7b48801938 --- /dev/null +++ b/app/tests/momentary-layer/1-normal/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p \ No newline at end of file diff --git a/app/tests/momentary-layer/1-normal/keycode_events.snapshot b/app/tests/momentary-layer/1-normal/keycode_events.snapshot new file mode 100644 index 000000000000..0a00aa271507 --- /dev/null +++ b/app/tests/momentary-layer/1-normal/keycode_events.snapshot @@ -0,0 +1,4 @@ +mo_pressed: position 1 layer 1 +kp_pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +mo_released: position 1 layer 1 diff --git a/app/tests/momentary-layer/1-normal/native_posix_64.keymap b/app/tests/momentary-layer/1-normal/native_posix_64.keymap new file mode 100644 index 000000000000..88c70da98b4a --- /dev/null +++ b/app/tests/momentary-layer/1-normal/native_posix_64.keymap @@ -0,0 +1,31 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp B &mo 1 + &none &none>; + }; + + layer_1 { + bindings = < + &kp C &trans + &none &none>; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/momentary-layer/2-early-key-release/events.patterns b/app/tests/momentary-layer/2-early-key-release/events.patterns new file mode 100644 index 000000000000..bd7b48801938 --- /dev/null +++ b/app/tests/momentary-layer/2-early-key-release/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p \ No newline at end of file diff --git a/app/tests/momentary-layer/2-early-key-release/keycode_events.snapshot b/app/tests/momentary-layer/2-early-key-release/keycode_events.snapshot new file mode 100644 index 000000000000..e24f11f90398 --- /dev/null +++ b/app/tests/momentary-layer/2-early-key-release/keycode_events.snapshot @@ -0,0 +1,4 @@ +kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +mo_pressed: position 1 layer 1 +kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +mo_released: position 1 layer 1 diff --git a/app/tests/momentary-layer/2-early-key-release/native_posix_64.keymap b/app/tests/momentary-layer/2-early-key-release/native_posix_64.keymap new file mode 100644 index 000000000000..48da33e60e71 --- /dev/null +++ b/app/tests/momentary-layer/2-early-key-release/native_posix_64.keymap @@ -0,0 +1,31 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp B &mo 1 + &none &none>; + }; + + layer_1 { + bindings = < + &kp C &none + &none &none>; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/momentary-layer/3-covered/events.patterns b/app/tests/momentary-layer/3-covered/events.patterns new file mode 100644 index 000000000000..08b1e987eef3 --- /dev/null +++ b/app/tests/momentary-layer/3-covered/events.patterns @@ -0,0 +1,3 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*keymap_position_state_changed/kp_st/p \ No newline at end of file diff --git a/app/tests/momentary-layer/3-covered/keycode_events.snapshot b/app/tests/momentary-layer/3-covered/keycode_events.snapshot new file mode 100644 index 000000000000..87d12817327a --- /dev/null +++ b/app/tests/momentary-layer/3-covered/keycode_events.snapshot @@ -0,0 +1,2 @@ +mo_pressed: position 1 layer 1 +mo_released: position 1 layer 1 diff --git a/app/tests/momentary-layer/3-covered/native_posix_64.keymap b/app/tests/momentary-layer/3-covered/native_posix_64.keymap new file mode 100644 index 000000000000..42548533d1b6 --- /dev/null +++ b/app/tests/momentary-layer/3-covered/native_posix_64.keymap @@ -0,0 +1,32 @@ +#include +#include +#include + +/* +this test verifies that the correct key is released when a layer is enabled "on top" +and the original key is "covered". +*/ +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &trans &mo 1 + &trans &trans>; + }; + + layer_1 { + bindings = < + &trans &kp A + &trans &trans>; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; diff --git a/app/tests/momentary-layer/4-nested/events.patterns b/app/tests/momentary-layer/4-nested/events.patterns new file mode 100644 index 000000000000..08b1e987eef3 --- /dev/null +++ b/app/tests/momentary-layer/4-nested/events.patterns @@ -0,0 +1,3 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*keymap_position_state_changed/kp_st/p \ No newline at end of file diff --git a/app/tests/momentary-layer/4-nested/keycode_events.snapshot b/app/tests/momentary-layer/4-nested/keycode_events.snapshot new file mode 100644 index 000000000000..29b2e3fd3db8 --- /dev/null +++ b/app/tests/momentary-layer/4-nested/keycode_events.snapshot @@ -0,0 +1,6 @@ +mo_pressed: position 1 layer 1 +mo_pressed: position 0 layer 2 +kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +mo_released: position 0 layer 2 +mo_released: position 1 layer 1 diff --git a/app/tests/momentary-layer/4-nested/native_posix_64.keymap b/app/tests/momentary-layer/4-nested/native_posix_64.keymap new file mode 100644 index 000000000000..12fb6cdc7c72 --- /dev/null +++ b/app/tests/momentary-layer/4-nested/native_posix_64.keymap @@ -0,0 +1,38 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &none &mo 1 + &none &none>; + }; + + layer_1 { + bindings = < + &mo 2 &none + &none &none>; + }; + + layer_2 { + bindings = < + &none &none + &kp B &none>; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/momentary-layer/5-nested-early-key-release/events.patterns b/app/tests/momentary-layer/5-nested-early-key-release/events.patterns new file mode 100644 index 000000000000..08b1e987eef3 --- /dev/null +++ b/app/tests/momentary-layer/5-nested-early-key-release/events.patterns @@ -0,0 +1,3 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*keymap_position_state_changed/kp_st/p \ No newline at end of file diff --git a/app/tests/momentary-layer/5-nested-early-key-release/keycode_events.snapshot b/app/tests/momentary-layer/5-nested-early-key-release/keycode_events.snapshot new file mode 100644 index 000000000000..d14d78813369 --- /dev/null +++ b/app/tests/momentary-layer/5-nested-early-key-release/keycode_events.snapshot @@ -0,0 +1,6 @@ +mo_pressed: position 1 layer 1 +mo_pressed: position 0 layer 2 +kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +mo_released: position 1 layer 1 +mo_released: position 0 layer 2 +kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/momentary-layer/5-nested-early-key-release/native_posix_64.keymap b/app/tests/momentary-layer/5-nested-early-key-release/native_posix_64.keymap new file mode 100644 index 000000000000..f1f0afcbc40c --- /dev/null +++ b/app/tests/momentary-layer/5-nested-early-key-release/native_posix_64.keymap @@ -0,0 +1,38 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &none &mo 1 + &none &none>; + }; + + layer_1 { + bindings = < + &mo 2 &none + &none &none>; + }; + + layer_2 { + bindings = < + &none &none + &kp B &none>; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/momentary-layer/behavior_keymap.dtsi b/app/tests/momentary-layer/behavior_keymap.dtsi new file mode 100644 index 000000000000..8d63bc13502e --- /dev/null +++ b/app/tests/momentary-layer/behavior_keymap.dtsi @@ -0,0 +1,21 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp B &mo 1 + &trans &trans>; + }; + + layer_1 { + bindings = < + &kp C_NEXT &trans + &trans &trans>; + }; + }; +}; diff --git a/app/tests/mouse-keys/mkp/events.patterns b/app/tests/mouse-keys/mkp/events.patterns new file mode 100644 index 000000000000..2599345c2d72 --- /dev/null +++ b/app/tests/mouse-keys/mkp/events.patterns @@ -0,0 +1 @@ +s/.*zmk_hid_mouse_button_//p diff --git a/app/tests/mouse-keys/mkp/keycode_events.snapshot b/app/tests/mouse-keys/mkp/keycode_events.snapshot new file mode 100644 index 000000000000..ab58cc9575e5 --- /dev/null +++ b/app/tests/mouse-keys/mkp/keycode_events.snapshot @@ -0,0 +1,10 @@ +press: Button 0 count 1 +press: Mouse buttons set to 0x01 +press: Button 1 count 1 +press: Mouse buttons set to 0x03 +release: Button 1 count: 0 +release: Button 1 released +release: Mouse buttons set to 0x01 +release: Button 0 count: 0 +release: Button 0 released +release: Mouse buttons set to 0x00 diff --git a/app/tests/mouse-keys/mkp/native_posix.keymap b/app/tests/mouse-keys/mkp/native_posix.keymap new file mode 100644 index 000000000000..8e3071d4317d --- /dev/null +++ b/app/tests/mouse-keys/mkp/native_posix.keymap @@ -0,0 +1,27 @@ +#include +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &mkp LCLK &none + &none &mkp RCLK + >; + }; + }; +}; + + +&kscan { + events = < + ZMK_MOCK_PRESS (0,0,100) + ZMK_MOCK_PRESS (1,1,100) + ZMK_MOCK_RELEASE(1,1, 10) + ZMK_MOCK_RELEASE(0,0, 10) + >; +}; diff --git a/app/tests/mouse-keys/mkp/native_posix_64.keymap b/app/tests/mouse-keys/mkp/native_posix_64.keymap new file mode 100644 index 000000000000..8e3071d4317d --- /dev/null +++ b/app/tests/mouse-keys/mkp/native_posix_64.keymap @@ -0,0 +1,27 @@ +#include +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &mkp LCLK &none + &none &mkp RCLK + >; + }; + }; +}; + + +&kscan { + events = < + ZMK_MOCK_PRESS (0,0,100) + ZMK_MOCK_PRESS (1,1,100) + ZMK_MOCK_RELEASE(1,1, 10) + ZMK_MOCK_RELEASE(0,0, 10) + >; +}; diff --git a/app/tests/none/behavior_keymap.dtsi b/app/tests/none/behavior_keymap.dtsi new file mode 100644 index 000000000000..162ca992fdf5 --- /dev/null +++ b/app/tests/none/behavior_keymap.dtsi @@ -0,0 +1,21 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &none &mo 1 + &kp A &none>; + }; + + lower_layer { + bindings = < + &none &trans + &none &kp A>; + }; + }; +}; diff --git a/app/tests/none/layered/events.patterns b/app/tests/none/layered/events.patterns new file mode 100644 index 000000000000..3c9d3f838c62 --- /dev/null +++ b/app/tests/none/layered/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode/kp/p \ No newline at end of file diff --git a/app/tests/none/layered/keycode_events.snapshot b/app/tests/none/layered/keycode_events.snapshot new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/tests/none/layered/native_posix_64.keymap b/app/tests/none/layered/native_posix_64.keymap new file mode 100644 index 000000000000..b1e84c306613 --- /dev/null +++ b/app/tests/none/layered/native_posix_64.keymap @@ -0,0 +1,8 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/none/normal/events.patterns b/app/tests/none/normal/events.patterns new file mode 100644 index 000000000000..3c9d3f838c62 --- /dev/null +++ b/app/tests/none/normal/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode/kp/p \ No newline at end of file diff --git a/app/tests/none/normal/keycode_events.snapshot b/app/tests/none/normal/keycode_events.snapshot new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/tests/none/normal/native_posix.keymap b/app/tests/none/normal/native_posix.keymap new file mode 100644 index 000000000000..502f7ccc4731 --- /dev/null +++ b/app/tests/none/normal/native_posix.keymap @@ -0,0 +1,8 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/none/normal/native_posix_64.keymap b/app/tests/none/normal/native_posix_64.keymap new file mode 100644 index 000000000000..502f7ccc4731 --- /dev/null +++ b/app/tests/none/normal/native_posix_64.keymap @@ -0,0 +1,8 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/sticky-keys/1-os-dn-up/events.patterns b/app/tests/sticky-keys/1-os-dn-up/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/sticky-keys/1-os-dn-up/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/sticky-keys/1-os-dn-up/keycode_events.snapshot b/app/tests/sticky-keys/1-os-dn-up/keycode_events.snapshot new file mode 100644 index 000000000000..d260989478c0 --- /dev/null +++ b/app/tests/sticky-keys/1-os-dn-up/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/sticky-keys/1-os-dn-up/native_posix_64.keymap b/app/tests/sticky-keys/1-os-dn-up/native_posix_64.keymap new file mode 100644 index 000000000000..f9612928a32a --- /dev/null +++ b/app/tests/sticky-keys/1-os-dn-up/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,1200) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/sticky-keys/10-callum-mods-quick-release/events.patterns b/app/tests/sticky-keys/10-callum-mods-quick-release/events.patterns new file mode 100644 index 000000000000..b1342af4d971 --- /dev/null +++ b/app/tests/sticky-keys/10-callum-mods-quick-release/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p diff --git a/app/tests/sticky-keys/10-callum-mods-quick-release/keycode_events.snapshot b/app/tests/sticky-keys/10-callum-mods-quick-release/keycode_events.snapshot new file mode 100644 index 000000000000..5ee7c1036960 --- /dev/null +++ b/app/tests/sticky-keys/10-callum-mods-quick-release/keycode_events.snapshot @@ -0,0 +1,10 @@ +pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0xE2 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0xE2 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/sticky-keys/10-callum-mods-quick-release/native_posix_64.keymap b/app/tests/sticky-keys/10-callum-mods-quick-release/native_posix_64.keymap new file mode 100644 index 000000000000..560c8424e1a8 --- /dev/null +++ b/app/tests/sticky-keys/10-callum-mods-quick-release/native_posix_64.keymap @@ -0,0 +1,39 @@ +#include +#include +#include + +&sk { + quick-release; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &sk LEFT_CONTROL &kp A + &sk LEFT_SHIFT &sk LEFT_ALT>; + }; + }; +}; + +&kscan { + events = < + /* tap sk LEFT_CONTROL */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* tap sk LEFT_SHIFT */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + /* tap sk LEFT_ALT */ + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + /* tap A */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* tap A (no sticky keys anymore) */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; diff --git a/app/tests/sticky-keys/10-callum-mods/events.patterns b/app/tests/sticky-keys/10-callum-mods/events.patterns new file mode 100644 index 000000000000..b1342af4d971 --- /dev/null +++ b/app/tests/sticky-keys/10-callum-mods/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p diff --git a/app/tests/sticky-keys/10-callum-mods/keycode_events.snapshot b/app/tests/sticky-keys/10-callum-mods/keycode_events.snapshot new file mode 100644 index 000000000000..3e46e581165e --- /dev/null +++ b/app/tests/sticky-keys/10-callum-mods/keycode_events.snapshot @@ -0,0 +1,8 @@ +pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/sticky-keys/10-callum-mods/native_posix_64.keymap b/app/tests/sticky-keys/10-callum-mods/native_posix_64.keymap new file mode 100644 index 000000000000..28f2db3d140e --- /dev/null +++ b/app/tests/sticky-keys/10-callum-mods/native_posix_64.keymap @@ -0,0 +1,42 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &sk E &sl 1 + &kp A &kp B>; + }; + + lower_layer { + bindings = < + &sk LEFT_CONTROL &kp X + &sk LEFT_SHIFT &kp Z>; + }; + }; +}; + +&kscan { + events = < + /* press sl lower_layer */ + ZMK_MOCK_PRESS(0,1,10) + /* tap sk LEFT_CONTROL */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* tap sk LEFT_SHIFT */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + /* release sl lower_layer */ + ZMK_MOCK_RELEASE(0,1,10) + /* tap A (with left control and left shift enabled) */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + /* tap A (no sticky keys anymore) */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/sticky-keys/10-sl-sl-kp/events.patterns b/app/tests/sticky-keys/10-sl-sl-kp/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/sticky-keys/10-sl-sl-kp/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/sticky-keys/10-sl-sl-kp/keycode_events.snapshot b/app/tests/sticky-keys/10-sl-sl-kp/keycode_events.snapshot new file mode 100644 index 000000000000..922c582c6544 --- /dev/null +++ b/app/tests/sticky-keys/10-sl-sl-kp/keycode_events.snapshot @@ -0,0 +1,8 @@ +pressed: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/sticky-keys/10-sl-sl-kp/native_posix_64.keymap b/app/tests/sticky-keys/10-sl-sl-kp/native_posix_64.keymap new file mode 100644 index 000000000000..42bb9cfd23f2 --- /dev/null +++ b/app/tests/sticky-keys/10-sl-sl-kp/native_posix_64.keymap @@ -0,0 +1,64 @@ +#include +#include +#include + +/* + sticky layers should quick-release. + Thus, the second keypress should be on the default layer, not on the lower_layer. +*/ + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &sl 1 &kp A + &none &none>; + }; + + layer_1 { + bindings = < + &sl 2 &none + &none &none>; + }; + + layer_2 { + bindings = < + &none &kp NUM_1 + &none &none>; + }; + }; +}; + +&kscan { + events = < + /* press sl 1 */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* press sl 2 */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* press 1 */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* press A */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + + /* repeat test to check if cleanup is done correctly */ + /* press sl 1 */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* press sl 2 */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* press 1 */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* press A */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + + >; +}; \ No newline at end of file diff --git a/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/events.patterns b/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/keycode_events.snapshot b/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/keycode_events.snapshot new file mode 100644 index 000000000000..c85d8b49fadd --- /dev/null +++ b/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/keycode_events.snapshot @@ -0,0 +1,10 @@ +pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/native_posix_64.keymap b/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/native_posix_64.keymap new file mode 100644 index 000000000000..131e7069cbac --- /dev/null +++ b/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/native_posix_64.keymap @@ -0,0 +1,26 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&sk { + quick-release; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + /* second key is pressed shortly after the first. It should not be capitalized. */ + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(1,1,10) + + /* repeat test to check if cleanup is done correctly */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup/events.patterns b/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup/keycode_events.snapshot b/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup/keycode_events.snapshot new file mode 100644 index 000000000000..addbca8c1550 --- /dev/null +++ b/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup/keycode_events.snapshot @@ -0,0 +1,8 @@ +pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup/native_posix_64.keymap b/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup/native_posix_64.keymap new file mode 100644 index 000000000000..4a0c50c83473 --- /dev/null +++ b/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup/native_posix_64.keymap @@ -0,0 +1,19 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + + /* repeat test to check if cleanup is done correctly */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/sticky-keys/2-sl-dn-up-kcdn-kcup/events.patterns b/app/tests/sticky-keys/2-sl-dn-up-kcdn-kcup/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/sticky-keys/2-sl-dn-up-kcdn-kcup/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/sticky-keys/2-sl-dn-up-kcdn-kcup/keycode_events.snapshot b/app/tests/sticky-keys/2-sl-dn-up-kcdn-kcup/keycode_events.snapshot new file mode 100644 index 000000000000..5f43bbdf55d2 --- /dev/null +++ b/app/tests/sticky-keys/2-sl-dn-up-kcdn-kcup/keycode_events.snapshot @@ -0,0 +1,8 @@ +pressed: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/sticky-keys/2-sl-dn-up-kcdn-kcup/native_posix_64.keymap b/app/tests/sticky-keys/2-sl-dn-up-kcdn-kcup/native_posix_64.keymap new file mode 100644 index 000000000000..93239797c71a --- /dev/null +++ b/app/tests/sticky-keys/2-sl-dn-up-kcdn-kcup/native_posix_64.keymap @@ -0,0 +1,51 @@ +#include +#include +#include + +/* + sticky layers should quick-release. + Thus, the second keypress should be on the default layer, not on the lower_layer. +*/ + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &sk E &sl 1 + &kp A &kp B>; + }; + + lower_layer { + bindings = < + &sk LEFT_CONTROL &kp X + &kp Y &kp Z>; + }; + }; +}; + +&kscan { + events = < + /* press sl 1 */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* press X */ + ZMK_MOCK_PRESS(0,1,10) + /* press A */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(1,0,10) + + /* repeat test to check if cleanup is done correctly */ + /* press sl 1 */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* press X */ + ZMK_MOCK_PRESS(0,1,10) + /* press Y */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/sticky-keys/3a-os-dn-kcdn-kcup-up/events.patterns b/app/tests/sticky-keys/3a-os-dn-kcdn-kcup-up/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/sticky-keys/3a-os-dn-kcdn-kcup-up/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/sticky-keys/3a-os-dn-kcdn-kcup-up/keycode_events.snapshot b/app/tests/sticky-keys/3a-os-dn-kcdn-kcup-up/keycode_events.snapshot new file mode 100644 index 000000000000..1b091a6a144f --- /dev/null +++ b/app/tests/sticky-keys/3a-os-dn-kcdn-kcup-up/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/sticky-keys/3a-os-dn-kcdn-kcup-up/native_posix_64.keymap b/app/tests/sticky-keys/3a-os-dn-kcdn-kcup-up/native_posix_64.keymap new file mode 100644 index 000000000000..c635dade668b --- /dev/null +++ b/app/tests/sticky-keys/3a-os-dn-kcdn-kcup-up/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/sticky-keys/3b-os-dn-kcdn-up-kcup/events.patterns b/app/tests/sticky-keys/3b-os-dn-kcdn-up-kcup/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/sticky-keys/3b-os-dn-kcdn-up-kcup/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/sticky-keys/3b-os-dn-kcdn-up-kcup/keycode_events.snapshot b/app/tests/sticky-keys/3b-os-dn-kcdn-up-kcup/keycode_events.snapshot new file mode 100644 index 000000000000..6e004ec2b46f --- /dev/null +++ b/app/tests/sticky-keys/3b-os-dn-kcdn-up-kcup/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/sticky-keys/3b-os-dn-kcdn-up-kcup/native_posix_64.keymap b/app/tests/sticky-keys/3b-os-dn-kcdn-up-kcup/native_posix_64.keymap new file mode 100644 index 000000000000..e629d270488c --- /dev/null +++ b/app/tests/sticky-keys/3b-os-dn-kcdn-up-kcup/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/sticky-keys/4-os-dn-up-kcdn-timer-kcup/events.patterns b/app/tests/sticky-keys/4-os-dn-up-kcdn-timer-kcup/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/sticky-keys/4-os-dn-up-kcdn-timer-kcup/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/sticky-keys/4-os-dn-up-kcdn-timer-kcup/keycode_events.snapshot b/app/tests/sticky-keys/4-os-dn-up-kcdn-timer-kcup/keycode_events.snapshot new file mode 100644 index 000000000000..6e004ec2b46f --- /dev/null +++ b/app/tests/sticky-keys/4-os-dn-up-kcdn-timer-kcup/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/sticky-keys/4-os-dn-up-kcdn-timer-kcup/native_posix_64.keymap b/app/tests/sticky-keys/4-os-dn-up-kcdn-timer-kcup/native_posix_64.keymap new file mode 100644 index 000000000000..2404a5823dc6 --- /dev/null +++ b/app/tests/sticky-keys/4-os-dn-up-kcdn-timer-kcup/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,800) + ZMK_MOCK_PRESS(1,0,400) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/sticky-keys/5-os-kcdn-dn-kcup-up/events.patterns b/app/tests/sticky-keys/5-os-kcdn-dn-kcup-up/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/sticky-keys/5-os-kcdn-dn-kcup-up/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/sticky-keys/5-os-kcdn-dn-kcup-up/keycode_events.snapshot b/app/tests/sticky-keys/5-os-kcdn-dn-kcup-up/keycode_events.snapshot new file mode 100644 index 000000000000..03495b4658b8 --- /dev/null +++ b/app/tests/sticky-keys/5-os-kcdn-dn-kcup-up/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/sticky-keys/5-os-kcdn-dn-kcup-up/native_posix_64.keymap b/app/tests/sticky-keys/5-os-kcdn-dn-kcup-up/native_posix_64.keymap new file mode 100644 index 000000000000..7cf04b7d0ad5 --- /dev/null +++ b/app/tests/sticky-keys/5-os-kcdn-dn-kcup-up/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,0,1100) + >; +}; \ No newline at end of file diff --git a/app/tests/sticky-keys/7-os-dn-up-kc1dn-kc2dn-kc1up-kc2up/events.patterns b/app/tests/sticky-keys/7-os-dn-up-kc1dn-kc2dn-kc1up-kc2up/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/sticky-keys/7-os-dn-up-kc1dn-kc2dn-kc1up-kc2up/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/sticky-keys/7-os-dn-up-kc1dn-kc2dn-kc1up-kc2up/keycode_events.snapshot b/app/tests/sticky-keys/7-os-dn-up-kc1dn-kc2dn-kc1up-kc2up/keycode_events.snapshot new file mode 100644 index 000000000000..3c757bbb2f27 --- /dev/null +++ b/app/tests/sticky-keys/7-os-dn-up-kc1dn-kc2dn-kc1up-kc2up/keycode_events.snapshot @@ -0,0 +1,6 @@ +pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/sticky-keys/7-os-dn-up-kc1dn-kc2dn-kc1up-kc2up/native_posix_64.keymap b/app/tests/sticky-keys/7-os-dn-up-kc1dn-kc2dn-kc1up-kc2up/native_posix_64.keymap new file mode 100644 index 000000000000..a22d0a5a272d --- /dev/null +++ b/app/tests/sticky-keys/7-os-dn-up-kc1dn-kc2dn-kc1up-kc2up/native_posix_64.keymap @@ -0,0 +1,15 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,0,100) + ZMK_MOCK_RELEASE(1,1,100) + >; +}; \ No newline at end of file diff --git a/app/tests/sticky-keys/8-lsk-osk-combination-quick-release/events.patterns b/app/tests/sticky-keys/8-lsk-osk-combination-quick-release/events.patterns new file mode 100644 index 000000000000..b1342af4d971 --- /dev/null +++ b/app/tests/sticky-keys/8-lsk-osk-combination-quick-release/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p diff --git a/app/tests/sticky-keys/8-lsk-osk-combination-quick-release/keycode_events.snapshot b/app/tests/sticky-keys/8-lsk-osk-combination-quick-release/keycode_events.snapshot new file mode 100644 index 000000000000..d71c3968318e --- /dev/null +++ b/app/tests/sticky-keys/8-lsk-osk-combination-quick-release/keycode_events.snapshot @@ -0,0 +1,12 @@ +pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/sticky-keys/8-lsk-osk-combination-quick-release/native_posix_64.keymap b/app/tests/sticky-keys/8-lsk-osk-combination-quick-release/native_posix_64.keymap new file mode 100644 index 000000000000..69db16352afe --- /dev/null +++ b/app/tests/sticky-keys/8-lsk-osk-combination-quick-release/native_posix_64.keymap @@ -0,0 +1,55 @@ +#include +#include +#include + +&sk { + quick-release; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &sk LEFT_SHIFT &sl 1 + &kp A &kp B>; + }; + + lower_layer { + bindings = < + &sk LEFT_CONTROL &kp X + &kp Y &kp Z>; + }; + }; +}; + +&kscan { + events = < + /* tap sl lower_layer */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* tap sk LEFT_CONTROL */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* tap A */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + /* tap B */ + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + + /* tap sk LEFT_SHIFT */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* tap sl lower_layer */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* tap Y */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + /* tap B */ + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + >; +}; diff --git a/app/tests/sticky-keys/8-lsk-osk-combination/events.patterns b/app/tests/sticky-keys/8-lsk-osk-combination/events.patterns new file mode 100644 index 000000000000..b1342af4d971 --- /dev/null +++ b/app/tests/sticky-keys/8-lsk-osk-combination/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p diff --git a/app/tests/sticky-keys/8-lsk-osk-combination/keycode_events.snapshot b/app/tests/sticky-keys/8-lsk-osk-combination/keycode_events.snapshot new file mode 100644 index 000000000000..f1aa915bf056 --- /dev/null +++ b/app/tests/sticky-keys/8-lsk-osk-combination/keycode_events.snapshot @@ -0,0 +1,8 @@ +pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0xE0 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/sticky-keys/8-lsk-osk-combination/native_posix_64.keymap b/app/tests/sticky-keys/8-lsk-osk-combination/native_posix_64.keymap new file mode 100644 index 000000000000..9523a75e98da --- /dev/null +++ b/app/tests/sticky-keys/8-lsk-osk-combination/native_posix_64.keymap @@ -0,0 +1,46 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &sk E &sl 1 + &kp A &kp B>; + }; + + lower_layer { + bindings = < + &sk LEFT_CONTROL &kp X + &kp Y &kp Z>; + }; + }; +}; + +&kscan { + events = < + /* tap sl lower_layer */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* tap sk LEFT_CONTROL */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* tap A */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + + /* repeat */ + /* tap sl */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* tap sk */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* tap A */ + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/sticky-keys/9-sk-dn-up-dn-up/events.patterns b/app/tests/sticky-keys/9-sk-dn-up-dn-up/events.patterns new file mode 100644 index 000000000000..833100f6ac43 --- /dev/null +++ b/app/tests/sticky-keys/9-sk-dn-up-dn-up/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/sticky-keys/9-sk-dn-up-dn-up/keycode_events.snapshot b/app/tests/sticky-keys/9-sk-dn-up-dn-up/keycode_events.snapshot new file mode 100644 index 000000000000..6e3a0c3a8352 --- /dev/null +++ b/app/tests/sticky-keys/9-sk-dn-up-dn-up/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/sticky-keys/9-sk-dn-up-dn-up/native_posix_64.keymap b/app/tests/sticky-keys/9-sk-dn-up-dn-up/native_posix_64.keymap new file mode 100644 index 000000000000..67efb6afe5cd --- /dev/null +++ b/app/tests/sticky-keys/9-sk-dn-up-dn-up/native_posix_64.keymap @@ -0,0 +1,26 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &sk LEFT_SHIFT &none + &none &none + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* the sticky key is pressed again, so the previous one must be cancelled */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,1200) + >; +}; \ No newline at end of file diff --git a/app/tests/sticky-keys/behavior_keymap.dtsi b/app/tests/sticky-keys/behavior_keymap.dtsi new file mode 100644 index 000000000000..182ef58e1a8b --- /dev/null +++ b/app/tests/sticky-keys/behavior_keymap.dtsi @@ -0,0 +1,21 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &sk E &mo 1 + &kp A &kp B>; + }; + + lower_layer { + bindings = < + &sk LEFT_CONTROL &kp X + &kp Y &kp Z>; + }; + }; +}; diff --git a/app/tests/tap-dance/1a-tap1/events.patterns b/app/tests/tap-dance/1a-tap1/events.patterns new file mode 100644 index 000000000000..1768fc210624 --- /dev/null +++ b/app/tests/tap-dance/1a-tap1/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/1a-tap1/keycode_events.snapshot b/app/tests/tap-dance/1a-tap1/keycode_events.snapshot new file mode 100644 index 000000000000..38bc54c3b310 --- /dev/null +++ b/app/tests/tap-dance/1a-tap1/keycode_events.snapshot @@ -0,0 +1,5 @@ +td_binding_pressed: 0 created new tap dance +td_binding_pressed: 0 tap dance pressed +td_binding_released: 0 tap dance keybind released +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/1a-tap1/native_posix_64.keymap b/app/tests/tap-dance/1a-tap1/native_posix_64.keymap new file mode 100644 index 000000000000..4e65cfa1186b --- /dev/null +++ b/app/tests/tap-dance/1a-tap1/native_posix_64.keymap @@ -0,0 +1,11 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,200) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/1b-tap2/events.patterns b/app/tests/tap-dance/1b-tap2/events.patterns new file mode 100644 index 000000000000..1768fc210624 --- /dev/null +++ b/app/tests/tap-dance/1b-tap2/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/1b-tap2/keycode_events.snapshot b/app/tests/tap-dance/1b-tap2/keycode_events.snapshot new file mode 100644 index 000000000000..c23537b9c459 --- /dev/null +++ b/app/tests/tap-dance/1b-tap2/keycode_events.snapshot @@ -0,0 +1,7 @@ +td_binding_pressed: 0 created new tap dance +td_binding_pressed: 0 tap dance pressed +td_binding_released: 0 tap dance keybind released +td_binding_pressed: 0 tap dance pressed +td_binding_released: 0 tap dance keybind released +kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/1b-tap2/native_posix_64.keymap b/app/tests/tap-dance/1b-tap2/native_posix_64.keymap new file mode 100644 index 000000000000..47fa8c3398b2 --- /dev/null +++ b/app/tests/tap-dance/1b-tap2/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,200) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/1c-tap3/events.patterns b/app/tests/tap-dance/1c-tap3/events.patterns new file mode 100644 index 000000000000..1768fc210624 --- /dev/null +++ b/app/tests/tap-dance/1c-tap3/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/1c-tap3/keycode_events.snapshot b/app/tests/tap-dance/1c-tap3/keycode_events.snapshot new file mode 100644 index 000000000000..1e68bae9fa9d --- /dev/null +++ b/app/tests/tap-dance/1c-tap3/keycode_events.snapshot @@ -0,0 +1,9 @@ +td_binding_pressed: 0 created new tap dance +td_binding_pressed: 0 tap dance pressed +td_binding_released: 0 tap dance keybind released +td_binding_pressed: 0 tap dance pressed +td_binding_released: 0 tap dance keybind released +td_binding_pressed: 0 tap dance pressed +td_binding_released: 0 tap dance keybind released +kp_pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/1c-tap3/native_posix_64.keymap b/app/tests/tap-dance/1c-tap3/native_posix_64.keymap new file mode 100644 index 000000000000..6b01dfff761a --- /dev/null +++ b/app/tests/tap-dance/1c-tap3/native_posix_64.keymap @@ -0,0 +1,15 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,200) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/2a-hold1/events.patterns b/app/tests/tap-dance/2a-hold1/events.patterns new file mode 100644 index 000000000000..1768fc210624 --- /dev/null +++ b/app/tests/tap-dance/2a-hold1/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/2a-hold1/keycode_events.snapshot b/app/tests/tap-dance/2a-hold1/keycode_events.snapshot new file mode 100644 index 000000000000..5af4e5f0a3d7 --- /dev/null +++ b/app/tests/tap-dance/2a-hold1/keycode_events.snapshot @@ -0,0 +1,5 @@ +td_binding_pressed: 0 created new tap dance +td_binding_pressed: 0 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 0 tap dance keybind released +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/2a-hold1/native_posix_64.keymap b/app/tests/tap-dance/2a-hold1/native_posix_64.keymap new file mode 100644 index 000000000000..c16f875b42f2 --- /dev/null +++ b/app/tests/tap-dance/2a-hold1/native_posix_64.keymap @@ -0,0 +1,11 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/2b-hold2/events.patterns b/app/tests/tap-dance/2b-hold2/events.patterns new file mode 100644 index 000000000000..1768fc210624 --- /dev/null +++ b/app/tests/tap-dance/2b-hold2/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/2b-hold2/keycode_events.snapshot b/app/tests/tap-dance/2b-hold2/keycode_events.snapshot new file mode 100644 index 000000000000..0a44f7465b3d --- /dev/null +++ b/app/tests/tap-dance/2b-hold2/keycode_events.snapshot @@ -0,0 +1,7 @@ +td_binding_pressed: 0 created new tap dance +td_binding_pressed: 0 tap dance pressed +td_binding_released: 0 tap dance keybind released +td_binding_pressed: 0 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0xE2 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 0 tap dance keybind released +kp_released: usage_page 0x07 keycode 0xE2 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/2b-hold2/native_posix_64.keymap b/app/tests/tap-dance/2b-hold2/native_posix_64.keymap new file mode 100644 index 000000000000..499488867fac --- /dev/null +++ b/app/tests/tap-dance/2b-hold2/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/2c-hold3/events.patterns b/app/tests/tap-dance/2c-hold3/events.patterns new file mode 100644 index 000000000000..1768fc210624 --- /dev/null +++ b/app/tests/tap-dance/2c-hold3/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/2c-hold3/keycode_events.snapshot b/app/tests/tap-dance/2c-hold3/keycode_events.snapshot new file mode 100644 index 000000000000..f8a232a1de08 --- /dev/null +++ b/app/tests/tap-dance/2c-hold3/keycode_events.snapshot @@ -0,0 +1,9 @@ +td_binding_pressed: 0 created new tap dance +td_binding_pressed: 0 tap dance pressed +td_binding_released: 0 tap dance keybind released +td_binding_pressed: 0 tap dance pressed +td_binding_released: 0 tap dance keybind released +td_binding_pressed: 0 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0xE3 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 0 tap dance keybind released +kp_released: usage_page 0x07 keycode 0xE3 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/2c-hold3/native_posix_64.keymap b/app/tests/tap-dance/2c-hold3/native_posix_64.keymap new file mode 100644 index 000000000000..7bedd6508b64 --- /dev/null +++ b/app/tests/tap-dance/2c-hold3/native_posix_64.keymap @@ -0,0 +1,15 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/3a-tap-int-mid/events.patterns b/app/tests/tap-dance/3a-tap-int-mid/events.patterns new file mode 100644 index 000000000000..1768fc210624 --- /dev/null +++ b/app/tests/tap-dance/3a-tap-int-mid/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/3a-tap-int-mid/keycode_events.snapshot b/app/tests/tap-dance/3a-tap-int-mid/keycode_events.snapshot new file mode 100644 index 000000000000..fe67e6e11082 --- /dev/null +++ b/app/tests/tap-dance/3a-tap-int-mid/keycode_events.snapshot @@ -0,0 +1,10 @@ +td_binding_pressed: 2 created new tap dance +td_binding_pressed: 2 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 1 created new tap dance +td_binding_pressed: 1 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 1 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 2 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/3a-tap-int-mid/native_posix_64.keymap b/app/tests/tap-dance/3a-tap-int-mid/native_posix_64.keymap new file mode 100644 index 000000000000..903b9a88c722 --- /dev/null +++ b/app/tests/tap-dance/3a-tap-int-mid/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/3b-tap-int-seq/events.patterns b/app/tests/tap-dance/3b-tap-int-seq/events.patterns new file mode 100644 index 000000000000..1768fc210624 --- /dev/null +++ b/app/tests/tap-dance/3b-tap-int-seq/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/3b-tap-int-seq/keycode_events.snapshot b/app/tests/tap-dance/3b-tap-int-seq/keycode_events.snapshot new file mode 100644 index 000000000000..31113ffc4aa9 --- /dev/null +++ b/app/tests/tap-dance/3b-tap-int-seq/keycode_events.snapshot @@ -0,0 +1,10 @@ +td_binding_pressed: 2 created new tap dance +td_binding_pressed: 2 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 1 created new tap dance +td_binding_pressed: 1 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 2 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 1 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/3b-tap-int-seq/native_posix_64.keymap b/app/tests/tap-dance/3b-tap-int-seq/native_posix_64.keymap new file mode 100644 index 000000000000..7d10b7152ab6 --- /dev/null +++ b/app/tests/tap-dance/3b-tap-int-seq/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/3c-tap-int-after/events.patterns b/app/tests/tap-dance/3c-tap-int-after/events.patterns new file mode 100644 index 000000000000..1768fc210624 --- /dev/null +++ b/app/tests/tap-dance/3c-tap-int-after/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/3c-tap-int-after/keycode_events.snapshot b/app/tests/tap-dance/3c-tap-int-after/keycode_events.snapshot new file mode 100644 index 000000000000..38b560dbfdeb --- /dev/null +++ b/app/tests/tap-dance/3c-tap-int-after/keycode_events.snapshot @@ -0,0 +1,10 @@ +td_binding_pressed: 2 created new tap dance +td_binding_pressed: 2 tap dance pressed +td_binding_released: 2 tap dance keybind released +kp_pressed: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 1 created new tap dance +td_binding_pressed: 1 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 1 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/3c-tap-int-after/native_posix_64.keymap b/app/tests/tap-dance/3c-tap-int-after/native_posix_64.keymap new file mode 100644 index 000000000000..571a877f642d --- /dev/null +++ b/app/tests/tap-dance/3c-tap-int-after/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/3d-hold-int-mid/events.patterns b/app/tests/tap-dance/3d-hold-int-mid/events.patterns new file mode 100644 index 000000000000..1768fc210624 --- /dev/null +++ b/app/tests/tap-dance/3d-hold-int-mid/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/3d-hold-int-mid/keycode_events.snapshot b/app/tests/tap-dance/3d-hold-int-mid/keycode_events.snapshot new file mode 100644 index 000000000000..7787336f361e --- /dev/null +++ b/app/tests/tap-dance/3d-hold-int-mid/keycode_events.snapshot @@ -0,0 +1,10 @@ +td_binding_pressed: 0 created new tap dance +td_binding_pressed: 0 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 1 created new tap dance +td_binding_pressed: 1 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 1 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 0 tap dance keybind released +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/3d-hold-int-mid/native_posix_64.keymap b/app/tests/tap-dance/3d-hold-int-mid/native_posix_64.keymap new file mode 100644 index 000000000000..0220977a6ddb --- /dev/null +++ b/app/tests/tap-dance/3d-hold-int-mid/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/3e-hold-int-seq/events.patterns b/app/tests/tap-dance/3e-hold-int-seq/events.patterns new file mode 100644 index 000000000000..1768fc210624 --- /dev/null +++ b/app/tests/tap-dance/3e-hold-int-seq/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/3e-hold-int-seq/keycode_events.snapshot b/app/tests/tap-dance/3e-hold-int-seq/keycode_events.snapshot new file mode 100644 index 000000000000..052caec25ded --- /dev/null +++ b/app/tests/tap-dance/3e-hold-int-seq/keycode_events.snapshot @@ -0,0 +1,10 @@ +td_binding_pressed: 0 created new tap dance +td_binding_pressed: 0 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 1 created new tap dance +td_binding_pressed: 1 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 0 tap dance keybind released +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 1 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/3e-hold-int-seq/native_posix_64.keymap b/app/tests/tap-dance/3e-hold-int-seq/native_posix_64.keymap new file mode 100644 index 000000000000..58595291bdd2 --- /dev/null +++ b/app/tests/tap-dance/3e-hold-int-seq/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/3f-hold-int-after/events.patterns b/app/tests/tap-dance/3f-hold-int-after/events.patterns new file mode 100644 index 000000000000..1768fc210624 --- /dev/null +++ b/app/tests/tap-dance/3f-hold-int-after/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/3f-hold-int-after/keycode_events.snapshot b/app/tests/tap-dance/3f-hold-int-after/keycode_events.snapshot new file mode 100644 index 000000000000..f4250f4941e9 --- /dev/null +++ b/app/tests/tap-dance/3f-hold-int-after/keycode_events.snapshot @@ -0,0 +1,10 @@ +td_binding_pressed: 0 created new tap dance +td_binding_pressed: 0 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 0 tap dance keybind released +kp_released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 1 created new tap dance +td_binding_pressed: 1 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 1 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/3f-hold-int-after/native_posix_64.keymap b/app/tests/tap-dance/3f-hold-int-after/native_posix_64.keymap new file mode 100644 index 000000000000..78770b13d803 --- /dev/null +++ b/app/tests/tap-dance/3f-hold-int-after/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/4a-single/events.patterns b/app/tests/tap-dance/4a-single/events.patterns new file mode 100644 index 000000000000..1768fc210624 --- /dev/null +++ b/app/tests/tap-dance/4a-single/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/4a-single/keycode_events.snapshot b/app/tests/tap-dance/4a-single/keycode_events.snapshot new file mode 100644 index 000000000000..6d60e8429af3 --- /dev/null +++ b/app/tests/tap-dance/4a-single/keycode_events.snapshot @@ -0,0 +1,5 @@ +td_binding_pressed: 1 created new tap dance +td_binding_pressed: 1 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 1 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/4a-single/native_posix_64.keymap b/app/tests/tap-dance/4a-single/native_posix_64.keymap new file mode 100644 index 000000000000..d473a7d2e695 --- /dev/null +++ b/app/tests/tap-dance/4a-single/native_posix_64.keymap @@ -0,0 +1,11 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/5a-tdint-mid/events.patterns b/app/tests/tap-dance/5a-tdint-mid/events.patterns new file mode 100644 index 000000000000..1768fc210624 --- /dev/null +++ b/app/tests/tap-dance/5a-tdint-mid/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/5a-tdint-mid/keycode_events.snapshot b/app/tests/tap-dance/5a-tdint-mid/keycode_events.snapshot new file mode 100644 index 000000000000..a84766e302cf --- /dev/null +++ b/app/tests/tap-dance/5a-tdint-mid/keycode_events.snapshot @@ -0,0 +1,10 @@ +td_binding_pressed: 2 created new tap dance +td_binding_pressed: 2 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 3 created new tap dance +td_binding_pressed: 3 tap dance pressed +td_binding_released: 3 tap dance keybind released +td_binding_released: 2 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/5a-tdint-mid/native_posix_64.keymap b/app/tests/tap-dance/5a-tdint-mid/native_posix_64.keymap new file mode 100644 index 000000000000..79bdf2f70816 --- /dev/null +++ b/app/tests/tap-dance/5a-tdint-mid/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(1,0,200) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/5b-tdint-seq/events.patterns b/app/tests/tap-dance/5b-tdint-seq/events.patterns new file mode 100644 index 000000000000..1768fc210624 --- /dev/null +++ b/app/tests/tap-dance/5b-tdint-seq/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/5b-tdint-seq/keycode_events.snapshot b/app/tests/tap-dance/5b-tdint-seq/keycode_events.snapshot new file mode 100644 index 000000000000..4380a057560b --- /dev/null +++ b/app/tests/tap-dance/5b-tdint-seq/keycode_events.snapshot @@ -0,0 +1,10 @@ +td_binding_pressed: 2 created new tap dance +td_binding_pressed: 2 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 3 created new tap dance +td_binding_pressed: 3 tap dance pressed +td_binding_released: 2 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 3 tap dance keybind released +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/5b-tdint-seq/native_posix_64.keymap b/app/tests/tap-dance/5b-tdint-seq/native_posix_64.keymap new file mode 100644 index 000000000000..012d932d60e3 --- /dev/null +++ b/app/tests/tap-dance/5b-tdint-seq/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(1,1,200) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/5c-tdint-after/events.patterns b/app/tests/tap-dance/5c-tdint-after/events.patterns new file mode 100644 index 000000000000..1768fc210624 --- /dev/null +++ b/app/tests/tap-dance/5c-tdint-after/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/5c-tdint-after/keycode_events.snapshot b/app/tests/tap-dance/5c-tdint-after/keycode_events.snapshot new file mode 100644 index 000000000000..4e54ac229424 --- /dev/null +++ b/app/tests/tap-dance/5c-tdint-after/keycode_events.snapshot @@ -0,0 +1,10 @@ +td_binding_pressed: 2 created new tap dance +td_binding_pressed: 2 tap dance pressed +td_binding_released: 2 tap dance keybind released +kp_pressed: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 3 created new tap dance +td_binding_pressed: 3 tap dance pressed +td_binding_released: 3 tap dance keybind released +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/5c-tdint-after/native_posix_64.keymap b/app/tests/tap-dance/5c-tdint-after/native_posix_64.keymap new file mode 100644 index 000000000000..fea96a563d9e --- /dev/null +++ b/app/tests/tap-dance/5c-tdint-after/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,200) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/5d-tdint-multiple/events.patterns b/app/tests/tap-dance/5d-tdint-multiple/events.patterns new file mode 100644 index 000000000000..1768fc210624 --- /dev/null +++ b/app/tests/tap-dance/5d-tdint-multiple/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/5d-tdint-multiple/keycode_events.snapshot b/app/tests/tap-dance/5d-tdint-multiple/keycode_events.snapshot new file mode 100644 index 000000000000..e5e024a81299 --- /dev/null +++ b/app/tests/tap-dance/5d-tdint-multiple/keycode_events.snapshot @@ -0,0 +1,15 @@ +td_binding_pressed: 2 created new tap dance +td_binding_pressed: 2 tap dance pressed +td_binding_released: 2 tap dance keybind released +kp_pressed: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 3 created new tap dance +td_binding_pressed: 3 tap dance pressed +td_binding_released: 3 tap dance keybind released +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 2 created new tap dance +td_binding_pressed: 2 tap dance pressed +td_binding_released: 2 tap dance keybind released +kp_pressed: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/5d-tdint-multiple/native_posix_64.keymap b/app/tests/tap-dance/5d-tdint-multiple/native_posix_64.keymap new file mode 100644 index 000000000000..f98be05ff994 --- /dev/null +++ b/app/tests/tap-dance/5d-tdint-multiple/native_posix_64.keymap @@ -0,0 +1,15 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,200) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/6-combo-tap2/events.patterns b/app/tests/tap-dance/6-combo-tap2/events.patterns new file mode 100644 index 000000000000..1768fc210624 --- /dev/null +++ b/app/tests/tap-dance/6-combo-tap2/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/6-combo-tap2/keycode_events.snapshot b/app/tests/tap-dance/6-combo-tap2/keycode_events.snapshot new file mode 100644 index 000000000000..227d9cf29836 --- /dev/null +++ b/app/tests/tap-dance/6-combo-tap2/keycode_events.snapshot @@ -0,0 +1,7 @@ +td_binding_pressed: 4 created new tap dance +td_binding_pressed: 4 tap dance pressed +td_binding_released: 4 tap dance keybind released +td_binding_pressed: 4 tap dance pressed +td_binding_released: 4 tap dance keybind released +kp_pressed: usage_page 0x07 keycode 0x1F implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x1F implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/6-combo-tap2/native_posix_64.keymap b/app/tests/tap-dance/6-combo-tap2/native_posix_64.keymap new file mode 100644 index 000000000000..a8a82fd9f6b5 --- /dev/null +++ b/app/tests/tap-dance/6-combo-tap2/native_posix_64.keymap @@ -0,0 +1,17 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,200) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/behavior_keymap.dtsi b/app/tests/tap-dance/behavior_keymap.dtsi new file mode 100644 index 000000000000..66ffdf2e0cc0 --- /dev/null +++ b/app/tests/tap-dance/behavior_keymap.dtsi @@ -0,0 +1,64 @@ +#include +#include +#include + +/ { + behaviors { + ht: hold_tap { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + tapping-term-ms = <200>; + quick_tap_ms = <0>; + flavor = "tap-preferred"; + bindings = <&kp>, <&kp>; + }; + + tdm: tap_dance_mixed { + compatible = "zmk,behavior-tap-dance"; + #binding-cells = <0>; + tapping-term-ms = <200>; + bindings = <&ht LSHIFT A>, <&ht LALT B>, <&ht LGUI C>; + }; + + tdb: tap_dance_basic { + compatible = "zmk,behavior-tap-dance"; + #binding-cells = <0>; + tapping-term-ms = <200>; + bindings = <&kp N1>, <&kp N2>, <&kp N3>; + }; + + td2: tap_dance_basic_2 { + compatible = "zmk,behavior-tap-dance"; + #binding-cells = <0>; + tapping-term-ms = <200>; + bindings = <&kp A>, <&kp B>, <&kp C>; + }; + + tds: tap_dance_single { + compatible = "zmk,behavior-tap-dance"; + #binding-cells = <0>; + tapping-term-ms = <200>; + bindings = <&kp S>; + }; + }; + + combos { + compatible = "zmk,combos"; + + td_combo { + bindings = <&tdb>; + key-positions = <0 1>; + timeout-ms = <50>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &tdm &tds + &tdb &td2>; + }; + }; +}; diff --git a/app/tests/to-layer/behavior_keymap.dtsi b/app/tests/to-layer/behavior_keymap.dtsi new file mode 100644 index 000000000000..0be9cb9641fa --- /dev/null +++ b/app/tests/to-layer/behavior_keymap.dtsi @@ -0,0 +1,21 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &to 0 &to 1 + &kp A &kp S>; + }; + + second_layer { + bindings = < + &to 0 &to 1 + &kp J &kp K>; + }; + }; +}; diff --git a/app/tests/to-layer/normal/events.patterns b/app/tests/to-layer/normal/events.patterns new file mode 100644 index 000000000000..fcebc4b0eb03 --- /dev/null +++ b/app/tests/to-layer/normal/events.patterns @@ -0,0 +1,3 @@ +s/.*hid_listener_keycode/kp/p +s/.*to_keymap_binding/to/p +s/.*layer_changed/layer_changed/p \ No newline at end of file diff --git a/app/tests/to-layer/normal/keycode_events.snapshot b/app/tests/to-layer/normal/keycode_events.snapshot new file mode 100644 index 000000000000..a98f7479ac99 --- /dev/null +++ b/app/tests/to-layer/normal/keycode_events.snapshot @@ -0,0 +1,18 @@ +kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +to_pressed: position 1 layer 1 +layer_changed: layer 1 state 1 +to_released: position 1 layer 1 +kp_pressed: usage_page 0x07 keycode 0x0E implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x0E implicit_mods 0x00 explicit_mods 0x00 +to_pressed: position 0 layer 0 +layer_changed: layer 1 state 0 +layer_changed: layer 0 state 1 +to_released: position 0 layer 0 +kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +to_pressed: position 0 layer 0 +to_released: position 0 layer 0 +to_pressed: position 1 layer 1 +layer_changed: layer 1 state 1 +to_released: position 1 layer 1 diff --git a/app/tests/to-layer/normal/native_posix_64.keymap b/app/tests/to-layer/normal/native_posix_64.keymap new file mode 100644 index 000000000000..6ccc9088bb23 --- /dev/null +++ b/app/tests/to-layer/normal/native_posix_64.keymap @@ -0,0 +1,29 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +// Press key A +// To layer 1 +// Press key J +// To layer 0 +// Press key S +// To layer 0 -- does nothing + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/toggle-layer/behavior_keymap.dtsi b/app/tests/toggle-layer/behavior_keymap.dtsi new file mode 100644 index 000000000000..1ff4a81f3e49 --- /dev/null +++ b/app/tests/toggle-layer/behavior_keymap.dtsi @@ -0,0 +1,27 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp B &tog 1 + &kp D &kp G>; + }; + + lower_layer { + bindings = < + &kp C_NEXT &trans + &kp L &kp J>; + }; + + raise_layer { + bindings = < + &kp W &kp U + &kp X &kp M>; + }; + }; +}; diff --git a/app/tests/toggle-layer/early-key-release/events.patterns b/app/tests/toggle-layer/early-key-release/events.patterns new file mode 100644 index 000000000000..397fef4f3198 --- /dev/null +++ b/app/tests/toggle-layer/early-key-release/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*tog_keymap_binding/tog/p \ No newline at end of file diff --git a/app/tests/toggle-layer/early-key-release/keycode_events.snapshot b/app/tests/toggle-layer/early-key-release/keycode_events.snapshot new file mode 100644 index 000000000000..8ac4a3d291c4 --- /dev/null +++ b/app/tests/toggle-layer/early-key-release/keycode_events.snapshot @@ -0,0 +1,6 @@ +kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +tog_pressed: position 1 layer 1 +kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +tog_released: position 1 layer 1 +kp_pressed: usage_page 0x0C keycode 0xB5 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x0C keycode 0xB5 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/toggle-layer/early-key-release/native_posix_64.keymap b/app/tests/toggle-layer/early-key-release/native_posix_64.keymap new file mode 100644 index 000000000000..0a0c88ea845a --- /dev/null +++ b/app/tests/toggle-layer/early-key-release/native_posix_64.keymap @@ -0,0 +1,9 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/toggle-layer/normal/events.patterns b/app/tests/toggle-layer/normal/events.patterns new file mode 100644 index 000000000000..397fef4f3198 --- /dev/null +++ b/app/tests/toggle-layer/normal/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*tog_keymap_binding/tog/p \ No newline at end of file diff --git a/app/tests/toggle-layer/normal/keycode_events.snapshot b/app/tests/toggle-layer/normal/keycode_events.snapshot new file mode 100644 index 000000000000..515772a4d1f7 --- /dev/null +++ b/app/tests/toggle-layer/normal/keycode_events.snapshot @@ -0,0 +1,4 @@ +tog_pressed: position 1 layer 1 +tog_released: position 1 layer 1 +kp_pressed: usage_page 0x0C keycode 0xB5 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x0C keycode 0xB5 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/toggle-layer/normal/native_posix_64.keymap b/app/tests/toggle-layer/normal/native_posix_64.keymap new file mode 100644 index 000000000000..97bdd17993d0 --- /dev/null +++ b/app/tests/toggle-layer/normal/native_posix_64.keymap @@ -0,0 +1,8 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/transparent/behavior_keymap.dtsi b/app/tests/transparent/behavior_keymap.dtsi new file mode 100644 index 000000000000..b70c84218c27 --- /dev/null +++ b/app/tests/transparent/behavior_keymap.dtsi @@ -0,0 +1,21 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &trans &mo 1 + &kp A &none>; + }; + + lower_layer { + bindings = < + &trans &trans + &trans &kp A>; + }; + }; +}; diff --git a/app/tests/transparent/layered/events.patterns b/app/tests/transparent/layered/events.patterns new file mode 100644 index 000000000000..3c9d3f838c62 --- /dev/null +++ b/app/tests/transparent/layered/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode/kp/p \ No newline at end of file diff --git a/app/tests/transparent/layered/keycode_events.snapshot b/app/tests/transparent/layered/keycode_events.snapshot new file mode 100644 index 000000000000..570e7d159b07 --- /dev/null +++ b/app/tests/transparent/layered/keycode_events.snapshot @@ -0,0 +1,2 @@ +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/transparent/layered/native_posix_64.keymap b/app/tests/transparent/layered/native_posix_64.keymap new file mode 100644 index 000000000000..b1e84c306613 --- /dev/null +++ b/app/tests/transparent/layered/native_posix_64.keymap @@ -0,0 +1,8 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/transparent/normal/events.patterns b/app/tests/transparent/normal/events.patterns new file mode 100644 index 000000000000..3c9d3f838c62 --- /dev/null +++ b/app/tests/transparent/normal/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode/kp/p \ No newline at end of file diff --git a/app/tests/transparent/normal/keycode_events.snapshot b/app/tests/transparent/normal/keycode_events.snapshot new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/tests/transparent/normal/native_posix_64.keymap b/app/tests/transparent/normal/native_posix_64.keymap new file mode 100644 index 000000000000..502f7ccc4731 --- /dev/null +++ b/app/tests/transparent/normal/native_posix_64.keymap @@ -0,0 +1,8 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/wpm/1-single_keypress/events.patterns b/app/tests/wpm/1-single_keypress/events.patterns new file mode 100644 index 000000000000..c49e6c00bd17 --- /dev/null +++ b/app/tests/wpm/1-single_keypress/events.patterns @@ -0,0 +1,2 @@ +s/.*wpm_work_handler: //p +s/.*wpm_event_listener: //p \ No newline at end of file diff --git a/app/tests/wpm/1-single_keypress/keycode_events.snapshot b/app/tests/wpm/1-single_keypress/keycode_events.snapshot new file mode 100644 index 000000000000..c86f323ba3b3 --- /dev/null +++ b/app/tests/wpm/1-single_keypress/keycode_events.snapshot @@ -0,0 +1,7 @@ +key_pressed_count 1 keycode 5 +Raised WPM state changed 12 wpm_update_counter 1 +Raised WPM state changed 6 wpm_update_counter 2 +Raised WPM state changed 4 wpm_update_counter 3 +Raised WPM state changed 3 wpm_update_counter 4 +Raised WPM state changed 2 wpm_update_counter 5 +Raised WPM state changed 0 wpm_update_counter 1 diff --git a/app/tests/wpm/1-single_keypress/native_posix_64.conf b/app/tests/wpm/1-single_keypress/native_posix_64.conf new file mode 100644 index 000000000000..670f63d80f49 --- /dev/null +++ b/app/tests/wpm/1-single_keypress/native_posix_64.conf @@ -0,0 +1,6 @@ +CONFIG_GPIO=n +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_ZMK_WPM=y \ No newline at end of file diff --git a/app/tests/wpm/1-single_keypress/native_posix_64.keymap b/app/tests/wpm/1-single_keypress/native_posix_64.keymap new file mode 100644 index 000000000000..2b113409e52a --- /dev/null +++ b/app/tests/wpm/1-single_keypress/native_posix_64.keymap @@ -0,0 +1,10 @@ +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* Wait for the worker to trigger and reset after 5 seconds, followed by a 0 at 6 seconds */ + ZMK_MOCK_PRESS(0,0,6000) + >; +}; \ No newline at end of file diff --git a/app/tests/wpm/2-multiple_keypress/events.patterns b/app/tests/wpm/2-multiple_keypress/events.patterns new file mode 100644 index 000000000000..c49e6c00bd17 --- /dev/null +++ b/app/tests/wpm/2-multiple_keypress/events.patterns @@ -0,0 +1,2 @@ +s/.*wpm_work_handler: //p +s/.*wpm_event_listener: //p \ No newline at end of file diff --git a/app/tests/wpm/2-multiple_keypress/keycode_events.snapshot b/app/tests/wpm/2-multiple_keypress/keycode_events.snapshot new file mode 100644 index 000000000000..a0e8f7a8db3d --- /dev/null +++ b/app/tests/wpm/2-multiple_keypress/keycode_events.snapshot @@ -0,0 +1,4 @@ +key_pressed_count 1 keycode 5 +Raised WPM state changed 12 wpm_update_counter 1 +key_pressed_count 2 keycode 5 +Raised WPM state changed 8 wpm_update_counter 3 diff --git a/app/tests/wpm/2-multiple_keypress/native_posix_64.conf b/app/tests/wpm/2-multiple_keypress/native_posix_64.conf new file mode 100644 index 000000000000..980eff5c0abf --- /dev/null +++ b/app/tests/wpm/2-multiple_keypress/native_posix_64.conf @@ -0,0 +1,6 @@ +CONFIG_GPIO=n +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_ZMK_WPM=y diff --git a/app/tests/wpm/2-multiple_keypress/native_posix_64.keymap b/app/tests/wpm/2-multiple_keypress/native_posix_64.keymap new file mode 100644 index 000000000000..869a5208c4c4 --- /dev/null +++ b/app/tests/wpm/2-multiple_keypress/native_posix_64.keymap @@ -0,0 +1,15 @@ +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + //1st WPM worker call - 12wpm - 1 key press in 1 second + ZMK_MOCK_PRESS(0,0,1000) + ZMK_MOCK_RELEASE(0,0,10) + // 2nd WPM worker call - 12wpm - 2 key press in 2 second + // note there is no event for this as WPM hasn't changed + // 3rd WPM worker call - 8wpm - 2 key press in 3 seconds + ZMK_MOCK_PRESS(0,0,2000) + >; +}; \ No newline at end of file diff --git a/app/tests/wpm/behavior_keymap.dtsi b/app/tests/wpm/behavior_keymap.dtsi new file mode 100644 index 000000000000..5f7cfd2dfeb6 --- /dev/null +++ b/app/tests/wpm/behavior_keymap.dtsi @@ -0,0 +1,16 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp B &none + &none &none + >; + }; + }; +}; diff --git a/app/west.yml b/app/west.yml new file mode 100644 index 000000000000..f72f2f398bcd --- /dev/null +++ b/app/west.yml @@ -0,0 +1,125 @@ +manifest: + defaults: + remote: upstream + + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos + - name: zmkfirmware + url-base: https://github.com/zmkfirmware + - name: upstream + url-base: https://github.com/zephyrproject-rtos + - name: babblesim + url-base: https://github.com/BabbleSim + group-filter: [-babblesim] + projects: + - name: zephyr + remote: zmkfirmware + revision: v3.2.0+zmk-fixes + clone-depth: 1 + import: + name-blocklist: + - ci-tools + - hal_altera + - hal_cypress + - hal_infineon + - hal_microchip + - hal_nxp + - hal_openisa + - hal_silabs + - hal_xtensa + - hal_st + - hal_ti + - loramac-node + - mcuboot + - mcumgr + - net-tools + - openthread + - edtt + - trusted-firmware-m + - sof + - name: bsim + repo-path: babblesim-manifest + revision: 908ffde6298a937c6549dbfa843a62caab26bfc5 + path: tools/bsim + groups: + - babblesim + - name: babblesim_base + remote: babblesim + repo-path: base.git + path: tools/bsim/components + revision: 02838ca04c4562e68dc876196828d8121679e537 + groups: + - babblesim + - name: babblesim_ext_2G4_libPhyComv1 + remote: babblesim + repo-path: ext_2G4_libPhyComv1.git + path: tools/bsim/components/ext_2G4_libPhyComv1 + revision: 9018113a362fa6c9e8f4b9cab9e5a8f12cc46b94 + groups: + - babblesim + - name: babblesim_ext_2G4_phy_v1 + remote: babblesim + repo-path: ext_2G4_phy_v1.git + path: tools/bsim/components/ext_2G4_phy_v1 + revision: cf2d86e736efac4f12fad5093ed2da2c5b406156 + groups: + - babblesim + - name: babblesim_ext_2G4_channel_NtNcable + remote: babblesim + repo-path: ext_2G4_channel_NtNcable.git + path: tools/bsim/components/ext_2G4_channel_NtNcable + revision: 20a38c997f507b0aa53817aab3d73a462fff7af1 + groups: + - babblesim + - name: babblesim_ext_2G4_channel_multiatt + remote: babblesim + repo-path: ext_2G4_channel_multiatt.git + path: tools/bsim/components/ext_2G4_channel_multiatt + revision: e09bc2d14b1975f969ad19c6ed23eb20e5dc3d09 + groups: + - babblesim + - name: babblesim_ext_2G4_modem_magic + remote: babblesim + repo-path: ext_2G4_modem_magic.git + path: tools/bsim/components/ext_2G4_modem_magic + revision: cb70771794f0bf6f262aa474848611c68ae8f1ed + groups: + - babblesim + - name: babblesim_ext_2G4_modem_BLE_simple + remote: babblesim + repo-path: ext_2G4_modem_BLE_simple.git + path: tools/bsim/components/ext_2G4_modem_BLE_simple + revision: ce975a3259fd0dd761d371b60435242d54794bad + groups: + - babblesim + - name: babblesim_ext_2G4_device_burst_interferer + remote: babblesim + repo-path: ext_2G4_device_burst_interferer.git + path: tools/bsim/components/ext_2G4_device_burst_interferer + revision: 5b5339351d6e6a2368c686c734dc8b2fc65698fc + groups: + - babblesim + - name: babblesim_ext_2G4_device_WLAN_actmod + remote: babblesim + repo-path: ext_2G4_device_WLAN_actmod.git + path: tools/bsim/components/ext_2G4_device_WLAN_actmod + revision: 9cb6d8e72695f6b785e57443f0629a18069d6ce4 + groups: + - babblesim + - name: babblesim_ext_2G4_device_playback + remote: babblesim + repo-path: ext_2G4_device_playback.git + path: tools/bsim/components/ext_2G4_device_playback + revision: 85c645929cf1ce995d8537107d9dcbd12ed64036 + groups: + - babblesim + - name: babblesim_ext_libCryptov1 + remote: babblesim + repo-path: ext_libCryptov1.git + path: tools/bsim/components/ext_libCryptov1 + revision: eed6d7038e839153e340bd333bc43541cb90ba64 + groups: + - babblesim + self: + west-commands: scripts/west-commands.yml diff --git a/docs/.eslintignore b/docs/.eslintignore new file mode 100644 index 000000000000..b7dab5e9cbfe --- /dev/null +++ b/docs/.eslintignore @@ -0,0 +1,2 @@ +node_modules +build \ No newline at end of file diff --git a/docs/.eslintrc.js b/docs/.eslintrc.js new file mode 100644 index 000000000000..b5fc07457a15 --- /dev/null +++ b/docs/.eslintrc.js @@ -0,0 +1,28 @@ +module.exports = { + env: { + browser: true, + commonjs: true, + es2021: true, + node: true, + }, + extends: [ + "eslint:recommended", + "plugin:react/recommended", + "plugin:mdx/recommended", + "prettier", + ], + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + ecmaVersion: 2021, + sourceType: "module", + }, + plugins: ["react"], + rules: {}, + settings: { + react: { + version: "detect", + }, + }, +}; diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 000000000000..b2d6de30624f --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,20 @@ +# Dependencies +/node_modules + +# Production +/build + +# Generated files +.docusaurus +.cache-loader + +# Misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/docs/.nvmrc b/docs/.nvmrc new file mode 100644 index 000000000000..1a2f5bd20451 --- /dev/null +++ b/docs/.nvmrc @@ -0,0 +1 @@ +lts/* \ No newline at end of file diff --git a/docs/.prettierignore b/docs/.prettierignore new file mode 100644 index 000000000000..2e03c0b08132 --- /dev/null +++ b/docs/.prettierignore @@ -0,0 +1,5 @@ +node_modules +build +.docusaurus +*.mustache +hardware-metadata.json diff --git a/docs/.prettierrc.js b/docs/.prettierrc.js new file mode 100644 index 000000000000..2a1f0b48af9e --- /dev/null +++ b/docs/.prettierrc.js @@ -0,0 +1,3 @@ +module.exports = { + endOfLine: "auto", +}; diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000000..1fd6775d534c --- /dev/null +++ b/docs/README.md @@ -0,0 +1,29 @@ +# Website + +This website is built using [Docusaurus 2](https://v2.docusaurus.io/), a modern static website generator. + +## License + +The ZMK Documentation is licensed [CC-BY-NC-SA](http://creativecommons.org/licenses/by-nc-sa/4.0/). + +### Installation + +```sh +$ npm ci +``` + +### Local Development + +```sh +$ npm start +``` + +This command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server. + +### Build + +```sh +$ npm build +``` + +This command generates static content into the `build` directory and can be served using any static contents hosting service. diff --git a/docs/blog/2020-05-24-wip.md b/docs/blog/2020-05-24-wip.md new file mode 100644 index 000000000000..9b81bdff3d3d --- /dev/null +++ b/docs/blog/2020-05-24-wip.md @@ -0,0 +1,13 @@ +--- +title: WIP +author: Pete Johanson +author_title: Project Creator +author_url: https://gitlab.com/petejohanson +author_image_url: https://www.gravatar.com/avatar/2001ceff7e9dc753cf96fcb2e6f41110 +tags: [keyboards, firmware, oss, ble] +--- + +This blog is a work-in-progress as I work on basic docs + blog on this nascent keyboard firmware. + +As is, there are more features _missing_ from ZMK than features it has. As always with pre-alpha software, +if something breaks, you get to keep both halves! (especially if it is a split KB) diff --git a/docs/blog/2020-08-12-zmk-sotf-1.md b/docs/blog/2020-08-12-zmk-sotf-1.md new file mode 100644 index 000000000000..afa03405a70a --- /dev/null +++ b/docs/blog/2020-08-12-zmk-sotf-1.md @@ -0,0 +1,52 @@ +--- +title: "ZMK State Of The Firmware #1" +author: Pete Johanson +author_title: Project Creator +author_url: https://gitlab.com/petejohanson +author_image_url: https://www.gravatar.com/avatar/2001ceff7e9dc753cf96fcb2e6f41110 +tags: [SOTF, keyboards, firmware, oss, ble] +--- + +Welcome to the first ZMK "State Of The Firmware"! + +With interest and Discord activity growing, it seemed important to lay out the progress made recently, current major bugs/showstoppers, and planned next steps. + +## Recent Activity + +There's been lots of various activity in ZMK land! + +- [Nicell](https://github.com/Nicell) (nice!nano creator) contributed initial [RGB Underglow](/docs/features/underglow) ([#64](https://github.com/zmkfirmware/zmk/pull/64)) support to ZMK. +- Tons of [documentation](/docs) work. +- Refactoring ([#73](https://github.com/zmkfirmware/zmk/pull/73), [#74](https://github.com/zmkfirmware/zmk/pull/74)) of [keymaps](/docs/features/keymaps) to make them simpler for users. +- Mod-Tap Behavior (docs coming!) is much improved ([#69](https://github.com/zmkfirmware/zmk/pull/69)) and usable now. +- An initial [`setup.sh`](http://localhost:3000/docs/user-setup#user-config-setup-script) script was created, allowing users to quickly bootstrap a "user config" setup and push it to GitHub, where GitHub Actions will build the firmware for you. +- Corne shield ([#80](https://github.com/zmkfirmware/zmk/pull/80)) shield definition was added. +- Initial [encoder](/docs/features/encoders) support ([#61](https://github.com/zmkfirmware/zmk/pull/61)) was added. + +## Bugs and Showstoppers + +Despite the flurry of activity, there are still some serious bugs and show stoppers that potential ZMK users should be aware of: + +- [Bluetooth Related](https://github.com/zmkfirmware/zmk/issues/58) - There are several key bugs and fixes needed, including one complete show stopper: + - Fully working split wireless is not working. In particular, both split halves can properly pair, but once they do so, pairing with the _central_ host will not work. Workaround: You can currently have both halves pair, and use USB on the central side (Left side right now for Kyria, Corne, Lily58) and receive HID events over USB. - Fixed in 8b61beb. + - BT bond information is not currently stored to the devices, so after powering off or restarting your device, users need to re-pair +- USB - There is one important USB related bug which is a showstopper: + - The Zephyr USB stack does not have a built in queue for endpoint data being written. As a result, HID events sent by ZMK are sometimes dropped, or lost. - Fixed by careyk007 in #93. + +## Next Steps + +There's plenty of places to go next! To help keep folks in the loop for what's next, I've created a [Core Functionality](https://github.com/zmkfirmware/zmk/projects/1) project/kanban board in GitHub, where users should be able to get some visibility into items being focused on. + +Of course, at the top of that list currently is the above bugs/showstoppers, and then from there, I hope to: + +- Work on power management. +- Improve our documentation on various aspects of the system, mostly around: + - End user documentation for understanding how to use ZMK, better installation docs, etc. + - Developer focused documentation, so interested contributors can start building out more behaviors and ZMK functionality. +- Implement true "hold" detection, useful for several behaviors such as Mod-Tap and Layer-Tap. +- Hopefully acquire a proper and official USB Product ID for use for the project. +- Fun things that come up along the way! + +## Thanks! + +A big thanks for everyone who has shown interest in the project, tested things, asked questions, and contributed PRs ([Nicell](https://github.com/Nicell), [CrossR](https://github.com/CrossR), [careyk007](https://github.com/careyk007)). diff --git a/docs/blog/2020-09-21-zmk-sotf-2.md b/docs/blog/2020-09-21-zmk-sotf-2.md new file mode 100644 index 000000000000..61e294225d4f --- /dev/null +++ b/docs/blog/2020-09-21-zmk-sotf-2.md @@ -0,0 +1,106 @@ +--- +title: "ZMK State Of The Firmware #2" +author: Pete Johanson +author_title: Project Creator +author_url: https://gitlab.com/petejohanson +author_image_url: https://www.gravatar.com/avatar/2001ceff7e9dc753cf96fcb2e6f41110 +tags: [SOTF, keyboards, firmware, oss, ble] +--- + +Welcome to the second ZMK "State Of The Firmware" (SOTF)! + +This update will cover all the major activity since [SOTF #1](/blog/2020/08/12/zmk-sotf-1), preparations for the upcoming +Hacktoberfest activity, and a current open call for community feedback on a ZMK mascot. + +## Recent Activity + +So much going on in ZMK! + +- Added a new generic [Hold Tap behavior](https://zmk.dev/docs/behaviors/hold-tap) + in [#146](https://github.com/zmkfirmware/zmk/pull/146) which now powers mod-tap, layer-tap, etc. - [okke-formsma] +- [BLE profile/connection management](https://zmk.dev/docs/behaviors/bluetooth) + in [#133](https://github.com/zmkfirmware/zmk/pull/133) - [petejohanson] +- Integration tests were added to automate testing of behaviors in [#131](https://github.com/zmkfirmware/zmk/pull/131) by [BrainWart] & [petejohanson] +- [Toggle layer behavior](https://zmk.dev/docs/behaviors/layers#toggle-layer), e.g. `&tog LOWER`, in + [#98](https://github.com/zmkfirmware/zmk/pull/98) - [BrainWart] +- Key fix for dropped press/release over HID [#93](https://github.com/zmkfirmware/zmk/pull/93)/[#96](https://github.com/zmkfirmware/zmk/pull/96) - [careyk007](https://github.com/careyk007) & [petejohanson] +- Code formatting standardized using `clang-format` in [#183](https://github.com/zmkfirmware/zmk/pull/183) - [petejohanson] +- [Bootloader reset behavior](https://zmk.dev/docs/behaviors/reset#bootloader-reset), e.g. `&bootloader`, in [#116](https://github.com/zmkfirmware/zmk/pull/116) - [petejohanson] +- Various bug fixes and documentation + +## New Shields + +- QAZ in [#130](https://github.com/zmkfirmware/zmk/pull/130) - [tominabox1](https://github.com/tominabox1) +- Iris in [#151](https://github.com/zmkfirmware/zmk/pull/151) - [kurtis-lew](https://github.com/kurtis-lew) +- RoMac 2.1 in [#122](https://github.com/zmkfirmware/zmk/pull/122) - [bmcgavin](https://github.com/bmcgavin) +- Sofle in [#118](https://github.com/zmkfirmware/zmk/pull/118) - [CrossR](https://github.com/CrossR) +- splitreus62 in [#92](https://github.com/zmkfirmware/zmk/pull/92) - [Na-Cly](https://github.com/Na-Cly) + +## New Boards + +- DZ60RGB rev1 in [#166](https://github.com/zmkfirmware/zmk/pull/166) - [Nicell] +- nrfMicro in [#101](https://github.com/zmkfirmware/zmk/pull/101) - [okke-formsma] +- BlueMicro840 [#91](https://github.com/zmkfirmware/zmk/pull/91) - [Na-Cly](https://github.com/Na-Cly) + +## Hacktoberfest Preparation + +[Hacktoberfest](https://hacktoberfest.digitalocean.com/) is a yearly celebration of open source, +which encourages participation in OSS, especially from new contributors. + +The ZMK contributors have been busy preparing for folks to join in on the fun by contributing to +ZMK! + +- There is now a basic [Contributing Guide](https://github.com/zmkfirmware/zmk/blob/main/CONTRIBUTING.md) to help newcomers get oriented, and get up to speed. +- The [`Hacktoberfest`](https://github.com/zmkfirmware/zmk/issues?q=is%3Aissue+is%3Aopen+label%3AHacktoberfest) + issue label will help participants discover good issues to work on. + (The existing [`good first issue`](https://github.com/zmkfirmware/zmk/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) label also helps with this) + +We're looking forward to the launch of Hacktoberfest! + +## Mascot Selection Feedback + +The ZMK project would like to settle on a mascot! We're soliciting community feedback as part of +the process before a final mascot is selected. + +The current mascots up for consideration are: + +- Griffin +- Peregrine Falcon +- Zapata Wren +- Zorro (south american fox) + +If you're interested in helping with the decision, head over to [Issue #195](https://github.com/zmkfirmware/zmk/issues/195) and add a reaction! + +## Coming Soon! + +There still lots of activity in ZMK, and plenty of exciting upcoming changes. + +- Improved modifier infrastructure, including "shifted keycodes" - [okke-formsma] +- Battery percentage reporting over BLE - [Nicell] +- Complete defines for HID keycodes/usage IDs - [innovaker](https://github.com/innovaker) +- Additional core BLE connection/bond management work - [petejohanson] +- Improved power management - [petejohanson], [Nicell] +- One shot mod/layer behaviors - [okke-formsma] + +## Statistics + +Some statistics of interest for ZMK: + +- GitHub + - 115 Closed PRs + - 64 Stars + - 48 Forks +- Discord Chat + - 186 total registered +- Website (last 30 days) + - 7.4K page views + - 474 new users + +## Thanks! + +Thanks again to the numerous contributors and users who have made working on ZMK such a pleasure! + +[okke-formsma]: https://github.com/okke-formsma +[nicell]: https://github.com/Nicell +[petejohanson]: https://github.com/petejohanson +[brainwart]: https://github.com/BrainWart diff --git a/docs/blog/2020-10-03-bootloader-fix.md b/docs/blog/2020-10-03-bootloader-fix.md new file mode 100644 index 000000000000..aceee49012d3 --- /dev/null +++ b/docs/blog/2020-10-03-bootloader-fix.md @@ -0,0 +1,197 @@ +--- +title: Fixing the Mysterious Broken Bootloader +author: Nick Winans +author_title: Contributor +author_url: https://github.com/Nicell +author_image_url: https://avatars1.githubusercontent.com/u/9439650 +tags: [bootloader, keyboards, firmware, oss, ble] +--- + +Recently I was able to fix the "stuck in the bootloader" issue in +[#322](https://github.com/zmkfirmware/zmk/pull/322) that had been plaguing us +for quite some time. I want to go over what the issue was, how the issue was +diagnosed, and how it was fixed. + +## Background + +What exactly is the "stuck in the bootloader" issue? Seemingly randomly, users' +keyboards would suddenly stop working and when they would reset their keyboard +they would get put into the bootloader instead of back into the firmware. This +would require the user to re-flash the firmware again to get into the firmware. +That wouldn't be so bad except for the fact that once this occurs, every reset +would require the user to re-flash the firmware again. The only way to really +fix this issue was to re-flash the bootloader itself, which is a huge pain. + +Going into this, all we knew was that this issue was most likely introduced +somewhere in the [#133](https://github.com/zmkfirmware/zmk/pull/133), which +added Bluetooth profile management. We've had quite a few attempts at trying to +recreate the issue, but we never were able to get it to happen consistently. + +## Diagnosing the issue + +This issue had been happening sporadically for the past month, and I finally +decided to dig in to see what was going on. We started in the Discord and +discussed what was common between all of the people who have experienced this +issue. Everyone who had this issue reported that they did quite a bit of profile +switching. This lined up with the possible connection to the Bluetooth profile +management pull request. + +### Pinpointing the cause + +I had a hunch that this was related to the settings system. The settings system +is used by profile Bluetooth switching, and the settings system works directly +with the system flash. Based on this hunch, I tried spamming the RGB underglow +cycle behavior on my main keyboard. Sure enough after a couple minutes, I got +stuck in the bootloader. I was even able to reproduce it again. + +This was an important discovery for two reasons. First, I was able to recreate +the issue consistently, which meant I could set up logging and more closely +monitor what the board was doing. Second, this more or less proved that it was +specifically the settings system at fault. Both Bluetooth profile switching and +RGB underglow cycling trigger it, and the one common piece is they save their +state to settings. + +### Settings system overview + +To understand what's going wrong, we first need to understand how the settings +system works. Here's a diagram to explain the flash space that the settings +system holds for our nRF52840 based boards (nice!nano, nRFMicro, BlueMicro). + +![Settings Diagram](https://i.imgur.com/DF2t3Oq.png) + +The settings flash space lives at the end of the flash of the chip. In this case +it starts at `0xF8000` and is `0x8000` bytes long, which is 32KB in more +comprehensible units. Then due to the chip's architecture, this flash space is +broken into pages, which are `0x1000` bytes in size (4KB). + +The backend that carries out the settings save and read operation in ZMK is +called NVS. NVS calls these pages sectors. Due to how flash works, you can't +write to the same bytes multiple times without erasing them first, and to erase +bytes, you need to erase the entire sector of flash. This means when NVS writes +to the settings flash if there's no erased space available for the new value, it +will need to erase a sector. + +### Logging discoveries + +So first I enabled logging of the NVS module by adding +`CONFIG_NVS_LOG_LEVEL_DBG=y` to my `.conf` file. I repeated the same test of +spamming RGB underglow effect cycle and the resulting logs I got were this: + +```log +[00:00:00.000,671] fs_nvs: 8 Sectors of 4096 bytes +[00:00:00.000,671] fs_nvs: alloc wra: 3, f70 +[00:00:00.000,671] fs_nvs: data wra: 3, f40 +// A bunch of effect cycle spam +[00:02:34.781,188] fs_nvs: Erasing flash at fd000, len 4096 +// A bunch more effect cycle spam +[00:06:42.219,970] fs_nvs: Erasing flash at ff000, len 4096 +// A bunch more effect cycle spam +// KABOOM - bootloader issue +``` + +So at start up, we can see that the 8 sectors of 4KB are found by NVS properly, +however, I wasn't sure what the second and third lines meant, but we'll get back +to that. Nonetheless the next two logs from NVS showed erasing the sector at +`0xFD000` and then erasing the `0xFF000` sector. + +![Erased Sectors](https://i.imgur.com/DmLycMJ.png) + +It's really odd that the third to last sector and the last sector are erased, +and then shortly after the bootloader issue is hit. I really had no explanation +for this behavior. + +### Reaching out to Zephyr + +At this point, I nor anyone else working on the ZMK project knew enough about +NVS to explain what was going on here. [Pete +Johanson](https://github.com/petejohanson), project founder, reached out on the +Zephyr Project's Slack (ZMK is built on top of Zephyr if you weren't aware). +Justin B and Laczen assisted by first explaining that those `alloc wra` and +`data wra` logs from earlier are showing what data NVS found at startup. + +More specifically, `data wra` should be `0` when it first starts up on a clean +flash. As we can see from my earlier logging on a clean flash I was instead +getting `f40`. NVS is finding data in our settings sectors when they should be +blank! We were then given the advice to double check our bootloader. + +### The Adafruit nRF52 Bootloader + +Most of the boards the contributors of ZMK use have the [Adafruit nRF52 +Bootloader](https://github.com/adafruit/Adafruit_nRF52_Bootloader), which allows +for extremely easy flashing by dragging and dropping `.uf2` files onto the board +as a USB drive. Every bootloader takes up a portion of the flash, and in the +README explains that the first `0x26000` is reserved for the bootloader with the +nRF52840, and we've properly allocated that. + +However, there isn't a full explanation of the flash allocation of the +bootloader in the README. There's a possibility that the bootloader is using +part of the same flash area we're using. I reached out on the Adafruit Discord, +and [Dan Halbert](https://github.com/dhalbert) pointed me towards the [linker +map](https://github.com/adafruit/Adafruit_nRF52_Bootloader/blob/master/linker/nrf52840.ld) +of the nRF52840. Let's take a look. + +```linker-script +FLASH (rx) : ORIGIN = 0xF4000, LENGTH = 0xFE000-0xF4000-2048 /* 38 KB */ + +BOOTLOADER_CONFIG (r): ORIGIN = 0xFE000 - 2048, LENGTH = 2048 + +/** Location of mbr params page in flash. */ +MBR_PARAMS_PAGE (rw) : ORIGIN = 0xFE000, LENGTH = 0x1000 + +/** Location of bootloader setting in flash. */ +BOOTLOADER_SETTINGS (rw) : ORIGIN = 0xFF000, LENGTH = 0x1000 +``` + +Here's a diagram to show this a bit better. + +![Adafruit Bootloader Diagram](https://i.imgur.com/TEOA31m.png) + +We've found the issue! As you can see from the red bar (representing our +settings flash area), we've put the settings flash area _right on top_ of the +Adafruit bootloader's flash space. Oops! + +This also shines some light on why NVS erased `0xFD000` and `0xFF000` sectors. +It's possible there was no flash written to `0xFD000` because the bootloader +didn't use up all of that space it has, and then there possibly weren't any +bootloader settings set yet, so `0xFF000` could be used and erased by NVS too. + +After erasing `0xFF000`, NVS probably next erased a rather important part of the +bootloader that resulted in this issue at hand. In my opinion, we're pretty +lucky that it didn't delete an even more vital part of the bootloader. At least +we could still get to it, so that we could re-flash the bootloader easily! + +## The solution + +Now that we've found the issue, we can pretty easily fix this. We'll need to +move the settings flash area back so that it doesn't overlap with the +bootloader. First we calculate the size of the of flash area the bootloader is using. + +```linker-script +0x100000 (end of flash) - 0x0F4000 (start of bootloader) = 0xC000 (48KB) +``` + +So the bootloader is using the last 48KB of the flash, this means all we need to +do is shift back the settings area and code space `0xC000` bytes. We'll apply +this to all of the `.dts` files for the boards that were affected by this issue. + +```diff + code_partition: partition@26000 { +- reg = <0x00026000 0x000d2000>; ++ reg = <0x00026000 0x000c6000>; + }; + + +- storage_partition: partition@f8000 { ++ storage_partition: partition@ec000 { +- reg = <0x000f8000 0x00008000>; ++ reg = <0x000ec000 0x00008000>; + }; +``` + +And with those changes, we should no longer run into this issue! In the process +of these changes, we lost 48KB of space for application code, but we're only +using around 20% of it anyways. 🎉 + +## Article Updates + +- 12/2023: Removed the deprecated `label` property from code snippets. diff --git a/docs/blog/2020-11-09-zmk-sotf-3.md b/docs/blog/2020-11-09-zmk-sotf-3.md new file mode 100644 index 000000000000..11d670403464 --- /dev/null +++ b/docs/blog/2020-11-09-zmk-sotf-3.md @@ -0,0 +1,156 @@ +--- +title: "ZMK State Of The Firmware #3" +author: Pete Johanson +author_title: Project Creator +author_url: https://gitlab.com/petejohanson +author_image_url: https://www.gravatar.com/avatar/2001ceff7e9dc753cf96fcb2e6f41110 +tags: [SOTF, keyboards, firmware, oss, ble] +--- + +Welcome to the third ZMK "State Of The Firmware" (SOTF)! + +This update will cover all the major activity since [SOTF #2](/blog/2020/09/21/zmk-sotf-2). This edition comes a bit later than planned, but the amount of features and changes will hopefully make it worth it! + +## Recent Activity + +Here's a summary of the various major changes since last time, broken down by theme: + +### Keymaps/Behaviors + +Tons of activity related to keymaps, so we'll go into more detail this time. + +#### Codes Overhaul + +[innovaker] _completely_ overhauled the set of available codes for keymaps, and simultaneously has created +_beautiful_ [documentation](/docs/codes) to help users visualize the codes, and also understand if they are supported on their particular operating system. + +This also laid the foundation for the other keymap related changes that are now available. + +#### Modified (Shifted) Codes + +[okke-formsma] added the ability to apply modifiers to a code, e.g.: + +```dts +&kp LC(C) +``` + +which sends `Control + c` when pressed. This feature is often used on smaller keyboards to achieve "shifted keycodes", e.g. `LS(N1)` to send a `!`. +To make this easier, in addition to all the normal codes, we now have defines for common shifted codes, e.g. `EXCL` for `!`, `AT` for `@`, etc. + +To learn more, check out the [Modifiers](/docs/codes/modifiers) documentation. + +#### Simplified Key Press Behavior + +In previous versions of ZMK, users needed to be careful to select between the `&kp` and `&cp` behaviors in their keymaps, depending on +whether the particular keycode they wanted to send was in the "HID consumer page" or not. Forcing users to understand the difference and get +this right was awkward and error prone. + +[petejohanson] and [innovaker] have reduced this complexity. Users can now simply use `&kp` with all available codes and ZMK will +handle sending the right events to the connected host. + +### Power Management + +Several important power management features have been added to ZMK, helping save power for many use cases. + +#### BLE Battery Level Reporting + +[Nicell] added the necessary [driver](https://github.com/zmkfirmware/zmk/pull/293) and [core code](https://github.com/zmkfirmware/zmk/pull/306) to send BLE battery level notifications to hosts that support displaying them. Testing seems to show this works with Windows and GNOME, but macOS does not display the battery info. + +#### External Power Control + +[megamind4089] added a new [driver](https://github.com/zmkfirmware/zmk/pull/242) and [behavior](https://github.com/zmkfirmware/zmk/pull/258) to allow users to toggle (on/off) the external power supplied by boards such as the nRFMicro +and nice!nano that have specialized hardware for this purpose. + +With this change, you can add + +```dts +&ext_power EP_TOG +``` + +to toggle (on/off) the power to external hardware like RGB underglow or OLEDs. Check out the [external power control](/docs/behaviors/power#external-power-control) docs for more info. + +#### Deep Sleep + +[petejohanson] has contributed the initial [deep sleep](https://github.com/zmkfirmware/zmk/pull/211) support to ZMK. This work also +included some automatic power savings by switching to PORT events on the nRF52 chips, which reduces the idle power draw, even without deep sleep. Deep sleep is currently not turned on by default, but will be soon. + +### Miscellaneous + +#### Output Selection + +[joelspadin] added [output selection](/docs/behaviors/outputs) to allow selecting whether to send output over USB or BLE if both are connected. This should now help avoid having "double keypresses" when your keyboard is plugged into a host. + +#### Bootloader Corruption Fix + +[Nicell] has already [blogged about this](/blog/2020/10/03/bootloader-fix), but for those that missed it, a _major_, and incredibly difficult to pin down bug involving corruption of the bootloader on devices using the Adafruit nRF52 bootloader has been fixed by [Nicell]. If you've encountered this bug, flashing the latest firmware should prevent it from reoccurring. Unfortunately, due to the nature of this fix, you will need to re-pair your keyboard with your hosts, as the fix involves changing where settings are stored in the flash of the controller. + +#### Official USB Product ID + +[petejohanson] has gotten an official [USB product ID](https://github.com/openmoko/openmoko-usb-oui/pull/15) assigned to the ZMK Firmware. For anyone looking to uniquely identify a USB device running the ZMK Firmware, you can match on: + +- Vendor ID: `0x1d50` +- Product ID: `0x615e` + +We are incredibly grateful that Openmoko Inc., in the wake of discontinuing the openmoko projects, has made this an option for OSS projects. + +#### Development: Remote Docker Container Integration + +[idan](https://github.com/idan) contributed [VSCode devcontainer integration](https://github.com/zmkfirmware/zmk/pull/209) to make it easier for developers to build and develop ZMK without having to do complicated local toolchain setup and configuration. This also opens up some amazing future flexibility for things like [GitHub Codespaces](https://twitter.com/ZMKFirmware/status/1315760616779505678?s=20). + +There's some follow up tweaks necessary for better supporting using this with user config repositories, which will be available soon. + +## New Shields + +- Reviung41 in [#297](https://github.com/zmkfirmware/zmk/pull/297) - [Nicell] +- Boardsource 3x4 in [#296](https://github.com/zmkfirmware/zmk/pull/296) - [neegool](https://github.com/neegool) +- NIBBLE in [#292](https://github.com/zmkfirmware/zmk/pull/292) - [jaygreco](https://github.com/jaygreco) +- Microdox in [#245](https://github.com/zmkfirmware/zmk/pull/245) - [careyk007](https://github.com/careyk007) +- MakerDiary M60 in [#233](https://github.com/zmkfirmware/zmk/pull/233) - [megamind4089] +- TGX4 in [#226](https://github.com/zmkfirmware/zmk/pull/226) - [mubeenkhan94](https://github.com/mubeenkhan94) +- Quefrency V1 in [#216](https://github.com/zmkfirmware/zmk/pull/216) - [noar-t](https://github.com/noar-t) +- Cradio in [#224](https://github.com/zmkfirmware/zmk/pull/224) - [davidphilipbarr](https://github.com/davidphilipbarr) +- Romac+ in [#198](https://github.com/zmkfirmware/zmk/pull/198) - [reizero00](https://github.com/reizero00) + +## New Boards + +- MakerDiary nRF52840 M.2 Module in [#233](https://github.com/zmkfirmware/zmk/pull/233) - [megamind4089] + +## Testing + +There has been an _amazing_ amount of testing from various users as we develop new features. In particular, we'd like to give a shout out to [tominabox1](https://github.com/tominabox1) who has been tireless in providing detailed and thorough testing of +changes as they are being developed. + +## Coming Soon! + +Some items listed in the last coming soon section are still under active development. + +- OLED work, including battery and USB/BLE connection status - [petejohanson] +- One shot mod/layer behaviors - [okke-formsma] +- A power profiler page for the website, to help users estimate their battery life for a given keyboard - [Nicell] +- A keymap converter to automatically update keymaps to the new codes and use of `&kp` everywhere - [joelspadin] + +## Statistics + +Some statistics of interest for ZMK: + +- GitHub (lifetime stats) + - 210 Closed PRs + - 116 Stars + - 101 Forks +- Discord Chat + - 363 total registered +- Website (last 30 days) + - 8.5K page views + - 766 new users + +## Thanks! + +Thanks again to the numerous contributors and users who have made working on ZMK such a pleasure! + +[okke-formsma]: https://github.com/okke-formsma +[nicell]: https://github.com/Nicell +[petejohanson]: https://github.com/petejohanson +[brainwart]: https://github.com/BrainWart +[innovaker]: https://github.com/innovaker +[megamind4089]: https://github.com/megamind4089 +[joelspadin]: https://github.com/joelspadin diff --git a/docs/blog/2021-01-27-zmk-sotf-4.md b/docs/blog/2021-01-27-zmk-sotf-4.md new file mode 100644 index 000000000000..823c4c5fdcad --- /dev/null +++ b/docs/blog/2021-01-27-zmk-sotf-4.md @@ -0,0 +1,198 @@ +--- +title: "ZMK State Of The Firmware #4" +author: Pete Johanson +author_title: Project Creator +author_url: https://gitlab.com/petejohanson +author_image_url: https://www.gravatar.com/avatar/2001ceff7e9dc753cf96fcb2e6f41110 +tags: [SOTF, keyboards, firmware, oss, ble] +--- + +Welcome to the fourth ZMK "State Of The Firmware" (SOTF)! + +This update will cover all the major activity since [SOTF #3](/blog/2020/11/09/zmk-sotf-3). + +## Recent Activity + +Here's a summary of the various major changes since last time, broken down by theme: + +### Keymaps/Behaviors + +Since last time, there have been several new powerful keymap features and behaviors added, including one of the most asked for features, combos! + +#### Combos + +The initial [combos](/docs/features/combos) work has landed! The amazing [okke-formsma] has once again delivered another powerful feature for ZMK. Combos are "position based", and are configured in a new toplevel node next to they `keymap` node in user's keymap files. + +An example, that would send the `ESC` keycode when pressing both the first and second positions on your keyboard: + +```dts +/ { + combos { + compatible = "zmk,combos"; + combo_esc { + timeout-ms = <50>; + key-positions = <0 1>; + bindings = <&kp ESC>; + }; + }; +}; +``` + +:::note +Combos currently are "global", and not scoped to a given active layer. There is future planned work to allow enabling a certain combo for only certain active layers. +::: + +#### Sticky Keys (One-Shot Mods/Layers) Behavior + +[okke-formsma] also contributed the initial "sticky keys" behavior, which can be used for functionality sometimes called "one shot mods" or "one shot layers". In your keymap, this would like like: + +```dts +&sk LEFT_CONTROL +``` + +for a sticky key/modifier, or: + +```dts +&sl NAV +``` + +for a sticky layer. + +#### `&to` Layer Behavior + +[mcrosson] contributed the new [`&to`](/docs/behaviors/layers#to-layer) layer related behavior. This can be used to completely replace the active layer with a new one. + +This is most frequently used when using multiple core base layers with different layouts, e.g. QWERTY and DVORAK, to switch between them. + +#### Grave Escape Behavior + +[okke-formsma] added an implementation of the "Grave Escape" behavior, developing a more generic "mod-morph" behavior to do so. Adding + +```dts +&gresc +``` + +to your keymap will send `ESC` when pressed on its own, but will send `` ` `` when pressed with a GUI or Shift modifier held. + +#### RGB Underglow Color Selection + +[mcrosson] updated the [RGB Underglow behavior](/docs/behaviors/underglow) to allow [binding an explicit color selection](/docs/behaviors/underglow#examples) to a key position. + +#### Keymap Upgrader + +[joelspadin] completed the [Keymap Upgrader](/docs/codes/keymap-upgrader) which can be used to update your keymap to using the latest supported codes, and move away from the old deprecated codes. + +If you've made keymap customizations, please make sure to run your keymaps through the upgrader, since the old deprecated codes will be removed in a future version of ZMK. + +### Displays + +There has been lots of work to get display support complete enough for use by end users. Although not quite ready for prime time, it is incredibly close, and we are looking forward to having the last few items completed and the feature documented! + +#### Idle Blanking + +[petejohanson] added idle blanking for displays, which ensures they will go blank, and into low power mode, after a short period of inactivity from the user. This ensures we avoid burn-in for OLEDs, and helps improve battery life. + +#### Battery and Output Widgets + +[petejohanson] implemented the first two complete, dynamic "widgets" for the displays for ZMK, adding a small battery indicator, which includes charging status, and a small output indicator, showing the currently active output (USB or BLE). When using BLE, the indicator also shows the active profile slot, as well as if the profile slot is open, awaiting connection from the paired host, or is actively connected to the host for that profile slot. + +#### Highest Layer Display + +[mcrosson] has contributed the next display widget, showing the highest active layer in the keymap. [petejohanson] then added a small follow up to allow layers in keymaps to add a `name` property to each layer, e.g. `name = "Nav";` and have that name be displayed in the widget instead of the numeric layer number. + +#### WPM + +New contributor [allymparker](https://github.com/allymparker) added our fourth widget, a words-per-minute display! This widget work also included creating the core state logic for tracking the WPM. + +For now, this widget is only working on the central side of split keyboards. + +### Miscellaneous + +#### Zephyr 2.4 + +[innovaker] is at it again with some crucial core fixes, helping prepare and test the upgrade of ZMK to Zephyr 2.4. The updated Zephyr release brings with it some key BLE stability fixes, as well as various other core improvements that improve ZMK. This was a huge undertaking! + +#### BLE Deadlock Fixes + +[petejohanson] was heads down diagnosing and fixing a deadlock issue on BLE that was frustrating and plaguing many users. After finally pinpointing the underlying root cause, he developed a fix and roped in many testers on Discord to help stress test things before merging. + +#### Central/Peripheral Selection + +Previously overriding the selection of left as central, and right as peripheral for wireless splits required making local edits to the configuration files, and maintaining them in a ZMK fork. + +[petejohanson] updated [the config files](https://github.com/zmkfirmware/zmk/pull/510) to allow users to override this in their `_left.conf`/`_right.conf` files in their user repos. + +#### Improved Docker Containers + +As part of the Zephyr 2.4. prep work, [innovaker], along with lots of testing and input from [mcrosson], developed a brand new pair of [Docker images](https://github.com/zmkfirmware/zmk-docker) which is now published to Docker Hub as [zmkfirmware/zmk-build-arm](https://hub.docker.com/repository/docker/zmkfirmware/zmk-build-arm) and [zmkfirmware/zmk-dev-arm](https://hub.docker.com/repository/docker/zmkfirmware/zmk-build-arm). + +The previously blogged VSCode + Docker integration, as well as our GH Action build automation was all moved over to the new images. + +#### Settings Debounce + +[nicell] contributed settings debounce work, to help avoid unnecessary extra writes to flash when making various changes that should be saved, +such as the active BLE profile, external VCC on/off, etc. + +## New Shields + +- Jorne & Jian in [#331](https://github.com/zmkfirmware/zmk/pull/331) - [krikun98](https://github.com/krikun98) +- tidbit in [#424](https://github.com/zmkfirmware/zmk/pull/424) - [mcrosson](https://github.com/mcrosson) +- Helix in [#429](https://github.com/zmkfirmware/zmk/pull/429) - [KingCoinless](https://github.com/KingCoinless) +- BFO-9000 in [#472](https://github.com/zmkfirmware/zmk/pull/472) - [pbz](https://github.com/pbz) +- CRBN in [#493](https://github.com/zmkfirmware/zmk/pull/483) - [ReFil](https://github.com/ReFil) +- Eek in [#529](https://github.com/zmkfirmware/zmk/pull/529) - [MangoIV](https://github.com/MangoIV) + +## New Boards + +- BDN9 Rev2 in [#557](https://github.com/zmkfirmware/zmk/pull/557) - [petejohanson] + +## Sponsorship + +Since it's inception, quite a few users have inquired whether they could sponsor any of the contributors involved in ZMK. Although we are not intending to directly fund any individual contributors for their work on ZMK, there _is_ good that can come from folks sponsoring ZMK. + +You can see the full discussion on [#497](https://github.com/zmkfirmware/zmk/issues/497), but some items that are being considered with sponsorship funds: + +- Hiring a designer to complete the logo/mascot work. +- Creating stickers to send as thank-yous to first time contributors. +- Hosting costs for GitHub Pro. +- Other hosting costs, e.g. Docker Hub. + +For anyone looking to contribute, you can find the [ZMK Firmware project](https://opencollective.com/zmkfirmware) is now set up on [Open Collective](https://opencollective.com). + +## Coming Soon! + +Some items listed in the last coming soon section are still under active development. + +- A power profiler page for the website, to help users estimate their battery life for a given keyboard - [Nicell] +- Behavior "locality", allowing improved split usage for things like `&sys_reset`, and controlling external power and RGB underglow for both sides - [petejohanson] +- More modular approach to external boards/shields, custom code, user keymaps, etc. +- More shields and boards + +## Statistics + +Some statistics of interest for ZMK: + +- GitHub (lifetime stats) + - 389 Closed PRs + - 199 Stars + - 163 Forks +- Discord Chat + - 702 total registered +- Website (last 30 days) + - 11.5K page views + - 1K new users + +## Thanks! + +Thanks again to the numerous contributors, testers, and users who have made working on ZMK such a pleasure! + +[okke-formsma]: https://github.com/okke-formsma +[mcrosson]: https://github.com/mcrosson +[nicell]: https://github.com/Nicell +[petejohanson]: https://github.com/petejohanson +[innovaker]: https://github.com/innovaker +[joelspadin]: https://github.com/joelspadin + +## Article Updates + +- 12/2023: The `label` property for keymap layers was renamed to `display-name`. diff --git a/docs/blog/2021-07-17-zephyr-2-5.md b/docs/blog/2021-07-17-zephyr-2-5.md new file mode 100644 index 000000000000..153027bb4cd7 --- /dev/null +++ b/docs/blog/2021-07-17-zephyr-2-5.md @@ -0,0 +1,75 @@ +--- +title: "Zephyr 2.5 Update" +author: Pete Johanson +author_title: Project Creator +author_url: https://gitlab.com/petejohanson +author_image_url: https://www.gravatar.com/avatar/2001ceff7e9dc753cf96fcb2e6f41110 +tags: [firmware, zephyr, core] +--- + +I'm happy to announce that we have completed the [work](https://github.com/zmkfirmware/zmk/pull/736/) to upgrade ZMK to [Zephyr 2.5](https://docs.zephyrproject.org/2.5.0/releases/release-notes-2.5.html)! + +A big part of this work was some _major_ refactors and improvements by [innovaker] to our [zmk-docker](https://github.com/zmkfirmware/zmk-docker/) Docker image and GH Actions automation. + +- Faster build times with improved caching. +- Integration tests which automatically verify new images. +- PRs to the repo now build properly and run the tests as well. +- Build images for multiple target architectures, e.g. `zmk-build-riscv64`, all in parallel. +- Nightly builds to be sure we're pulling in the latest OS/package updates, to ensure we keep our images up to date, address any reported vulnerabilities, etc. +- Faster upgrade paths for future Zephyr SDK and Zephyr versions. + +In addition, [petejohanson] did the upgrade work to adjust ZMK for the Zephyr changes. + +- Updated to newer devicetree/driver Zephyr API +- Adjustment for Zephyr pinmux changes +- Fixes for power management, LVGL, and formatter changes + +## Getting The Changes + +Use the following steps to update to the latest tooling in order to properly use the new ZMK changes: + +### User Config Repositories Using GitHub Actions + +Existing user config repositories using Github Actions to build will pull down Zephyr 2.5 automatically, +and should work, fine as is. However, to upgrade to the newer Docker image, you should: + +- Open `.github/workflows/build.yml` in your editor/IDE +- Change `zmkfirmware/zmk-build-arm:2.4` to `zmkfirmware/zmk-build-arm:2.5` wherever it is found + +:::note + +If you created your user config repository a while ago, you may find that your `build.yml` file instead references +a `zephyr-west-action-arm` custom GitHub Action instead. In this case, the upgrade is not as direct. We suggest that +instead you [re-create your config repository](/docs/user-setup) to get an updated setup using the new automation +approach. + +::: + +### VS Code & Docker (Dev Container) + +If you build locally using VS Code & Docker then: + +- pull the latest ZMK `main` with `git pull` for your ZMK checkout +- reload the project +- if you are prompted to rebuild the remote container, click `Rebuild` +- otherwise, press `F1` and run `Remote Containers: Rebuild Container` +- Once the container has rebuilt and reloaded, run `west update` to pull the updated Zephyr version and its dependencies. + +Once the container has rebuilt, VS Code will be running the 2.5 Docker image. + +### Local Host Development + +The following steps will get you building ZMK locally against Zephyr 2.5: + +- Run the updated [toolchain installation](/docs/development/setup#toolchain-installation) steps, and once completed, remove the previously installed SDK version (optional, existing SDK should still work) +- pull the latest ZMK `main` with `git pull` for your ZMK checkout +- run `west update` to pull the updated Zephyr version and its dependencies + +From there, you should be ready to build as normal! + +## Thanks! + +Thanks again to [innovaker] for all the hard work, and to all the testers who have helped verify ZMK functionality on the newer Zephyr version. + +[petejohanson]: https://github.com/petejohanson +[innovaker]: https://github.com/innovaker diff --git a/docs/blog/2022-03-08-zephyr-3-0-upgrade-prep.md b/docs/blog/2022-03-08-zephyr-3-0-upgrade-prep.md new file mode 100644 index 000000000000..2f3c79eef953 --- /dev/null +++ b/docs/blog/2022-03-08-zephyr-3-0-upgrade-prep.md @@ -0,0 +1,29 @@ +--- +title: "Zephyr 3.0 Update Preparation" +author: Pete Johanson +author_title: Project Creator +author_url: https://gitlab.com/petejohanson +author_image_url: https://www.gravatar.com/avatar/2001ceff7e9dc753cf96fcb2e6f41110 +tags: [firmware, zephyr, core] +--- + +As preparation for completing the [work](https://github.com/zmkfirmware/zmk/pull/1143) to upgrade ZMK to [Zephyr 3.0](https://docs.zephyrproject.org/3.0.0/releases/release-notes-3.0.html), users with user config repositories who wish to avoid future build failures with their GitHub Actions workflows can take steps to adjust +their repositories now. + +GitHub Actions needs to use our latest Docker image to ensure continued compatibility with the ZMK codebase on Zephyr 3.0 (and beyond). You should: + +- Open `.github/workflows/build.yml` in your editor/IDE +- Change `zmkfirmware/zmk-build-arm:2.5` to `zmkfirmware/zmk-build-arm:stable` wherever it is found + +Once the changes are committed and pushed, the build will run as expected. + +A future blog post will outline the complete Zephyr 3.0 changes once that work is finalized. + +:::note + +If you created your user config repository a while ago, you may find that your `build.yml` file instead references +a `zephyr-west-action-arm` custom GitHub Action instead. In this case, the upgrade is not as direct. We suggest that +instead you [re-create your config repository](/docs/user-setup) to get an updated setup using the new automation +approach. + +::: diff --git a/docs/blog/2022-04-02-zephyr-3-0.md b/docs/blog/2022-04-02-zephyr-3-0.md new file mode 100644 index 000000000000..3b16b87ea781 --- /dev/null +++ b/docs/blog/2022-04-02-zephyr-3-0.md @@ -0,0 +1,229 @@ +--- +title: "Zephyr 3.0 Update" +author: Pete Johanson +author_title: Project Creator +author_url: https://gitlab.com/petejohanson +author_image_url: https://www.gravatar.com/avatar/2001ceff7e9dc753cf96fcb2e6f41110 +tags: [firmware, zephyr, core] +--- + +I'm happy to announce that we have completed the [work](https://github.com/zmkfirmware/zmk/pull/1143) to upgrade ZMK to [Zephyr 3.0](https://docs.zephyrproject.org/3.0.0/releases/release-notes-3.0.html)! + +[petejohanson] did the upgrade work to adjust ZMK for the Zephyr changes. + +- Moving to Zephyr's UF2 build integration that was submitted upstream by [petejohanson] +- Additional `color-mapping` property needed for ws2812 LED strep devicetree nodes +- Zephyr core API changes, including delayed work, USB/HID +- Adjust for pinctrl changes on stm32 +- Fixes for power management and log formatter changes + +## Getting The Changes + +Use the following steps to update to the latest tooling in order to properly use the new ZMK changes: + +### User Config Repositories Using GitHub Actions + +Existing user config repositories using Github Actions to build will pull down Zephyr 3.0 automatically, however to build properly, the repository needs to be updated to use the `stable` Docker image tag for the build: + +- Open `.github/workflows/build.yml` in your editor/IDE +- Change `zmkfirmware/zmk-build-arm:2.5` to `zmkfirmware/zmk-build-arm:stable` wherever it is found +- Locate and delete the lines for the DTS output step, which is no longer needed: + + ```yaml + - name: ${{ steps.variables.outputs.display-name }} DTS File + if: ${{ always() }} + run: | + if [ -f "build/zephyr/${{ matrix.board }}.pre.tmp" ]; then cat -n build/zephyr/${{ matrix.board }}.pre.tmp; fi + if [ -f "build/zephyr/zephyr.dts" ]; then cat -n build/zephyr/zephyr.dts; fi + ``` + +:::note + +If you created your user config repository a while ago, you may find that your `build.yml` file instead references +a `zephyr-west-action-arm` custom GitHub Action instead. In this case, the upgrade is not as direct. We suggest that +instead you [re-create your config repository](/docs/user-setup) to get an updated setup using the new automation +approach. + +::: + +### VS Code & Docker (Dev Container) + +If you build locally using VS Code & Docker then: + +- pull the latest ZMK `main` with `git pull` for your ZMK checkout +- reload the project +- if you are prompted to rebuild the remote container, click `Rebuild` +- otherwise, press `F1` and run `Remote Containers: Rebuild Container` +- Once the container has rebuilt and reloaded, run `west update` to pull the updated Zephyr version and its dependencies. + +Once the container has rebuilt, VS Code will be running the 3.0 Docker image. + +### Local Host Development + +The following steps will get you building ZMK locally against Zephyr 3.0: + +- Run the updated [toolchain installation](/docs/development/setup#toolchain-installation) steps, and once completed, remove the previously installed SDK version (optional, existing SDK should still work) +- pull the latest ZMK `main` with `git pull` for your ZMK checkout +- run `west update` to pull the updated Zephyr version and its dependencies + +From there, you should be ready to build as normal! + +## Board/Shield Changes + +The following changes have [already been completed](https://github.com/zmkfirmware/zmk/pull/1143/commits) for all boards/shields in ZMK `main` branch. For existing or new PRs, or out of tree boards, the following changes are necessary to properly work with the latest changes. + +### RGB Underglow + +Zephyr's WS2812 `led_strip` driver added a new required property. When adding [underglow](/docs/features/underglow#adding-rgb-underglow-to-a-board) to a board, you now must also add the additional include `#include ` at the top of your devicetree file, and add a `color-mapping` property like: + +```dts +led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* number of LEDs */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + color-mapping = ; +}; +``` + +:::note + +Standard WS2812 LEDs use a wire protocol where the bits for the colors green, red, and blue values are sent in that order. +If your board/shield uses LEDs that require the data sent in a different order, the `color-mapping` property ordering should be changed to match. + +::: + +### Display Selection + +Zephyr moved to using a `chosen` node named `zephyr,display` to select the display device to be used with LVGL, the underlying display library we use. + +For example, for a shield with: + +```dts +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + com-invdir; + segment-remap; + com-sequential; + prechargep = <0x22>; + }; +}; +``` + +You would add a `chosen` node like: + +```dts +/ { + chosen { + zephyr,display = &oled; + }; +}; +``` + +### USB Logging + +Zephyr unified the way the console/logging device is selected, removing the hacks that special-cased the USB CDC ACM output. +Now, the CDC ACM device is configured in the devicetree as well. To ensure that USB logging properly works with custom board definitions, +two sections of the `.dts` file need updating. + +Underneath the USB device, add the CDC ACM node: + +```dts +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; +``` + +Then, an additional `chosen` node (near the top of the file) will mark the CDC ACM device as the console: + +```dts +/ { + chosen { + ... + zephyr,console = &cdc_acm_uart; + }; + ... +}; +``` + +### UF2 Builds + +Previously, to get ZMK to build a UF2 image to flash to a given board required adding a `CMakeLists.txt` file that added a custom post build command. +Now, the only thing necessary to have Zephyr build a UF2 is to add the following to your `_defconfig` file: + +```ini +CONFIG_BUILD_OUTPUT_UF2=y +``` + +If updating an existing board, be sure to remove the previous `CMakeLists.txt` file to avoid generating the UF2 twice during a `west build`. + +For more details on the implementation, see [zephyr#31066](https://github.com/zephyrproject-rtos/zephyr/pull/31066). + +### STM32 Clock Configuration + +Clock configuration moved to devicetree as well, out of the Kconfig files. Here is a sample config for a board that uses the HSI for the PLL source: + +```dts +&clk_hsi { + status = "okay"; +}; + +&pll { + prediv = <1>; + mul = <12>; + clocks = <&clk_hsi>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <2>; +}; +``` + +After adding the nodes, be sure to remove the clock/PLL related configuration from the `_defconfig` file. + +## Seeeduino XIAO + +The Seeed(uino) XIAO has gained in popularity for use on smaller boards, and gained more traction with the release of the new XIAO BLE board, +powered by the popular nRF52840 SoC. As part of the 3.0 update, we've also more fully integrated the XIAO and XIAO BLE to make it easier to +build keyboard (shields) using either controller. + +## Future Hardware + +One of the exciting items that's one step closer as part of this work is [support for Raspberry Pi Pico/RP2040](https://github.com/zmkfirmware/zmk/issues/1085). +With Zephyr 3.0 merged, this start the process for getting those controllers/chips supported by ZMK. Follow the issue to keep track of progress. +This will also enable us to support the XIAO compatible Adafruit Qt Py RP2040 and XIAO RP2040. + +## Thanks! + +Thanks to all the testers who have helped verify ZMK functionality on the newer Zephyr version. + +[petejohanson]: https://github.com/petejohanson + +## Article Updates + +- 12/2023: Removed the deprecated `label` property from code snippets. diff --git a/docs/blog/2022-04-10-zmk-sotf-5.md b/docs/blog/2022-04-10-zmk-sotf-5.md new file mode 100644 index 000000000000..43cb4e672097 --- /dev/null +++ b/docs/blog/2022-04-10-zmk-sotf-5.md @@ -0,0 +1,268 @@ +--- +title: "ZMK State Of The Firmware #5" +author: Pete Johanson +author_title: Project Creator +author_url: https://gitlab.com/petejohanson +author_image_url: https://www.gravatar.com/avatar/2001ceff7e9dc753cf96fcb2e6f41110 +tags: [SOTF, keyboards, firmware, oss, ble] +--- + +Welcome to the fifth ZMK "State Of The Firmware" (SOTF)! + +This update will cover all the major activity since [SOTF #4](/blog/2021/01/27/zmk-sotf-4). That was over a year ago, so lots to cover! + +## Recent Activity + +Here's a summary of the various major changes since last time, broken down by theme: + +### Keymaps/Behaviors + +Since last time, there have been several new powerful keymap features and behaviors added, including several asked for features, such as tap-dance and macros. + +#### Caps Word + +[petejohanson] added the [caps word](/docs/behaviors/caps-word) behavior, i.e. `&caps_word`, in [#823](https://github.com/zmkfirmware/zmk/pull/823) that allows toggling a mode where all all alpha characters are sent +to the host capitalized until a non-alpha, non-"continue list" keycode is sent. This can be useful for typing things like `CONFIG_ENABLE_CAPS_WORD` without having to hold down shift. This is similar in spirit to using the caps lock key, but with the added benefit of turning itself off automatically. + +#### Key Repeat + +[petejohanson] added the new [key repeat](/docs/behaviors/key-repeat) behavior in [#1034](https://github.com/zmkfirmware/zmk/pull/1034) to allow repeating the last sent key-press again, including any modifiers that were applied to that key press. It can be added to your keymap using the simple `&key_repeat` reference. + +#### Macros + +[petejohanson], taking heavy inspiration on the initial work from [okke-formsma], added [macro support](/docs/behaviors/macros) in [#1168](https://github.com/zmkfirmware/zmk/pull/1166). Several [common patterns](/docs/behaviors/macros#common-patterns) are documented, but one example, changing the underglow color as you activate/deactivate a layer, looks like: + +```dts +ZMK_MACRO(layer_color_macro, + wait-ms = <0>; + tap-ms = <0>; + bindings + = <¯o_press &mo 1> + , <¯o_tap &rgb_ug RGB_COLOR_HSB(128,100,100)> + , <¯o_pause_for_release> + , <¯o_release &mo 1> + , <¯o_tap &rgb_ug RGB_COLOR_HSB(300,100,50)>; +) +``` + +#### Tap Dance + +[kurtis-lew] worked diligently to add the [tap-dance behavior](/docs/behaviors/tap-dance) in [#1139](https://github.com/zmkfirmware/zmk/pull/1139), allowing different behaviors to be invoked based on the number of times +a user taps a single key in their keymap, e.g. + +```dts +/ { + behaviors { + td0: tap_dance_0 { + compatible = "zmk,behavior-tap-dance"; + #binding-cells = <0>; + tapping-term-ms = <200>; + bindings = <&kp N1>, <&kp N2>, <&kp N3>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &td0 + >; + }; + }; +}; +``` + +#### Conditional Layers + +[bcat] added [conditional layers](/docs/features/conditional-layers) in [#830](https://github.com/zmkfirmware/zmk/pull/830) as a generalized version of the common "adjust layer" pattern on smaller keyboards. + +Example: + +```dts +/ { + conditional_layers { + compatible = "zmk,conditional-layers"; + tri_layer { + if-layers = <1 2>; + then-layer = <3>; + }; + }; +}; +``` + +#### Combos + +[mcrosson] added the [layer specific combos](https://zmk.dev/docs/features/combos#configuration) in [#661](https://github.com/zmkfirmware/zmk/pull/661), so users can make certain combos only triggerable when the layers set for the combo are active. + +This is used by the [ZMK implementation](https://github.com/artseyio/zmk-artsey) of [ARTSEY](https://artsey.io/) extensively. + +#### Sticky Keys + +[okke-formsma] updated [sticky keys](/docs/behaviors/sticky-key) in [#1122](https://github.com/zmkfirmware/zmk/pull/1122) to add the `ignore-modifiers;` property; when set, sticky keys won't release when other modifiers are pressed. This allows you to combine sticky modifiers, which is popularly used with ["callum-style mods"](https://github.com/callum-oakley/qmk_firmware/tree/master/users/callum#oneshot-modifiers). + +#### Hold-Tap Improvements + +[jmding8](https://github.com/jmding8) added an additional [positional hold-tap configuration](https://zmk.dev/docs/behaviors/hold-tap#positional-hold-tap-and-hold-trigger-key-positions) in [#835](https://github.com/zmkfirmware/zmk/pull/835) to help certain sequences produce the expected results. + +[jmding8](https://github.com/jmding8) also added an additional [hold-tap flavor: `tap-unless-interrupted`](https://zmk.dev/docs/behaviors/hold-tap#flavors) in [#1018](https://github.com/zmkfirmware/zmk/pull/1018) which works very well with the new positional hold-tap config. + +[okke-formsma] implemented [`retro-tap` hold-tap property](https://zmk.dev/docs/behaviors/hold-tap#retro-tap) in [#667](https://github.com/zmkfirmware/zmk/pull/667) + +[okke-formsma] _also_ added [`quick-tap-ms` hold-tap property](https://zmk.dev/docs/behaviors/hold-tap#quick-tap-ms) in [#655](https://github.com/zmkfirmware/zmk/pull/655) + +### Apple Device Compatibility Improvements + +#### Pairing + +[petejohanson] did some sleuthing and fixed a long standing problem with inconsistent pairing with macOS in [#946]](https://github.com/zmkfirmware/zmk/pull/946). With the changes, macOS more reliably pairs with ZMK devices. + +#### Consumer (Media) Codes + +Another persistent bug that Apple users experienced was related to crashes and problems with keyboard configurations, that was traced to an issue with ZMK's HID usage that was fixed by [petejohanson] in [#726](https://github.com/zmkfirmware/zmk/pull/726). + +### Debounce Enhancements + +[joelspadin] applied some major enhancements to our [debouncing](/docs/features/debouncing) approach to allow fine grained control of our debouncing in [#888](https://github.com/zmkfirmware/zmk/pull/888), including allowing [eager debouncing](/docs/features/debouncing#eager-debouncing) which can reduce key press latency. + +### Split Improvements + +#### Behavior Locality + +The long awaited locality enhancement was finally merged by [petejohanson] in [#547](https://github.com/zmkfirmware/zmk/pull/547), allowing more fine grained control of where certain behaviors are invoked. Some key improvements thanks to the changes: + +- [RGB Underglow](/docs/features/underglow) behaviors now run globally, so enabling/disabling RGB, changing the color, animation, etc. applies to both sides of a split properly. +- [Reset](/docs/behaviors/reset#reset)/[Bootloader](/docs/behaviors/reset#bootloader) behaviors now run wherever the key was pressed. For example, adding a `&bootloader` reference to the peripheral side of a split will now put that side of the split into the bootloader when pressed. + +#### Split Connections + +[petejohanson] also added fixes to improve split re-connection for certain scenarios in [#984](https://github.com/zmkfirmware/zmk/pull/984), helping ensure splits properly connect when one side or the other is reset. + +### Hardware Support + +#### Backlight + +[bortoz](https://github.com/bortoz) added [single color backlight support](/docs/features/backlight) in [#904](https://github.com/zmkfirmware/zmk/pull/904) for those keyboards that have it as an alternative to RGB underglow. + +#### E-Paper Display (EPD) Driver + +[petejohanson] worked with [LOWPROKB](https://github.com/LOWPROKB) to add support for the E-Paper Displays (EPD) in [#895](https://github.com/zmkfirmware/zmk/pull/895) used in keyboards like the Corne-ish Zen. + +#### nRF VDDH Battery Sensing + +[joelspadin] added a new sensor driver to support battery charge calculation by sensing voltage on the VDDH pin on nRF52 chips in [#750](https://github.com/zmkfirmware/zmk/pull/750), which is particularly useful for designs +using "high voltage mode" with that SoC. + +### Miscellaneous + +#### Documentation + +[dxmh] and [caksoylar](https://github.com/caksoylar) have joined the ZMK organization to help with documentation, and have been doing an amazing job adding new docs, and leading reviewing docs related PRs to free other contributors up to focus on other areas. It's been an incredible addition to ZMK! + +#### NKRO Support + +[petejohanson]'s work on the HID foundation also included adding support for full NKRO HID in [#726](https://github.com/zmkfirmware/zmk/pull/726) that can be enabled by adding the following to your `.conf` file for your config: + +```ini +CONFIG_ZMK_HID_REPORT_TYPE_NKRO=y +``` + +#### Power Profiler + +It's been live for a while, but [nicell] added an amazing [power profiler](/power-profiler) in [#312](https://github.com/zmkfirmware/zmk/pull/312) to allow users to estimate their battery life for various hardware configurations. + +#### Min/Max Underglow Brightness + +[malinges](https://github.com/malinges) added support for configuring min/max underglow brightness in [#944](https://github.com/zmkfirmware/zmk/pull/944) by setting the values in your `.conf` file as percentages of full: + +```ini +CONFIG_ZMK_RGB_UNDERGLOW_BRT_MIN=20 +CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX=80 +``` + +This can be useful to be sure that lowering brightness doesn't set the brightness to zero, and raising the brightness doesn't consume too much power. + +#### Zephyr 3.0 + +[petejohanson] helped prepare and test the upgrade of ZMK to Zephyr 3.0 in [#1143](https://github.com/zmkfirmware/zmk/pull/1143). The updated Zephyr release brings with it some key BLE stability fixes, as well as various other core improvements that improve ZMK. This was a huge undertaking! + +## New Shields + +- Contra in [#633](https://github.com/zmkfirmware/zmk/pull/633) - [iangus](https://github.com/iangus) +- Naked60 in [#681](https://github.com/zmkfirmware/zmk/pull/681) - [xiushak](https://github.com/xiushak) +- Murphpad in [#806](https://github.com/zmkfirmware/zmk/pull/806) - [kylemccreery](https://github.com/kylemccreery) +- A. Dux in [#951](https://github.com/zmkfirmware/zmk/pull/951) - [dxmh] +- Bat43 in [#956](https://github.com/zmkfirmware/zmk/pull/956) - [dnaq](https://github.com/dnaq) +- Zodiark in [#959](https://github.com/zmkfirmware/zmk/pull/959) - [Aleblazer](https://github.com/Aleblazer) +- Osprette in [#974](https://github.com/zmkfirmware/zmk/pull/974) - [smores56](https://github.com/smores56) +- Knob Goblin in [#990](https://github.com/zmkfirmware/zmk/pull/990) - [lucasuyezu](https://github.com/lucasuyezu) +- Redox in [#1002](https://github.com/zmkfirmware/zmk/pull/1002) - [toddmok](https://github.com/toddmok) +- Elephant42 in [#1009](https://github.com/zmkfirmware/zmk/pull/1009) - [filoxo](https://github.com/filoxo) +- Chalice in [#1022](https://github.com/zmkfirmware/zmk/pull/1022) - [joshajohnson](https://github.com/joshajohnson) +- Boardsource 5x12 in [#1027](https://github.com/zmkfirmware/zmk/pull/1027) - [fsargent](https://github.com/fsargent) +- Jiran in [#1048](https://github.com/zmkfirmware/zmk/pull/1048) - [krikun98](https://github.com/krikun98) +- keeb.io Fourier in [#1056](https://github.com/zmkfirmware/zmk/pull/1056) - [TheButlah](https://github.com/TheButlah) +- Lotus58 in [#1090](https://github.com/zmkfirmware/zmk/pull/1090) - [nettema](https://github.com/nettema) +- Clog in [#1092](https://github.com/zmkfirmware/zmk/pull/1092) - [smores56](https://github.com/smores56) +- Kyria rev2 in [#1112](https://github.com/zmkfirmware/zmk/pull/1112) - [petejohanson] +- Leeloo in [#1165](https://github.com/zmkfirmware/zmk/pull/1165) - [ClicketySplit](https://github.com/ClicketySplit) +- 2% Milk in [#1135](https://github.com/zmkfirmware/zmk/pull/1135) - [kurtis-lew] + +## New Boards + +- Ferris rev02 in [#642](https://github.com/zmkfirmware/zmk/pull/642) - [petejohanson] +- nice!60 in [#810](https://github.com/zmkfirmware/zmk/pull/810) - [nicell] +- nice!nano v2 in [#867](https://github.com/zmkfirmware/zmk/pull/867) - [nicell] +- Mikoto 520 in [#985](https://github.com/zmkfirmware/zmk/pull/985) - [mrninhvn](https://github.com/mrninhvn) +- S40NC in [#1021](https://github.com/zmkfirmware/zmk/pull/1021) - [kylemccreery](https://github.com/kylemccreery) +- BT60 in [#1029](https://github.com/zmkfirmware/zmk/pull/1029) - [ReFil](https://github.com/ReFil) +- Seeeduino XIAO BLE (as part of the Zephyr 3.0 work) in [#1143](https://github.com/zmkfirmware/zmk/pull/1143) - [petejohanson] + +## Board/Shield Metadata + +[nicell] and [petejohanson] worked together in [#883](https://github.com/zmkfirmware/zmk/pull/883) to settle on a [metadata format](/docs/development/hardware-metadata-files) that is used to document every board and shield. This now drives automatic generation of our [supported hardware](/docs/hardware) page and our +more nuanced GH Actions automation for testing changes to ZMK. + +## Coming Soon! + +Some items listed in the last coming soon section are still under active development. + +- RP2040 support +- Peripheral rotary encoder support +- Caps/Scroll/Num Lock LED support +- Mouse Keys +- Wired split support +- More modular approach to external boards/shields, custom code, user keymaps, etc. +- More shields and boards + +## Statistics + +Some statistics of interest for ZMK: + +- GitHub (lifetime stats) + - 105 Contributors + - 791 Closed PRs + - 849 Stars + - 832 Forks +- Discord Chat + - 3430 total registered +- Website (last 30 days) + - 35.9K page views + - 3.29K new users + +## Thanks! + +As we approach the two year birthday for ZMK, I am reminded of how far we have come in such a short time, in large part thanks to the _amazing_ community that has grown around it. I am so grateful to have so many contributors, testers, and user believing in the project and helping make it a joy to work on. + +[okke-formsma]: https://github.com/okke-formsma +[mcrosson]: https://github.com/mcrosson +[nicell]: https://github.com/Nicell +[petejohanson]: https://github.com/petejohanson +[kurtis-lew]: https://github.com/kurtis-lew +[joelspadin]: https://github.com/joelspadin +[bcat]: https://github.com/bcat +[dxmh]: https://github.com/dxmh + +## Article Updates + +- 12/2023: Removed the deprecated `label` property from code snippets. diff --git a/docs/blog/2022-04-21-zmk-2yo.md b/docs/blog/2022-04-21-zmk-2yo.md new file mode 100644 index 000000000000..6ebadb960a62 --- /dev/null +++ b/docs/blog/2022-04-21-zmk-2yo.md @@ -0,0 +1,71 @@ +--- +title: "ZMK's Second Birthday" +author: Pete Johanson +author_title: Project Creator +author_url: https://gitlab.com/petejohanson +author_image_url: https://www.gravatar.com/avatar/2001ceff7e9dc753cf96fcb2e6f41110 +tags: [keyboards, firmware, oss] +--- + +Two years ago, today, I minted the first ever commit for ZMK: + +``` +commit 85c8be89dea8f7a00e8efb06d38e2b32f3459935 +Author: Pete Johanson +Date: Tue Apr 21 16:20:34 2020 -0400 + + Initial work. + + .gitignore | 1 + + .gitmodules | 3 +++ + CMakeLists.txt | 40 +++++++++++++++++++++++++++++++++++++++ + src/main.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + src/zmk_lib.h | 7 +++++++ + zephyr-rust | 1 + + 6 files changed, 112 insertions(+) +``` + +I will never forget that commit. Not because of the code it contained (please don't look, it's not worth it!), but for what it started. + +Working on ZMK has given me the opportunity to reconnect with old friends ([@brixmeister](https://twitter.com/brixmeister) was my Gentoo mentor/sponsor when I became a contributor there on my first ever OSS project, and is a current active Zephyr RTOS contributor!), make new ones, and learn so much from the amazing mechanical keyboard community. + +## First Keyboard + +But I'm getting ahead of myself! Back to early ZMK. I present you the first ZMK keyboard: + +![stm32wb55rg dev kit keyboard](assets/2022-04-21-zmk-2yo/first-zmk-keyboard.jpg) + +That first "keyboard" taught me a _lot_. It forced me to dust off my long forgotten, rudimentary electronics knowledge, and gave me my first taste of really combining the physical/tangible with code in a way that years of doing backend API development never had. + +I was _hooked_. + +## Zephyr RTOS + +Early in my brainstorming, I knew I needed a foundation to build upon that would get me "a lot for free." I evaluated several different real-time operating systems (RTOSes) and happened upon [Zephyr](https://zephyrproject.org/). It immediately ticked all the boxes I wanted: + +- Robust, open source Bluetooth stack, supporting multiple SoCs. At the time, I was trying out stm32wb thanks to some interest among keyboard designers, but I also so there were other compelling choices that might be a good fit. +- An open source, non-copyleft license. I am a firm believer in F/OSS, and wanted to use a license that was as unrestricted as possible. +- Had a lot of core APIs available, so I could focus on the keyboard functionality, not the plumbing. I love tinkering, but I wanted to focus my time on the interesting bits, not infrastructure. + +I'm really happy with the choice, it has served us incredibly well the past two years. + +## Real Keyboard + +At some point, somehow, [innovaker] introduced me to [nicell] who graciously sent me a few of the early pre-production nice!nano controllers, which I was able to get running on my Kyria. Doing so required the first split code, as well as lots of general improvements. + +![kyria keyboard](assets/2022-04-21-zmk-2yo/kyria-first-split.jpg) + +The day I was finally able to type on a wireless, split keyboard running ZMK was deeply momentous for me! + +## Onward and Upward + +We've come a long way since then, with our [supported hardware](/docs/hardware), [features](/docs/features/keymaps) and [behaviors](/docs/behaviors/key-press) growing regularly. + +ZMK powered keyboards are now available in group buys and in stock at various vendors; compatible controllers have been used in a wide range of builds to empower our users to free themselves from their USB/TRRS cables and move about untethered. + +This progress is only possible thanks to all of the contributors who've joined me in the vision for a wireless-first world. I am so grateful for everyone who has given their time to contribute code, answer questions on our Discord server, write more documentation, and especially all the users who have trusted us to make their input devices work. + +I can't wait to see what we can accomplish together in the next two years. + +[innovaker]: https://github.com/innovaker +[nicell]: https://github.com/Nicell diff --git a/docs/blog/2023-04-06-zephyr-3-2.md b/docs/blog/2023-04-06-zephyr-3-2.md new file mode 100644 index 000000000000..69ecb6dd032c --- /dev/null +++ b/docs/blog/2023-04-06-zephyr-3-2.md @@ -0,0 +1,303 @@ +--- +title: "Zephyr 3.2 Update" +author: Pete Johanson +author_title: Project Creator +author_url: https://gitlab.com/petejohanson +author_image_url: https://www.gravatar.com/avatar/2001ceff7e9dc753cf96fcb2e6f41110 +tags: [firmware, zephyr, core] +--- + +I'm happy to announce that we have completed the [work](https://github.com/zmkfirmware/zmk/pull/1499) to upgrade ZMK to [Zephyr 3.2](https://docs.zephyrproject.org/3.2.0/releases/release-notes-3.2.html)! + +[petejohanson] did the upgrade work to adjust ZMK for the Zephyr changes, with help from [Nicell] on the LVGL pieces. + +- Upgrade to LVGL 8.x API, and move to the new Kconfig settings. +- Tons of RP2040 work. +- Zephyr core API changes, including DTS `label` use changes. +- Move to [pinctrl](https://docs.zephyrproject.org/3.2.0/hardware/pinctrl/index.html) Zephyr subsystem. + +## Getting The Changes + +Use the following steps to update to the latest tooling in order to properly use the new ZMK changes: + +### User Config Repositories Using GitHub Actions + +Existing user config repositories using Github Actions to build will pull down Zephyr 3.2 automatically, however if you created your user config a while ago, you may need to update it to reference our shared build configuration to leverage the correct Docker image. + +1. Replace the contents of your `.github/workflows/build.yml` with: + + ```yaml + on: [push, pull_request, workflow_dispatch] + + jobs: + build: + uses: zmkfirmware/zmk/.github/workflows/build-user-config.yml@main + ``` + +1. If it doesn't exist already, add a new file to your repository named `build.yaml`: + + ```yaml + # This file generates the GitHub Actions matrix + # For simple board + shield combinations, add them + # to the top level board and shield arrays, for more + # control, add individual board + shield combinations to + # the `include` property, e.g: + # + # board: [ "nice_nano_v2" ] + # shield: [ "corne_left", "corne_right" ] + # include: + # - board: bdn9_rev2 + # - board: nice_nano_v2 + # shield: reviung41 + # + --- + ``` + +and then update it as appropriate to build the right shields/boards for your configuration. + +### Upgrade a manual script + +If you have a custom GitHub Actions workflow you need to maintain for some reason, you can update the workflow to to use the `stable` Docker image tag for the build: + +- Open `.github/workflows/build.yml` in your editor/IDE +- Change `zmkfirmware/zmk-build-arm:2.5` to `zmkfirmware/zmk-build-arm:stable` wherever it is found +- Locate and delete the lines for the DTS output step, which is no longer needed: + + ```yaml + - name: ${{ steps.variables.outputs.display-name }} DTS File + if: ${{ always() }} + run: | + if [ -f "build/zephyr/${{ matrix.board }}.pre.tmp" ]; then cat -n build/zephyr/${{ matrix.board }}.pre.tmp; fi + if [ -f "build/zephyr/zephyr.dts" ]; then cat -n build/zephyr/zephyr.dts; fi + ``` + +### VS Code & Docker (Dev Container) + +If you build locally using VS Code & Docker then: + +- pull the latest ZMK `main` with `git pull` for your ZMK checkout +- reload the project +- if you are prompted to rebuild the remote container, click `Rebuild` +- otherwise, press `F1` and run `Remote Containers: Rebuild Container` +- Once the container has rebuilt and reloaded, run `west update` to pull the updated Zephyr version and its dependencies. + +Once the container has rebuilt, VS Code will be running the 3.2 Docker image. + +### Local Host Development + +The following steps will get you building ZMK locally against Zephyr 3.2: + +- Run the updated [toolchain installation](/docs/development/setup#toolchain-installation) steps, and once completed, remove the previously installed SDK version (optional, existing SDK should still work) +- Install the latest version of `west` by running `pip3 install --user --update west`. +- pull the latest ZMK `main` with `git pull` for your ZMK checkout +- run `west update` to pull the updated Zephyr version and its dependencies + +From there, you should be ready to build as normal! + +## Known Issues + +A few testers have reported inconsistent issues with bluetooth connections on Windows after upgrading, which can be resolved by re-pairing your keyboard by: + +1. Remove the device from Windows. +1. Clear the profile on your keyboard that is associated with the Windows device by triggering `&bt BT_CLR` on your keymap while that profile is active. +1. Restart Windows. +1. Re-connect Windows to your keyboard. + +## Windows Battery Reporting Fix + +Zephyr 3.2 introduced [a new Kconfig setting](https://github.com/zephyrproject-rtos/zephyr/pull/48929) that can be used to work around a bug in Windows related to battery reporting. Check out our [bluetooth config](/docs/config/bluetooth) for the full details. The key new configuration that can be set if using Windows is: + +```ini +CONFIG_BT_GATT_ENFORCE_SUBSCRIPTION=n +``` + +## Keymap Changes + +Due to conflicts with new devicetree node labels added for Zephyr's [reset system](https://docs.zephyrproject.org/3.2.0/hardware/peripherals/reset.html), the `&reset` behavior has been renamed to `&sys_reset`. + +All of the in-tree keymaps have been fixed, but you may encounter build failures about duplicate names, requiring you rename the behavior reference in your keymap. Use the [Keymap Upgrader](/docs/codes/keymap-upgrader) and this will get fixed for you automatically. + +## Board/Shield Changes + +The following changes have [already been completed](https://github.com/zmkfirmware/zmk/pull/1499/commits) for all boards/shields in ZMK `main` branch. For existing or new PRs, or out of tree boards, the following changes are necessary to properly work with the latest changes. + +### Move to `pinctrl` driver + +Before this change, setting up the details of pins to use them for peripherals like SPI, I2C, etc. was a mix of platform specific driver code. Zephyr has moved to the newer `pinctrl` system to unify the handling of pin configuration, with additional flexibility for things like low power modes for those pins, etc. + +#### Board specific shield overlays + +The main area this affects existing shields is those with board specific overrides, e.g. `/boards/seeeduino_xiao_ble.overlay`, that sets up additional components on custom buses, e.g. addressable RGB LEDs leveraging the SPI MOSI pin. + +#### nRF52 Pin Assignments + +Previously in ZMK, we relied on per-driver devicetree source properties to set the alternate pin functions for things like SPI or I2C. For example, here is the I2C bus setup as it was previously on the `nice_nano` board: + +```dts +&i2c0 { + compatible = "nordic,nrf-twi"; + sda-pin = <17>; + scl-pin = <20>; +}; +``` + +With the move to the `pinctrl` system, this setup now look like: + +```dts + &i2c0 { + compatible = "nordic,nrf-twi"; + pinctrl-0 = <&i2c0_default>; + pinctrl-1 = <&i2c0_sleep>; + pinctrl-names = "default", "sleep"; + }; +``` + +which references the `pinctrl` configuration: + +```dts +&pinctrl { + i2c0_default: i2c0_default { + group1 { + psels = , + ; + }; + }; + + i2c0_sleep: i2c0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; +``` + +Although slightly more _verbose_ this allows pin configuration infrastructure to be re-used, specify other modes, like sleep, etc. in a standard way across architectures. + +#### Out of Tree Boards/Shields + +All of the in-tree boards and shields have been upgraded, but if you maintain/use an out-of-tree board or shield that uses the converted boards and overrides pins for various buses, you may need to switch to `pinctrl` to match ZMK's new approach. + +The approach is the following when updating a _board_: + +1. Add an entry `CONFIG_PINCTRL=y` to the `_defconfig` file in the board directory. +1. Add a new file with the naming convention `-pinctrl.dtsi` to your board directory. +1. In the new file, add your `pinctrl` entries that set up different pin control configurations for whatever peripherals/buses are needed. Here's the nice!nano file as an example: + + ```dts + /* + * Copyright (c) 2022 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + + &pinctrl { + uart0_default: uart0_default { + group1 { + psels = ; + bias-pull-up; + }; + group2 { + psels = ; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + i2c0_default: i2c0_default { + group1 { + psels = , + ; + }; + }; + + i2c0_sleep: i2c0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + }; + ``` + +1. From the main `.dts` file, add an `#include "-pinctrl.dtsi"` to have the C-preprocessor combine the files. +1. Update the various peripheral nodes to use the new `pinctrl` configurations. For example, the following old configuration: + + ```dts + &i2c0 { + compatible = "nordic,nrf-twi"; + sda-pin = <15>; + scl-pin = <17>; + }; + ``` + + would be changed to: + + ```dts + &i2c0 { + compatible = "nordic,nrf-twi"; + pinctrl-0 = <&i2c0_default>; + pinctrl-1 = <&i2c0_sleep>; + pinctrl-names = "default", "sleep"; + }; + ``` + +Because `pinctrl` configuration is very dependent on the specific target SoC, you will rarely need to consider it for a shield overlay that leverages a pro micro or XIAO abstraction. As noted, you're more likely to need to fix up pinctrl settings is using a board specific shield overlay, e.g. `/boards/.overlay` to set things up. + +### LVGL Kconfig changes. + +With the update to LVGL 8.x, Zephyr now leverages an upstream Kconfig file for most LVGL settings. Due to this, the naming for many existing configs has been adjusted. For any configs moved upstream, the naming mostly involves a prefix change from `LVGL_` to the shorter `LV_`. For any that are still Zephyr specific configs, they are now prefixed with `LV_Z_` prefix. + +If you maintain or use an out of tree board/shield with a display, the following will need to be changed in your Kconfig files: + +- `LVGL_VDB_SIZE` -> `LV_Z_VDB_SIZE` +- `LVGL_DPI` -> `LV_DPI_DEF` +- `LVGL_BITS_PER_PIXEL` -> `LV_Z_BITS_PER_PIXEL` + +Other than those specific examples, most other Kconfig values can simply change the `LVGL_` prefix to `LV_`. + +## Raspberry Pi Pico/RP2040 Support + +This Zephyr update allows ZMK to support the new(-ish) RP2040 SoC found in the Raspberry Pi Pico. + +:::note + +ZMK does _not_ support wired split communication yet, so RP2040 is only usable for non-split keyboards. To follow progress on wired splits, see [#1117](https://github.com/zmkfirmware/zmk/pull/1117). + +::: + +### Supported Controllers + +The following RP2040 powered controllers have board definitions for folks to test: + +- Raspberry Pi Pico (`rpi_pico`) +- SparkFun Pro Micro RP2040 (`sparkfun_pro_micro_rp2040`) +- Adafruit Keyboar/KB2040 (`adafruit_kb2040`) +- Seeeduino XIAO RP2040 (`seeeduino_xiao_rp2040`) +- Adafruit Qt PY RP2040 (`adafruit_qt_py_rp2040`) +- BoardSource blok (`boardsource_blok`) +- Elite-Pi (compatible with the `sparkfun_pro_micro_rp2040` board) + +## Upcoming Changes + +### Display re-init + +Zephyr's improved [power domain](https://docs.zephyrproject.org/3.2.0/services/pm/power_domain.html#pm-power-domain) support is a foundation +upon which we can provide a proper fix for the [longstanding display re-init bug](https://github.com/zmkfirmware/zmk/issues/674) which has prevented +ZMK from formally supporting our display code. + +There is work still remaining to fully leverage the power domain system within ZMK to fix the bug, but upgrading Zephyr is the first necessary step. + +## Thanks! + +Thanks to all the testers who have helped verify ZMK functionality on the newer Zephyr version. + +[petejohanson]: https://github.com/petejohanson +[nicell]: https://github.com/Nicell diff --git a/docs/blog/2023-06-18-encoder-refactors.md b/docs/blog/2023-06-18-encoder-refactors.md new file mode 100644 index 000000000000..db544d38bc88 --- /dev/null +++ b/docs/blog/2023-06-18-encoder-refactors.md @@ -0,0 +1,121 @@ +--- +title: "Major Encoder Refactor" +author: Pete Johanson +author_title: Project Creator +author_url: https://gitlab.com/petejohanson +author_image_url: https://www.gravatar.com/avatar/2001ceff7e9dc753cf96fcb2e6f41110 +tags: [firmware, zephyr, sensors, encoders] +--- + +Today, we merged a significant change to the low level sensor code that is used to support encoders. In particular, +this paves the way for completing the work on supporting split peripheral sensors/encoders, and other future sensors +like pointing devices. + +As part of the work, backwards compatibility for existing shields has been retained, but only for a grace period to allow out-of-tree shields to move to the new approach for encoders. + +Special thanks to [joelspadin] for the _thorough_ code review and testing throughout the development of the refactor. + +## Summary of Changes + +The following items have been merged: + +1. Split configuration of hardware details, and behavior configuration to allow more flexible functionality of sensors/encoders, in particular linear encoders that lack detents/"clicks" as they rotate. +2. Support for upstream Zephyr sensor drivers, including the NRFX QDEC driver that can be used on nRF52 based keyboards. +3. Sensor data handling changes that pave the way for split sensor handling easily. + +## Configuration Changes + +The major changes to configuration in the devicetree files relates to how the number of steps/triggers for a given encoder are set. In particular, the number of pulses/steps for a given encoder is configured first, allowing ZMK to determine the exact angular degrees of change that is represented by a single pulse on the data lines to that encoder. + +Once that angular degrees mapping is completed, now independently there is a configuration setting to control how many triggers of the behavior in the keymap should occur for each full rotation of the sensor. Another way to think of this is "how many degrees of rotation results in a triggering of the sensor behavior in your keymap layer". + +Splitting these two parts of the encoder configuration allows greater flexibility, and fine grained control of encoder behavior for linear encoders that don't have fixed detents. + +### Old Configuration + +Previously, an encoder configuration looked like: + +```dts + left_encoder: encoder_left { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + resolution = <4>; + }; +``` + +Here, the `resolution` property was used to indicate how many encoder pulses should trigger the sensor behavior one time. Next, the encoder is selected in the sensors node: + +```dts + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + }; +``` + +That was the entirety of the configuration for encoders. + +### New Configuration + +```dts + left_encoder: encoder_left { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <80>; + }; +``` + +Here, the `steps` property is now used to indicate how many encoder pulses there are in a single complete rotation of the encoder. Next, the encoder is selected in the sensors node as before, but an additional configuration is used to indicate how many times the encoder should trigger the behavior in your keymap per rotation: + +```dts + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + triggers-per-rotation = <20>; + }; +``` + +For tactile encoders that have detents, the `triggers-per-rotation` would match the number of detents on the encoder. For linear encoders, the value can be chosen to suit your needs. + +## Zephyr Sensor Drivers + +The configuration changes bring ZMK's code in line with how upstream Zephyr sensor drivers handle rotations. This has the added advantage of allowing us to leverage other sensor drivers. On Nordic MCUs, like nRF52840, the NRFX QDEC driver can be used, for example: + +```dts +&pinctrl { + qdec_default: qdec_default { + group1 { + psels = , + ; + bias-pull-up; + }; + }; +}; + +// Set up the QDEC hardware based driver and give it the same label as the deleted node. +encoder: &qdec0 { + status = "okay"; + led-pre = <0>; + steps = <80>; + pinctrl-0 = <&qdec_default>; + pinctrl-names = "default"; +}; +``` + +The NRFX QDEC driver has the advantage of supporting optical encoders as well, and although it polls, it does so in hardware without waking the MCU core; initial basic power profiling is promising. + +## Split Sensor/Encoder Support + +In addition to the refactors for splitting the configuration, the changes merged included refactors designed to simplify and move forward with the long outstanding feature of supporting encoders on the peripheral side of split keyboards. That work is planned as a follow up. + +## Deprecation + +The old configuration will be supported for a period of one month, and then removed, giving users a grace period to complete the migration to the new separated configuration. + +[petejohanson]: https://github.com/petejohanson +[joelspadin]: https://github.com/joelspadin + +## Article Updates + +- 12/2023: Removed the deprecated `label` property from code snippets. diff --git a/docs/blog/2023-10-05-zmk-sotf-6.md b/docs/blog/2023-10-05-zmk-sotf-6.md new file mode 100644 index 000000000000..fb8dc131d213 --- /dev/null +++ b/docs/blog/2023-10-05-zmk-sotf-6.md @@ -0,0 +1,297 @@ +--- +title: "ZMK State Of The Firmware #6" +author: Cem Aksoylar +author_title: Documentation maintainer +author_url: https://github.com/caksoylar +author_image_url: https://avatars.githubusercontent.com/u/7876996 +tags: [SOTF, keyboards, firmware, oss, ble] +--- + +Welcome to the sixth ZMK "State Of The Firmware" (SOTF)! + +This update will cover all the major activity since [SOTF #5](/blog/2022/04/10/zmk-sotf-5). That was over a year ago (again!), so there are many new exciting features and plenty of improvements to cover! + +## Recent Activity + +Here's a summary of the various major changes since last time, broken down by theme: + +### Keymaps/Behaviors + +#### Hold-tap improvements + +[andrewjrae] added the [`require-prior-idle-ms` property](/docs/behaviors/hold-tap#require-prior-idle-ms) to the hold-tap behavior in [#1187](https://github.com/zmkfirmware/zmk/pull/1187) and [#1387](https://github.com/zmkfirmware/zmk/pull/1387), which prevents the hold behavior from triggering if it hasn't been a certain duration since the last key press. This is a useful feature to prevent accidental hold activations during quick typing and made its way into many keymaps! The same property was added to [combos](/docs/features/combos#configuration) as well to help prevent false combo activations. + +Note that an earlier iteration of this feature was supported with the `global-quick-tap` property, which did not allow customizing the timeout and used the value of `quick-tap-ms` for it. This property is now deprecated and users are encouraged to use `require-prior-idle-ms` instead. + +[urob] added the [`hold-trigger-on-release` property](/docs/behaviors/hold-tap#positional-hold-tap-and-hold-trigger-key-positions) in [#1423](https://github.com/zmkfirmware/zmk/pull/1423). This significantly increases the usefulness of positional constraints on hold-taps, since it allows combining multiple holds such as different modifiers for home row mods usage. + +#### Masking mods in mod-morphs + +[aumuell](https://github.com/aumuell), [vrinek](https://github.com/vrinek) and [urob] contributed to improving the behavior of [mod-morphs](/docs/behaviors/mod-morph) by masking the triggering modifiers and added `keep-mods` property in [#1412](https://github.com/zmkfirmware/zmk/pull/1412). This unlocks more use cases for mod-morphs, since you are no longer constrained to emitting keycodes that work well with the triggering modifier keycodes. + +As an example, you can now define a mod-morph that swaps `;` and `:` so that the former is the shifted version of the latter, which wasn't previously possible: + +```dts + col_semi: colon_semicolon { + compatible = "zmk,behavior-mod-morph"; + #binding-cells = <0>; + bindings = <&kp COLON>, <&kp SEMI>; + mods = <(MOD_LSFT|MOD_RSFT)>; + }; +``` + +#### Parameterized macros + +[petejohanson] added [macros that can be parameterized](/docs/behaviors/macros#parameterized-macros) with one or two parameters in [#1232](https://github.com/zmkfirmware/zmk/pull/1232). This allows users to define macros in a more modular way and is a nice quality-of-life improvement. + +As a simple example, you could define a macro that puts any keycode provided between double quotes as below, then use it like `&ql A` in your keymap: + +```dts + ql: quoted_letter { + #binding-cells = <1>; + compatible = "zmk,behavior-macro-one-param"; + bindings = + <&kp DQT>, + <¯o_param_1to1 &kp MACRO_PLACEHOLDER>, + <&kp DQT>; + }; +``` + +Please see the documentation page linked above for usage and more examples. + +#### Arbitrary behaviors on encoder rotation + +[nickconway](https://github.com/nickconway) and [petejohanson] added [sensor rotation behaviors](/docs/behaviors/sensor-rotate) to allow invoking arbitrary behaviors from encoders [#1758](https://github.com/zmkfirmware/zmk/pull/1758). Previously encoder rotations could only invoke the key-press behavior `&kp` through the `&inc_dec_kp` binding, whereas now you can define new sensor rotation behaviors to invoke others. + +(Note that currently behaviors that have "locality" such as `&rgb_ug` do not work as expected via encoder rotation bindings in split keyboards, due to issue [#1494](https://github.com/zmkfirmware/zmk/issues/1494).) + +#### Pre-releasing already pressed keys + +[andrewjrae] contributed a tweak to emitting keycodes in [#1828](https://github.com/zmkfirmware/zmk/pull/1828), where rolling multiple keys that involve the same keycode now releases the keycode before sending a press event again. While this might sound like a technical distinction, it leads to more correct behavior when quickly typing sequences like `+=` and makes the [key repeat behavior](/docs/behaviors/key-repeat) work properly when it is pressed before the previous key is released. + +#### Key toggle behavior + +[cgoates](https://github.com/cgoates) added the [key toggle behavior](/docs/behaviors/key-toggle) in [#1278](https://github.com/zmkfirmware/zmk/pull/1278), which can be used via its `&kt` binding to toggle the state of a keycode between pressed and released. + +#### Apple Globe key + +[ReFil] added support for the `C_AC_NEXT_KEYBOARD_LAYOUT_SELECT` keycode with alias `GLOBE` which acts as the Globe key in macOS and iOS in [#1938](https://github.com/zmkfirmware/zmk/pull/1938). Note that this keycode doesn't exactly behave like a Globe key that is present on an Apple keyboard and its limitations are documented in [this comment](https://github.com/zmkfirmware/zmk/pull/1938#issuecomment-1744579039) thanks to testing by [SethMilliken](https://github.com/SethMilliken). These limitations will be noted in the official [keycodes documentation](/docs/codes/applications) shortly. + +#### Bug fixes and other improvements + +[petejohanson], [andrewjrae] and [okke-formsma] tracked down and fixed an issue causing stuck keys when there are combos on key positions involving hold-tap behaviors in [#1411](https://github.com/zmkfirmware/zmk/pull/1411). This was an elusive bug that took a lot of effort from the community to nail down and fix! + +[nguyendown](https://github.com/nguyendown) and [joelspadin] tracked down and fixed a couple issues causing stuck keys with [sticky keys](/docs/behaviors/sticky-key) in [#1586](https://github.com/zmkfirmware/zmk/pull/1586), [#1745](https://github.com/zmkfirmware/zmk/pull/1745). + +[okke-formsma] fixed an issue allowing tap dances to be invoked by combos in [#1518](https://github.com/zmkfirmware/zmk/pull/1518). + +[petejohanson] tweaked the caps word behavior to ignore modifiers in [#1330](https://github.com/zmkfirmware/zmk/pull/1330). + +[HelloThisIsFlo](https://github.com/HelloThisIsFlo) documented a bug with combos involving overlapping keys and different timeouts, produced a reproducing unit test, then proceeded to fix it in [#1945](https://github.com/zmkfirmware/zmk/pull/1945). + +### Bluetooth and Split Improvements + +#### Multiple peripherals + +[xudongzheng] contributed to add support for more than one peripheral per keyboard in [#836](https://github.com/zmkfirmware/zmk/pull/836). This allows setups such as split keyboards with more than two halves, or enable a BLE-based "dongle mode" via a third device running ZMK that can stay connected to a computer via USB. + +Note that documentation is still lacking for utilizing more than one peripheral and there will potentially be future changes in the build system to allow for more seamless configuration. + +#### Pairing passkey requirement + +[petejohanson] added [the option to require passkey input](/docs/config/bluetooth) while pairing to new devices in [#1822](https://github.com/zmkfirmware/zmk/pull/1822). Enabling this will require you to enter a six digit passcode via the number keys on your keymap and press enter when pairing to a new device, enhancing security during the pairing procedure. + +#### Split keyboard improvements + +[petejohanson] contributed a fix to release held keys on peripheral disconnect [#1340](https://github.com/zmkfirmware/zmk/pull/1340), which makes scenarios where a split disconnects unexpectedly less painful. + +[petejohanson] also improved [the `settings_reset` shield](/docs/troubleshooting#split-keyboard-halves-unable-to-pair) by making it clear bonds more reliably, and allow it to build for all boards in [#1879](https://github.com/zmkfirmware/zmk/pull/1879). + +[petejohanson] and [xudongzheng] contributed additional split connectivity improvements, via using directed advertising in [#1913](https://github.com/zmkfirmware/zmk/pull/1913) and improving the robustness of central scanning in [#1912](https://github.com/zmkfirmware/zmk/pull/1912). + +### Hardware Support + +#### Encoders + +[petejohanson] contributed a major refactor of encoder (and more generally sensor) functionality in [#1039](https://github.com/zmkfirmware/zmk/pull/1039). While the documentation for these changes are still in progress, check out the [dedicated blog post](/blog/2023/06/18/encoder-refactors) for more details. + +This refactor paved way to implementing a long-awaited feature, encoder support in peripheral halves of split keyboards! Building upon the work by [stephen](https://github.com/stephen) in [#728](https://github.com/zmkfirmware/zmk/pull/728), [petejohanson] implemented support in [#1841](https://github.com/zmkfirmware/zmk/pull/1841). + +#### Direct GPIO driver + +[joelspadin] extended the comprehensive debouncing framework used for matrix scan driver to the [direct GPIO driver](/docs/config/kscan#direct-gpio-driver) in [#1288](https://github.com/zmkfirmware/zmk/pull/1288). + +[kurtis-lew] added toggle mode support for direct GPIO driver in [#1305](https://github.com/zmkfirmware/zmk/pull/1305). This allows for adding toggle switches to a keyboard, by properly reading their initial state on boot and making sure the power use is efficient. + +#### IO peripheral drivers + +[petejohanson] added support for the 595 shift register commonly used with smaller controllers like Seeeduino Xiaos, in [#1325](https://github.com/zmkfirmware/zmk/pull/1325). + +[zhiayang](https://github.com/zhiayang) added the driver for the MAX7318 GPIO expander in [#1295](https://github.com/zmkfirmware/zmk/pull/1295). + +#### Underglow auto-off options + +[ReFil] added two [new RGB auto off options](/docs/config/underglow), one using an idle timeout and the other USB status in [#1010](https://github.com/zmkfirmware/zmk/pull/1010). + +#### nice!view support + +[nicell] added support for nice!view, a memory display optimized for low power use in [#1462](https://github.com/zmkfirmware/zmk/pull/1462). +He also contributed a custom vertically-oriented status screen that is automatically enabled when the `nice_view` shield is used in [#1768](https://github.com/zmkfirmware/zmk/pull/1768), since the default status screen has a horizontal orientation. +Please see the instructions in the [nice!view README](https://github.com/zmkfirmware/zmk/blob/main/app/boards/shields/nice_view/README.md) if you would like to restore the stock status screen. + +#### E-paper display initialization + +[petejohanson] contributed EPD initialization improvements in [#1098](https://github.com/zmkfirmware/zmk/pull/1098), which makes the keyboards using slow refresh displays such as the Corne-ish Zen much more responsive during initial boot. + +#### Xiao BLE improvements + +Various improvements were made for the Seeeduino Xiao BLE board in [#1293](https://github.com/zmkfirmware/zmk/pull/1293), [d0176f36](https://github.com/zmkfirmware/zmk/commit/d0176f36), [#1545](https://github.com/zmkfirmware/zmk/pull/1545) and [#1927](https://github.com/zmkfirmware/zmk/pull/1927) by [petejohanson] and [caksoylar], enabling features necessary for ZMK and improving its power use. + +### Zephyr 3.2 Upgrade + +[petejohanson] once again contributed the massive work necessary for upgrading ZMK to Zephyr 3.2 in [#1499](https://github.com/zmkfirmware/zmk/pull/1499), with review help from [joelspadin] and testing by the community. This Zephyr release brings with it upgrades to the display library LVGL, adds official support for the RP2040 controllers and many internal refactors to help future development. +Check out the [dedicated blog post](/blog/2023/04/06/zephyr-3-2) for more details! + +### Documentation + +#### Configuration docs + +[joelspadin], through a massive amount of work in [#722](https://github.com/zmkfirmware/zmk/pull/722), contributed a whole new section to the documentation: [configuration](/docs/config)! It enumerates the configuration options for each ZMK feature that might be relevant to users in dedicated pages, making it a very handy reference. + +In addition, the [overview page](/docs/config) presents an overview of how configuration works in Zephyr in the context of ZMK, in terms of devicetree files (like the keymap files or shield overlays), and Kconfig ones (like the `.conf` files). It is very helpful in de-mystifying what the various files do and what syntax is expected in them. + +#### New behavior guide + +For users or future contributors that might want to dive into writing their own ZMK behaviors, [kurtis-lew] wrote a useful [guide on how to create new behaviors](/docs/development/new-behavior) in [#1268](https://github.com/zmkfirmware/zmk/pull/1268). + +#### Tap dance and hold-tap documentation improvements + +[kurtis-lew] also improved the documentation for these two behaviors in [#1298](https://github.com/zmkfirmware/zmk/pull/1298), by updating the diagrams to better clarify how their timings work and adding examples for scenarios that are frequently asked by users. + +#### Battery sensor documentation + +[joelspadin] also added documentation for setting up battery sensors, typically required for new boards, in [#868](https://github.com/zmkfirmware/zmk/pull/868). + +#### Shield interconnects + +[petejohanson] updated the [new shield guide](/docs/development/new-shield) for non-Pro Micro interconnects including Xiao, Arduino Uno and Blackpill in [#1607](https://github.com/zmkfirmware/zmk/pull/1607). + +#### Bluetooth feature page + +[petejohanson] and [caksoylar] added a new [Bluetooth feature page](/docs/features/bluetooth) as part of [#1499](https://github.com/zmkfirmware/zmk/pull/1499) and in [#1818](https://github.com/zmkfirmware/zmk/pull/1499), detailing ZMK's Bluetooth implementation and troubleshooting for common problems. + +In addition to the specific contributions listed above, various improvements and fixes to documentation are made by many users from the community, including but not limited to [kurtis-lew], [joelspadin], [filterpaper], [byran.tech](https://github.com/byran.tech), [dxmh] and [caksoylar]. These contributions are are all very appreciated! + +### Miscellaneous + +#### Reusable GitHub build workflow + +[elagil](https://github.com/elagil) helped switch the build workflow used by the [user config repos](/docs/user-setup) to a reusable one in [#1183](https://github.com/zmkfirmware/zmk/pull/1183) and it was further tweaked by [filterpaper] in [#1258](https://github.com/zmkfirmware/zmk/pull/1258). This allows any changes in the workflow to be propagated automatically to users, rather than requiring them to make the updates. The build workflow can be customized by the users [using input parameters](https://github.com/zmkfirmware/zmk/blob/main/.github/workflows/build-user-config.yml#L5) if desired. + +#### Pre-commit hooks + +[joelspadin] added various [pre-commit](https://pre-commit.com/) hooks and added checks to the repo to run them for each commit in [#1651](https://github.com/zmkfirmware/zmk/pull/1651). These hooks and resulting updates standardize formatting across devicetree and other source files, reducing busywork on both contributors and reviewers. + +#### Zephyr usage and other refactors + +[joelspadin] also contributed a few refactor PRs such as [#1269](https://github.com/zmkfirmware/zmk/pull/1269), [#1255](https://github.com/zmkfirmware/zmk/pull/1255) and [#1803](https://github.com/zmkfirmware/zmk/pull/1803), generally improving code quality and bringing the codebase in line with the latest Zephyr conventions. + +[petejohanson] refactored the drivers structure to bring it in line with the current Zephyr conventions for out-of-tree drivers in [#1919](https://github.com/zmkfirmware/zmk/pull/1919). + +#### Updated USB polling interval default + +USB HID polling interval now defaults to 1 ms, i.e. a 1000Hz polling rate, thanks to [joelspadin]'s tweak in [#1271](https://github.com/zmkfirmware/zmk/pull/1271). + +#### Additional display config options + +[caksoylar] added a couple configuration options for displays, including a setting to invert display colors in [#1754](https://github.com/zmkfirmware/zmk/pull/1754) and an option to display the battery percentage for the stock status screen in [#1563](https://github.com/zmkfirmware/zmk/pull/1563). + +## New Shields + +- Eternal keypad [#1136](https://github.com/zmkfirmware/zmk/pull/1136) - [halcyonCorsair](https://github.com/halcyonCorsair) +- nullbits SNAP [#1319](https://github.com/zmkfirmware/zmk/pull/1319) - [jaygreco](https://github.com/jaygreco) +- Aurora Sweep [#1504](https://github.com/zmkfirmware/zmk/pull/1504), Corne [#1520](https://github.com/zmkfirmware/zmk/pull/1520), Lily58 [#1553](https://github.com/zmkfirmware/zmk/pull/1553), Sofle [#1864](https://github.com/zmkfirmware/zmk/pull/1864), and Helix [#1873](https://github.com/zmkfirmware/zmk/pull/1873) - [petejohanson] +- ZMK Uno shield [#1576](https://github.com/zmkfirmware/zmk/pull/1576) - [petejohanson] +- Waterfowl [#1554](https://github.com/zmkfirmware/zmk/pull/1554) - [JW2586](https://github.com/JW2586) +- Kyria Rev 3 [#1627](https://github.com/zmkfirmware/zmk/pull/1627) - [petejohanson] +- Leeloo v2 and Leeloo-Micro [#1762](https://github.com/zmkfirmware/zmk/pull/1762) - [ClicketySplit](https://github.com/ClicketySplit) +- Spaceman Pancake [#1400](https://github.com/zmkfirmware/zmk/pull/1400) - [jasonhazel](https://github.com/jasonhazel) +- Reviung5 [#1548](https://github.com/zmkfirmware/zmk/pull/1548) - [zblesk](https://github.com/zblesk) + +## New Boards + +- RP2040 boards, including Sparkfun Pro Micro, Adafruit KB2040 and Seeeduino Xiao RP2040 were added as part of the Zephyr 3.2 upgrade in [#1499](https://github.com/zmkfirmware/zmk/pull/1499) - [petejohanson] +- Puchi BLE [#1445](https://github.com/zmkfirmware/zmk/pull/1445) - [BenRoe](https://github.com/BenRoe) +- nRFMicro 1.3/1.4 (nRF52833) [#912](https://github.com/zmkfirmware/zmk/pull/912) - [pashutk](https://github.com/pashutk) +- nRF5340 DK [#1562](https://github.com/zmkfirmware/zmk/pull/1562) - [joelspadin] +- PillBug [#1530](https://github.com/zmkfirmware/zmk/pull/1530) - [kylemccreery](https://github.com/kylemccreery) +- Preonic Rev 3 [#1575](https://github.com/zmkfirmware/zmk/pull/1575) - [jeromeOlivier](https://github.com/jeromeOlivier) +- Corne-ish Zen v2 [#1498](https://github.com/zmkfirmware/zmk/pull/1498) and v1 [#1593](https://github.com/zmkfirmware/zmk/pull/1593) - [LOWPROKB](https://github.com/LOWPROKB) and [caksoylar] +- Polarity Works CKP family of boards [#1547](https://github.com/zmkfirmware/zmk/pull/1547) - [ReFil] + +## Coming Soon! + +Some items listed in the last coming soon section are still under active development and other new exciting items are in progress: + +- Automatic/simple BLE profile management +- Soft off support for turning the keyboard "off" through firmware +- Improved automatic power management for devices with multiple peripherals, e.g. OLED displays and RGB LEDs +- Caps/Scroll/Num Lock LED support +- Mouse keys +- Wired split support +- More modular approach to external boards/shields, custom code, user keymaps, etc. +- More shields and boards + +## Statistics + +Some statistics of interest for ZMK: + +- GitHub (lifetime stats) + - 166 Contributors + - 1256 Closed PRs + - 1883 Stars + - 1949 Forks +- Discord Chat + - 8055 total registered (130% up from last SOTF!) +- Website (last 30 days) + - 52K page views + - 4.7K new users + +## Sponsorship + +While ZMK is an open source project that uses the permissive MIT license, below are opportunities for anyone who would like to show their support to the project financially. + +### Open Collective + +The ZMK project has an [Open Collective sponsorship](https://opencollective.com/zmkfirmware) that has been going for two and a half years. +This fund helps pay for project costs like domain registration or development of hardware such as the [ZMK Uno shield](https://github.com/zmkfirmware/zmk-uno). +Note that donations to this fund do _not_ pay for the work of any individual contributor directly. + +### Contributor sponsorships + +Project creator and lead Pete Johanson has a [GitHub sponsorship](https://github.com/sponsors/petejohanson) set up that you can contribute to, in order to directly support his time and efforts in developing and maintaining ZMK. +He has also been traveling full time while focusing on ZMK and keyboard hardware design for more than a year now! +If you are curious, you can check out [his blog post](https://petejohanson.dev/blog/new-journey-2022) on deciding to embark on this adventure, in addition to his thoughts on contributor vs. project sponsorship, and sustainability of open source projects in general. + +## Thanks! + +As the first person to author a State Of The Firmware post besides Pete, I'd like to take the opportunity to thank him for his efforts on leading and developing ZMK, along with fostering a great community of contributors and users around it. + +Also a big thank you to contributors that submit patches and perform reviews, testers that help validate changes, and users that take time out of their day to help out folks with ZMK usage on [Discord channels](https://zmk.dev/community/discord/invite), GitHub issues and other communities. + +[okke-formsma]: https://github.com/okke-formsma +[andrewjrae]: https://github.com/andrewjrae +[xudongzheng]: https://github.com/xudongzheng +[nicell]: https://github.com/Nicell +[petejohanson]: https://github.com/petejohanson +[kurtis-lew]: https://github.com/kurtis-lew +[joelspadin]: https://github.com/joelspadin +[dxmh]: https://github.com/dxmh +[caksoylar]: https://github.com/caksoylar +[urob]: https://github.com/urob +[filterpaper]: https://github.com/filterpaper +[ReFil]: https://github.com/ReFil + +## Article Updates + +- 12/2023: Removed the deprecated `label` property from code snippets. diff --git a/docs/blog/2023-11-09-keymap-editor.md b/docs/blog/2023-11-09-keymap-editor.md new file mode 100644 index 000000000000..1fe3b86772da --- /dev/null +++ b/docs/blog/2023-11-09-keymap-editor.md @@ -0,0 +1,109 @@ +--- +title: "Community Spotlight Series #1: Keymap Editor" +author: Cem Aksoylar +author_title: Documentation maintainer +author_url: https://github.com/caksoylar +author_image_url: https://avatars.githubusercontent.com/u/7876996 +tags: [keyboards, firmware, community] +--- + +import ThemedImage from '@theme/ThemedImage'; + + + +This blog post is the first in a series of posts where we highlight projects within the ZMK ecosystem that we think are cool and that the users might benefit from knowing about them. We are starting the series with a big one, [Keymap Editor] by [Nick Coutsos](https://github.com/nickcoutsos)! + +In the rest of the post we leave it to Nick himself to introduce the project, detail his goals and motivation in developing such a tool, and talk about the future of the project. Stay tuned for future installments in the series! + +## What is Keymap Editor? + +_[Keymap Editor]_ is a web based graphical editor for ZMK keymaps. It provides a visual way to manage the contents of your keymap and if nothing else offers two critical features: + +1. Automatic formatting of the keymap file, so that bindings arrays remain readable +2. Searchable behaviors, keycodes, commands, etc, so you won't have to remember if it's `LCTL` or `LCTRL` (I just had to double check myself and I guessed wrong, apparently) + +## What can Keymap Editor do? + +- Render [devicetree keymaps](/docs/features/keymaps) using pre-defined, auto-generated, or side-loadable keyboard layouts +- Integrate with a GitHub repo to streamline firmware builds, or FileSystem/Clipboard if you'd still rather build locally +- Edit [combos](/docs/features/combos), [behaviors](/docs/behaviors/key-press), [macros](/docs/behaviors/macros), [conditional layers](/docs/features/conditional-layers) and [rotary encoder bindings](/docs/behaviors/sensor-rotate) +- Manage references: moving a layer or renaming a behavior will look for references throughout your keymap and update them. + +But check back regularly, because I update pretty often. A recent significant achievement was enabling [parameterized macros](/docs/behaviors/macros#parameterized-macros) and tying it in with my existing parameter type resolution so, yeah, you can finally create that reusable macro combining bluetooth profile selection with RGB backlight colour. Or use it for an actual useful thing, even. _(See also: [Using Parameterized Macros in Keymap Editor](https://github.com/nickcoutsos/keymap-editor/wiki/Using-Parameterized-Macros-in-Keymap-Editor))_ + +My goals are, broadly: + +- **Treat code as a first-class entity:** as long as ZMK keymaps are described in devicetree code then an editor needs to produce readable devicetree code. +- **Flexibly support ZMK features:** use of any ZMK keymap feature should theoretically be achievable within the app. In some cases this can mean more initial setup _(See also: [my thoughts on implementing "autoshift"](https://github.com/nickcoutsos/keymap-editor/wiki/Autoshift-using-ZMK-behaviors))_ but having that foundation makes its easier to add shortcuts and niceties — something I do quite often now. +- **Don't get in the way of not-yet-supported features:** If a new ZMK feature is released and the app isn't able to add it natively, you can always edit your keymap file directly. While the app may not _recognize_ the new features, further changes through the app should not break your keymap. + +## History of Keymap Editor + +When I started writing Keymap Editor I had a handwired Dactyl variant running QMK. Manually editing keymap code was fine, but keeping things readable was important to me, and automating that was the best way to ensure consistency. Programmatically modifying source code was beyond me at the time so the first version persisted keymap data in JSON and spat out formatted versions of both the JSON and C keymaps. + +After switching to ZMK I added a few more features, I guess as a pandemic project, and then gradually migrated from generating a templated keymap file to manipulating devicetree syntax directly, and that has made a big difference in adding new ZMK features. + +## Why am I doing this? + +It started out as a useful tool for me. I shared it with the ZMK community and gained a little traction, and then apparently quite a bit of traction — turns out it's useful for a lot of people. + +I'm a software developer because I enjoy building things. Much of my day-to-day work isn't user facing, so seeing how helpful the keymap editor has been for people in the ZMK community is a big motivator to keep improving it. + +## Future plans + +### Runtime updates + +Streamlining the keymap update process is probably top of mind for most users, but that involves a really big _firmware_ feature, and I'm the wrong person to tackle it. + +That said, once there's a protocol I would _absolutely_ be down to integrate it as an additional keymap source. Being able to pull data directly from the keyboard should unlock a lot of possibilities and ease some of the constraints imposed by using devicetree code as a medium. + +### Simplifying behavior use + +I think a lot of people would like to see the concept of behaviors abstracted away for new users and to prompt them with + +- _"When the key is tapped..."_, +- _"When the key is held..."_, +- _"When the key is double-tapped..."_ and so on. + +Users who are less familiar with ZMK's behaviors and how they are composed may find these prompts to be more intuitive, and their answers could be mapped to an appropriate combination of behaviors managed internally by an editor. + +### Uh, what else? + +This has been long enough already, if you're looking for a feature I haven't mentioned don't assume I won't add it. Feel free to make feature requests on the GitHub repo, and I'd be happy to discuss it! + +## About Me And My Keebs + +I like computers and write software. Many in this field enjoy using mechanical +keyboards for their feel or aesthetics, but what piqued my interest was the +Dactyl keyboard. I think, ergonomics aside, I'm more interested in the DIY/maker +aspect than the collecting of keyboards and switches. + +So [I made a Dactyl](https://github.com/nickcoutsos/dactyl-flatpacked/), and +then [I made another Dactyl](https://github.com/nickcoutsos/dactyl-deskmount/) +and I made a third Dactyl that isn't interesting enough to photograph, but now +I'm using ZMK so I left room for 18650 cells. + +That last Dactyl (with MX browns and a cheap blank XDA keycap set) serves me +well the eight or so hours a day I'll spend at my desk, but I also spend a good +deal of time computing on my couch where I'll use... my Macbook's built-in +keyboard. + +In case that's not surprising enough I'll leave you with this: despite all of +the work and testing I've put into the keymap editor project, I've only updated +an actual keymap once in the last year. + +Thank you and good night. + +## More information + +- [Keymap Editor Wiki](https://github.com/nickcoutsos/keymap-editor/wiki) +- [Keymap Editor Discussions](https://github.com/nickcoutsos/keymap-editor/discussions) +- (YouTube video) [Ben Frain's overview of the Keymap Editor](https://www.youtube.com/watch?v=Vy7IoQAe3oU) + +[Keymap Editor]: http://nickcoutsos.github.io/keymap-editor diff --git a/docs/blog/assets/2022-04-21-zmk-2yo/first-zmk-keyboard.jpg b/docs/blog/assets/2022-04-21-zmk-2yo/first-zmk-keyboard.jpg new file mode 100644 index 000000000000..ae119f521f6f Binary files /dev/null and b/docs/blog/assets/2022-04-21-zmk-2yo/first-zmk-keyboard.jpg differ diff --git a/docs/blog/assets/2022-04-21-zmk-2yo/kyria-first-split.jpg b/docs/blog/assets/2022-04-21-zmk-2yo/kyria-first-split.jpg new file mode 100644 index 000000000000..bc007903f6c3 Binary files /dev/null and b/docs/blog/assets/2022-04-21-zmk-2yo/kyria-first-split.jpg differ diff --git a/docs/blog/assets/2023-11-09-keymap-editor/editor-screenshot-dark.png b/docs/blog/assets/2023-11-09-keymap-editor/editor-screenshot-dark.png new file mode 100644 index 000000000000..166edf8ae806 Binary files /dev/null and b/docs/blog/assets/2023-11-09-keymap-editor/editor-screenshot-dark.png differ diff --git a/docs/blog/assets/2023-11-09-keymap-editor/editor-screenshot-light.png b/docs/blog/assets/2023-11-09-keymap-editor/editor-screenshot-light.png new file mode 100644 index 000000000000..cdaae5c799da Binary files /dev/null and b/docs/blog/assets/2023-11-09-keymap-editor/editor-screenshot-light.png differ diff --git a/docs/docs/assets/dev-setup/vscode_devcontainer.png b/docs/docs/assets/dev-setup/vscode_devcontainer.png new file mode 100644 index 000000000000..e5c22b0ac4f8 Binary files /dev/null and b/docs/docs/assets/dev-setup/vscode_devcontainer.png differ diff --git a/docs/docs/assets/features/beta-testing/pr-repo-branch.png b/docs/docs/assets/features/beta-testing/pr-repo-branch.png new file mode 100644 index 000000000000..68856d0b59a7 Binary files /dev/null and b/docs/docs/assets/features/beta-testing/pr-repo-branch.png differ diff --git a/docs/docs/assets/features/beta-testing/repo-branch.png b/docs/docs/assets/features/beta-testing/repo-branch.png new file mode 100644 index 000000000000..741e69a4e947 Binary files /dev/null and b/docs/docs/assets/features/beta-testing/repo-branch.png differ diff --git a/docs/docs/assets/features/beta-testing/repo-url.png b/docs/docs/assets/features/beta-testing/repo-url.png new file mode 100644 index 000000000000..aed37137ea71 Binary files /dev/null and b/docs/docs/assets/features/beta-testing/repo-url.png differ diff --git a/docs/docs/assets/features/keymaps/layer-diagram.png b/docs/docs/assets/features/keymaps/layer-diagram.png new file mode 100644 index 000000000000..7b42daae87c7 Binary files /dev/null and b/docs/docs/assets/features/keymaps/layer-diagram.png differ diff --git a/docs/docs/assets/hold-tap/case1_2.svg b/docs/docs/assets/hold-tap/case1_2.svg new file mode 100644 index 000000000000..697d73462cc5 --- /dev/null +++ b/docs/docs/assets/hold-tap/case1_2.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/docs/assets/hold-tap/case_hold_preferred.svg b/docs/docs/assets/hold-tap/case_hold_preferred.svg new file mode 100644 index 000000000000..70b27014c7d1 --- /dev/null +++ b/docs/docs/assets/hold-tap/case_hold_preferred.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/docs/assets/hold-tap/comparison.svg b/docs/docs/assets/hold-tap/comparison.svg new file mode 100644 index 000000000000..5193d8468286 --- /dev/null +++ b/docs/docs/assets/hold-tap/comparison.svg @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/docs/assets/interconnects/arduino_uno/pinout.png b/docs/docs/assets/interconnects/arduino_uno/pinout.png new file mode 100644 index 000000000000..b79607006324 Binary files /dev/null and b/docs/docs/assets/interconnects/arduino_uno/pinout.png differ diff --git a/docs/docs/assets/interconnects/blackpill/pinout.png b/docs/docs/assets/interconnects/blackpill/pinout.png new file mode 100644 index 000000000000..3f15c620d208 Binary files /dev/null and b/docs/docs/assets/interconnects/blackpill/pinout.png differ diff --git a/docs/docs/assets/interconnects/pro_micro/pinout.png b/docs/docs/assets/interconnects/pro_micro/pinout.png new file mode 100644 index 000000000000..7e548da51541 Binary files /dev/null and b/docs/docs/assets/interconnects/pro_micro/pinout.png differ diff --git a/docs/docs/assets/interconnects/seeed_xiao/pinout.png b/docs/docs/assets/interconnects/seeed_xiao/pinout.png new file mode 100644 index 000000000000..74a1005335a7 Binary files /dev/null and b/docs/docs/assets/interconnects/seeed_xiao/pinout.png differ diff --git a/docs/docs/assets/tap-dance/timing_diagram.svg b/docs/docs/assets/tap-dance/timing_diagram.svg new file mode 100644 index 000000000000..3bf0b137e574 --- /dev/null +++ b/docs/docs/assets/tap-dance/timing_diagram.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/docs/assets/troubleshooting/filetransfer/linux.png b/docs/docs/assets/troubleshooting/filetransfer/linux.png new file mode 100644 index 000000000000..c192dfab8fe4 Binary files /dev/null and b/docs/docs/assets/troubleshooting/filetransfer/linux.png differ diff --git a/docs/docs/assets/troubleshooting/filetransfer/mac.png b/docs/docs/assets/troubleshooting/filetransfer/mac.png new file mode 100644 index 000000000000..f28ca8d78369 Binary files /dev/null and b/docs/docs/assets/troubleshooting/filetransfer/mac.png differ diff --git a/docs/docs/assets/troubleshooting/filetransfer/windows.png b/docs/docs/assets/troubleshooting/filetransfer/windows.png new file mode 100644 index 000000000000..91cb8a616bba Binary files /dev/null and b/docs/docs/assets/troubleshooting/filetransfer/windows.png differ diff --git a/docs/docs/assets/troubleshooting/splitpairing/corecoverage.png b/docs/docs/assets/troubleshooting/splitpairing/corecoverage.png new file mode 100755 index 000000000000..a2a928be1f8e Binary files /dev/null and b/docs/docs/assets/troubleshooting/splitpairing/corecoverage.png differ diff --git a/docs/docs/assets/usb-logging/com.jpg b/docs/docs/assets/usb-logging/com.jpg new file mode 100644 index 000000000000..e2ab9a8372ba Binary files /dev/null and b/docs/docs/assets/usb-logging/com.jpg differ diff --git a/docs/docs/assets/usb-logging/putty.jpg b/docs/docs/assets/usb-logging/putty.jpg new file mode 100644 index 000000000000..dfbb4bd73d7c Binary files /dev/null and b/docs/docs/assets/usb-logging/putty.jpg differ diff --git a/docs/docs/assets/user-setup/firmware-archive.png b/docs/docs/assets/user-setup/firmware-archive.png new file mode 100644 index 000000000000..9cb6f7deba37 Binary files /dev/null and b/docs/docs/assets/user-setup/firmware-archive.png differ diff --git a/docs/docs/assets/user-setup/github-actions-link.png b/docs/docs/assets/user-setup/github-actions-link.png new file mode 100644 index 000000000000..c12483b1154d Binary files /dev/null and b/docs/docs/assets/user-setup/github-actions-link.png differ diff --git a/docs/docs/behaviors/backlight.md b/docs/docs/behaviors/backlight.md new file mode 100644 index 000000000000..322530e37639 --- /dev/null +++ b/docs/docs/behaviors/backlight.md @@ -0,0 +1,61 @@ +--- +title: Backlight Behavior +sidebar_label: Backlight +--- + +## Summary + +This page contains [backlight](../features/backlight.md) behaviors supported by ZMK. + +## Backlight Action Defines + +Backlight actions defines are provided through the [`dt-bindings/zmk/backlight.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/backlight.h) header, +which is added at the top of the keymap file: + +```dts +#include +``` + +This will allow you to reference the actions defined in this header such as `BL_TOG`. + +Here is a table describing the action for each define: + +| Define | Action | +| ---------- | --------------------------- | +| `BL_ON` | Turn on backlight | +| `BL_OFF` | Turn off backlight | +| `BL_TOG` | Toggle backlight on and off | +| `BL_INC` | Increase brightness | +| `BL_DEC` | Decrease brightness | +| `BL_CYCLE` | Cycle brightness | +| `BL_SET` | Set a specific brightness | + +## Behavior Binding + +- Reference: `&bl` +- Parameter #1: The backlight action define, e.g. `BL_TOG` or `BL_INC` +- Parameter #2: Only applies to `BL_SET`and is the brightness value + +:::note Backlight settings persistence +The backlight settings that are changed via the `&bl` behavior will be saved to flash storage and hence persist across restarts and firmware flashes. +They will also override the start values set by [`CONFIG_ZMK_BACKLIGHT_*_START` settings](../config/backlight.md#kconfig). +However the settings will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory. +::: + +### Examples + +1. Toggle backlight on/off + + ```dts + &bl BL_TOG + ``` + +1. Sets a specific brightness + + ```dts + &bl BL_SET 50 + ``` + +## Split Keyboards + +Backlight behaviors are global: This means that when triggered, they affect both the central and peripheral side of split keyboards. diff --git a/docs/docs/behaviors/bluetooth.md b/docs/docs/behaviors/bluetooth.md new file mode 100644 index 000000000000..b34614e6205f --- /dev/null +++ b/docs/docs/behaviors/bluetooth.md @@ -0,0 +1,103 @@ +--- +title: Bluetooth Behavior +sidebar_label: Bluetooth +--- + +## Summary + +The bluetooth behavior allows management of various settings and states related to the bluetooth connection(s) +between the keyboard and the host. By default, ZMK supports five "profiles" for selecting which bonded host +computer/laptop/keyboard should receive the keyboard input; many of the commands here operate on those profiles. + +:::note Connection Management +When pairing to a host device ZMK saves bond information to the selected profile. It will not replace this when you initiate pairing with another device. To pair with a new device select an unused profile with `BT_SEL`, `BT_NXT` or `BT_PRV` bindings, or by clearing an existing profile using `BT_CLR`. + +A ZMK device may show as "connected" on multiple hosts at the same time. This is working as intended, and only the host associated with the active profile will receive keystrokes. + +An _inactive_ connected profile can be explicitly disconnected using the `BT_DISC` behavior. This can be helpful in +cases when host devices behave differently when a bluetooth keyboard is connected, for example by hiding their on-screen +keyboard. Note that at present the active bluetooth profile will immediately reconnect if disconnected. This is true +even if OUT_USB is selected. To remain disconnected, another bluetooth profile must be first selected using (e.g.) +`BT_SEL`. + +::: + +## Bluetooth Command Defines + +Bluetooth command defines are provided through the [`dt-bindings/zmk/bt.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/bt.h) header, +which is added at the top of the keymap file: + +```dts +#include +``` + +This will allow you to reference the actions defined in this header such as `BT_CLR`. + +Here is a table describing the command for each define: + +| Define | Action | +| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `BT_CLR` | Clear bond information between the keyboard and host for the selected profile. | +| `BT_NXT` | Switch to the next profile, cycling through to the first one when the end is reached. | +| `BT_PRV` | Switch to the previous profile, cycling through to the last one when the beginning is reached. | +| `BT_SEL` | Select the 0-indexed profile by number; must include a number as an argument in the keymap to work correctly, e.g. `BT_SEL 0`. | +| `BT_DISC` | Disconnect from the 0-indexed profile by number, if it's currently connected and inactive; must include a number as an argument in the keymap to work correctly, e.g. `BT_DISC 0`. | + +:::note Selected profile persistence +The profile that is selected by the `BT_SEL`/`BT_PRV`/`BT_NXT` actions will be saved to flash storage and hence persist across restarts and firmware flashes. +However it will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory. +::: + +## Bluetooth Behavior + +The bluetooth behavior completes an bluetooth action given on press. + +### Behavior Binding + +- Reference: `&bt` +- Parameter #1: The bluetooth command define, e.g. `BT_CLR` +- Parameter #2: Only applies to `BT_SEL` and is the 0-indexed profile by number + +### Examples + +1. Behavior binding to clear the paired host for the selected profile: + + ```dts + &bt BT_CLR + ``` + +1. Behavior binding to select the next profile: + + ```dts + &bt BT_NXT + ``` + +1. Behavior binding to select the previous profile: + + ```dts + &bt BT_PRV + ``` + +1. Behavior binding to select the 2nd profile (passed parameters are [zero based](https://en.wikipedia.org/wiki/Zero-based_numbering)): + + ```dts + &bt BT_SEL 1 + ``` + +## Bluetooth Pairing and Profiles + +ZMK support bluetooth “profiles” which allows connection to multiple devices (5 by default). Each profile stores the bluetooth MAC address of a peer, which can be empty if a profile has not been paired with a device yet. Upon switching to a profile, ZMK does the following: + +- If a profile has not been paired with a peer yet, ZMK automatically advertises itself as connectable. You can discover your keyboard from bluetooth scanning on your laptop / tablet. If you try to connect, it will trigger the _pairing_ procedure. After pairing, the bluetooth MAC address of the peer device will be stored in the current profile. Pairing also negotiates a random key for secure communication between the device and the keyboard. +- If a profile has been paired but the peer is not connected yet, ZMK will also advertise itself as connectable. In the future, the behavior might change to _direct advertising_ which only target the peer with the stored bluetooth MAC address. In this state, if the peer is powered on and moved within the distance of bluetooth signal coverage, it should automatically connect to the keyboard. +- If a profile has been paired and is currently connected, ZMK will not advertise it as connectable. + +The bluetooth MAC address and negotiated keys during pairing are stored in the permanent storage on your chip and can be reused even after reflashing the firmware. If for some reason you want to delete the stored information, you can bind the `BT_CLR` behavior described above to a key and use it to clear the _current_ profile. + +:::note Number of Profiles +Please note there are five available Bluetooth profiles by default. If you need to adjust the number of available profiles, set `CONFIG_BT_MAX_CONN` _and_ `CONFIG_BT_MAX_PAIRED` to the desired number of profiles, `n`, or `n+1` for split keyboards, in your `zmk-config` `.conf` file. +::: + +:::note +If you clear bond of a paired profile, make sure you do the same thing on the peer device as well (typically achieved by _removing_ or _forgetting_ the bluetooth connection). Otherwise the peer will try to connect to your keyboard whenever it discovers it. But while the MAC address of both devices could remain the same, the security key no longer match: the peer device still possess the old key negotiated in the previous pairing procedure, but our keyboard firmware has deleted that key. So the connection will fail. If you [enabled USB logging](../development/usb-logging.md), you might see a lot of failed connection attempts due to the reason of “Security failed”. +::: diff --git a/docs/docs/behaviors/caps-word.md b/docs/docs/behaviors/caps-word.md new file mode 100644 index 000000000000..77c8fd20d2a8 --- /dev/null +++ b/docs/docs/behaviors/caps-word.md @@ -0,0 +1,72 @@ +--- +title: Caps Word Behavior +sidebar_label: Caps Word +--- + +## Summary + +The caps word behavior behaves similar to a caps lock, but will automatically deactivate when any key not in a continue list is pressed, or if the caps word key is pressed again. For smaller keyboards using [mod-taps](/docs/behaviors/mod-tap), this can help avoid repeated alternating holds when typing words in all caps. + +The modifiers are applied only to to the alphabetic (`A` to `Z`) keycodes, to avoid automatically applying them to numeric values, etc. + +### Behavior Binding + +- Reference: `&caps_word` + +Example: + +```dts +&caps_word +``` + +### Configuration + +#### Continue List + +By default, the caps word will remain active when any alphanumeric character or underscore (`UNDERSCORE`), backspace (`BACKSPACE`), or delete (`DELETE`) characters are pressed. Any other non-modifier keycode sent will turn off caps word. If you would like to override this, you can set a new array of keys in the `continue-list` property in your keymap: + +```dts +&caps_word { + continue-list = ; +}; + +/ { + keymap { + ... + }; +}; +``` + +#### Applied Modifier(s) + +In addition, if you would like _multiple_ modifiers, instead of just `MOD_LSFT`, you can override the `mods` property: + +```dts +&caps_word { + mods = <(MOD_LSFT | MOD_LALT)>; +}; + +/ { + keymap { + ... + }; +}; +``` + +### Multiple Caps Breaks + +If you want to use multiple caps breaks with different codes to break the caps, you can add additional caps words instances to use in your keymap: + +```dts +/ { + prog_caps: prog_caps { + compatible = "zmk,behavior-caps-word"; + #binding-cells = <0>; + continue-list = ; + }; + + keymap { + ... + }; +}; +``` diff --git a/docs/docs/behaviors/hold-tap.md b/docs/docs/behaviors/hold-tap.md new file mode 100644 index 000000000000..64fb9396c129 --- /dev/null +++ b/docs/docs/behaviors/hold-tap.md @@ -0,0 +1,329 @@ +--- +title: Hold-Tap Behavior +sidebar_label: Hold-Tap +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Summary + +Hold-tap is the basis for other behaviors such as layer-tap and mod-tap. + +Simply put, the hold-tap key will output the 'hold' behavior if it's held for a while, and output the 'tap' behavior when it's tapped quickly. + +### Hold-Tap + +The graph below shows how the hold-tap decides between a 'tap' and a 'hold'. + +![Simple behavior](../assets/hold-tap/case1_2.svg) + +By default, the hold-tap is configured to also select the 'hold' functionality if another key is tapped while it's active: + +![Hold preferred behavior](../assets/hold-tap/case_hold_preferred.svg) + +We call this the 'hold-preferred' flavor of hold-taps. While this flavor may work very well for a ctrl/escape key, it's not very well suited for home-row mods or layer-taps. That's why there are two more flavors to choose from: 'tap-preferred' and 'balanced'. + +#### Flavors + +- The 'hold-preferred' flavor triggers the hold behavior when the `tapping-term-ms` has expired or another key is pressed. +- The 'balanced' flavor will trigger the hold behavior when the `tapping-term-ms` has expired or another key is pressed and released. +- The 'tap-preferred' flavor triggers the hold behavior when the `tapping-term-ms` has expired. Pressing another key within `tapping-term-ms` does not affect the decision. +- The 'tap-unless-interrupted' flavor triggers a hold behavior only when another key is pressed before `tapping-term-ms` has expired. It triggers the tap behavior in all other situations. + +When the hold-tap key is released and the hold behavior has not been triggered, the tap behavior will trigger. + +![Hold-tap comparison](../assets/hold-tap/comparison.svg) + +### Basic usage + +For basic usage, please see the [mod-tap](mod-tap.md) and [layer-tap](layers.md#layer-tap) pages. + +### Advanced Configuration + +#### `tapping-term-ms` + +Defines how long a key must be pressed to trigger Hold behavior. + +#### `quick-tap-ms` + +If you press a tapped hold-tap again within `quick-tap-ms` milliseconds of the first press, it will always trigger the tap behavior. This is useful for things like a backspace, where a quick tap+hold holds backspace pressed. Set this to a negative value to disable. The default is -1 (disabled). + +#### `require-prior-idle-ms` + +`require-prior-idle-ms` is like `quick-tap-ms` however it will apply for _any_ non-modifier key pressed before it. This effectively disables the hold-tap when typing quickly, which can be quite useful for homerow mods. It can also have the effect of removing the input delay when typing quickly. + +For example, the following hold-tap configuration enables `require-prior-idle-ms` with a 125 millisecond term, alongside `quick-tap-ms` with a 200 millisecond term. + +```dts +rpi: require_prior_idle { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <200>; + quick-tap-ms = <200>; + require-prior-idle-ms = <125>; + bindings = <&kp>, <&kp>; +}; +``` + +If you press `&kp A` and then `&rpi LEFT_SHIFT B` **within** 125 ms, then `ab` will be output. Importantly, `b` will be output immediately since it was within the `require-prior-idle-ms`, without waiting for a timeout or an interrupting key. In other words, the `&rpi LEFT_SHIFT B` binding will only have its underlying hold-tap behavior if it is pressed 125 ms **after** the previous key press; otherwise it will act like `&kp B`. + +Note that the greater the value of `require-prior-idle-ms` is, the harder it will be to invoke the hold behavior, making this feature less applicable for use-cases like capitalizing letters while typing normally. However, if the hold behavior isn't used during fast typing, then it can be an effective way to mitigate misfires. + +#### `retro-tap` + +If `retro-tap` is enabled, the tap behavior is triggered when releasing the hold-tap key if no other key was pressed in the meantime. + +For example, if you press `&mt LEFT_SHIFT A` and then release it without pressing another key, it will output `a`. + +```dts +&mt { + retro-tap; +}; +``` + +#### Positional hold-tap and `hold-trigger-key-positions` + +Including `hold-trigger-key-positions` in your hold-tap definition turns on the positional hold-tap feature. With positional hold-tap enabled, if you press any key **NOT** listed in `hold-trigger-key-positions` before `tapping-term-ms` expires, it will produce a tap. + +In all other situations, positional hold-tap will not modify the behavior of your hold-tap. Positional hold-tap is useful when used with home-row modifiers: for example, if you have a home-row modifier key in the left hand, by including only key positions from the right hand in `hold-trigger-key-positions`, you will only get hold behaviors during cross-hand key combinations. + +:::info +Note that `hold-trigger-key-positions` is an array of key position indexes. Key positions are numbered sequentially according to your keymap, starting with 0. So if the first key in your keymap is Q, this key is in position 0. The next key (probably W) will be in position 1, et cetera. +::: + +See the following example, which uses a hold-tap behavior definition, configured with the `hold-preferred` flavor, and with positional hold-tap enabled: + +```dts +#include +#include + +/ { + behaviors { + pht: positional_hold_tap { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "hold-preferred"; + tapping-term-ms = <400>; + quick-tap-ms = <200>; + bindings = <&kp>, <&kp>; + hold-trigger-key-positions = <1>; // <---[[the W key]] + }; + }; + keymap { + compatible = "zmk,keymap"; + default_layer { + bindings = < + // position 0 position 1 position 2 + &pht LEFT_SHIFT Q &kp W &kp E + >; + }; + }; +}; +``` + +- The sequence `(pht_down, E_down, E_up, pht_up)` produces `qe`. The normal hold behavior (LEFT_SHIFT) **IS** modified into a tap behavior (Q) by positional hold-tap because the first key pressed after the hold-tap key is the `E key`, which is in position 2, which **is NOT** included in `hold-trigger-key-positions`. +- The sequence `(pht_down, W_down, W_up, pht_up)` produces `W`. The normal hold behavior (LEFT_SHIFT) **is NOT** modified into a tap behavior (Q) by positional hold-tap because the first key pressed after the hold-tap key is the `W key`, which is in position 1, which **IS** included in `hold-trigger-key-positions`. +- If the `LEFT_SHIFT / Q key` is held by itself for longer than `tapping-term-ms`, a hold behavior is produced. This is because positional hold-tap only modifies the behavior of a hold-tap if another key is pressed before the `tapping-term-ms` period expires. + +By default, `hold-trigger-key-positions` are evaluated upon the first _key press_ after +the hold-tap. For homerow mods, this is not always ideal, because it prevents combining multiple modifiers unless they are included in `hold-trigger-key-positions`. To overwrite this behavior, one can set `hold-trigger-on-release`. If set to true, the evaluation of `hold-trigger-key-positions` gets delayed until _key release_. This allows combining multiple modifiers when the next key is _held_, while still deciding the hold-tap in favor of a tap when the next key is _tapped_. + +#### Using different behavior types with hold-taps + +You can create instances of hold-taps invoking most [behavior types](../features/keymaps.md#behaviors) for hold or tap actions, by referencing their node labels in the `bindings` value. +The two parameters that are passed to the hold-tap in your keymap will be forwarded to the referred behaviors, first one to the hold behavior and second one to the tap. + +If you use behaviors that accept no parameters such as [mod-morphs](mod-morph.md) or [macros](macros.md), you can pass a dummy parameter value such as `0` to the hold-tap when you use it in your keymap. +For instance, a hold-tap with node label `caps` and `bindings = <&kp>, <&caps_word>;` can be used in the keymap as below to send the caps lock keycode on hold and invoke the [caps word behavior](caps-word.md) on tap: + +```dts +&caps CAPS 0 +``` + +:::info +You cannot use behaviors that expect more than one parameter such as [`&bt`](bluetooth.md) and [`&rgb_ug`](underglow.md) with hold-taps, due to the limitations of the [devicetree keymap format](../config/index.md#devicetree-files). +One workaround is to create a [macro](macros.md) that invokes those behaviors and use the macro as the hold or tap action. +::: + +### Example Use-Cases + + + + + +The following are suggested hold-tap configurations that work well with home row mods: + +##### Option 1: cross-hand only modifiers, using `tap-unless-interrupted` and positional hold-tap (`hold-trigger-key-positions`) + +```dts title="Homerow Mods: Cross-hand Example" +#include +#include + +/ { + behaviors { + lh_pht: left_positional_hold_tap { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "tap-unless-interrupted"; + tapping-term-ms = <100>; // <---[[produces tap if held longer than tapping-term-ms]] + quick-tap-ms = <200>; + bindings = <&kp>, <&kp>; + hold-trigger-key-positions = <5 6 7 8 9 10>; // <---[[right-hand keys]] + }; + }; + + keymap { + compatible = "zmk,keymap"; + default_layer { + bindings = < + // position 0 pos 1 pos 2 pos 3 pos 4 pos 5 pos 6 pos 7 pos 8 pos 9 pos 10 + &lh_pht LSFT A &lh_pht LGUI S &lh_pht LALT D &lh_pht LCTL F &kp G &kp H &kp I &kp J &kp K &kp L &kp SEMI + >; + }; + }; +}; +``` + +##### Option 2: `tap-preferred` + +```dts title="Homerow Mods: Tap-Preferred Example" +#include +#include + +/ { + behaviors { + hm: homerow_mods { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + tapping-term-ms = <150>; + quick-tap-ms = <0>; + flavor = "tap-preferred"; + bindings = <&kp>, <&kp>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + default_layer { + bindings = < + &hm LCTRL A &hm LGUI S &hm LALT D &hm LSHIFT F + >; + }; + }; +}; +``` + +##### Option 3: `balanced` + +```dts title="Homerow Mods: Balanced Example" +#include +#include + +/ { + behaviors { + bhm: balanced_homerow_mods { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + tapping-term-ms = <200>; // <---[[moderate duration]] + quick-tap-ms = <0>; + flavor = "balanced"; + bindings = <&kp>, <&kp>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + default_layer { + bindings = < + &bhm LCTRL A &bhm LGUI S &bhm LALT D &bhm LSHIFT F + >; + }; + }; +}; +``` + + + + + +A popular method of implementing Autoshift in ZMK involves a C-preprocessor macro, commonly defined as `AS(keycode)`. This macro applies the `LSHIFT` modifier to the specified `keycode` when `AS(keycode)` is held, and simply performs a [keypress](key-press.md), `&kp keycode`, when the `AS(keycode)` binding is tapped. This simplifies the use of Autoshift in a keymap, as the complete hold-tap bindings for each desired Autoshift key, as in `&as LS() &as LS() ... &as LS() `, can be quite cumbersome to use when applied to a large portion of the keymap. + +```dts title="Hold-Tap Example: Autoshift" +#include +#include + +#define AS(keycode) &as LS(keycode) keycode // Autoshift Macro + +/ { + behaviors { + as: auto_shift { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + tapping_term_ms = <135>; + quick_tap_ms = <0>; + flavor = "tap-preferred"; + bindings = <&kp>, <&kp>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + default_layer { + bindings = < + AS(Q) AS(W) AS(E) AS(R) AS(T) AS(Y) // Autoshift applied for QWERTY keys + >; + }; + }; +}; +``` + + + + + +This hold-tap example implements a [momentary-layer](layers.md/#momentary-layer) when the keybind is held and a [toggle-layer](layers.md/#toggle-layer) when it is tapped. Similar to the Autoshift and Sticky Hold use-cases, a `MO_TOG(layer)` macro is defined such that the `&mo` and `&tog` behaviors can target a single layer. + +```dts title="Hold-Tap Example: Momentary layer on Hold, Toggle layer on Tap" +#include +#include + +#define MO_TOG(layer) &mo_tog layer layer // Macro to apply momentary-layer-on-hold/toggle-layer-on-tap to a specific layer + +/ { + behaviors { + mo_tog: behavior_mo_tog { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "hold-preferred"; + tapping-term-ms = <200>; + bindings = <&mo>, <&tog>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + default_layer { + bindings = < + &mo_tog 2 1 // &mo 2 on hold, &tog 1 on tap + MO_TOG(3) // &mo 3 on hold, &tog 3 on tap + >; + }; + }; +}; +``` + + + + + +### Comparison to QMK + +The `hold-preferred` flavor works similar to the `HOLD_ON_OTHER_KEY_PRESS` setting in QMK. The `balanced` flavor is similar to the `PERMISSIVE_HOLD` setting, and the `tap-preferred` flavor is the QMK default. diff --git a/docs/docs/behaviors/key-press.md b/docs/docs/behaviors/key-press.md new file mode 100644 index 000000000000..a298d040b451 --- /dev/null +++ b/docs/docs/behaviors/key-press.md @@ -0,0 +1,49 @@ +--- +title: Key Press Behaviors +sidebar_label: Key Press +--- + +## Summary + +The most basic of behaviors, is the ability to send certain keycode presses and releases in response to activating +a certain key. + +The categories of supported codes are: + +- [Keyboard & Keypad](../codes/keyboard-keypad.mdx) +- [Editing](../codes/editing.mdx) +- [Media](../codes/media.mdx) +- [Applications](../codes/applications.mdx) +- [Input Assist](../codes/input-assist.mdx) +- [Power](../codes/power.mdx) + +Please visit the [codes](../codes/index.mdx) section for a comprehensive list. + +For advanced users, user-defined HID usages are also supported but must be encoded, please see [`dt-bindings/zmk/keys.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/keys.h) for further insight. + +## Keycode Defines + +To make it easier to encode the HID keycode numeric values, most keymaps include +the [`dt-bindings/zmk/keys.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/keys.h) header +provided by ZMK near the top: + +```dts +#include +``` + +Doing so makes a set of defines such as `A`, `N1`, etc. available for use with these behaviors + +## Key Press + +The "key press" behavior sends standard keycodes on press/release. + +### Behavior Binding + +- Reference: `&kp` +- Parameter: The keycode usage ID from the usage page, e.g. `N4` or `A` + +Example: + +```dts +&kp A +``` diff --git a/docs/docs/behaviors/key-repeat.md b/docs/docs/behaviors/key-repeat.md new file mode 100644 index 000000000000..9772fdb4e0a3 --- /dev/null +++ b/docs/docs/behaviors/key-repeat.md @@ -0,0 +1,38 @@ +--- +title: Key Repeat Behavior +sidebar_label: Key Repeat +--- + +## Summary + +The key repeat behavior when triggered will send whatever keycode was last sent/triggered. + +### Behavior Binding + +- Reference: `&key_repeat` + +Example: + +```dts +&key_repeat +``` + +### Configuration + +#### Usage Pages + +By default, the key repeat will only track the last pressed key from the HID "Key" usage page, and ignore events from other usages, e.g. Consumer page. + +If you'd rather have the repeat also capture and send Consumer page usages, you can update the existing behavior: + +```dts +&key_repeat { + usage-pages = ; +}; + +/ { + keymap { + ... + }; +}; +``` diff --git a/docs/docs/behaviors/key-toggle.md b/docs/docs/behaviors/key-toggle.md new file mode 100644 index 000000000000..080b5b53aa69 --- /dev/null +++ b/docs/docs/behaviors/key-toggle.md @@ -0,0 +1,26 @@ +--- +title: Key Toggle Behavior +sidebar_label: Key Toggle +--- + +## Summary + +The key toggle behavior toggles the press of a key. +If the key is not currently pressed, key toggle will press it, holding it until the key toggle is pressed again or the key is released in some other way. +If the key _is_ currently pressed, key toggle will release it. + +Example uses for key toggle include shift lock, or `ALT-TAB` window switching without holding down the `ALT` modifier. + +### Behavior Binding + +- Reference: `&kt` +- Parameter: The [keycode](../codes/index.mdx), e.g. `LALT` or `DOWN_ARROW` + +Example: + +```dts +&kt LALT +``` + +You can use any keycode that works for `&kp` as parameter to `&kt`, however, [modified keys](../codes/modifiers.mdx#modifier-functions) such as `LA(A)` will be toggled based on the status of the base keycode (in this case `A`). +In other words, modifiers are ignored when determining whether or not the key is currently pressed. diff --git a/docs/docs/behaviors/layers.md b/docs/docs/behaviors/layers.md new file mode 100644 index 000000000000..162b792fcd4d --- /dev/null +++ b/docs/docs/behaviors/layers.md @@ -0,0 +1,155 @@ +--- +title: Layer Behaviors +sidebar_label: Layers +--- + +## Summary + +Often, you may want a certain key position to alter which layers are enabled, change the default layer, etc. +Some of those behaviors are still in the works; the ones that are working now are documented here. + +## Defines To Refer To Layers + +When working with layers, you may have several different key positions with bindings that enable/disable those layers. +To make it easier to refer to those layers in your key bindings, and to change which layers are where later, you can +add a set of `#define`s at the top of your keymap file, and use those layer in your keymap. + +For example, if you have three layers, you can add the following to the top of your keymap: + +```dts +#define DEFAULT 0 +#define LOWER 1 +#define RAISE 2 +``` + +This allows you to use those defines, e.g. `LOWER` later in your keymap. + +## Momentary Layer + +The "momentary layer" behavior enables a layer while a certain key is pressed. Immediately upon +activation of the key, the layer is enabled, and immediately upon release of the key, the layer is disabled +again. + +### Behavior Binding + +- Reference: `&mo` +- Parameter: The layer number to enable/disable, e.g. `1` + +Example: + +```dts +&mo LOWER +``` + +## Layer-tap + +The "layer-tap" behavior enables a layer when a key is held, and outputs a [keypress](key-press.md) when the key is only tapped for a short time. + +### Behavior Binding + +- Reference: `<` +- Parameter: The layer number to enable when held, e.g. `1` +- Parameter: The keycode to send when tapped, e.g. `A` + +Example: + +```dts +< LOWER SPACE +``` + +### Configuration + +You can configure a different tapping term or tweak other properties noted in the [hold-tap](hold-tap.md#advanced-configuration) documentation page in your keymap: + +```dts +< { + tapping-term-ms = <200>; +}; + +/ { + keymap { + ... + }; +}; +``` + +:::info +Functionally, the layer-tap is a [hold-tap](hold-tap.md) of the ["tap-preferred" flavor](hold-tap.md/#flavors) and a [`tapping-term-ms`](hold-tap.md/#tapping-term-ms) of 200 that takes in a [`momentary layer`](#momentary-layer) and a [keypress](key-press.md) as its "hold" and "tap" parameters, respectively. + +For users who want to send a different [keycode](../codes/index.mdx) depending on if the same key is held or tapped, see [Mod-Tap](mod-tap.md). + +Similarly, for users looking to create a keybind like the layer-tap that depending on how long the key is held, invokes behaviors like [sticky keys](sticky-key.md) or [key toggles](key-toggle.md), see [Hold-Tap](hold-tap.md). + +::: + +## To Layer + +The "to layer" behavior enables a layer and disables _all_ other layers _except_ the default layer. + +### Behavior Binding + +- Reference: `&to` +- Parameter: The layer number to enable, e.g. `1` + +Example: + +```dts +&to 3 +``` + +## Toggle Layer + +The "toggle layer" behavior enables a layer until the layer is manually disabled. + +### Behavior Binding + +- Reference: `&tog` +- Parameter: The layer number to enable/disable, e.g. `1` + +Example: + +```dts +&tog LOWER +``` + +"Toggle layer" for a : + +```dts +#define DEFAULT 0 +#define NAVI 1 + +#define NONE 0 + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &tog NAVI &kp KP_DIVIDE &kp KP_MULTIPLY &kp KP_MINUS + &kp NUMBER_7 &kp NUMBER_8 &kp NUMBER_9 &kp KP_PLUS + &kp NUMBER_4 &kp NUMBER_5 &kp NUMBER_6 &kp KP_PLUS + &kp NUMBER_1 &kp NUMBER_2 &kp NUMBER_3 &kp RETURN + &kp NUMBER_0 &kp NUMBER_0 &kp DOT &kp RETURN + >; + }; + + nav_layer { + bindings = < + &tog NAVI &kp KP_DIVIDE &kp KP_MULTIPLY &kp KP_MINUS + &kp HOME &kp UP &kp PAGE_UP &kp KP_PLUS + &kp LEFT &none &kp RIGHT &kp KP_PLUS + &kp END &kp DOWN &kp PAGE_DOWN &kp RETURN + &kp INSERT &kp INSERT &kp DEL &kp RETURN + >; + }; + }; +}; +``` + +It is possible to use "toggle layer" to have keys that raise and lower the layers as well. + +## Conditional Layers + +The "conditional layers" feature enables a particular layer when all layers in a specified set are active. +For more information, see [conditional layers](../features/conditional-layers.md). diff --git a/docs/docs/behaviors/macros.md b/docs/docs/behaviors/macros.md new file mode 100644 index 000000000000..37ca80ffbb5a --- /dev/null +++ b/docs/docs/behaviors/macros.md @@ -0,0 +1,331 @@ +--- +title: Macro Behavior +sidebar_label: Macros +--- + +## Summary + +The macro behavior allows configuring a list of other behaviors to invoke +when the macro is pressed and/or released. + +## Macro Definition + +Each macro you want to use in your keymap gets defined first, then bound in your keymap. + +A macro definition looks like: + +```dts +/ { + macros { + zed_em_kay: zed_em_kay { + compatible = "zmk,behavior-macro"; + #binding-cells = <0>; + bindings + = <¯o_press &kp LSHFT> + , <¯o_tap &kp Z &kp M &kp K> + , <¯o_release &kp LSHFT> + ; + }; + }; +}; +``` + +:::note +The text before the colon (`:`) in the declaration of the macro node is the "node label", and is the text +used to reference the macro in your keymap. +::: + +The macro can then be bound in your keymap by referencing it by the label `&zed_em_kay`, e.g.: + +```dts + raise_layer { + bindings = <&zed_em_kay>; + }; +``` + +:::note +For use cases involving sending a single keycode with modifiers, for instance ctrl+tab, the [key press behavior](key-press.md) +with [modifier functions](../codes/modifiers.mdx#modifier-functions) can be used instead of a macro. +::: + +### Bindings + +Like [hold-taps](/docs/behaviors/hold-tap), macros are created by composing other behaviors, and any of those behaviors can +be added to the `bindings` list, e.g.: + +```dts +bindings + = <&to 1> + , <&bl BL_ON> + , <&kp Z &kp M &kp K &kp EXCLAMATION> + ; +``` + +## Macro Controls + +There are a set of special macro controls that can be included in the `bindings` list to modify the +way the macro is processed. + +### Binding Activation Mode + +Bindings in a macro are activated differently, depending on the current "activation mode" of the macro. + +Available modes: + +- Tap - The default mode; when in this mode, the macro will press, then release, each behavior in the `bindings` list. This mode is useful for + basic keycode output to hosts, i.e. when activating a `&kp` behavior. +- Press - In this mode, the macro will only trigger a press on each behavior in the `bindings` list. This is useful for holding down modifiers for some duration of a macro, e.g. `&kp LALT`. +- Release - In this mode, the macro will only trigger a release on each behavior in the `bindings` list. This is useful for releasing modifiers previously pressed earlier in the macro processing, e.g. `&kp LALT`. + +To modify the activation mode, macro controls can be added at any point in the `bindings` list. + +- `¯o_tap` +- `¯o_press` +- `¯o_release` + +A concrete example, used to hold a modifier, tap multiple keys, then release the modifier, would look like: + +```dts +bindings + = <¯o_press &kp LSHFT> + , <¯o_tap &kp Z &kp M &kp K> + , <¯o_release &kp LSHFT> + ; +``` + +### Processing Continuation on Release + +The macro can be paused so that only part of the `bindings` list is processed when the macro is pressed, and the remainder is processed once +the macro itself is released. + +To pause the macro until release, use `¯o_pause_for_release`. For example, this macro will press a modifier and activate a layer when the macro is pressed. Once the macro is released, it will release the modifier and deactivate the layer by releasing the `&mo`: + +```dts +bindings + = <¯o_press &mo 1 &kp LSHFT> + , <¯o_pause_for_release> + , <¯o_release &mo 1 &kp LSHFT> + ; +``` + +### Wait Time + +The wait time setting controls how long of a delay is introduced between behaviors in the `bindings` list. The initial wait time for a macro, +which is equal to the value of [`CONFIG_ZMK_MACRO_DEFAULT_WAIT_MS`](../config/behaviors.md#macro) by default, can +be set by assigning a value to the `wait-ms` property of the macro, e.g. `wait-ms = <20>;`. If you want to update the wait time at any +point in the macro bindings list, use `¯o_wait_time`, e.g. `¯o_wait_time 30`. A full example: + +```dts +wait-ms = <10>; +bindings + = <&kp F &kp A &kp S &kp T> + , <¯o_wait_time 500> + , <&kp S &kp L &kp O &kp W> + ; +``` + +### Tap Time + +The tap time setting controls how long a tapped behavior is held in the `bindings` list. The initial tap time for a macro, +which is equal to the value of [`CONFIG_ZMK_MACRO_DEFAULT_TAP_MS`](../config/behaviors.md#macro) by default, can +be set by assigning a value to the `tap-ms` property of the macro, e.g. `tap-ms = <20>;`. If you want to update the tap time at any +point in a macro bindings list, use `¯o_tap_time`, e.g. `¯o_tap_time 30`. A full example: + +```dts +bindings + = <¯o_tap_time 10> + , <&kp S &kp H &kp O &kp R &kp T> + , <¯o_tap_time 500> + , <&kp L &kp O &kp N &kp G> + ; +``` + +### Behavior Queue Limit + +Macros use an internal queue to invoke each behavior in the bindings list when triggered, which has a size of 64 by default. Bindings in "press" and "release" modes correspond to one event in the queue, whereas "tap" mode bindings correspond to two (one for press and one for release). As a result, the effective number of actions processed might be less than 64 and this can cause problems for long macros. + +To prevent issues with longer macros, you can change the size of this queue via the `CONFIG_ZMK_BEHAVIORS_QUEUE_SIZE` setting in your configuration, [typically through your `.conf` file](../config/index.md). For example, `CONFIG_ZMK_BEHAVIORS_QUEUE_SIZE=512` would allow your macro to type about 256 characters. + +Another limit worth noting is that the maximum number of bindings you can pass to a `bindings` field in the [Devicetree](../config/index.md#devicetree-files) is 256, which also constrains how many behaviors can be invoked by a macro. + +## Parameterized Macros + +Macros can also be "parameterized", allowing them to be bound in your keymap with unique values passed into them, e.g.: + +```dts + raise_layer { + bindings = <&my_one_param_macro A> + }; +``` + +### Defining Parameterized Macros + +Parameterized macros must be defined using specific values for the `compatible` and `#binding-cells` properties, depending on how many parameters they require (up to a maximum of two): + +```dts +/ { + macros { + // 0 params macro + my_macro: my_macro { + // ... + compatible = "zmk,behavior-macro"; + #binding-cells = <0>; // Must be 0 + bindings = /* ... */; + }; + + // 1 param macro + my_one_param_macro: my_one_param_macro { + // ... + compatible = "zmk,behavior-macro-one-param"; + #binding-cells = <1>; // Must be 1 + bindings = /* ... */; + }; + + // 2 params macro + my_two_param_macro: my_two_param_macro { + // ... + compatible = "zmk,behavior-macro-two-param"; + #binding-cells = <2>; // Must be 2 + bindings = /* ... */; + }; + }; +}; +``` + +### Parameters, Bindings and Controls + +There are special macro controls which must be used in order to forward received parameters to the macro's `bindings`. These controls are "one shot" and will determine how received parameters are used on the very next (non-macro control) behavior in the macro's `bindings` list. + +For example, to pass the first parameter received into a `&kp` binding, you would use: + +```dts +bindings = <¯o_param_1to1>, <&kp MACRO_PLACEHOLDER>; +``` + +Because `kp` takes one parameter, you can't simply make the second entry `<&kp>` in the `bindings` list. Whatever value you do pass in will be replaced when the macro is triggered, so you can put _any_ value there, e.g. `0`, `A` keycode, etc. To make it very obvious that the parameter there is not actually going to be used, you can use `MACRO_PLACEHOLDER` which is simply an alias for `0`. + +The available parameter controls are: + +- `¯o_param_1to1` - pass the first parameter of the macro into the first parameter of the next behavior in the `bindings` list. +- `¯o_param_1to2` - pass the first parameter of the macro into the second parameter of the next behavior in the `bindings` list. + +* `¯o_param_2to1` - pass the second parameter of the macro into the first parameter of the next behavior in the `bindings` list. +* `¯o_param_2to2` - pass the second parameter of the macro into the second parameter of the next behavior in the `bindings` list. + +## Common Patterns + +Below are some examples of how the macro behavior can be used for various useful functionality. + +### Layer Activation + More + +Macros make it easy to combine a [layer behavior](/docs/behaviors/layers), e.g. `&mo` with another behavior at the same time. +Common examples are enabling one or more modifiers when the layer is active, or changing the RBG underglow color. + +To achieve this, a combination of a 0ms wait time and splitting the press and release between a `¯o_pause_for_release` is used: + +#### Layer + Modifier + +```dts +/** + * Temporarily switches to a layer (`&mo`) while a modifier is held. + * Analogous to QMK's `LM()`, using a parameterized macro. + * + * Params: + * 1. Layer to switch to + * 2. Modifier to press while layer is active + * + * Example: + * `&lm NUM_LAYER LSHIFT` + */ +lm: lm { + compatible = "zmk,behavior-macro-two-param"; + wait-ms = <0>; + tap-ms = <0>; + #binding-cells = <2>; + bindings + = <¯o_param_1to1> + , <¯o_press &mo MACRO_PLACEHOLDER> + , <¯o_param_2to1> + , <¯o_press &kp MACRO_PLACEHOLDER> + , <¯o_pause_for_release> + , <¯o_param_2to1> + , <¯o_release &kp MACRO_PLACEHOLDER> + , <¯o_param_1to1> + , <¯o_release &mo MACRO_PLACEHOLDER> + ; +}; +``` + +#### Layer + Underglow Color + +To trigger a different underglow when the macro is pressed, and when it is released, we use the macro "press" activation mode whenever triggering the `&rgb_ug` behavior: + +```dts +wait-ms = <0>; +tap-ms = <0>; +bindings + = <¯o_press &mo 1> + , <¯o_tap &rgb_ug RGB_COLOR_HSB(128,100,100)> + , <¯o_pause_for_release> + , <¯o_release &mo 1> + , <¯o_tap &rgb_ug RGB_COLOR_HSB(300,100,50)>; +``` + +### Keycode Sequences + +The other common use case for macros is to sending sequences of keycodes to the connected host. Here, a wait and tap time of at least 30ms is recommended to +avoid having HID notifications grouped at the BLE protocol level and then processed out of order: + +```dts +wait-ms = <40>; +tap-ms = <40>; +bindings + = <&kp Z &kp M &kp K> + , <&kp SPACE> + , <&kp R &kp O &kp C &kp K &kp S> + ; +``` + +### Unicode Sequences + +Many operating systems allow a special sequence to input unicode characters, e.g. [Windows alt codes](https://support.microsoft.com/en-us/office/insert-ascii-or-unicode-latin-based-symbols-and-characters-d13f58d3-7bcb-44a7-a4d5-972ee12e50e0). You can use macros to automate inputting the sequences, e.g. below macro inserts `£` on Windows: + +```dts +wait-ms = <40>; +tap-ms = <40>; +bindings + = <¯o_press &kp LALT> + , <¯o_tap &kp KP_N0 &kp KP_N1 &kp KP_N6 &kp KP_N3> + , <¯o_release &kp LALT> + ; +``` + +## Convenience C Macro + +To avoid repetition or possible typos when declaring a **zero parameter macro**, a convenience _C_ macro, named `ZMK_MACRO(name, props)` can be used to simplify things: + +```dts + ZMK_MACRO(my_zero_param_macro, + wait-ms = <30>; + tap-ms = <40>; + bindings = <&kp Z &kp M &kp K>; + ) +``` + +:::note +`ZMK_MACRO()` **only supports declaring non-parameterized (zero parameter) macros**; parameterized declarations are not currently supported. +::: + +This can be used instead of a complete macro definition. During the firmware build process, the example above would produce the complete macro definition below: + +```dts + my_zero_param_macro: my_zero_param_macro { + compatible = "zmk,behavior-macro"; + #binding-cells = <0>; + wait-ms = <30>; + tap-ms = <40>; + bindings = <&kp Z &kp M &kp K>; + }; +``` + +Using the C macro is entirely optional, and is provided only as a convenience. diff --git a/docs/docs/behaviors/misc.md b/docs/docs/behaviors/misc.md new file mode 100644 index 000000000000..c71f87c061b0 --- /dev/null +++ b/docs/docs/behaviors/misc.md @@ -0,0 +1,42 @@ +--- +title: Miscellaneous Behaviors +sidebar_label: Miscellaneous +--- + +## Summary + +There are a few miscellaneous behaviors that are helpful when working with layers in keymaps, +in particular, with handling what happens in higher layers, and if events are passed to +the next layer or not + +## Transparent + +The transparent behavior simply ignores key position presses/releases, so they will be +passed down to the next active layer in the stack. + +### Behavior Binding + +- Reference: `&trans` +- Parameters: None + +Example: + +```dts +&trans +``` + +## None + +The none behavior simply swallows and stops key position presses/releases, so they will **not** +be passed down to the next active layer in the stack. + +### Behavior Binding + +- Reference: `&none` +- Parameters: None + +Example: + +```dts +&none +``` diff --git a/docs/docs/behaviors/mod-morph.md b/docs/docs/behaviors/mod-morph.md new file mode 100644 index 000000000000..d5b3d589b71b --- /dev/null +++ b/docs/docs/behaviors/mod-morph.md @@ -0,0 +1,88 @@ +--- +title: Mod-Morph Behavior +sidebar_label: Mod-Morph +--- + +## Summary + +The Mod-Morph behavior sends a different keypress, depending on whether a specified modifier is being held during the keypress. + +- If you tap the key by itself, the first keycode is sent. +- If you tap the key while holding the specified modifier, the second keycode is sent. + +## Mod-Morph + +The Mod-Morph behavior acts as one of two keycodes, depending on if the required modifier is being held during the keypress. + +### Configuration + +An example of how to implement the mod-morph "Grave Escape": + +```dts +/ { + behaviors { + gresc: grave_escape { + compatible = "zmk,behavior-mod-morph"; + #binding-cells = <0>; + bindings = <&kp ESC>, <&kp GRAVE>; + mods = <(MOD_LGUI|MOD_LSFT|MOD_RGUI|MOD_RSFT)>; + }; + }; +}; +``` + +Note that this specific mod-morph exists in ZMK by default using code `&gresc`. + +### Behavior Binding + +- Reference: `&gresc` +- Parameter: None + +Example: + +```dts +&gresc +``` + +### Mods + +This is how you determine what modifiers will activate the morphed version of the keycode. + +Available Modifiers: + +- `MOD_LSFT` +- `MOD_RSFT` +- `MOD_LCTL` +- `MOD_RCTL` +- `MOD_LALT` +- `MOD_RALT` +- `MOD_LGUI` +- `MOD_RGUI` + +Example: + +```dts +mods = <(MOD_LGUI|MOD_LSFT|MOD_RGUI|MOD_RSFT)>; +``` + +### Advanced configuration + +`keep-mods` + +When a modifier specified in `mods` is being held, it won't be sent along with the morphed keycode unless it is also specified in `keep-mods`. By default `keep-mods` equals `0`, which means no modifier specified in `mods` will be sent along with the morphed keycode. + +For example, the following configuration morphs `LEFT_SHIFT` + `BACKSPACE` into `DELETE`, and morphs `RIGHT_SHIFT` + `BACKSPACE` into `RIGHT_SHIFT` + `DELETE`. + +```dts +/ { + behaviors { + bspc_del: backspace_delete { + compatible = "zmk,behavior-mod-morph"; + #binding-cells = <0>; + bindings = <&kp BACKSPACE>, <&kp DELETE>; + mods = <(MOD_LSFT|MOD_RSFT)>; + keep-mods = <(MOD_RSFT)>; + }; + }; +}; +``` diff --git a/docs/docs/behaviors/mod-tap.md b/docs/docs/behaviors/mod-tap.md new file mode 100644 index 000000000000..d789a8b723c8 --- /dev/null +++ b/docs/docs/behaviors/mod-tap.md @@ -0,0 +1,54 @@ +--- +title: Mod-Tap Behavior +sidebar_label: Mod-Tap +--- + +## Summary + +The Mod-Tap behavior sends a different keypress, depending on whether it's held or tapped. + +- If you hold the key for longer than 200ms, the first keycode ("mod") is sent. +- If you tap the key (release before 200ms), the second keycode ("tap") is sent. + +If you press another key within the 200ms, the 'mod' behavior is also activated. + +## Mod-Tap + +The Mod-Tap behavior either acts as a held modifier, or as a tapped keycode. + +### Behavior Binding + +- Reference: `&mt` +- Parameter #1: The keycode to be sent when activating as a modifier, e.g. `LSHIFT` +- Parameter #2: The keycode to sent when used as a tap, e.g. `A`, `B`. + +Example: + +```dts +&mt LSHIFT A +``` + +### Configuration + +You can configure a different tapping term in your keymap: + +```dts +&mt { + tapping-term-ms = <400>; +}; + +/ { + keymap { + ... + }; +}; +``` + +:::info +Under the hood, the mod-tap is simply a [hold-tap](hold-tap.md) of the ["hold-preferred" flavor](hold-tap.md/#flavors) with a [`tapping-term-ms`](hold-tap.md/#tapping-term-ms) of 200 that takes in two [keypresses](key-press.md) as its "hold" and "tap" parameters. This means that the mod-tap can be used to invoke **any** [keycode](../codes/index.mdx), and is not limited to only activating [modifier keys](../codes/modifiers.mdx) when it is held. + +For users who want to momentarily access a specific [layer](../features/keymaps#layers) while a key is held and send a keycode when the same key is tapped, see [Layer-Tap](layers.md/#layer-tap). + +Similarly, for users looking to create a keybind like the mod-tap that invokes behaviors _other_ than [keypresses](key-press.md), like [sticky keys](sticky-key.md) or [key toggles](key-toggle.md), see [Hold-Tap](hold-tap.md). + +::: diff --git a/docs/docs/behaviors/mouse-emulation.md b/docs/docs/behaviors/mouse-emulation.md new file mode 100644 index 000000000000..9ed0dd8e07b4 --- /dev/null +++ b/docs/docs/behaviors/mouse-emulation.md @@ -0,0 +1,66 @@ +--- +title: Mouse Emulation Behaviors +sidebar_label: Mouse Emulation +--- + +## Summary + +Mouse emulation behaviors send mouse events. Currently, only mouse button presses are supported, but movement +and scroll action support is planned for the future. + +Whenever the Mouse Emulation feature is turned on or off, the HID protocol used to communicate events to hosts changes. Unfortunately, those changes are not always detected automatically, and might require re-pairing your keyboard to your devices to work over bluetooth. If mouse behaviors are still not recognized by your device after doing that, you can try [these troubleshooting steps](../features/bluetooth.md#windows-connected-but-not-working). + +## Configuration Option + +This feature can be enabled or disabled explicitly via a config option: + +``` +CONFIG_ZMK_MOUSE=y +``` + +If you use the mouse key press behavior in your keymap, the feature will automatically be enabled for you. + +## Mouse Button Defines + +To make it easier to encode the HID mouse button numeric values, include +the [`dt-bindings/zmk/mouse.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/mouse.h) header +provided by ZMK near the top: + +``` +#include +``` + +## Mouse Button Press + +This behavior can press/release up to 5 mouse buttons. + +### Behavior Binding + +- Reference: `&mkp` +- Parameter: A `uint8` with bits 0 through 4 each referring to a button. + +The following defines can be passed for the parameter: + +| Define | Action | +| :------------ | :------------- | +| `MB1`, `LCLK` | Left click | +| `MB2`, `RCLK` | Right click | +| `MB3`, `MCLK` | Middle click | +| `MB4` | Mouse button 4 | +| `MB5` | Mouse button 5 | + +Mouse buttons 4 and 5 typically map to "back" and "forward" actions in most applications. + +### Examples + +The following will send a left click press when the binding is triggered: + +``` +&mkp LCLK +``` + +This example will send press of the fourth mouse button when the binding is triggered: + +``` +&mkp MB4 +``` diff --git a/docs/docs/behaviors/outputs.md b/docs/docs/behaviors/outputs.md new file mode 100644 index 000000000000..46b567cfdfcd --- /dev/null +++ b/docs/docs/behaviors/outputs.md @@ -0,0 +1,70 @@ +--- +title: Output Selection Behavior +sidebar_label: Output Selection +--- + +## Summary + +The output behavior allows selecting whether keyboard output is sent to the +USB or bluetooth connection when both are connected. This allows connecting a +keyboard to USB for power but outputting to a different device over bluetooth. + +By default, output is sent to USB when both USB and BLE are connected. +Once you select a different output, it will be remembered until you change it again. + +:::note Powering the keyboard via USB +ZMK is not always able to detect if the other end of a USB connection accepts keyboard input or not. +So if you are using USB only to power your keyboard (for example with a charger or a portable power bank), you will want +to select the BLE output through below behavior to be able to send keystrokes to the selected bluetooth profile. +::: + +## Output Command Defines + +Output command defines are provided through the [`dt-bindings/zmk/outputs.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/outputs.h) +header, which is added at the top of the keymap file: + +```dts +#include +``` + +This allows you to reference the actions defined in this header: + +| Define | Action | +| --------- | ----------------------------------------------- | +| `OUT_USB` | Prefer sending to USB | +| `OUT_BLE` | Prefer sending to the current bluetooth profile | +| `OUT_TOG` | Toggle between USB and BLE | + +## Output Selection Behavior + +The output selection behavior changes the preferred output on press. + +### Behavior Binding + +- Reference: `&out` +- Parameter #1: Command, e.g. `OUT_BLE` + +:::note External power state persistence +The endpoint that is selected by the `&out` behavior will be saved to flash storage and hence persist across restarts and firmware flashes. +However it will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory. +::: + +### Examples + +1. Behavior binding to prefer sending keyboard output to USB + + ```dts + &out OUT_USB + ``` + +1. Behavior binding to prefer sending keyboard output to the current bluetooth profile + + ```dts + &out OUT_BLE + ``` + +1. Behavior binding to toggle between preferring USB and BLE + + ```dts + &out OUT_TOG + ``` diff --git a/docs/docs/behaviors/power.md b/docs/docs/behaviors/power.md new file mode 100644 index 000000000000..5251d76cb135 --- /dev/null +++ b/docs/docs/behaviors/power.md @@ -0,0 +1,73 @@ +--- +title: Power Management Behaviors +sidebar_label: Power Management +--- + +## Summary + +These page contains some of the power management behaviors currently supported by ZMK. + +## External Power Control + +The External power control behavior allows enabling or disabling the VCC power output +to save power. Some of the LEDs will consume power even in OFF state. To preserve +battery life in this scenario, some controller boards have support to disable the +external power completely. + +The following boards currently support this feature: + +- nRFMicro +- nice!nano + +## External Power Control Command Defines + +External power control command defines are provided through the [`dt-bindings/zmk/ext_power.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/ext_power.h) header, +which is added at the top of the keymap file: + +```dts +#include +``` + +This will allow you to reference the actions defined in this header such as `EXT_POWER_OFF_CMD`. + +Here is a table describing the command for each define: + +| Define | Action | Alias | +| ---------------------- | --------------------------- | -------- | +| `EXT_POWER_OFF_CMD` | Disable the external power. | `EP_OFF` | +| `EXT_POWER_ON_CMD` | Enable the external power. | `EP_ON` | +| `EXT_POWER_TOGGLE_CMD` | Toggle the external power. | `EP_TOG` | + +### Behavior Binding + +- Reference: `&ext_power` +- Parameter#1: Command, e.g `EP_ON` + +:::note External power state persistence +The on/off state that is set by the `&ext_power` behavior will be saved to flash storage and hence persist across restarts and firmware flashes. +However it will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory. +::: + +### Example: + +1. Behavior binding to enable the external power + + ```dts + &ext_power EP_ON + ``` + +1. Behavior binding to disable the external power + + ```dts + &ext_power EP_OFF + ``` + +1. Behavior binding to toggle the external power + + ```dts + &ext_power EP_TOG + ``` + +## Split Keyboards + +Power management behaviors are global: This means that when triggered, they affects both the central and peripheral side of split keyboards. diff --git a/docs/docs/behaviors/reset.md b/docs/docs/behaviors/reset.md new file mode 100644 index 000000000000..b7850eca77db --- /dev/null +++ b/docs/docs/behaviors/reset.md @@ -0,0 +1,51 @@ +--- +title: Reset Behaviors +sidebar_label: Reset +--- + +## Summary + +There are two available behaviors that can be used to trigger a reset of the keyboard. +The first is a soft reset, that will simply reset and re-run the currently flashed +firmware; the second when triggered will reset into the bootloader, allowing you to +flash a new firmware to the keyboard. + +## Reset + +The basic reset behavior will reset the keyboard and re-run the firmware flashed +to the device + +### Behavior Binding + +- Reference: `&sys_reset` +- Parameters: None + +Example: + +```dts +&sys_reset +``` + +## Bootloader Reset + +The bootloader reset behavior will reset the keyboard and put it into bootloader mode, allowing +you to flash a new firmware. + +### Behavior Binding + +- Reference: `&bootloader` +- Parameters: None + +Example: + +```dts +&bootloader +``` + +## Split Keyboards + +Both basic and bootloader reset behaviors are source-specific: This means that it affects the side of the keyboard that contains the behavior binding for split keyboards. For example if you press a key with the `&sys_reset` binding on the left half of the keyboard, the left half will be reset. If you want to be able to reset both sides you can put the bindings on both sides of the keyboard and activate it on the side you would like to reset. + +:::note Peripheral invocation +The peripheral side of the keyboard has to be paired and connected to the central side in order to be able to activate these behaviors, even if it is possible to trigger the behavior using only keys on that side. This is because the key bindings are processed on the central side which would then instruct the peripheral side to reset. +::: diff --git a/docs/docs/behaviors/sensor-rotate.md b/docs/docs/behaviors/sensor-rotate.md new file mode 100644 index 000000000000..f8476baeb708 --- /dev/null +++ b/docs/docs/behaviors/sensor-rotate.md @@ -0,0 +1,75 @@ +--- +title: Sensor Rotation +sidebar_label: Sensor Rotation +--- + +## Summary + +The Sensor Rotation behavior triggers a different behavior, depending on whether the sensor is rotated clockwise or counter-clockwise. Two variants of this behavior are available, allowing either fully specifying the +two behaviors and their parameters together, or allowing binding the sensor rotation with different clockwise and counterclockwise parameters in the keymap itself. + +## Sensor Rotation + +The standard sensor rotation behavior allows fully binding behaviors to be invoked: + +- If rotated clockwise, the first bound behavior is triggered. +- If rotated counter-clockwise, the second bound behavior is triggered. + +### Configuration + +Here is an example that binds the [RGB Underglow Behavior](/docs/behaviors/underglow.md) to change the RGB brightness: + +```dts +/ { + behaviors { + rgb_encoder: rgb_encoder { + compatible = "zmk,behavior-sensor-rotate"; + #sensor-binding-cells = <0>; + bindings = <&rgb_ug RGB_BRI>, <&rgb_ug RGB_BRD>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + base { + ... + sensor-bindings = <&rgb_encoder>; + } + }; +}; +``` + +## Variable Sensor Rotation + +The variable sensor rotation behavior is configured with two behaviors that each expect a single parameter, +allowing the sensor rotation instance to be bound with two parameters at usage time. + +- If rotated clockwise, the first bound behavior is triggered with the first parameter passed to the sensor rotation. +- If rotated counter-clockwise, the second bound behavior is triggered with the second parameter passed to the sensor rotation. + +### Configuration + +Here is an example, showing how send key presses on rotation: + +First, defining the sensor rotation itself, binding the [Key Press Behavior](/docs/behaviors/key-press.md) twice, then binding it in the `sensor-bindings` property of a keymap layer: + +```dts +/ { + behaviors { + rot_kp: sensor_rotate_kp { + compatible = "zmk,behavior-sensor-rotate-var"; + #sensor-binding-cells = <2>; + bindings = <&kp>, <&kp>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + base { + ... + sensor-bindings = <&rot_kp PG_UP PG_DN>; + } + } +}; +``` diff --git a/docs/docs/behaviors/sticky-key.md b/docs/docs/behaviors/sticky-key.md new file mode 100644 index 000000000000..f40bb521e10d --- /dev/null +++ b/docs/docs/behaviors/sticky-key.md @@ -0,0 +1,84 @@ +--- +title: Sticky Key Behavior +sidebar_label: Sticky Key +--- + +## Summary + +A sticky key stays pressed until another key is pressed. It is often used for 'sticky shift'. By using a sticky shift, you don't have to hold the shift key to write a capital. + +### Behavior Binding + +- Reference: `&sk` +- Parameter #1: The keycode , e.g. `LSHIFT` + +Example: + +```dts +&sk LSHIFT +``` + +You can use any keycode that works for `&kp` as parameter to `&sk`: + +```dts +&sk LG(LS(LA(LCTRL))) +``` + +### Configuration + +#### `release-after-ms` + +By default, sticky keys stay pressed for a second if you don't press any other key. You can configure this with the `release-after-ms` setting. + +#### `quick-release` + +Some typists may find that using a sticky shift key interspersed with rapid typing results in two or more capitalized letters instead of one. This happens as the sticky key is active until the next key is released, under which other keys may be pressed and will receive the modifier. You can enable the `quick-release` setting to instead deactivate the sticky key on the next key being pressed, as opposed to released. + +#### `ignore-modifiers` + +This setting is enabled by default. It ensures that if a sticky key modifier is pressed before a previously pressed sticky key is released, the modifiers will get combined so you can add more sticky keys or press a regular key to apply the modifiers. This is to accommodate _callum-style mods_ where you are prone to rolling sticky keys. If you want sticky key modifiers to only chain after release, you can disable this setting. Please note that activating multiple modifiers via [modifier functions](https://zmk.dev/docs/codes/modifiers#modifier-functions) such as `&sk LS(LALT)`, require `ignore-modifiers` enabled in order to function properly. + +#### Example + +```dts +&sk { + release-after-ms = <2000>; + quick-release; + /delete-property/ ignore-modifiers; +}; + +/ { + keymap { + ... + }; +}; +``` + +This configuration would apply to all sticky keys. This may not be appropriate if using `quick-release` as you'll lose the ability to chain sticky key modifiers. A better approach for this use case would be to create a new behavior: + +```dts +/ { + behaviors { + skq: sticky_key_quick_release { + compatible = "zmk,behavior-sticky-key"; + #binding-cells = <1>; + bindings = <&kp>; + release-after-ms = <1000>; + quick-release; + ignore-modifiers; + }; + }; + + keymap { + ... + }; +}; +``` + +### Advanced usage + +Sticky keys can be combined; if you tap `&sk LCTRL` and then `&sk LSHIFT` and then `&kp A`, the output will be ctrl+shift+a. + +### Comparison to QMK + +In QMK, sticky keys are known as 'one shot mods'. diff --git a/docs/docs/behaviors/sticky-layer.md b/docs/docs/behaviors/sticky-layer.md new file mode 100644 index 000000000000..41c2ccf55d79 --- /dev/null +++ b/docs/docs/behaviors/sticky-layer.md @@ -0,0 +1,45 @@ +--- +title: Sticky Layer Behavior +sidebar_label: Sticky Layer +--- + +## Summary + +A sticky layer stays pressed until another key is pressed. By using a sticky layer, you don't have to hold the layer key to access a layer. Instead, tap the sticky layer key to activate the layer until the next keypress. + +By default, sticky layers stay pressed for a second if you don't press any other key. You can configure this with the `release-after-ms` setting (see below). + +### Behavior Binding + +- Reference: `&sl` +- Parameter #1: The layer to activate , e.g. `1` + +Example: + +```dts +&sl 1 +``` + +### Configuration + +You can configure a different `release-after-ms` in your keymap: + +```dts +&sl { + release-after-ms = <2000>; +}; + +/ { + keymap { + ... + }; +}; +``` + +### Advanced usage + +Sticky layers behave slightly different from sticky keys. They are configured to `quick-release`. This means that the layer is released immediately when another key is pressed. "Normal" sticky keys are not `quick-release`; they are released when the next key is released. This makes it possible to combine sticky layers and sticky keys as such: tap `&sl 1`, tap `&sk LSHIFT` on layer 1, tap `&kp A` on base layer to output shift+A. + +### Comparison to QMK + +In QMK, sticky layers are known as 'one shot layers'. diff --git a/docs/docs/behaviors/tap-dance.md b/docs/docs/behaviors/tap-dance.md new file mode 100644 index 000000000000..1566cf18faa2 --- /dev/null +++ b/docs/docs/behaviors/tap-dance.md @@ -0,0 +1,107 @@ +--- +title: Tap-Dance Behavior +sidebar_label: Tap-Dance +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Summary + +A tap-dance key invokes a different behavior (e.g. `kp`) corresponding to how many times it is pressed. For example, you could configure a tap-dance key that acts as `LSHIFT` if tapped once, or Caps _Lock_ if tapped twice. The expandability of the number of [`bindings`](#bindings) attached to a particular tap-dance is a great way to add more functionality to a single key, especially for keyboards with a limited number of keys. Tap-dances are completely custom, so for every unique tap-dance key,a new tap-dance must be defined in your keymap's `behaviors`. + +Tap-dances are designed to resolve immediately when interrupted by another keypress. Meaning, when a keybind is pressed other than any active tap-dances, the tap-dance will activate according to the current value of its counter before the interrupting keybind is registered. + +### Configuration + +#### `tapping-term-ms` + +Defines the maximum elapsed time after the last tap-dance keybind press before a binding is selected from [`bindings`](#bindings). Default value is `200`ms. + +#### `bindings` + +An array of one or more keybinds. This list can include [any ZMK keycode](../codes/) and any listed ZMK behavior, like [hold-taps](hold-tap.md), or [sticky keys](sticky-key.md). The index of a keybind in the `bindings` array corresponds to the number of times the tap-dance binding is pressed. For example, in the [basic tap-dance counter](#basic-example-counter) shown below, `&kp N2` is the second binding in the array of `bindings`: we then see an output of `2` when the `td0` binding is pressed twice. + +The number of bindings in this array also determines the tap-dance's maximum number of keypresses. When a tap-dance reaches its maximum number of keypresses, it will immediately invoke the last behavior in its list of `bindings`, rather than waiting for [`tapping-term-ms`](#tapping-term-ms) to expire before the output is displayed. + +### Example Usage + + + + + +This example configures a tap-dance named `td0` that outputs the number of times its binding is pressed from 1-3. + +```dts title="Basic Tap-Dance Example: Counter" +#include +#include + +/ { + behaviors { + td0: tap_dance_0 { + compatible = "zmk,behavior-tap-dance"; + #binding-cells = <0>; + tapping-term-ms = <200>; + bindings = <&kp N1>, <&kp N2>, <&kp N3>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &td0 + >; + }; + }; +}; +``` + +The following image describes the behavior of this particular tap-dance. + +![Timing Diagram](../assets/tap-dance/timing_diagram.svg) + +:::note +Alphanumeric [`key press`](key-press.md) bindings, like those used for `td0`, will release as soon as an interrupting key press occurs. For instance, if a modifier key like `LSHIFT` were to replace the `N1` binding in the last example above, it would remain pressed until `td0`'s binding is released and the output would instead be `J`. Any following alphanumeric key presses would be capitalized as long as `td0` is held down. +::: + + + + + +This example configures a mod-tap inside a tap-dance named `td_mt` that outputs `CAPSLOCK` on a single tap, `LSHIFT` on a single press and hold, and `LCTRL` when the tap-dance is pressed twice. + +```dts title="Advanced Tap-Dance Example: Nested Mod-Tap" +#include +#include + +/ { + behaviors { + td_mt: tap_dance_mod_tap { + compatible = "zmk,behavior-tap-dance"; + #binding-cells = <0>; + tapping-term-ms = <200>; + bindings = <&mt LSHIFT CAPSLOCK>, <&kp LCTRL>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &td_mt + >; + }; + }; +}; +``` + + + diff --git a/docs/docs/behaviors/underglow.md b/docs/docs/behaviors/underglow.md new file mode 100644 index 000000000000..f94d9008c04f --- /dev/null +++ b/docs/docs/behaviors/underglow.md @@ -0,0 +1,80 @@ +--- +title: RGB Underglow Behavior +sidebar_label: RGB Underglow +--- + +## Summary + +This page contains [RGB Underglow](../features/underglow.md) behaviors supported by ZMK. + +## RGB Action Defines + +RGB actions defines are provided through the [`dt-bindings/zmk/rgb.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/rgb.h) header, +which is added at the top of the keymap file: + +```dts +#include +``` + +This will allow you to reference the actions defined in this header such as `RGB_TOG`. + +Here is a table describing the action for each define: + +| Define | Action | +| --------------- | ---------------------------------------------------------------------------------------------- | +| `RGB_ON` | Turns the RGB feature on | +| `RGB_OFF` | Turns the RGB feature off | +| `RGB_TOG` | Toggles the RGB feature on and off | +| `RGB_HUI` | Increases the hue of the RGB feature | +| `RGB_HUD` | Decreases the hue of the RGB feature | +| `RGB_SAI` | Increases the saturation of the RGB feature | +| `RGB_SAD` | Decreases the saturation of the RGB feature | +| `RGB_BRI` | Increases the brightness of the RGB feature | +| `RGB_BRD` | Decreases the brightness of the RGB feature | +| `RGB_SPI` | Increases the speed of the RGB feature effect's animation | +| `RGB_SPD` | Decreases the speed of the RGB feature effect's animation | +| `RGB_EFF` | Cycles the RGB feature's effect forwards | +| `RGB_EFR` | Cycles the RGB feature's effect reverse | +| `RGB_COLOR_HSB` | Sets a specific [HSB (HSV)](https://en.wikipedia.org/wiki/HSL_and_HSV) value for the underglow | + +## Behavior Binding + +- Reference: `&rgb_ug` +- Parameter #1: The RGB action define, e.g. `RGB_TOG` or `RGB_BRI` +- Parameter #2: Only applies to `RGB_COLOR_HSB` and is the HSB representation of the color to set (see below for an example) + +:::note HSB Values + +When specifying HSB values you'll need to use `RGB_COLOR_HSB(h, s, b)` in your keymap file. + +Value Limits: + +- Hue values can _not_ exceed 360 (degrees) +- Saturation values can _not_ exceed 100 (percent) +- Brightness values can _not_ exceed 100 (percent) + +::: + +:::note RGB settings persistence +The RGB settings that are changed via the `&rgb_ug` behavior will be saved to flash storage and hence persist across restarts and firmware flashes. +They will also override the start values set by [`CONFIG_ZMK_RGB_*_START` settings](../config/underglow.md#kconfig). +However the settings will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory. +::: + +## Examples + +1. Toggle underglow on/off + + ```dts + &rgb_ug RGB_TOG + ``` + +1. Set a specific HSB color (green) + + ```dts + &rgb_ug RGB_COLOR_HSB(128,100,100) + ``` + +## Split Keyboards + +RGB underglow behaviors are global: This means that when triggered, they affect both the central and peripheral side of split keyboards. diff --git a/docs/docs/codes/_applications.mdx b/docs/docs/codes/_applications.mdx new file mode 100644 index 000000000000..099b701bb894 --- /dev/null +++ b/docs/docs/codes/_applications.mdx @@ -0,0 +1,9 @@ +import Table from "@site/src/components/codes/Table"; + +## Application Controls + + + +## Applications (Launch) + +
diff --git a/docs/docs/codes/_editing.mdx b/docs/docs/codes/_editing.mdx new file mode 100644 index 000000000000..2dd4d6310cc0 --- /dev/null +++ b/docs/docs/codes/_editing.mdx @@ -0,0 +1,9 @@ +import Table from "@site/src/components/codes/Table"; + +## Cut, Copy, Paste + +
+ +## Undo, Redo + +
diff --git a/docs/docs/codes/_footnotes/example.mdx b/docs/docs/codes/_footnotes/example.mdx new file mode 100644 index 000000000000..2dcdb1095d39 --- /dev/null +++ b/docs/docs/codes/_footnotes/example.mdx @@ -0,0 +1,13 @@ +This is an _example_ footnote for **code** tables. + +- Footnotes are supported per row by each operating system column. +- Footnotes support MDX syntax. +- A footnote's `id` is its filename by convention (i.e. `example`). +- Footnotes must be included and listed in `src/data/footnotes.js` because they're statically compiled. +- Footnotes are assigned within `src/data/hid.js` using `column-id: footnote-id(s)` `K`:`V` pairs (case-sensitive), where: + - `K` is the column's `id`. + - `V` is the footnote's `id`. + - `V` can also be an array of footnote ids (_optional_). +- The footnote system aims to prevent duplication of _sources_ (mdx). +- Footnotes are listed under each table, so try to avoid multiline notes unless it's necessary! +- Footnotes are automatically numbered. diff --git a/docs/docs/codes/_footnotes/globe.mdx b/docs/docs/codes/_footnotes/globe.mdx new file mode 100644 index 000000000000..f267a0ee0d3b --- /dev/null +++ b/docs/docs/codes/_footnotes/globe.mdx @@ -0,0 +1 @@ +Does not exactly replicate original key behavior on macOS, works for Globe+key modifiers but not Fn+key ([#1938](https://github.com/zmkfirmware/zmk/pull/1938#issuecomment-1744579039)). diff --git a/docs/docs/codes/_footnotes/ios-application.mdx b/docs/docs/codes/_footnotes/ios-application.mdx new file mode 100644 index 000000000000..ddd0650f2a78 --- /dev/null +++ b/docs/docs/codes/_footnotes/ios-application.mdx @@ -0,0 +1,2 @@ +Key press is registered, but has no visible effect in tested apps (Gmail, Safari, Notes) +iPhone 6 / iOS 12.4.6 diff --git a/docs/docs/codes/_footnotes/ios-power.mdx b/docs/docs/codes/_footnotes/ios-power.mdx new file mode 100644 index 000000000000..9f9397c13e8b --- /dev/null +++ b/docs/docs/codes/_footnotes/ios-power.mdx @@ -0,0 +1 @@ +Both iOS power keys lock the home screen. diff --git a/docs/docs/codes/_footnotes/macos-power.mdx b/docs/docs/codes/_footnotes/macos-power.mdx new file mode 100644 index 000000000000..4cd839981d45 --- /dev/null +++ b/docs/docs/codes/_footnotes/macos-power.mdx @@ -0,0 +1 @@ +Both macOS power keys ignore quick presses, sleep on deliberate press, and display a prompt on long-press. diff --git a/docs/docs/codes/_input-assist.mdx b/docs/docs/codes/_input-assist.mdx new file mode 100644 index 000000000000..7dc432b4dece --- /dev/null +++ b/docs/docs/codes/_input-assist.mdx @@ -0,0 +1,5 @@ +import Table from "@site/src/components/codes/Table"; + +## Input Assist + +
diff --git a/docs/docs/codes/_keyboard-keypad.mdx b/docs/docs/codes/_keyboard-keypad.mdx new file mode 100644 index 000000000000..063a854025e7 --- /dev/null +++ b/docs/docs/codes/_keyboard-keypad.mdx @@ -0,0 +1,61 @@ +import Table from "@site/src/components/codes/Table"; + +## Keyboard + +### Letters + +
+ +### Numbers + +
+ +### Symbols / Punctuation + +
+ +### Control & Whitespace + +
+ +### Navigation + +
+ +### Modifiers + +The [Modifiers](modifiers.mdx) page includes further information. + +
+ +### Locks + +
+ +### F Keys + +
+ +### International + +
+ +### Language + +
+ +### Miscellaneous + +
+ +## Keypad + +
+ +### Numbers + +
+ +### Symbols / Operations + +
diff --git a/docs/docs/codes/_media.mdx b/docs/docs/codes/_media.mdx new file mode 100644 index 000000000000..7be80ab932af --- /dev/null +++ b/docs/docs/codes/_media.mdx @@ -0,0 +1,21 @@ +import Table from "@site/src/components/codes/Table"; + +## Sound / Volume + +
+ +## Display + +
+ +## Media Controls + +
+ +## Consumer Menus + +
+ +## Consumer Controls + +
diff --git a/docs/docs/codes/_power.mdx b/docs/docs/codes/_power.mdx new file mode 100644 index 000000000000..dd06e9530433 --- /dev/null +++ b/docs/docs/codes/_power.mdx @@ -0,0 +1,5 @@ +import Table from "@site/src/components/codes/Table"; + +## Power & Lock + +
diff --git a/docs/docs/codes/applications.mdx b/docs/docs/codes/applications.mdx new file mode 100644 index 000000000000..68e24d36f95e --- /dev/null +++ b/docs/docs/codes/applications.mdx @@ -0,0 +1,15 @@ +--- +title: Applications +sidebar_label: Applications +hide_title: true +--- + +import OsLegend from "@site/src/components/codes/OsLegend"; +import ToastyContainer from "@site/src/components/codes/ToastyContainer"; +import Content, { toc as contentToc } from "./_applications.mdx"; + +export const toc = contentToc; + + + + diff --git a/docs/docs/codes/editing.mdx b/docs/docs/codes/editing.mdx new file mode 100644 index 000000000000..3475d6c21fb2 --- /dev/null +++ b/docs/docs/codes/editing.mdx @@ -0,0 +1,15 @@ +--- +title: Editing +sidebar_label: Editing +hide_title: true +--- + +import OsLegend from "@site/src/components/codes/OsLegend"; +import ToastyContainer from "@site/src/components/codes/ToastyContainer"; +import Content, { toc as contentToc } from "./_editing.mdx"; + +export const toc = contentToc; + + + + diff --git a/docs/docs/codes/index.mdx b/docs/docs/codes/index.mdx new file mode 100644 index 000000000000..a701b4ce4b0a --- /dev/null +++ b/docs/docs/codes/index.mdx @@ -0,0 +1,35 @@ +--- +title: Codes +sidebar_label: Full List +hide_title: true +slug: ./ +--- + +import SpellingCaution from "@site/src/components/codes/SpellingCaution"; +import OsLegend from "@site/src/components/codes/OsLegend"; +import ToastyContainer from "@site/src/components/codes/ToastyContainer"; +import Key, { toc as keyToc } from "./_keyboard-keypad.mdx"; +import Editing, { toc as editingToc } from "./_editing.mdx"; +import Media, { toc as mediaToc } from "./_media.mdx"; +import Applications, { toc as applicationsToc } from "./_applications.mdx"; +import InputAssist, { toc as inputAssistToc } from "./_input-assist.mdx"; +import Power, { toc as powerToc } from "./_power.mdx"; + +export const toc = [ + ...keyToc, + ...editingToc, + ...mediaToc, + ...applicationsToc, + ...inputAssistToc, + ...powerToc, +]; + + + + + + + + + + diff --git a/docs/docs/codes/input-assist.mdx b/docs/docs/codes/input-assist.mdx new file mode 100644 index 000000000000..e8406f5ccc09 --- /dev/null +++ b/docs/docs/codes/input-assist.mdx @@ -0,0 +1,15 @@ +--- +title: Input Assist +sidebar_label: Input Assist +hide_title: true +--- + +import OsLegend from "@site/src/components/codes/OsLegend"; +import ToastyContainer from "@site/src/components/codes/ToastyContainer"; +import Content, { toc as contentToc } from "./_input-assist.mdx"; + +export const toc = contentToc; + + + + diff --git a/docs/docs/codes/keyboard-keypad.mdx b/docs/docs/codes/keyboard-keypad.mdx new file mode 100644 index 000000000000..7b040bfd12ec --- /dev/null +++ b/docs/docs/codes/keyboard-keypad.mdx @@ -0,0 +1,15 @@ +--- +title: Keyboard & Keypad +sidebar_label: Keyboard & Keypad +hide_title: true +--- + +import OsLegend from "@site/src/components/codes/OsLegend"; +import ToastyContainer from "@site/src/components/codes/ToastyContainer"; +import Content, { toc as contentToc } from "./_keyboard-keypad.mdx"; + +export const toc = contentToc; + + + + diff --git a/docs/docs/codes/keymap-upgrader.mdx b/docs/docs/codes/keymap-upgrader.mdx new file mode 100644 index 000000000000..bcee82b5f623 --- /dev/null +++ b/docs/docs/codes/keymap-upgrader.mdx @@ -0,0 +1,21 @@ +--- +title: Keymap Upgrader +sidebar_label: Keymap Upgrader +hide_title: true +hide_table_of_contents: true +--- + +# Keymap Upgrader + +Many codes have been renamed to be more consistent with each other. +Paste the contents of a `.keymap` file below to upgrade all deprecated codes to their replacements. + +Hover your mouse over the upgraded keymap and click the `Copy` button to copy it to your clipboard. + +You will likely need to realign columns in the upgraded keymap. The upgrader also does not handle +codes inside a `#define`, so you will need to update those manually using +[this list of deprecated codes and replacements](https://github.com/zmkfirmware/zmk/blob/main/docs/src/data/keymap-upgrade.js). + +import KeymapUpgrader from "@site/src/components/KeymapUpgrader/index"; + + diff --git a/docs/docs/codes/media.mdx b/docs/docs/codes/media.mdx new file mode 100644 index 000000000000..c7884479077d --- /dev/null +++ b/docs/docs/codes/media.mdx @@ -0,0 +1,15 @@ +--- +title: Media +sidebar_label: Media +hide_title: true +--- + +import OsLegend from "@site/src/components/codes/OsLegend"; +import ToastyContainer from "@site/src/components/codes/ToastyContainer"; +import Content, { toc as contentToc } from "./_media.mdx"; + +export const toc = contentToc; + + + + diff --git a/docs/docs/codes/modifiers.mdx b/docs/docs/codes/modifiers.mdx new file mode 100644 index 000000000000..db88ee926d28 --- /dev/null +++ b/docs/docs/codes/modifiers.mdx @@ -0,0 +1,48 @@ +--- +title: Modifiers +sidebar_label: Modifiers +hide_title: true +--- + +import OsLegend from "@site/src/components/codes/OsLegend"; +import ToastyContainer from "@site/src/components/codes/ToastyContainer"; +import Table from "@site/src/components/codes/Table"; + + + + +## Modifiers + +Modifiers are the special keyboard keys: _shift_, _alt_, _control_ & _GUI_. + +Modifiers can be used in two forms within ZMK: + +- Modifier [Keys](#modifier-keys) → `LEFT_SHIFT` +- Modifier [Functions](#modifier-functions) → `LS(code)` + +
+ +### Modifier Keys + +These act like any other key code. + +- e.g. `&kp LEFT_GUI` pushes and releases the left GUI key. + +### Modifier Functions + +Modifier functions add one or more modifiers to a code. + +These functions take the form: `XX(code)` + +- Modifier functions apply a modifier to a code: + - `&kp LS(A)` = `LEFT_SHIFT`+`A` (a capitalized **A**). +- They can be combined: + - `&kp LC(RA(B))` = `LEFT_CONTROL`+`RIGHT_ALT`+`B` +- They can be applied to a modifier keycode to create combined modifier keys: + - `&kp LS(LALT)` = `LEFT_SHIFT` + `LEFT_ALT` +- Some basic codes already include a modifier function in their definition: + - `DOLLAR` = `LS(NUMBER_4)` +- There are left- and right-handed versions of each modifier (also see table above): + - `LS(x)`, `LC(x)`, `LA(x)`, `LG(x)`, `RS(x)`, `RC(x)`, `RA(x)`, `RG(x)` +- Modified keys can safely be rolled-over. Modifier functions are released when another key is pressed. + - Press `&kp LS(A)`, then press `&kp B`, release `&kp LS(A)` and release `&kp B` results in **Ab**. Only the A is capitalized. diff --git a/docs/docs/codes/power.mdx b/docs/docs/codes/power.mdx new file mode 100644 index 000000000000..2af3233fbc60 --- /dev/null +++ b/docs/docs/codes/power.mdx @@ -0,0 +1,15 @@ +--- +title: Power +sidebar_label: Power +hide_title: true +--- + +import OsLegend from "@site/src/components/codes/OsLegend"; +import ToastyContainer from "@site/src/components/codes/ToastyContainer"; +import Content, { toc as contentToc } from "./_power.mdx"; + +export const toc = contentToc; + + + + diff --git a/docs/docs/config/backlight.md b/docs/docs/config/backlight.md new file mode 100644 index 000000000000..8084be8953da --- /dev/null +++ b/docs/docs/config/backlight.md @@ -0,0 +1,40 @@ +--- +title: Backlight Configuration +sidebar_label: Backlight +--- + +See the [backlight feature page](../features/backlight.md) for more details, including instructions for adding backlight support to a board. + +See [Configuration Overview](index.md) for instructions on how to change these settings. + +## Kconfig + +Definition file: [zmk/app/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/Kconfig) + +| Option | Type | Description | Default | +| ------------------------------------ | ---- | ----------------------------------------------------- | ------- | +| `CONFIG_ZMK_BACKLIGHT` | bool | Enables LED backlight | n | +| `CONFIG_ZMK_BACKLIGHT_BRT_STEP` | int | Brightness step in percent | 20 | +| `CONFIG_ZMK_BACKLIGHT_BRT_START` | int | Default brightness in percent | 40 | +| `CONFIG_ZMK_BACKLIGHT_ON_START` | bool | Default backlight state | y | +| `CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE` | bool | Turn off backlight when keyboard goes into idle state | n | +| `CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB` | bool | Turn off backlight when USB is disconnected | n | + +:::note +The `*_START` settings only determine the initial backlight state. Any changes you make with the [backlight behavior](../behaviors/backlight.md) are saved to flash after a one minute delay and will be used after that. +::: + +## Devicetree + +Applies to: [`/chosen` node](https://docs.zephyrproject.org/latest/build/dts/intro.html#aliases-and-chosen-nodes) + +| Property | Type | Description | +| --------------- | ---- | -------------------------------------------- | +| `zmk,backlight` | path | The node for the backlight LED driver to use | + +See the Zephyr devicetree bindings for LED drivers: + +- [gpio-leds](https://docs.zephyrproject.org/3.0.0/reference/devicetree/bindings/gpio/gpio-leds.html) +- [pwm-leds](https://docs.zephyrproject.org/latest/build/dts/api/bindings/led/pwm-leds.html) + +See the [backlight feature page](../features/backlight.md) for examples of the properties that must be set to enable backlighting. diff --git a/docs/docs/config/battery.md b/docs/docs/config/battery.md new file mode 100644 index 000000000000..50f16cfea7e8 --- /dev/null +++ b/docs/docs/config/battery.md @@ -0,0 +1,59 @@ +--- +title: Battery Level +sidebar_label: Battery Level +--- + +See the [battery level feature page](../features/battery.md) for more details on configuring a battery sensor. + +See [Configuration Overview](index.md) for instructions on how to change these settings. + +### Kconfig + +Definition file: [zmk/app/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/Kconfig) + +| Config | Type | Description | Default | +| ------------------------------------ | ---- | ------------------------------------------------------ | ------- | +| `CONFIG_ZMK_BATTERY_REPORTING` | bool | Enables/disables all battery level detection/reporting | n | +| `CONFIG_ZMK_BATTERY_REPORT_INTERVAL` | int | Battery level report interval in seconds | 60 | + +:::note Default setting + +While `CONFIG_ZMK_BATTERY_REPORTING` is disabled by default it is implied by `CONFIG_ZMK_BLE`, thus any board with BLE enabled will have this automatically enabled unless explicitly overriden. + +::: + +:::note BLE reporting on MacOS + +On macOS the BLE battery reporting packets can cause the computer to wakeup from sleep. To prevent this, the battery _reporting_ service can be disabled by setting `CONFIG_BT_BAS=n`. This setting is independent of battery _monitoring_, for instance the battery level can still be indicated on a display. + +::: + +### Devicetree + +Applies to: [`/chosen` node](https://docs.zephyrproject.org/latest/guides/dts/intro.html#aliases-and-chosen-nodes) + +| Property | Type | Description | +| ------------- | ---- | --------------------------------------------- | +| `zmk,battery` | path | The node for the battery sensor driver to use | + +## Battery Voltage Divider Sensor + +Driver for reading the voltage of a battery using an ADC connected to a voltage divider. + +### Devicetree + +Applies to: `compatible = "zmk,battery-voltage-divider"` + +See [Zephyr's voltage divider documentation](https://docs.zephyrproject.org/latest/build/dts/api/bindings/adc/voltage-divider.html). + +## nRF VDDH Battery Sensor + +Driver for reading the voltage of a battery using a Nordic nRF52's VDDH pin. + +### Devicetree + +Applies to: `compatible = "zmk,battery-nrf-vddh"` + +Definition file: [zmk/app/module/dts/bindings/sensor/zmk,battery-nrf-vddh.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/module/dts/bindings/sensor/zmk%2Cbattery-nrf-vddh.yaml) + +This driver has no configuration. diff --git a/docs/docs/config/behaviors.md b/docs/docs/config/behaviors.md new file mode 100644 index 000000000000..09498e6bebd8 --- /dev/null +++ b/docs/docs/config/behaviors.md @@ -0,0 +1,258 @@ +--- +title: Behavior Configuration +sidebar_label: Behaviors +--- + +Some behaviors have properties to adjust how they behave. These can also be used as templates to create custom behaviors when none of the built-in behaviors do what you want. + +See [Configuration Overview](index.md) for instructions on how to change these settings. + +See the [zmk/app/dts/behaviors/](https://github.com/zmkfirmware/zmk/tree/main/app/dts/behaviors) folder for all default behaviors. + +## Common + +### Kconfig + +| Config | Type | Description | Default | +| --------------------------------- | ---- | ------------------------------------------------------------------------------------ | ------- | +| `CONFIG_ZMK_BEHAVIORS_QUEUE_SIZE` | int | Maximum number of behaviors to allow queueing from a macro or other complex behavior | 64 | + +## Caps Word + +Creates a custom behavior that behaves similar to a caps lock but deactivates when any key not in a continue list is pressed. + +See the [caps word behavior](../behaviors/caps-word.md) documentation for more details and examples. + +### Devicetree + +Definition file: [zmk/app/dts/bindings/behaviors/zmk,behavior-caps-word.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-caps-word.yaml) + +Applies to: `compatible = "zmk,behavior-caps-word"` + +| Property | Type | Description | Default | +| ---------------- | ----- | ------------------------------------------------------------------ | ------------------------------- | +| `#binding-cells` | int | Must be `<0>` | | +| `continue-list` | array | List of [key codes](/docs/codes) which do not deactivate caps lock | `` | +| `mods` | int | A bit field of modifiers to apply | `` | + +`continue-list` is treated as if it always includes alphanumeric characters (A-Z, 0-9). + +See [dt-bindings/zmk/modifiers.h](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/modifiers.h) for a list of modifiers. + +You can use the following nodes to tweak the default behaviors: + +| Node | Behavior | +| ------------ | -------------------------------------- | +| `&caps_word` | [Caps Word](../behaviors/caps-word.md) | + +## Hold-Tap + +Creates a custom behavior that triggers one behavior when a key is held or a different one when the key is tapped. + +See the [hold-tap behavior](../behaviors/hold-tap.md) documentation for more details and examples. + +### Devicetree + +Definition file: [zmk/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-hold-tap.yaml) + +Applies to: `compatible = "zmk,behavior-hold-tap"` + +| Property | Type | Description | Default | +| ---------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------- | ------------------ | +| `#binding-cells` | int | Must be `<2>` | | +| `bindings` | phandle array | A list of two behaviors (without parameters): one for hold and one for tap | | +| `flavor` | string | Adjusts how the behavior chooses between hold and tap | `"hold-preferred"` | +| `tapping-term-ms` | int | How long in milliseconds the key must be held to trigger a hold | | +| `quick-tap-ms` | int | Tap twice within this period (in milliseconds) to trigger a tap, even when held | -1 (disabled) | +| `require-prior-idle-ms` | int | Triggers a tap immediately if any non-modifier key was pressed within `require-prior-idle-ms` of the hold-tap. | -1 (disabled) | +| `retro-tap` | bool | Triggers the tap behavior on release if no other key was pressed during a hold | false | +| `hold-trigger-key-positions` | array | If set, pressing the hold-tap and then any key position _not_ in the list triggers a tap. | | + +This behavior forwards the first parameter it receives to the parameter of the first behavior specified in `bindings`, and second parameter to the parameter of the second behavior. + +The `flavor` property may be one of: + +- `"hold-preferred"` +- `"balanced"` +- `"tap-preferred"` +- `"tap-unless-interrupted"` + +See the [hold-tap behavior documentation](../behaviors/hold-tap.md) for an explanation of each flavor. + +`hold-trigger-key-positions` is an array of zero-based key position indices. + +You can use the following nodes to tweak the default behaviors: + +| Node | Behavior | +| ----- | --------------------------------------------- | +| `<` | [Layer-tap](../behaviors/layers.md#layer-tap) | +| `&mt` | [Mod-tap](../behaviors/mod-tap.md) | + +## Key Repeat + +Creates a custom behavior that repeats the whatever key code was last sent. + +See the [key repeat behavior](../behaviors/key-repeat.md) documentation for more details and examples. + +### Devicetree + +Definition file: [zmk/app/dts/bindings/behaviors/zmk,behavior-key-repeat.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-key-repeat.yaml) + +Applies to: `compatible = "zmk,behavior-key-repeat"` + +| Property | Type | Description | Default | +| ---------------- | ----- | -------------------------------- | ----------------- | +| `#binding-cells` | int | Must be `<0>` | | +| `usage-pages` | array | List of HID usage pages to track | `` | + +For the `usage-pages` property, use the `HID_USAGE_*` defines from [dt-bindings/zmk/hid_usage_pages.h](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/hid_usage_pages.h). + +You can use the following nodes to tweak the default behaviors: + +| Node | Behavior | +| ------------- | ---------------------------------------- | +| `&key_repeat` | [Key repeat](../behaviors/key-repeat.md) | + +## Macro + +Creates a custom behavior which triggers a sequence of other behaviors. + +See the [macro behavior](../behaviors/macros.md) documentation for more details and examples. + +### Kconfig + +| Config | Type | Description | Default | +| ---------------------------------- | ---- | -------------------------------------- | ------- | +| `CONFIG_ZMK_MACRO_DEFAULT_WAIT_MS` | int | Default value for `wait-ms` in macros. | 15 | +| `CONFIG_ZMK_MACRO_DEFAULT_TAP_MS` | int | Default value for `tap-ms` in macros. | 30 | + +### Devicetree + +Definition files: + +- [zmk/app/dts/bindings/behaviors/zmk,behavior-macro.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-macro.yaml) +- [zmk/app/dts/bindings/behaviors/zmk,behavior-macro-one-param.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-macro-one-param.yaml) +- [zmk/app/dts/bindings/behaviors/zmk,behavior-macro-two-param.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-macro-two-param.yaml) + +| Property | Type | Description | Default | +| ---------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | +| `compatible` | string | Macro type, **must be _one_ of**:
  • `"zmk,behavior-macro"`
  • `"zmk,behavior-macro-one-param"`
  • `"zmk,behavior-macro-two-param"`
| | +| `#binding-cells` | int | Must be
  • `<0>` if `compatible = "zmk,behavior-macro"`
  • `<1>` if `compatible = "zmk,behavior-macro-one-param"`
  • `<2>` if `compatible = "zmk,behavior-macro-two-param"`
| | +| `bindings` | phandle array | List of behaviors to trigger | | +| `wait-ms` | int | The default time to wait (in milliseconds) before triggering the next behavior. | `CONFIG_ZMK_MACRO_DEFAULT_WAIT_MS` | +| `tap-ms` | int | The default time to wait (in milliseconds) between the press and release events of a tapped behavior. | `CONFIG_ZMK_MACRO_DEFAULT_TAP_MS` | + +With `compatible = "zmk,behavior-macro-one-param"` or `compatible = "zmk,behavior-macro-two-param"`, this behavior forwards the parameters it receives according to the `¯o_param_*` control behaviors noted below. + +### Macro Control Behaviors + +The following macro-specific behaviors can be added at any point in the `bindings` list to change how the macro triggers subsequent behaviors. + +| Behavior | Description | +| -------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| `¯o_tap` | Switches to tap mode | +| `¯o_press` | Switches to press mode | +| `¯o_release` | Switches to release mode | +| `¯o_pause_for_release` | Pauses the macro until the macro key itself is released | +| `¯o_wait_time TIME` | Changes the time to wait (in milliseconds) before triggering the next behavior. | +| `¯o_tap_time TIME` | Changes the time to wait (in milliseconds) between the press and release events of a tapped behavior. | +| `¯o_param_1to1` | Forward the first parameter received by the macro to the first parameter of the next (non-macro control) behavior. | +| `¯o_param_1to2` | Forward the first parameter received by the macro to the second parameter of the next (non-macro control) behavior. | +| `¯o_param_2to1` | Forward the second parameter received by the macro to the first parameter of the next (non-macro control) behavior. | +| `¯o_param_2to2` | Forward the second parameter received by the macro to the second parameter of the next (non-macro control) behavior. | + +## Mod-Morph + +Creates a custom behavior that triggers one of two behaviors depending on whether certain modifiers are held. + +See the [mod-morph behavior](../behaviors/mod-morph.md) documentation for more details and examples. + +### Devicetree + +Definition file: [zmk/app/dts/bindings/behaviors/zmk,behavior-mod-morph.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-mod-morph.yaml) + +Applies to: `compatible = "zmk,behavior-mod-morph"` + +| Property | Type | Description | +| ---------------- | ------------- | --------------------------------------------------------------------------------- | +| `#binding-cells` | int | Must be `<0>` | +| `bindings` | phandle array | A list of two behaviors: one for normal press and one for mod morphed press | +| `mods` | int | A bit field of modifiers. The morph behavior is used if any of these are pressed. | + +See [dt-bindings/zmk/modifiers.h](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/modifiers.h) for a list of modifiers. + +You can use the following nodes to tweak the default behaviors: + +| Node | Behavior | +| -------- | ----------------------------------------- | +| `&gresc` | [Grave escape](../behaviors/mod-morph.md) | + +## Sensor Rotation + +Creates a custom behavior which sends a tap of other behaviors when a sensor is rotated. +Has two variants: with `compatible = "zmk,behavior-sensor-rotate"` it accepts no parameters when used, whereas with `compatible = "zmk,behavior-sensor-rotate-var"` it accepts two parameters. + +See the [sensor rotation behavior](../behaviors/sensor-rotate.md) documentation for more details and examples. + +### Devicetree + +Definition files: + +- [zmk/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-sensor-rotate.yaml) +- [zmk/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate-var.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-sensor-rotate-var.yaml) + +| Property | Type | Description | Default | +| ----------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | +| `compatible` | string | Sensor rotation type, **must be _one_ of**:
  • `"zmk,behavior-sensor-rotate"`
  • `"zmk,behavior-sensor-rotate-var"`
| | +| `#sensor-binding-cells` | int | Must be
  • `<0>` if `compatible = "zmk,behavior-sensor-rotate"`
  • `<2>` if `compatible = "zmk,behavior-sensor-rotate-var"`
| | +| `bindings` | phandle array | A list of two behaviors to trigger for each rotation direction, must include parameters for `"zmk,behavior-sensor-rotate"` and exclude them for `"zmk,behavior-sensor-rotate-var"` | | +| `tap-ms` | int | The tap duration (between press and release events) in milliseconds for behaviors in `bindings` | 5 | + +With `compatible = "zmk,behavior-sensor-rotate-var"`, this behavior forwards the first parameter it receives to the parameter of the first behavior specified in `bindings`, and second parameter to the parameter of the second behavior. + +## Sticky Key + +Creates a custom behavior that triggers a behavior and keeps it pressed it until another key is pressed and released. + +See the [sticky key behavior](../behaviors/sticky-key.md) and [sticky layer behavior](../behaviors/sticky-layer.md) documentation for more details and examples. + +### Devicetree + +Definition file: [zmk/app/dts/bindings/behaviors/zmk,behavior-sticky-key.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-sticky-key.yaml) + +Applies to: `compatible = "zmk,behavior-sticky-key"` + +| Property | Type | Description | Default | +| ------------------ | ------------- | ------------------------------------------------------------------------ | ------- | +| `#binding-cells` | int | Must be `<1>` | | +| `bindings` | phandle array | A behavior (without parameters) to trigger | | +| `release-after-ms` | int | Releases the key after this many milliseconds if no other key is pressed | 1000 | +| `quick-release` | bool | Release the sticky key on the next key press instead of release | false | +| `ignore-modifiers` | bool | If enabled, pressing a modifier key does not cancel the sticky key | true | + +This behavior forwards the one parameter it receives to the parameter of the behavior specified in `bindings`. + +You can use the following nodes to tweak the default behaviors: + +| Node | Behavior | +| ----- | -------------------------------------------- | +| `&sk` | [Sticky key](../behaviors/sticky-key.md) | +| `&sl` | [Sticky layer](../behaviors/sticky-layer.md) | + +## Tap Dance + +Creates a custom behavior that triggers a different behavior corresponding to the number of times the key is tapped. + +See the [tap dance behavior](../behaviors/tap-dance.md) documentation for more details and examples. + +### Devicetree + +Definition file: [zmk/app/dts/bindings/behaviors/zmk,behavior-tap-dance.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-tap-dance.yaml) + +Applies to: `compatible = "zmk,behavior-tap-dance"` + +| Property | Type | Description | Default | +| ----------------- | ------------- | -------------------------------------------------------------------------------------------- | ------- | +| `#binding-cells` | int | Must be `<0>` | | +| `bindings` | phandle array | A list of behaviors from which to select | | +| `tapping-term-ms` | int | The maximum time (in milliseconds) between taps before an item from `bindings` is triggered. | 200 | diff --git a/docs/docs/config/bluetooth.md b/docs/docs/config/bluetooth.md new file mode 100644 index 000000000000..9149b36bf377 --- /dev/null +++ b/docs/docs/config/bluetooth.md @@ -0,0 +1,18 @@ +--- +title: Bluetooth Configuration +sidebar_label: Bluetooth +--- + +See the [bluetooth feature page](../features/bluetooth.md) for more details on the general Bluetooth functionality in ZMK. + +See [Configuration Overview](index.md) for instructions on how to change these settings. + +## Kconfig + +| Option | Type | Description | Default | +| -------------------------------------- | ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | +| `CONFIG_ZMK_BLE_EXPERIMENTAL_CONN` | bool | Enables a combination of settings that are planned to be default in future versions of ZMK to improve connection stability. This includes changes to timing on BLE pairing initation, restores use of the updated/new LLCP implementation, and disables 2M PHY support. | n | +| `CONFIG_ZMK_BLE_EXPERIMENTAL_SEC` | bool | Enables a combination of settings that are planned to be officially supported in the future. This includes enabling BT Secure Connection passkey entry, and allows overwrite of keys from previously paired hosts. | n | +| `CONFIG_ZMK_BLE_EXPERIMENTAL_FEATURES` | bool | Aggregate config that enables both `CONFIG_ZMK_BLE_EXPERIMENTAL_CONN` and `CONFIG_ZMK_BLE_EXPERIMENTAL_SEC`. | n | +| `CONFIG_ZMK_BLE_PASSKEY_ENTRY` | bool | Enable passkey entry during pairing for enhanced security. (Note: After enabling this, you will need to re-pair all previously paired hosts.) | n | +| `CONFIG_BT_GATT_ENFORCE_SUBSCRIPTION` | bool | Low level setting for GATT subscriptions. Set to `n` to work around an annoying Windows bug with battery notifications. | y | diff --git a/docs/docs/config/combos.md b/docs/docs/config/combos.md new file mode 100644 index 000000000000..4f5ebba3d349 --- /dev/null +++ b/docs/docs/config/combos.md @@ -0,0 +1,43 @@ +--- +title: Combo Configuration +sidebar_label: Combos +--- + +See the [Combos feature page](../features/combos.md) for more details and examples. + +See [Configuration Overview](index.md) for instructions on how to change these settings. + +## Kconfig + +Definition file: [zmk/app/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/Kconfig) + +| Config | Type | Description | Default | +| ------------------------------------- | ---- | -------------------------------------------------------------- | ------- | +| `CONFIG_ZMK_COMBO_MAX_PRESSED_COMBOS` | int | Maximum number of combos that can be active at the same time | 4 | +| `CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY` | int | Maximum number of active combos that use the same key position | 5 | +| `CONFIG_ZMK_COMBO_MAX_KEYS_PER_COMBO` | int | Maximum number of keys to press to activate a combo | 4 | + +If `CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY` is 5, you can have 5 separate combos that use position `0`, 5 combos that use position `1`, and so on. + +If you want a combo that triggers when pressing 5 keys, you must set `CONFIG_ZMK_COMBO_MAX_KEYS_PER_COMBO` to 5. + +## Devicetree + +Applies to: `compatible = "zmk,combos"` + +Definition file: [zmk/app/dts/bindings/zmk,combos.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/zmk%2Ccombos.yaml) + +The `zmk,combos` node itself has no properties. It should have one child node per combo. + +Each child node can have the following properties: + +| Property | Type | Description | Default | +| ----------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------- | +| `bindings` | phandle-array | A [behavior](../features/keymaps.md#behaviors) to run when the combo is triggered | | +| `key-positions` | array | A list of key position indices for the keys which should trigger the combo | | +| `timeout-ms` | int | All the keys in `key-positions` must be pressed within this time in milliseconds to trigger the combo | 50 | +| `require-prior-idle-ms` | int | If any non-modifier key is pressed within `require-prior-idle-ms` before a key in the combo, the key will not be considered for the combo | -1 (disabled) | +| `slow-release` | bool | Releases the combo when all keys are released instead of when any key is released | false | +| `layers` | array | A list of layers on which the combo may be triggered. `-1` allows all layers. | `<-1>` | + +The `key-positions` array must not be longer than the `CONFIG_ZMK_COMBO_MAX_KEYS_PER_COMBO` setting, which defaults to 4. If you want a combo that triggers when pressing 5 keys, then you must change the setting to 5. diff --git a/docs/docs/config/displays.md b/docs/docs/config/displays.md new file mode 100644 index 000000000000..e22f0da8fbb7 --- /dev/null +++ b/docs/docs/config/displays.md @@ -0,0 +1,64 @@ +--- +title: Display Configuration +sidebar_label: Displays +--- + +See the [displays feature page](../features/displays.md) for more details. + +See [Configuration Overview](index.md) for instructions on how to change these settings. + +## Kconfig + +Definition files: + +- [zmk/app/src/display/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/src/display/Kconfig) +- [zmk/app/src/display/widgets/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/src/display/widgets/Kconfig) + +| Config | Type | Description | Default | +| -------------------------------------------------- | ---- | -------------------------------------------------------------- | ------- | +| `CONFIG_ZMK_DISPLAY` | bool | Enable support for displays | n | +| `CONFIG_ZMK_DISPLAY_INVERT` | bool | Invert display colors from black-on-white to white-on-black | n | +| `CONFIG_ZMK_WIDGET_LAYER_STATUS` | bool | Enable a widget to show the highest, active layer | y | +| `CONFIG_ZMK_WIDGET_BATTERY_STATUS` | bool | Enable a widget to show battery charge information | y | +| `CONFIG_ZMK_WIDGET_BATTERY_STATUS_SHOW_PERCENTAGE` | bool | If battery widget is enabled, show percentage instead of icons | n | +| `CONFIG_ZMK_WIDGET_OUTPUT_STATUS` | bool | Enable a widget to show the current output (USB/BLE) | y | +| `CONFIG_ZMK_WIDGET_WPM_STATUS` | bool | Enable a widget to show words per minute | n | + +Note that `CONFIG_ZMK_DISPLAY_INVERT` setting might not work as expected with custom status screens that utilize images. + +If `CONFIG_ZMK_DISPLAY` is enabled, exactly zero or one of the following options must be set to `y`. The first option is used if none are set. + +| Config | Description | +| ------------------------------------------- | ------------------------------ | +| `CONFIG_ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN` | Use the built-in status screen | +| `CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM` | Use a custom status screen | + +If `CONFIG_ZMK_DISPLAY` is enabled, exactly zero or one of the following options must be set to `y`. The first option is used if none are set. + +| Config | Description | +| ----------------------------------------- | ----------------------------------------- | +| `CONFIG_ZMK_DISPLAY_WORK_QUEUE_SYSTEM` | Use the system main thread for UI updates | +| `CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED` | Use a dedicated thread for UI updates | + +Using a dedicated thread requires more memory but prevents displays with slow updates (e.g. E-paper) from delaying key scanning and other processes. If enabled, the following options configure the thread: + +| Config | Type | Description | Default | +| ------------------------------------------------ | ---- | ---------------------------- | ------- | +| `CONFIG_ZMK_DISPLAY_DEDICATED_THREAD_STACK_SIZE` | int | Stack size for the UI thread | 2048 | +| `CONFIG_ZMK_DISPLAY_DEDICATED_THREAD_PRIORITY` | int | Priority for the UI thread | 5 | + +You must also configure the driver for your display. ZMK provides the following display drivers: + +- [IL0323](https://github.com/zmkfirmware/zmk/blob/main/app/module/drivers/display/Kconfig.il0323) + +Zephyr provides several display drivers as well. Search for the name of your display in [Zephyr's Kconfig options](https://docs.zephyrproject.org/latest/kconfig.html) documentation. + +## Devicetree + +See the Devicetree bindings for your display. Here are the bindings for common displays: + +- [IL0323](https://github.com/zmkfirmware/zmk/blob/main/app/module/dts/bindings/display/gooddisplay%2Cil0323.yaml) +- [SSD1306 (i2c)](https://docs.zephyrproject.org/latest/build/dts/api/bindings/display/solomon,ssd1306fb-i2c.html) +- [SSD1306 (spi)](https://docs.zephyrproject.org/latest/build/dts/api/bindings/display/solomon,ssd1306fb-spi.html) + +A full list of drivers provided by Zephyr can be found in [Zephyr's Devicetree bindings index](https://docs.zephyrproject.org/latest/build/dts/api/bindings.html). diff --git a/docs/docs/config/encoders.md b/docs/docs/config/encoders.md new file mode 100644 index 000000000000..b242f49b5bae --- /dev/null +++ b/docs/docs/config/encoders.md @@ -0,0 +1,82 @@ +--- +title: Encoder Configuration +sidebar_label: Encoders +--- + +See the [Encoders feature page](../features/encoders.md) for more details, including instructions for adding encoder support to a board. + +See [Configuration Overview](index.md) for instructions on how to change these settings. + +## EC11 Encoders + +### Kconfig + +Definition file: [zmk/app/module/drivers/sensor/ec11/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/module/drivers/sensor/ec11/Kconfig) + +| Config | Type | Description | Default | +| ------------------------------- | ---- | -------------------------------- | ------- | +| `CONFIG_EC11` | bool | Enable EC11 encoders | n | +| `CONFIG_EC11_THREAD_PRIORITY` | int | Priority of the encoder thread | 10 | +| `CONFIG_EC11_THREAD_STACK_SIZE` | int | Stack size of the encoder thread | 1024 | + +If `CONFIG_EC11` is enabled, exactly one of the following options must be set to `y`: + +| Config | Type | Description | +| ----------------------------------- | ---- | ----------------------------------------------- | +| `CONFIG_EC11_TRIGGER_NONE` | bool | No trigger (encoders are disabled) | +| `CONFIG_EC11_TRIGGER_GLOBAL_THREAD` | bool | Process encoder interrupts on the global thread | +| `CONFIG_EC11_TRIGGER_OWN_THREAD` | bool | Process encoder interrupts on their own thread | + +### Devicetree + +#### Keymap Sensor Config + +For shields/boards that export a `sensors` node configuration label, both global and per-sensor settings can be set by overriding the properties there. + +To override the general settings, update them on the exported `sensors` node, e.g.: + +``` +&sensors { + triggers-per-rotation = <18>; +}; +``` + +Per sensor overrides can be added with ordered nested nodes with the correct overrides, e.g.: + +``` +&sensors { + left_config { + triggers-per-rotation = <18>; + }; + + right_config { + triggers-per-rotation = <24>; + }; +}; +``` + +:::note + +The names of the child nodes are not important, and are applied in order to the sensors listed in the `sensors` property of the sensors node. + +::: + +Applies to the node and child nodes of: `compatible = "zmk,keymap-sensors"` + +Definition file: [zmk/app/drivers/zephyr/dts/bindings/zmk,keymap-sensors.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/drivers/zephyr/dts/bindings/zmk%2Ckeymap-sensors.yaml) + +| Property | Type | Description | Default | +| ----------------------- | ---- | --------------------------------------------------------------- | ------- | +| `triggers-per-rotation` | int | Number of times to trigger the bound behavior per full rotation | | + +#### EC11 Nodes + +Applies to: `compatible = "alps,ec11"` + +Definition file: [zmk/app/module/dts/bindings/sensor/alps,ec11.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/module/dts/bindings/sensor/alps%2Cec11.yaml) + +| Property | Type | Description | Default | +| --------- | ---------- | ---------------------------------------------- | ------- | +| `a-gpios` | GPIO array | GPIO connected to the encoder's A pin | | +| `b-gpios` | GPIO array | GPIO connected to the encoder's B pin | | +| `steps` | int | Number of encoder pulses per complete rotation | | diff --git a/docs/docs/config/index.md b/docs/docs/config/index.md new file mode 100644 index 000000000000..d8a2aecffefb --- /dev/null +++ b/docs/docs/config/index.md @@ -0,0 +1,258 @@ +--- +title: Configuration Overview +sidebar_label: Overview +--- + +ZMK has many configuration settings that can be changed to change the behavior of your keyboard. They are set in either Kconfig or Devicetree files. + +This page describes the Kconfig and Devicetree file formats and how to change settings in them. See the other pages in the configuration section for a list of settings you can change. + +:::note +All configuration is currently set at compile time. After changing any settings, you must build new firmware and flash it for the changes to apply. +::: + +## Config File Locations + +ZMK will search multiple folders for the config files described below. There are three primary locations it will search: + +### User Config Folder + +When building with a `zmk-config` folder, ZMK will search the `zmk-config/config` folder for the following config files, where `` is the name of the shield if using a shield, or the name of the board otherwise: + +- `.conf` (Kconfig) +- `.keymap` (Devicetree) + +These files hold your personal settings for the keyboard. All files are optional. If present, they override any configuration set in the board or shield folders. Otherwise, the default configuration and/or keymap is used. + +When using a split keyboard, you can use a single file without the `_left` or `_right` suffix to configure both sides. For example, `corne.conf` and `corne.keymap` will apply to both `corne_left` and `corne_right`. If a shared config file exists, any left or right files will be ignored. + +### Board Folder + +ZMK will search for config files in either of: + +- [`zmk/app/boards/arm/`](https://github.com/zmkfirmware/zmk/tree/main/app/boards/arm) +- `zmk-config/config/boards/arm/` + +...where `` is the name of the board. These files describe the hardware of the board. + +ZMK will search the board folder for the following config files: + +- `_defconfig` (Kconfig) +- `.conf` (Kconfig) +- `.dts` (Devicetree) +- `.keymap` (Devicetree, keyboards with onboard controllers only) + +Shared config files (excluding any `_left` or `_right` suffix) are not currently supported in board folders. + +For more documentation on creating and configuring a new board, see [Zephyr's board porting guide](https://docs.zephyrproject.org/latest/hardware/porting/board_porting.html#write-kconfig-files). + +### Shield Folder + +When building with a shield, ZMK will search for config files in either of: + +- [`zmk/app/boards/shields/`](https://github.com/zmkfirmware/zmk/tree/main/app/boards/shields) +- `zmk-config/config/boards/shields/` + +...where `` is the name of the shield. These files describe the hardware of the shield that the board is plugged into. + +ZMK will search the shield folder for the following config files: + +- `.conf` (Kconfig) +- `.overlay` (Devicetree) +- `.keymap` (Devicetree) + +Shared config files (excluding any `_left` or `_right` suffix) are not currently supported in shield folders. + +For more documentation on creating and configuring a new shield, see [Zephyr's shield documentation](https://docs.zephyrproject.org/latest/hardware/porting/shields.html) and [ZMK's new keyboard shield](../development/new-shield.md) guide. + +## Kconfig Files + +Kconfig is used to configure global settings such as the keyboard name and enabling certain hardware devices. These typically have a `.conf` file extension and are text files containing `CONFIG_XYZ=value` assignments, with one setting per line. + +Kconfig files look like this: + +```ini +CONFIG_ZMK_SLEEP=y +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y +``` + +The list of available settings is determined by various files in ZMK whose names start with `Kconfig`. Files ending with `_defconfig` use the same syntax, but are intended for setting configuration specific to the hardware which users typically won't need to change. Note that options are _not_ prefixed with `CONFIG_` in these files. + +See [Zephyr's Kconfig documentation](https://docs.zephyrproject.org/latest/build/kconfig/index.html) for more details on Kconfig files. + +### KConfig Value Types + +#### bool + +Either `y` for yes or `n` for no. + +Example: `CONFIG_FOO=y` + +#### int + +An integer. + +Example: `CONFIG_FOO=42` + +#### string + +Text surrounded by double quotes. + +Example: `CONFIG_FOO="foo"` + +## Devicetree Files + +Various Devicetree files are combined to build a tree that describes the hardware for a keyboard. They are also used to define keymaps. + +Devicetree files use various file extensions. These indicate the purpose of the file, but they have no effect on how the file is processed. Common file extensions for Devicetree files include: + +- `.dts`: The base hardware definition. +- `.overlay`: Adds to and/or overrides definitions in a `.dts` file. +- `.keymap`: Holds a keymap and user-specific hardware configuration. +- `.dtsi`: A file which is only intended to be `#include`d from another file. + +Devicetree files look like this: + +```dts +/ { + chosen { + zmk,kscan = &kscan0; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + }; +}; +``` + +Devicetree properties apply to specific nodes in the tree instead of globally. The properties that can be set for each node are determined by `.yaml` files in ZMK in the various `dts/bindings` folders. + +See [Zephyr's Devicetree guide](https://docs.zephyrproject.org/latest/build/dts/index.html) for more details on Devicetree files. + +### Changing Devicetree Properties + +Since Devicetree properties are set for specific nodes in the tree, you will first need to find the node you want to configure. You will typically need to +search through the `.dts` file for your board, `.overlay` file for your shield, or a `.dtsi` file included by those files using an `#include` statement. + +A Devicetree node looks like this: + +```dts +kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + // more properties and/or nodes... +}; +``` + +The part before the colon, `kscan0`, is a label. This is optional, and it provides a shortcut to allow changing the properties of the node. The part after the colon, `kscan`, is the node's name. The values inside the curly braces are the node's properties. + +The `compatible` property indicates what type of node it is. Search this documentation for the text inside the quotes to see which properties the node +supports. You can also search ZMK for a file whose name is the value of the `compatible` property with a `.yaml` file extension. + +To set a property, see below for examples for common property types, or see [Zephyr's Devicetree documentation](https://docs.zephyrproject.org/latest/build/dts/intro.html#writing-property-values) for more details on the syntax for properties. + +To change a property for an existing node, first find the node you want to change and find its label. Next, outside of any other node, write an ampersand (`&`) +followed by the node's label, an opening curly brace (`{`), one or more new property values, a closing curly brace (`}`), and a semicolon (`;`). + +For example, to adjust the debouncing of the `zmk,kscan-gpio-matrix` node shown above, you could add this to your keymap: + +```dts +&kscan0 { + debounce-press-ms = <0>; +}; +``` + +If the node you want to edit doesn't have a label, you can also write a new tree and it will be merged with the existing tree, overriding any properties. Adding this to your keymap would be equivalent to the previous example. + +```dts +/ { + kscan { + debounce-press-ms = <0>; + }; +}; +``` + +### Devicetree Property Types + +These are some of the property types you will see most often when working with ZMK. [Zephyr's Devicetree bindings documentation](https://docs.zephyrproject.org/latest/build/dts/bindings.html) provides more detailed information and a full list of types. + +#### bool + +True or false. To set the property to true, list it with no value. To set it to false, do not list it. + +Example: `property;` + +If a property has already been set to true and you need to override it to false, use the following command to delete the existing property: + +```dts +/delete-property/ the-property-name; +``` + +#### int + +A single integer surrounded by angle brackets. Also supports mathematical expressions. + +Example: `property = <42>;` + +#### string + +Text surrounded by double quotes. + +Example: `property = "foo";` + +#### array + +A list of integers surrounded by angle brackets and separated with spaces. Mathematical expressions can be used but must be surrounded by parenthesis. + +Example: `property = <1 2 3 4>;` + +Values can also be split into multiple blocks, e.g. `property = <1 2>, <3 4>;` + +#### phandle + +A single node reference surrounded by angle brackets. + +Example: `property = <&label>` + +#### phandles + +A list of node references surrounded by angle brackets. + +Example: `property = <&label1 &label2 &label3>` + +#### phandle array + +A list of node references and possibly numbers to associate with the node. Mathematical expressions can be used but must be surrounded by parenthesis. + +Example: `property = <&none &mo 1>;` + +Values can also be split into multiple blocks, e.g. `property = <&none>, <&mo 1>;` + +See the documentation for "phandle-array" in [Zephyr's Devicetree bindings documentation](https://docs.zephyrproject.org/latest/build/dts/bindings.html) +for more details on how parameters are associated with nodes. + +#### GPIO array + +This is just a phandle array. The documentation lists this as a different type to make it clear which properties expect an array of GPIOs. + +Each item in the array should be a label for a GPIO node (the names of which differ between hardware platforms) followed by an index and configuration flags. See [Zephyr's GPIO documentation](https://docs.zephyrproject.org/latest/hardware/peripherals/gpio.html) for a full list of flags. + +Example: + +```dts +some-gpios = + <&gpio0 0 GPIO_ACTIVE_HIGH>, + <&gpio0 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; +``` + +#### path + +A path to a node, either as a node reference or as a string. + +Examples: + +```dts +property = &label; +property = "/path/to/some/node"; +``` diff --git a/docs/docs/config/keymap.md b/docs/docs/config/keymap.md new file mode 100644 index 000000000000..4992438949d0 --- /dev/null +++ b/docs/docs/config/keymap.md @@ -0,0 +1,42 @@ +--- +title: Keymap Configuration +sidebar_label: Keymap +--- + +See [Configuration Overview](index.md) for instructions on how to change these settings. + +## Keymap + +### Devicetree + +Applies to: `compatible = "zmk,keymap"` + +Definition file: [zmk/app/dts/bindings/zmk,keymap.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/zmk%2Ckeymap.yaml) + +The `zmk,keymap` node itself has no properties. It should have one child node per layer of the keymap, starting with the default layer (layer 0). + +Each child node can have the following properties: + +| Property | Type | Description | +| ----------------- | ------------- | ---------------------------------------------------------------------- | +| `display-name` | string | Name for the layer on displays | +| `bindings` | phandle-array | List of [key behaviors](../features/keymaps.md#behaviors), one per key | +| `sensor-bindings` | phandle-array | List of sensor behaviors, one per sensor | + +Items for `bindings` must be listed in the order the keys are defined in the [keyboard scan configuration](kscan.md). + +Items for `sensor-bindings` must be listed in the order the [sensors](#keymap-sensors) are defined. + +## Keymap Sensors + +### Devicetree + +Applies to: `compatible = "zmk,keymap-sensors"` + +| Property | Type | Description | +| --------- | -------- | -------------------- | +| `sensors` | phandles | List of sensor nodes | + +The following types of nodes can be used as a sensor: + +- [`alps,ec11`](encoders.md#ec11-encoders) diff --git a/docs/docs/config/kscan.md b/docs/docs/config/kscan.md new file mode 100644 index 000000000000..65ea63ec8b78 --- /dev/null +++ b/docs/docs/config/kscan.md @@ -0,0 +1,479 @@ +--- +title: Keyboard Scan Configuration +sidebar_label: Keyboard Scan +--- + +See [Configuration Overview](index.md) for instructions on how to change these settings. + +## Common + +### Kconfig + +Definition files: + +- [zmk/app/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/Kconfig) +- [zmk/app/module/drivers/kscan/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/module/drivers/kscan/Kconfig) + +| Config | Type | Description | Default | +| -------------------------------------- | ---- | ---------------------------------------------------- | ------- | +| `CONFIG_ZMK_KSCAN_EVENT_QUEUE_SIZE` | int | Size of the event queue for kscan events | 4 | +| `CONFIG_ZMK_KSCAN_INIT_PRIORITY` | int | Keyboard scan device driver initialization priority | 40 | +| `CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS` | int | Global debounce time for key press in milliseconds | -1 | +| `CONFIG_ZMK_KSCAN_DEBOUNCE_RELEASE_MS` | int | Global debounce time for key release in milliseconds | -1 | + +If the debounce press/release values are set to any value other than `-1`, they override the `debounce-press-ms` and `debounce-release-ms` devicetree properties for all keyboard scan drivers which support them. See the [debouncing documentation](../features/debouncing.md) for more details. + +### Devicetree + +Applies to: [`/chosen` node](https://docs.zephyrproject.org/latest/guides/dts/intro.html#aliases-and-chosen-nodes) + +| Property | Type | Description | +| ---------------------- | ---- | ------------------------------------------------------------- | +| `zmk,kscan` | path | The node for the keyboard scan driver to use | +| `zmk,matrix_transform` | path | The node for the [matrix transform](#matrix-transform) to use | + +## Demux Driver + +Keyboard scan driver which works like a regular matrix but uses a demultiplexer to drive the rows or columns. This allows N GPIOs to drive N2 rows or columns instead of just N like with a regular matrix. + +:::note +Currently this driver does not honor the `CONFIG_ZMK_KSCAN_DEBOUNCE_*` settings. +::: + +### Devicetree + +Applies to: `compatible = "zmk,kscan-gpio-demux"` + +Definition file: [zmk/app/module/dts/bindings/kscan/zmk,kscan-gpio-demux.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/module/dts/bindings/kscan/zmk%2Ckscan-gpio-demux.yaml) + +| Property | Type | Description | Default | +| ----------------------- | ---------- | -------------------------------- | ------- | +| `input-gpios` | GPIO array | Input GPIOs | | +| `output-gpios` | GPIO array | Demultiplexer address GPIOs | | +| `debounce-period` | int | Debounce period in milliseconds | 5 | +| `polling-interval-msec` | int | Polling interval in milliseconds | 25 | + +## Direct GPIO Driver + +Keyboard scan driver where each key has a dedicated GPIO. + +### Kconfig + +Definition file: [zmk/app/module/drivers/kscan/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/module/drivers/kscan/Kconfig) + +| Config | Type | Description | Default | +| --------------------------------- | ---- | ------------------------------------------------ | ------- | +| `CONFIG_ZMK_KSCAN_DIRECT_POLLING` | bool | Poll for key presses instead of using interrupts | n | + +### Devicetree + +Applies to: `compatible = "zmk,kscan-gpio-direct"` + +Definition file: [zmk/app/module/dts/bindings/kscan/zmk,kscan-gpio-direct.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/module/dts/bindings/kscan/zmk%2Ckscan-gpio-direct.yaml) + +| Property | Type | Description | Default | +| ------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------- | ------- | +| `input-gpios` | GPIO array | Input GPIOs (one per key) | | +| `debounce-press-ms` | int | Debounce time for key press in milliseconds. Use 0 for eager debouncing. | 5 | +| `debounce-release-ms` | int | Debounce time for key release in milliseconds. | 5 | +| `debounce-scan-period-ms` | int | Time between reads in milliseconds when any key is pressed. | 1 | +| `poll-period-ms` | int | Time between reads in milliseconds when no key is pressed and `CONFIG_ZMK_KSCAN_DIRECT_POLLING` is enabled. | 10 | +| `toggle-mode` | bool | Use toggle switch mode. | n | + +By default, a switch will drain current through the internal pull up/down resistor whenever it is pressed. This is not ideal for a toggle switch, where the switch may be left in the "pressed" state for a long time. Enabling `toggle-mode` will make the driver flip between pull up and down as the switch is toggled to optimize for power. + +`toggle-mode` applies to all switches handled by the instance of the driver. To use a toggle switch with other, non-toggle, direct GPIO switches, create two instances of the direct GPIO driver, one with `toggle-mode` and the other without. Then, use a [composite driver](#composite-driver) to combine them. + +Assuming the switches connect each GPIO pin to the ground, the [GPIO flags](https://docs.zephyrproject.org/3.2.0/hardware/peripherals/gpio.html#api-reference) for the elements in `input-gpios` should be `(GPIO_ACTIVE_LOW | GPIO_PULL_UP)`: + +```dts + kscan0: kscan { + compatible = "zmk,kscan-gpio-direct"; + input-gpios + = <&pro_micro 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; + }; +``` + +## Matrix Driver + +Keyboard scan driver where keys are arranged on a matrix with one GPIO per row and column. + +Definition file: [zmk/app/module/drivers/kscan/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/module/drivers/kscan/Kconfig) + +| Config | Type | Description | Default | +| ---------------------------------------------- | ----------- | ------------------------------------------------------------------------- | ------- | +| `CONFIG_ZMK_KSCAN_MATRIX_POLLING` | bool | Poll for key presses instead of using interrupts | n | +| `CONFIG_ZMK_KSCAN_MATRIX_WAIT_BEFORE_INPUTS` | int (ticks) | How long to wait before reading input pins after setting output active | 0 | +| `CONFIG_ZMK_KSCAN_MATRIX_WAIT_BETWEEN_OUTPUTS` | int (ticks) | How long to wait between each output to allow previous output to "settle" | 0 | + +### Devicetree + +Applies to: `compatible = "zmk,kscan-gpio-matrix"` + +Definition file: [zmk/app/module/dts/bindings/kscan/zmk,kscan-gpio-matrix.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/module/dts/bindings/kscan/zmk%2Ckscan-gpio-matrix.yaml) + +| Property | Type | Description | Default | +| ------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------- | ----------- | +| `row-gpios` | GPIO array | Matrix row GPIOs in order, starting from the top row | | +| `col-gpios` | GPIO array | Matrix column GPIOs in order, starting from the leftmost row | | +| `debounce-press-ms` | int | Debounce time for key press in milliseconds. Use 0 for eager debouncing. | 5 | +| `debounce-release-ms` | int | Debounce time for key release in milliseconds. | 5 | +| `debounce-scan-period-ms` | int | Time between reads in milliseconds when any key is pressed. | 1 | +| `diode-direction` | string | The direction of the matrix diodes | `"row2col"` | +| `poll-period-ms` | int | Time between reads in milliseconds when no key is pressed and `CONFIG_ZMK_KSCAN_MATRIX_POLLING` is enabled. | 10 | + +The `diode-direction` property must be one of: + +| Value | Description | +| ----------- | --------------------------------------------------------------------- | +| `"row2col"` | Diodes point from rows to columns (cathodes are connected to columns) | +| `"col2row"` | Diodes point from columns to rows (cathodes are connected to rows) | + +Given the `diode-direction`, the [GPIO flags](https://docs.zephyrproject.org/3.2.0/hardware/peripherals/gpio.html#api-reference) for the elements in `row-` and `col-gpios` should be set appropriately. +The output pins (e.g. columns for `col2row`) should have the flag `GPIO_ACTIVE_HIGH`, and input pins (e.g. rows for `col2row`) should have the flags `(GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)`: + +```dts + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + col-gpios + = <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + ; + row-gpios + = <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +``` + +## Charlieplex Driver + +Keyboard scan driver where keys are arranged on a matrix with each GPIO used as both input and output. + +- With `interrupt-gpios` unset, this allows n pins to drive n\*(n-1) keys. +- With `interrupt-gpios` set, n pins will drive (n-1)\*(n-2) keys, but provide much improved power handling. + +Definition file: [zmk/app/module/drivers/kscan/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/module/drivers/kscan/Kconfig) + +| Config | Type | Description | Default | +| --------------------------------------------------- | ----------- | ------------------------------------------------------------------------- | ------- | +| `CONFIG_ZMK_KSCAN_CHARLIEPLEX_WAIT_BEFORE_INPUTS` | int (ticks) | How long to wait before reading input pins after setting output active | 0 | +| `CONFIG_ZMK_KSCAN_CHARLIEPLEX_WAIT_BETWEEN_OUTPUTS` | int (ticks) | How long to wait between each output to allow previous output to "settle" | 0 | + +### Devicetree + +Applies to: `compatible = "zmk,kscan-gpio-charlieplex"` + +Definition file: [zmk/app/module/dts/bindings/kscan/zmk,kscan-gpio-charlieplex.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/module/dts/bindings/kscan/zmk%2Ckscan-gpio-charlieplex.yaml) + +| Property | Type | Description | Default | +| ------------------------- | ---------- | ------------------------------------------------------------------------------------------- | ------- | +| `gpios` | GPIO array | GPIOs used, listed in order. | | +| `interrupt-gpios` | GPIO array | A single GPIO to use for interrupt. Leaving this empty will enable continuous polling. | | +| `debounce-press-ms` | int | Debounce time for key press in milliseconds. Use 0 for eager debouncing. | 5 | +| `debounce-release-ms` | int | Debounce time for key release in milliseconds. | 5 | +| `debounce-scan-period-ms` | int | Time between reads in milliseconds when any key is pressed. | 1 | +| `poll-period-ms` | int | Time between reads in milliseconds when no key is pressed and `interrupt-gpois` is not set. | 10 | + +Define the transform with a [matrix transform](#matrix-transform). The row is always the driven pin, and the column always the receiving pin (input to the controller). +For example, in `RC(5,0)` power flows from the 6th pin in `gpios` to the 1st pin in `gpios`. +Exclude all positions where the row and column are the same as these pairs will never be triggered, since no pin can be both input and output at the same time. + +## Composite Driver + +Keyboard scan driver which combines multiple other keyboard scan drivers. + +### Devicetree + +Applies to : `compatible = "zmk,kscan-composite"` + +Definition file: [zmk/app/dts/bindings/zmk,kscan-composite.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/zmk,kscan-composite.yaml) + +| Property | Type | Description | Default | +| -------- | ---- | --------------------------------------------- | ------- | +| `rows` | int | The number of rows in the composite matrix | | +| `cols` | int | The number of columns in the composite matrix | | + +The `zmk,kscan-composite` node should have one child node per keyboard scan driver that should be composited. Each child node can have the following properties: + +| Property | Type | Description | Default | +| --------------- | ------- | ------------------------------------------------------------------------------ | ------- | +| `kscan` | phandle | Label of the kscan driver to include | | +| `row-offset` | int | Shifts row 0 of the included driver to a new row in the composite matrix | 0 | +| `column-offset` | int | Shifts column 0 of the included driver to a new column in the composite matrix | 0 | + +### Example Configuration + +For example, consider a macropad with a 3x3 matrix and two direct GPIO keys: + +
+
+Matrix: + +
+ + + + + + + + +
Col 0Col 1Col 2
Row 0A0A1A2
Row 1A3A4A5
Row 2A6A7A8
+ + +
+Direct GPIO: + + + + + + + + +
Col 0Col 1
Row 0B0B1
+
+ + +To combine them, we need to create a composite matrix with enough rows and columns to fit both sets of keys without overlapping, then set row and/or columns offsets to shift them so they do not overlap. + +One possible way to do this is a 3x4 matrix where the direct GPIO keys are shifted to below the matrix keys... + + + + + + + + + + + +
Col 0Col 1Col 2
Row 0A0A1A2
Row 1A3A4A5
Row 2A6A7A8
Row 3B0B1(none)
+ +...which can be configured with the following Devicetree code: + +```dts +/ { + chosen { + zmk,kscan = &kscan0; + }; + + kscan0: kscan_composite { + compatible = "zmk,kscan-composite"; + rows = <4>; + columns = <3>; + + // Include the matrix driver + matrix { + kscan = <&kscan1>; + }; + + // Include the direct GPIO driver... + direct { + kscan = <&kscan2>; + row-offset = <3>; // ...and shift it to not overlap + }; + }; + + kscan1: kscan_matrix { + compatible = "zmk,kscan-gpio-matrix"; + // define 3x3 matrix here... + }; + + kscan2: kscan_direct { + compatible = "zmk,kscan-gpio-direct"; + // define 2 direct GPIOs here... + }; +} +``` + +## Mock Driver + +Mock keyboard scan driver that simulates key events. + +### Devicetree + +Applies to: `compatible = "zmk,kscan-mock"` + +Definition file: [zmk/app/dts/bindings/zmk,kscan-mock.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/zmk%2Ckscan-mock.yaml) + +| Property | Type | Description | Default | +| -------------- | ----- | --------------------------------------------- | ------- | +| `event-period` | int | Milliseconds between each generated event | | +| `events` | array | List of key events to simulate | | +| `rows` | int | The number of rows in the composite matrix | | +| `cols` | int | The number of columns in the composite matrix | | +| `exit-after` | bool | Exit the program after running all events | false | + +The `events` array should be defined using the macros from [app/module/include/dt-bindings/zmk/kscan_mock.h](https://github.com/zmkfirmware/zmk/blob/main/app/module/include/dt-bindings/zmk/kscan_mock.h). + +## Matrix Transform + +Defines a mapping from keymap logical positions to physical matrix positions. + +Transforms should be used any time the physical layout of a keyboard's keys does not match the layout of its electrical matrix and/or when not all positions in the matrix are used. This applies to most non-ortholinear boards. + +Transforms can also be used for keyboards with multiple layouts. You can define multiple matrix transform nodes, one for each layout, and users can select which one they want from the `/chosen` node in their keymaps. + +See the [new shield guide](../development/new-shield.md#optional-matrix-transform) for more documentation on how to define a matrix transform. + +### Devicetree + +Applies to: `compatible = "zmk,matrix-transform"` + +Definition file: [zmk/app/dts/bindings/zmk,matrix-transform.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/zmk%2Cmatrix-transform.yaml) + +| Property | Type | Description | Default | +| ------------ | ----- | --------------------------------------------------------------------- | ------- | +| `rows` | int | Number of rows in the transformed matrix | | +| `columns` | int | Number of columns in the transformed matrix | | +| `row-offset` | int | Adds an offset to all rows before looking them up in the transform | 0 | +| `col-offset` | int | Adds an offset to all columns before looking them up in the transform | 0 | +| `map` | array | A list of position transforms | | + +The `map` array should be defined using the `RC()` macro from [dt-bindings/zmk/matrix_transform.h](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/matrix_transform.h). It should have one item per logical position in the keymap. Each item should list the physical row and column that should trigger the key in that position. + +### Example: Skipping Unused Positions + +Any keyboard which is not a grid of 1 unit keys will likely have some unused positions in the matrix. A matrix transform can be used to skip the unused positions so users don't have to set them to `&none` in keymaps. + +```dts +// numpad.overlay +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + // define row-gpios with 5 elements and col-gpios with 4... + }; + + default_transform: matrix_transform { + compatible = "zmk,matrix-transform"; + rows = <5>; + columns = <4>; + // ┌───┬───┬───┬───┐ + // │NUM│ / │ * │ - │ + // ├───┼───┼───┼───┤ + // │ 7 │ 8 │ 9 │ + │ + // ├───┼───┼───┤ │ + // │ 4 │ 5 │ 6 │ │ + // ├───┼───┼───┼───┤ + // │ 1 │ 2 │ 3 │RET│ + // ├───┴───┼───┤ │ + // │ 0 │ . │ │ + // └───────┴───┴───┘ + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) + RC(2,0) RC(2,1) RC(2,2) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) + RC(4,0) RC(4,1) + >; + }; +}; +``` + +```dts +// numpad.keymap +/ { + keymap { + compatible = "zmk,keymap"; + default { + bindings = < + &kp KP_NUM &kp KP_DIV &kp KP_MULT &kp KP_MINUS + &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_PLUS + &kp KP_N4 &kp KP_N5 &kp KP_N6 + &kp KP_N1 &kp KP_N2 &kp KP_N3 &kp KP_ENTER + &kp KP_N0 &kp KP_DOT + >; + }; + } +}; +``` + +### Example: Non-standard Matrix + +Consider a keyboard with a [duplex matrix](https://wiki.ai03.com/books/pcb-design/page/matrices-and-duplex-matrix), where the matrix has twice as many rows and half as many columns as the keyboard has keys. A matrix transform can be used to correct for this so that keymaps can match the layout of the keys, not the layout of the matrix. + +```dts +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + // define row-gpios with 12 elements and col-gpios with 8... + }; + + default_transform: matrix_transform { + compatible = "zmk,matrix-transform"; + rows = <6>; + columns = <16>; + // ESC F1 F2 F3 ... + // ` 1 2 3 ... + // Tab Q W E ... + // Caps A S D ... + // Shift Z X C ... + // Ctrl Alt ... + map = < + RC(0,0) RC(1,0) RC(0,1) RC(1,1) // ... + RC(2,0) RC(3,0) RC(2,1) RC(3,1) // ... + RC(4,0) RC(5,0) RC(4,1) RC(5,1) // ... + RC(6,0) RC(7,0) RC(6,1) RC(7,1) // ... + RC(8,0) RC(9,0) RC(8,1) RC(9,1) // ... + RC(10,0) RC(11,0) // ... + >; + }; +}; +``` + +### Example: Charlieplex + +Since a charlieplex driver will never align with a keyboard directly due to the un-addressable positions, a matrix transform should be used to map the pairs to the layout of the keys. +Note that the entire addressable space does not need to be mapped. + +```devicetree +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-charlieplex"; + + interrupt-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN) >; + gpios + = <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN) > + , <&pro_micro 17 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN) > + , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN) > + , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN) > + , <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN) > + ; // addressable space is 5x5, (minus paired values) + }; + + default_transform: matrix_transform { + compatible = "zmk,matrix-transform"; + rows = <3>; + columns = <5>; + // Q W E R + // A S D F + // Z X C V + map = < + RC(0,1) RC(0,2) RC(0,3) RC(0,4) + RC(1,0) RC(1,2) RC(1,3) RC(1,4) + RC(2,0) RC(2,1) RC(2,3) RC(2,4) + >; + }; +}; +``` diff --git a/docs/docs/config/power.md b/docs/docs/config/power.md new file mode 100644 index 000000000000..75e1b26ab8bb --- /dev/null +++ b/docs/docs/config/power.md @@ -0,0 +1,46 @@ +--- +title: Power Management Configuration +sidebar_label: Power Management +--- + +See [Configuration Overview](index.md) for instructions on how to +change these settings. + +## Idle/Sleep + +Configuration for entering low power modes when the keyboard is idle. + +In the idle state, peripherals such as displays and lighting are disabled, but the keyboard remains connected to Bluetooth so it can immediately respond when you press a key. + +In the deep sleep state, the keyboard additionally disconnects from Bluetooth and any external power output is disabled. This state uses very little power, but it may take a few seconds to reconnect after waking. + +### Kconfig + +Definition file: [zmk/app/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/Kconfig) + +| Config | Type | Description | Default | +| ------------------------------- | ---- | ----------------------------------------------------- | ------- | +| `CONFIG_ZMK_IDLE_TIMEOUT` | int | Milliseconds of inactivity before entering idle state | 30000 | +| `CONFIG_ZMK_SLEEP` | bool | Enable deep sleep support | n | +| `CONFIG_ZMK_IDLE_SLEEP_TIMEOUT` | int | Milliseconds of inactivity before entering deep sleep | 900000 | + +## External Power Control + +Driver for enabling or disabling power to peripherals such as displays and lighting. This driver must be configured to use [power management behaviors](../behaviors/power.md). + +### Kconfig + +Definition file: [zmk/app/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/Kconfig) + +| Config | Type | Description | Default | +| ---------------------- | ---- | ----------------------------------------------- | ------- | +| `CONFIG_ZMK_EXT_POWER` | bool | Enable support to control external power output | y | + +### Devicetree + +Applies to: `compatible = "zmk,ext-power-generic"` + +| Property | Type | Description | +| --------------- | ---------- | ------------------------------------------------------------- | +| `control-gpios` | GPIO array | List of GPIOs which should be active to enable external power | +| `init-delay-ms` | int | number of milliseconds to delay after initializing the driver | diff --git a/docs/docs/config/system.md b/docs/docs/config/system.md new file mode 100644 index 000000000000..4629ea0f790e --- /dev/null +++ b/docs/docs/config/system.md @@ -0,0 +1,118 @@ +--- +title: System Configuration +sidebar_label: System +--- + +These are general settings that control how the keyboard behaves and which features it supports. Several of these settings come from Zephyr and are not specific to ZMK, but they are listed here because they are relevant to how a keyboard functions. + +See [Configuration Overview](index.md) for instructions on how to change these settings. + +## Kconfig + +Definition file: [zmk/app/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/Kconfig) + +### General + +| Config | Type | Description | Default | +| ----------------------------------- | ------ | ----------------------------------------------------------------------------- | ------- | +| `CONFIG_ZMK_KEYBOARD_NAME` | string | The name of the keyboard (max 16 characters) | | +| `CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE` | int | Milliseconds to wait after a setting change before writing it to flash memory | 60000 | +| `CONFIG_ZMK_WPM` | bool | Enable calculating words per minute | n | +| `CONFIG_HEAP_MEM_POOL_SIZE` | int | Size of the heap memory pool | 8192 | + +### HID + +| Config | Type | Description | Default | +| ------------------------------------- | ---- | -------------------------------------------------------------- | ------- | +| `CONFIG_ZMK_HID_INDICATORS` | bool | Enable reciept of HID/LED indicator state from connected hosts | n | +| `CONFIG_ZMK_HID_CONSUMER_REPORT_SIZE` | int | Number of consumer keys simultaneously reportable | 6 | + +Exactly zero or one of the following options may be set to `y`. The first is used if none are set. + +| Config | Description | +| --------------------------------- | ----------------------------------------------------------------------------------------------------- | +| `CONFIG_ZMK_HID_REPORT_TYPE_HKRO` | Enable `CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE` key roll over. | +| `CONFIG_ZMK_HID_REPORT_TYPE_NKRO` | Enable full N-key roll over. This may prevent the keyboard from working with some BIOS/UEFI versions. | + +:::note NKRO usages + +By default the NKRO max usage is set so as to maximize compatibility, however certain less frequently used keys (F13-F24 and INTL1-8) will not work with it. One solution is to set `CONFIG_ZMK_HID_KEYBOARD_NKRO_EXTENDED_REPORT=y`, however this is known to break compatibility with Android and thus not enabled by default. + +::: + +If `CONFIG_ZMK_HID_REPORT_TYPE_HKRO` is enabled, it may be configured with the following options: + +| Config | Type | Description | Default | +| ------------------------------------- | ---- | ------------------------------------------------- | ------- | +| `CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE` | int | Number of keyboard keys simultaneously reportable | 6 | + +If `CONFIG_ZMK_HID_REPORT_TYPE_NKRO` is enabled, it may be configured with the following options: + +| Config | Type | Description | Default | +| ---------------------------------------------- | ---- | -------------------------------------------------------------------- | ------- | +| `CONFIG_ZMK_HID_KEYBOARD_NKRO_EXTENDED_REPORT` | bool | Enable less frequently used key usages, at the cost of compatibility | n | + +Exactly zero or one of the following options may be set to `y`. The first is used if none are set. + +| Config | Description | +| --------------------------------------------- | ------------------------------------------------------------------------------------ | +| `CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_FULL` | Enable all consumer key codes, but may have compatibility issues with some host OSes | +| `CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_BASIC` | Prevents using some consumer key codes, but allows compatibility with more host OSes | + +### USB + +| Config | Type | Description | Default | +| --------------------------------- | ------ | --------------------------------------- | --------------- | +| `CONFIG_USB` | bool | Enable USB drivers | | +| `CONFIG_USB_DEVICE_VID` | int | The vendor ID advertised to USB | `0x1D50` | +| `CONFIG_USB_DEVICE_PID` | int | The product ID advertised to USB | `0x615E` | +| `CONFIG_USB_DEVICE_MANUFACTURER` | string | The manufacturer name advertised to USB | `"ZMK Project"` | +| `CONFIG_USB_HID_POLL_INTERVAL_MS` | int | USB polling interval in milliseconds | 1 | +| `CONFIG_ZMK_USB` | bool | Enable ZMK as a USB keyboard | | +| `CONFIG_ZMK_USB_INIT_PRIORITY` | int | USB init priority | 50 | + +### Bluetooth + +See [Zephyr's Bluetooth stack architecture documentation](https://docs.zephyrproject.org/latest/guides/bluetooth/bluetooth-arch.html) +for more information on configuring Bluetooth. + +| Config | Type | Description | Default | +| ------------------------------------------- | ---- | --------------------------------------------------------------------- | ------- | +| `CONFIG_BT` | bool | Enable Bluetooth support | | +| `CONFIG_BT_BAS` | bool | Enable the Bluetooth BAS (battery reporting service) | y | +| `CONFIG_BT_MAX_CONN` | int | Maximum number of simultaneous Bluetooth connections | 5 | +| `CONFIG_BT_MAX_PAIRED` | int | Maximum number of paired Bluetooth devices | 5 | +| `CONFIG_ZMK_BLE` | bool | Enable ZMK as a Bluetooth keyboard | | +| `CONFIG_ZMK_BLE_CLEAR_BONDS_ON_START` | bool | Clears all bond information from the keyboard on startup | n | +| `CONFIG_ZMK_BLE_CONSUMER_REPORT_QUEUE_SIZE` | int | Max number of consumer HID reports to queue for sending over BLE | 5 | +| `CONFIG_ZMK_BLE_KEYBOARD_REPORT_QUEUE_SIZE` | int | Max number of keyboard HID reports to queue for sending over BLE | 20 | +| `CONFIG_ZMK_BLE_INIT_PRIORITY` | int | BLE init priority | 50 | +| `CONFIG_ZMK_BLE_THREAD_PRIORITY` | int | Priority of the BLE notify thread | 5 | +| `CONFIG_ZMK_BLE_THREAD_STACK_SIZE` | int | Stack size of the BLE notify thread | 512 | +| `CONFIG_ZMK_BLE_PASSKEY_ENTRY` | bool | Experimental: require typing passkey from host to pair BLE connection | n | + +Note that `CONFIG_BT_MAX_CONN` and `CONFIG_BT_MAX_PAIRED` should be set to the same value. On a split keyboard they should only be set for the central and must be set to one greater than the desired number of bluetooth profiles. + +### Logging + +| Config | Type | Description | Default | +| ------------------------ | ---- | ---------------------------------------- | ------- | +| `CONFIG_ZMK_USB_LOGGING` | bool | Enable USB CDC ACM logging for debugging | n | +| `CONFIG_ZMK_LOG_LEVEL` | int | Log level for ZMK debug messages | 4 | + +### Split keyboards + +Following split keyboard settings are defined in [zmk/app/src/split/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/src/split/Kconfig) (generic) and [zmk/app/src/split/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/src/split/bluetooth/Kconfig) (bluetooth). + +| Config | Type | Description | Default | +| ----------------------------------------------------- | ---- | ------------------------------------------------------------------------ | ------- | +| `CONFIG_ZMK_SPLIT` | bool | Enable split keyboard support | n | +| `CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS` | bool | Enable split keyboard support for passing indicator state to peripherals | n | +| `CONFIG_ZMK_SPLIT_BLE` | bool | Use BLE to communicate between split keyboard halves | y | +| `CONFIG_ZMK_SPLIT_ROLE_CENTRAL` | bool | `y` for central device, `n` for peripheral | | +| `CONFIG_ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE` | int | Max number of key state events to queue when received from peripherals | 5 | +| `CONFIG_ZMK_SPLIT_BLE_CENTRAL_SPLIT_RUN_STACK_SIZE` | int | Stack size of the BLE split central write thread | 512 | +| `CONFIG_ZMK_SPLIT_BLE_CENTRAL_SPLIT_RUN_QUEUE_SIZE` | int | Max number of behavior run events to queue to send to the peripheral(s) | 5 | +| `CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_STACK_SIZE` | int | Stack size of the BLE split peripheral notify thread | 650 | +| `CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_PRIORITY` | int | Priority of the BLE split peripheral notify thread | 5 | +| `CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_POSITION_QUEUE_SIZE` | int | Max number of key state events to queue to send to the central | 10 | diff --git a/docs/docs/config/underglow.md b/docs/docs/config/underglow.md new file mode 100644 index 000000000000..1209e60ecc07 --- /dev/null +++ b/docs/docs/config/underglow.md @@ -0,0 +1,49 @@ +--- +title: RGB Underglow Configuration +sidebar_label: RGB Underglow +--- + +See the [RGB Underglow feature page](../features/underglow.md) for more details, including instructions for adding underglow support to a board. + +See [Configuration Overview](index.md) for instructions on how to change these settings. + +## Kconfig + +RGB underglow depends on [Zephyr's LED strip driver](https://github.com/zephyrproject-rtos/zephyr/tree/main/drivers/led_strip), which provides additional Kconfig options. + +Definition file: [zmk/app/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/Kconfig) + +| Config | Type | Description | Default | +| ---------------------------------------- | ---- | --------------------------------------------------------- | ------- | +| `CONFIG_ZMK_RGB_UNDERGLOW` | bool | Enable RGB underglow | n | +| `CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER` | bool | Underglow toggling also controls external power | y | +| `CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE` | bool | Turn off RGB underglow when keyboard goes into idle state | n | +| `CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_USB` | bool | Turn off RGB underglow when USB is disconnected | n | +| `CONFIG_ZMK_RGB_UNDERGLOW_HUE_STEP` | int | Hue step in degrees (0-359) used by RGB actions | 10 | +| `CONFIG_ZMK_RGB_UNDERGLOW_SAT_STEP` | int | Saturation step in percent used by RGB actions | 10 | +| `CONFIG_ZMK_RGB_UNDERGLOW_BRT_STEP` | int | Brightness step in percent used by RGB actions | 10 | +| `CONFIG_ZMK_RGB_UNDERGLOW_HUE_START` | int | Default hue in degrees (0-359) | 0 | +| `CONFIG_ZMK_RGB_UNDERGLOW_SAT_START` | int | Default saturation percent (0-100) | 100 | +| `CONFIG_ZMK_RGB_UNDERGLOW_BRT_START` | int | Default brightness in percent (0-100) | 100 | +| `CONFIG_ZMK_RGB_UNDERGLOW_SPD_START` | int | Default effect speed (1-5) | 3 | +| `CONFIG_ZMK_RGB_UNDERGLOW_EFF_START` | int | Default effect index from the effect list (see below) | 0 | +| `CONFIG_ZMK_RGB_UNDERGLOW_ON_START` | bool | Default on state | y | + +Values for `CONFIG_ZMK_RGB_UNDERGLOW_EFF_START`: + +| Value | Effect | +| ----- | ----------- | +| 0 | Solid color | +| 1 | Breathe | +| 2 | Spectrum | +| 3 | Swirl | + +:::note +The `*_START` settings only determine the initial underglow state. Any changes you make with the [underglow behavior](../behaviors/underglow.md) are saved to flash after a one minute delay and will be used after that. +::: + +## Devicetree + +ZMK does not have any Devicetree properties of its own. See the Devicetree bindings for [Zephyr's LED strip drivers](https://github.com/zephyrproject-rtos/zephyr/tree/main/dts/bindings/led_strip). + +See the [RGB underglow feature page](../features/underglow.md) for examples of the properties that must be set to enable underglow. diff --git a/docs/docs/customization.md b/docs/docs/customization.md new file mode 100644 index 000000000000..a68e8595fa96 --- /dev/null +++ b/docs/docs/customization.md @@ -0,0 +1,78 @@ +--- +title: Customizing ZMK/zmk-config folders +sidebar_label: Customizing ZMK +--- + +After verifying you can successfully flash the default firmware, you will probably want to begin customizing your keymap and other keyboard options. +[In the initial setup tutorial](user-setup.md), you created a Github repository called `zmk-config`. This repository is a discrete filesystem which works +with the main `zmk` firmware repository to build your desired firmware. The main advantage of a discrete configuration folder is ensuring that the +working components of ZMK are kept separate from your personal keyboard settings, reducing the amount of file manipulation in the configuration process. +This makes flashing ZMK to your keyboard much easier, especially because you don't need to keep an up-to-date copy of zmk on your computer at all times. + +By default, the `zmk-config` folder should contain two files: + +- `.conf` +- `.keymap` + +However, your config folder can also be modified to include a `boards/` directory for keymaps and configurations for multiple boards/shields +outside of the default keyboard setting definitions. + +## Configuration Changes + +The setup script creates a `config/.conf` file that allows you to add additional configuration options to +control what features and options are built into your firmware. Opening that file with your text editor will allow you to see the +various config settings that can be commented/uncommented to modify how your firmware is built. + +Refer to the [Configuration](/docs/config) documentation for more details on this file. + +## Keymap + +Once you have the basic user config completed, you can find the keymap file in `config/.keymap` and customize from there. +Refer to the [Keymap](features/keymaps.md) documentation to learn more. + +## Publishing + +After making any changes you want, you should commit the changes and then push them to GitHub. That will trigger a new +GitHub Actions job to build your firmware which you can download once it completes. + +:::note +If you need to, a review of [Learn The Basics Of Git In Under 10 Minutes](https://www.freecodecamp.org/news/learn-the-basics-of-git-in-under-10-minutes-da548267cc91/) will help you get these steps right. +::: + +:::note +It is also possible to build firmware locally on your computer by following the [toolchain setup](development/setup.md) and +[building instructions](development/build-flash.md), which includes pointers to +[building using your `zmk-config` folder](development/build-flash.md#building-from-zmk-config-folder). +::: + +## Flashing Your Changes + +For normal keyboards, follow the same flashing instructions as before to flash your updated firmware. + +For split keyboards, only the central (left) side will need to be reflashed if you are just updating your keymap. +More troubleshooting information for split keyboards can be found [here](troubleshooting.md#split-keyboard-halves-unable-to-pair). + +## Building Additional Keyboards + +You can build additional keyboards with GitHub actions by appending them to `build.yml` in your `zmk-config` folder. For instance assume that we have set up a Corne shield with nice!nano during [initial setup](user-setup.md) and we want to add a Lily58 shield with nice!nano v2. The following is an example `build.yaml` file that would accomplish that: + +```yaml +include: + - board: nice_nano + shield: corne_left + - board: nice_nano + shield: corne_right + - board: nice_nano_v2 + shield: lily58_left + - board: nice_nano_v2 + shield: lily58_right +``` + +In addition to updating `build.yaml`, Lily58's shield files should also be added into the `config` sub-folder inside `zmk-config` together with your Corne files, e.g.: + +``` +corne.conf +corne.keymap +lily58.conf +lily58.keymap +``` diff --git a/docs/docs/development/boards-shields-keymaps.md b/docs/docs/development/boards-shields-keymaps.md new file mode 100644 index 000000000000..77d8361a8df6 --- /dev/null +++ b/docs/docs/development/boards-shields-keymaps.md @@ -0,0 +1,52 @@ +--- +title: Boards, Shields, and Keymaps +--- + +## Architecture Overview + +The foundational elements needed to get a specific keyboard working with ZMK can be broken down into: + +- A [KSCAN driver](https://docs.zephyrproject.org/2.5.0/reference/peripherals/kscan.html), which uses `compatible="zmk,kscan-gpio-matrix"` for GPIO matrix based keyboards, or uses `compatible="zmk,kscan-gpio-direct"` for small direct wires. +- An optional matrix transform, which defines how the KSCAN row/column events are translated into logical "key positions". This is required for non-rectangular keyboards/matrices, where the key positions don't naturally follow the row/columns from the GPIO matrix. +- A keymap, which binds each key position to a behavior, e.g. key press, mod-tap, momentary layer, in a set of layers. + +These three core architectural elements are defined per-keyboard, and _where_ they are defined depends on the specifics of how that +keyboard works. For an overview on the general concepts of boards and shields, please see the [FAQs on boards and shields](../faq.md#why-boards-and-shields--why-not-just-keyboard). + +## Self-Contained Keyboard + +For a self-contained keyboard that includes the microprocessor, all of the above architecture components are included in the Zephyr _board_ definition. You can see an example for the [Planck V6](https://github.com/zmkfirmware/zmk/tree/main/app/boards/arm/planck) board directory. + +With this type of keyboard, the full ZMK definition for the keyboard exists +in the `app/boards/${arch}/${board_name}` directory, e.g. `app/boards/arm/planck/`. In that directory, you'll have the following: + +- A `Kconfig.board` file that defines the toplevel Kconfig item for the board, including which SoC Kconfig setting it depends on. +- A `Kconfig.defconfig` file that sets some initial defaults when building this keyboard. This usually includes: + - Setting `ZMK_KEYBOARD_NAME` to a value, for the product name to be used for USB/BLE info. + - Setting `ZMK_USB` and/or `ZMK_BLE` for the default values for which HID transport(s) to enable by default +- A `${board_name}_defconfig` file that forces specific Kconfig settings that are specific to this hardware configuration. Mostly this is SoC settings around the specific hardware configuration. +- `${board_name}.dts` which contains all the devicetree definitions, including: + - An `#include` line that pulls in the specific microprocessor that is used, e.g. `#include `. + - A [chosen](https://docs.zephyrproject.org/2.5.0/guides/dts/intro.html#aliases-and-chosen-nodes) node named `zmk,kscan` which references the configured KSCAN driver (usually a GPIO matrix) + - (Optional) A [chosen](https://docs.zephyrproject.org/2.5.0/guides/dts/intro.html#aliases-and-chosen-nodes) node named `zmk,matrix_transform` that defines the mapping from KSCAN row/column values to the logical key position for the keyboard. +- A `board.cmake` file with CMake directives for how to flash to the device. +- A `${board_name}.keymap` file that includes the default keymap for that keyboard. Users will be able to override this keymap in their user configs. + +## Pro Micro Compatible Keyboard + +![Labelled Pro Micro pins](../assets/interconnects/pro_micro/pinout.png) + +For keyboards that require a (usually Pro Micro compatible) add-on board to operate, the ZMK integration pieces are places +in the _shield_ definition for that keyboard, allowing users to +swap in different Pro Micro compatible boards (e.g. Proton-C, or nice!nano) and build a firmware the matches their actual +combination of physical components. + +With this type of keyboard, the partial definition for the keyboard exists +in the `app/boards/shields/${board_name}` directory, e.g. `app/boards/shields/clueboard_california/`. In that directory, you'll have the following: + +- A `Kconfig.shield` that defines the toplevel Kconfig value for the shield, which uses a supplied utility to function to default the value based on the shield list, e.g. `def_bool $(shields_list_contains,clueboard_california)`. +- A `Kconfig.defconfig` file to set default values for things like `ZMK_KEYBOARD_NAME` +- A `${shield_name}.overlay` file, which is a devicetree overlay file, that includes: + - A [chosen](https://docs.zephyrproject.org/2.5.0/guides/dts/intro.html#aliases-and-chosen-nodes) node named `zmk,kscan` which references the configured KSCAN driver (usually a GPIO matrix). For these keyboards, to be compatible with any Pro Micro compatible boards, the KSCAN configuration should reference the [nexus node](https://docs.zephyrproject.org/2.5.0/guides/porting/shields.html#gpio-nexus-nodes) that ZMK has standardized on. In particular, the `&pro_micro` aliases can be used to reference the standard digital pins of a Pro Micro for shields. + - (Optional) A [chosen](https://docs.zephyrproject.org/2.5.0/guides/dts/intro.html#aliases-and-chosen-nodes) node named `zmk,matrix_transform` that defines the mapping from KSCAN row/column values to the logical key position for the keyboard. +- A `keymap/keymap.overlay` file that includes the default keymap for that keyboard. Users will be able to override this keymap in their user configs. diff --git a/docs/docs/development/build-flash.md b/docs/docs/development/build-flash.md new file mode 100644 index 000000000000..1699ac5ce4cb --- /dev/null +++ b/docs/docs/development/build-flash.md @@ -0,0 +1,178 @@ +--- +title: Building and Flashing +sidebar_label: Building and Flashing +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +export const OsTabs = (props) => ({props.children}); + +## Building + +From here on, building and flashing ZMK should all be done from the `app/` subdirectory of the ZMK checkout: + +```sh +cd app +``` + +To build for your particular keyboard, the behavior varies slightly depending on if you are building for a keyboard with +an onboard MCU, or one that uses an MCU board addon. + +### Keyboard (Shield) + MCU Board + +ZMK treats keyboards that take an MCU addon board as [shields](https://docs.zephyrproject.org/2.5.0/guides/porting/shields.html), and treats the smaller MCU board as the true [board](https://docs.zephyrproject.org/2.5.0/guides/porting/board_porting.html) + +Given the following: + +- MCU Board: Proton-C +- Keyboard PCB: kyria_left +- Keymap: default + +You can build ZMK with the following: + +```sh +west build -b proton_c -- -DSHIELD=kyria_left +``` + +### Keyboard With Onboard MCU + +Keyboards with onboard MCU chips are simply treated as the [board](https://docs.zephyrproject.org/2.5.0/guides/porting/board_porting.html) as far as Zephyr™ is concerned. + +Given the following: + +- Keyboard: Planck (rev6) +- Keymap: default + +you can build ZMK with the following: + +```sh +west build -b planck_rev6 +``` + +### Pristine Building + +When building for a new board and/or shield after having built one previously, you may need to enable the pristine build option. This option removes all existing files in the build directory before regenerating them, and can be enabled by adding either --pristine or -p to the command: + +```sh +west build -p -b nice_nano_v2 -- -DSHIELD=kyria_left +``` + +### Building For Split Keyboards + +:::note +For split keyboards, you will have to build and flash each side separately the first time you install ZMK. +::: + +By default, the `build` command outputs a single .uf2 file named `zmk.uf2` so building left and then right immediately after will overwrite your left firmware. In addition, you will need to pristine build each side to ensure the correct files are used. To avoid having to pristine build every time and separate the left and right build files, we recommend setting up separate build directories for each half. You can do this by using the `-d` parameter and first building left into `build/left`: + +```sh +west build -d build/left -b nice_nano_v2 -- -DSHIELD=kyria_left +``` + +and then building right into `build/right`: + +```sh +west build -d build/right -b nice_nano_v2 -- -DSHIELD=kyria_right +``` + +This produces `left` and `right` subfolders under the `build` directory and two separate .uf2 files. For future work on a specific half, use the `-d` parameter again to ensure you are building into the correct location. + +:::tip +Build times can be significantly reduced after the initial build by omitting all build arguments except the build directory, e.g. `west build -d build/left`. The additional options and intermediate build outputs from your initial build are cached and reused for unchanged files. +::: + +### Building with external modules + +ZMK supports loading additional boards, shields, code, etc. from [external Zephyr modules](https://docs.zephyrproject.org/3.2.0/develop/modules.html), facilitating out-of-tree management and versioning independent of the ZMK repository. To build with any additional modules, use the `ZMK_EXTRA_MODULES` define added to your `west build` command. + +For instance, building with the `my-vendor-keebs-module` checked out to your documents directory, you would build like: + +``` +west build -b nice_nano_v2 -- -DSHIELD=vendor_shield -DZMK_EXTRA_MODULES="C:/Users/myUser/Documents/my-vendor-keebs-module" +``` + +When adding multiple modules, make sure they are separated by a semicolon, e.g.: + +``` +west build -b nice_nano_v2 -- -DSHIELD=vendor_shield -DZMK_EXTRA_MODULES="C:/Users/myUser/Documents/my-vendor-keebs-module;C:/Users/myUser/Documents/my-other-keebs-module" +``` + +### Building from `zmk-config` Folder + +Instead of building .uf2 files using the default keymap and config files, you can build directly from your [`zmk-config` folder](../user-setup.md#github-repo) by adding +`-DZMK_CONFIG="C:/the/absolute/path/config"` to your `west build` command. **Notice that this path should point to the folder labelled `config` within your `zmk-config` folder.** + +For instance, building kyria firmware from a user `myUser`'s `zmk-config` folder on Windows 10 may look something like this: + +```sh +west build -b nice_nano -- -DSHIELD=kyria_left -DZMK_CONFIG="C:/Users/myUser/Documents/Github/zmk-config/config" +``` + +:::caution +The above command must still be invoked from the `zmk/app` directory as noted above, rather than the config directory. Otherwise, you will encounter errors such as `ERROR: source directory "." does not contain a CMakeLists.txt; is this really what you want to build?`. Alternatively you can add the `-s /path/to/zmk/app` flag to your `west` command. +::: + +In order to make your `zmk-config` folder available when building within the VSCode Remote Container, you need to create a docker volume named `zmk-config` +by binding it to the full path of your config directory. If you have run the VSCode Remote Container before, it is likely that docker has created this +volume automatically -- we need to delete the default volume before binding it to the correct path. Follow the following steps: + +1. Stop the container by exiting VSCode. You can verify no container is running via the command `docker ps`. +1. Remove all the containers that are not running via the command `docker container prune`. We need to remove the ZMK container before we can delete the default `zmk-config` volume referenced by it. If you do not want to delete all the containers that are not running, you can find the id of the ZMK container and use `docker rm` to delete that one only. +1. Remove the default volume via the command `docker volume rm zmk-config`. + +Then you can bind the `zmk-config` volume to the correct path pointing to your local [zmk-config](customization.md) folder: + +```sh +docker volume create --driver local -o o=bind -o type=none -o \ + device="/full/path/to/your/zmk-config/" zmk-config +``` + +Now start VSCode and rebuild the container after being prompted. You should be able to see your zmk-config mounted to `/workspaces/zmk-config` inside the container. So you can build your custom firmware with `-DZMK_CONFIG="/workspaces/zmk-config/config"`. + +## Flashing + +The above build commands generate a UF2 file in `build/zephyr` (or +`build/left|right/zephyr` if you followed the instructions for splits) and is by +default named `zmk.uf2`. If your board supports USB Flashing Format (UF2), copy +that file onto the root of the USB mass storage device for your board. The +controller should flash your built firmware, unmount the USB storage device and +automatically restart once flashing is complete. + +Alternatively, if your board supports flashing and you're not developing from +within a Dockerized environment, enable Device Firmware Upgrade (DFU) mode on +your board and run the following command to flash: + +```sh +west flash +``` + +## Multi-CPU and Dual-Chip Bluetooth Boards + +Zephyr supports running the Bluetooth host and controller on separate processors. In such a configuration, ZMK always runs on the host processor, but you may need to build and flash separate firmware for the controller. Zephyr provides sample code which can be used as the controller firmware for Bluetooth HCI over [RPMsg](https://docs.zephyrproject.org/3.2.0/samples/bluetooth/hci_rpmsg/README.html), [SPI](https://docs.zephyrproject.org/3.2.0/samples/bluetooth/hci_spi/README.html), [UART](https://docs.zephyrproject.org/3.2.0/samples/bluetooth/hci_uart/README.html), and [USB](https://docs.zephyrproject.org/3.2.0/samples/bluetooth/hci_usb/README.html). See [Zephyr's Bluetooth Stack Architecture documentation](https://docs.zephyrproject.org/3.2.0/connectivity/bluetooth/bluetooth-arch.html) for more details. + +The following documentation shows how to build and flash ZMK for boards that use a dual-chip configuration. + +### nRF5340 + +To build and flash the firmware for the nRF5340 development kit's network core, run the following command from the root of the ZMK repo: + +```sh +cd zephyr/samples/bluetooth/hci_rpmsg +west build -b nrf5340dk_nrf5340_cpunet +west flash +``` + +You can then build and flash ZMK firmware using the normal steps described above. The network core's firmware only needs to be updated whenever ZMK upgrades to a new version of Zephyr. + +For a custom nRF5340-based board, you will need to define two Zephyr boards: one for the application core and one for the network core. The [nRF5340 DK's board definition](https://github.com/zephyrproject-rtos/zephyr/tree/main/boards/arm/nrf5340dk_nrf5340) can be used as reference. Replace `nrf5340dk_nrf5340_cpunet` with the name of your network core board. diff --git a/docs/docs/development/clean-room.md b/docs/docs/development/clean-room.md new file mode 100644 index 000000000000..82db3a0406e9 --- /dev/null +++ b/docs/docs/development/clean-room.md @@ -0,0 +1,28 @@ +--- +title: Clean Room Implementation +sidebar_label: Clean Room +--- + +:::warning + +Anyone wanting to contribute code to ZMK _MUST_ read this, and adhere to the steps outlines in order to not violate any licenses/copyright of other projects + +::: + +ZMK Firmware is a [clean room design](https://en.wikipedia.org/wiki/Clean_room_design) keyboard firmware, that +borrows/implements a lot of the features found in popular keyboard firmwares projects like [QMK](https://qmk.fm) +and [TMK](https://github.com/tmk/tmk_keyboard). However, in order for ZMK to use the MIT, it _must_ not +incorporate any of the GPL licensed code from those projects. + +In order to achieve this, all code for ZMK has been implemented completely fresh, _without_ referencing, copying, +or duplicating any of the GPL code found in those other projects, even though they are open source software. + +## Contributor Requirements + +Contributors to ZMK must adhere to the following standard. + +- Implementations of features for ZMK _MUST NOT_ reuse any existing code from any projects not licensed with the MIT license. +- Contributors _MUST NOT_ study or refer to any GPL licensed source code while working on ZMK. +- Contributors _MAY_ read the documentation from other GPL licensed projects, to gain a broad understanding of the behavior of certain features in order to implement equivalent features for ZMK. +- Contributors _MAY_ refer to the [QMK Configurator](https://config.qmk.fm/) to inspect existing layouts/keymaps for + keyboards, and re-implement them for ZMK. diff --git a/docs/docs/development/documentation.md b/docs/docs/development/documentation.md new file mode 100644 index 000000000000..ff45d80aa76a --- /dev/null +++ b/docs/docs/development/documentation.md @@ -0,0 +1,57 @@ +--- +title: Documentation +sidebar_label: Documentation +--- + +This document outlines how to test your documentation changes locally and prepare the changes for a pull request. + +The documentation is written with [Docusaurus](https://docusaurus.io/). The ZMK source code has all of the necessary Docusaurus dependencies included but referencing their documentation can be helpful at times. + +The general process for updating the ZMK documentation is: + +1. Update the documentation +2. Test the changes locally +3. Ensure the sources are formatted properly and linted +4. Create a Pull Request for review and inclusion into the ZMK sources + +:::note +If you are working with the documentation from within VS Code+Docker please be aware the documentation will not be auto-generated when making changes while the server is running. You'll need to restart the server when saving changes to the documentation. +::: + +:::note +You will need `Node.js` and `npm` installed to update the documentation. If you're using the ZMK dev container (Docker) the necessary dependencies are already installed. Otherwise, you must install these dependencies yourself. Since `Node.js` packages in Linux distributions tend to be outdated, it's recommended to install the current version from a repository like [NodeSource](https://github.com/nodesource/distributions) to avoid build errors. +::: + +## Testing Documentation Updates Locally + +To verify documentation updates locally, follow the following procedure. The `npm` commands and first step will need to be run from a terminal. + +1. Navigate to the `docs` folder +2. Run `npm ci` to build the necessary tools if you haven't run it before or the ZMK sources were updated +3. Run `npm start` to start the local server that will let you see your documentation updates via a web browser +4. If a web browser doesn't open automatically: you'll need to open a browser window or tab and navigate to `http://localhost:3000` to view your changes +5. Verify the changes look good + +## Formatting and Linting Your Changes + +Prior to submitting a documentation pull request, you'll want to run the format and check commands. These commands are run as part of the verification process on pull requests so it's good to run them ahead of submitting documentation updates. + +The format command can be run with the following procedure in a terminal that's inside the ZMK source directory. + +1. Navigate to the `docs` folder +2. Run `npm run prettier:format` + +The check commands can be run with the following procedure in a terminal that's inside the ZMK source directory. + +1. Navigate to the `docs` folder +2. Run `npm run prettier:check` +3. Run `npm run lint` +4. Run `npm run build` + +:::warning +If any of the above steps throw an error, they need to be addressed and all of the checks re-run prior to submitting a pull request. +::: + +## Submitting a Pull Request + +Once the above sections are complete the documentation updates are ready to submit as a pull request. diff --git a/docs/docs/development/hardware-metadata-files.md b/docs/docs/development/hardware-metadata-files.md new file mode 100644 index 000000000000..46fad411abb9 --- /dev/null +++ b/docs/docs/development/hardware-metadata-files.md @@ -0,0 +1,113 @@ +--- +title: Hardware Metadata Files +--- + +## Overview + +ZMK makes use of an additional metadata YAML file for all boards and shields to provide high level information about the hardware to be incorporated into setup scripts/utilities, website hardware list, etc. + +The naming convention for metadata files is `{item_id}.zmk.yml`, where the `item_id` is the board/shield identifier, including version information but excluding any optional split `_left`/`_right` suffix, e.g. `corne.zmk.yml` or `nrfmicro_11.zmk.yml`. + +## Example File + +Here is a sample `corne.zmk.yml` file from the repository: + +```yaml +file_format: "1" +id: corne +name: Corne +type: shield +url: https://github.com/foostan/crkbd/ +requires: + - pro_micro +exposes: + - i2c_oled +features: + - keys + - display +siblings: + - corne_left + - corne_right +``` + +## Schema + +ZMK uses a [JSON Schema](https://github.com/zmkfirmware/zmk/blob/main/schema/hardware-metadata.schema.json) file to validate metadata files and sure all required properties are present, and all other optional properties provided conform to the expected format. You can validate all metadata files in the repository by running `west metadata check` from your configured ZMK repository. + +## File Format + +The first line of every metadata file should contain the file format. As of today, the only acceptable file format is `1`, which should be written like: + +```yaml +file_format: "1" +``` + +:::note + +ZMK plans to expand on the initial based set of metadata properties, while maintaining backwards compatibility. In particular, new _optional_ properties may be added to file format `1` as time progress, and when new set of properties is settled upon as being required moving forward, a new major version of the file format will be created to encompass those changes. + +::: + +### Item ID and Name + +All metadata files should then contain two key pieces of identifying information, the `id` for the item, and the `name` which used a the human readable display name in various UI locations: + +```yaml +id: corne +name: Corne +``` + +### Item Types + +Each metadata file includes a `type` property uniquely identifying the type of item, be it `board`, `shield`, or the less frequently needed `interconnect` (which is used to document generic hardware interconnects like the Pro Micro format): + +```yaml +type: shield +``` + +### URL + +The `url` property should contain the canonical URL used to learn more about the board/shield, e.g. the main vendor website or GitHub repository for a given keyboard/controller: + +```yaml +url: https://github.com/foostan/crkbd/ +``` + +### Interconnect Requires/Exposes + +For boards and shields, one of the key pieces of high level information is compatibility between the two items. In particular, a board usually exposes one ore more "interconnects", the physical location/type of connections available, and their assigned possible uses (e.g. GPIO, power, ground, i2c, etc). Similarly, a shield is usually designed around one (or sometimes more) "interconnects" that allow it to connect to one of those boards. + +In ZMK, we encode both of those scenarios with the `exposes` and `requires` properties, respectively. For example, for a Corne shield that requires a Pro Micro compatible controller to function, and simultaneously exposes a four pin header to be used by standard i2c OLED modules, the metadata file contains: + +```yaml +requires: + - pro_micro +exposes: + - i2c_oled +``` + +### Features + +Boards and shields should document the sets of hardware features found on them using the `features` array. There is a fixed enum of possible values to use here, which will be expanded over time. The current set of possible `features` values is: + +- `keys` - Any board or shield that contains keyboard keys should include this feature. It is a central feature used to determine if we have a "complete combination" for ZMK to produce a keyboard firmware when performing setup. +- `display` - Indicates the hardware includes a display for use with the ZMK display functionality. +- `encoder` - Indicates the hardware contains one or more rotary encoders. +- `underglow` - Indicates the hardware includes underglow LEDs. +- `backlight` - Indicates the hardware includes backlight LEDs. +- `pointer` (future) - Used to indicate the hardware includes one or more pointer inputs, e.g. joystick, touchpad, or trackpoint. + +### Siblings + +The `siblings` array is used to identify multiple hardware items designed to be used together as one logical device. Right now, that primarily is used to identify the two halves of a split keyboard, but future enhancements will include more complicated and flexible combinations. + +The array should contain the complete hardware IDs of the siblings that combine in the logical device, e.g. with the `corne.zmk.yml` file: + +```yaml +id: corne +siblings: + - corne_left + - corne_right +``` + +Future versions of the metadata file format will be expanded to allow documenting any specifics of each sibling that are unique, e.g. if only the left side contains the `encoder` feature. diff --git a/docs/docs/development/ide-integration.md b/docs/docs/development/ide-integration.md new file mode 100644 index 000000000000..f0403dbba36a --- /dev/null +++ b/docs/docs/development/ide-integration.md @@ -0,0 +1,114 @@ +--- +title: IDE Integration +sidebar_label: IDE Integration +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +export const OsTabs = (props) => ({props.children}); + +## Visual Studio Code + +Visual Studio Code needs to know some things about the project such as include +paths and compiler paths before features such as code completion, go to definition, +and graying out disabled code blocks will work. Fortunately, CMake can generate +that configuration for us automatically. + +### Create a Compilation Database + +To configure `west` to tell CMake to generate a compilation database, open a +terminal to the ZMK repository and run the following command: + +```sh +west config build.cmake-args -- -DCMAKE_EXPORT_COMPILE_COMMANDS=ON +``` + +Every [build](build-flash.md#building) will now update the database. You will +need to build once to create the database before code completion will work. +We'll tell Visual Studio Code where to find the database in the next step. + +:::note +If you have set any other CMake arguments such as the path to your zmk-config, the +above command will overwrite them. You should instead provide the flag to export +compile commands and all other arguments surrounded by quotes. For example: + +```sh +west config build.cmake-args -- "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DZMK_CONFIG=/path/to/zmk-config/config" +``` + +::: + +### Create a C/C++ Configuration + +Install the [C/C++ extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools), +then run **F1 > C/C++: Edit Configurations (UI)**. It should automatically create +a new configuration for you, but if the text box under **Configuration name** is empty, +click **Add Configuration**, enter a name, and click **OK**. + +Change these options: + +| Option | Value | +| ------------------------------------- | ------------------------------------------------------ | +| Compiler path | Path to your toolchain's GCC binary (see below) | +| IntelliSense mode | `linux-gcc-arm`, `windows-gcc-arm`, or `macos-gcc-arm` | +| Advanced Settings > Compiler commands | `${workspaceFolder}/app/build/compile_commands.json` | + +If you are developing inside a Docker container, set the IntelliSense mode to `linux-gcc-arm` regardless of the host operating system. + +#### Compiler Path + +Open VS Code's integrated terminal and run the following command: + +```sh +cmake -P zephyr/cmake/verify-toolchain.cmake +``` + +This should print something like + +``` +-- ZEPHYR_TOOLCHAIN_VARIANT: zephyr +-- SDK_VERSION: 0.15.2 +-- ZEPHYR_SDK_INSTALL_DIR : /home/marvin/.local/zephyr-sdk-0.15.2 +``` + +Your compiler path is the value of `ZEPHYR_SDK_INSTALL_DIR` plus `/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc`, for example: + +``` +/home/marvin/.local/zephyr-sdk-0.15.2/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc +``` + +If you are building for an platform other than ARM, replace `/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc` with the path to the compiler for the appropriate architecture, for example: + +``` +/home/marvin/.local/zephyr-sdk-0.15.2/riscv64-zephyr-elf/bin/riscv64-zephyr-elf-gcc +``` + +#### Compiler Commands Path + +When building with all default options, the path to the compilation database file +is `${workspaceFolder}/app/build/compile_commands.json` as shown in the table above, +however some arguments to `west build` can change this path. + +The `-d` or `--build-dir` option lets you change the build directory to something +other than `build`. Replace `build` in the above path with what you set this to. +For example, if you build with `-d build/my_shield`, the path is +`${workspaceFolder}/app/build/my_shield/compile_commands.json`. If you use this +to keep builds for multiple keyboards separate, you may want to create a separate +C/C++ configuration for each one in VS Code. + +You can also build from the root folder of the project instead of the `app` +folder by adding `-S app` to your CMake arguments. In this case, simply remove +`app` from the path to `compile_commands.json`, for example, +`${workspaceFolder}/build/compile_commands.json`. diff --git a/docs/docs/development/new-behavior.md b/docs/docs/development/new-behavior.md new file mode 100644 index 000000000000..59872963f10f --- /dev/null +++ b/docs/docs/development/new-behavior.md @@ -0,0 +1,493 @@ +--- +title: New Behavior +sidebar_label: New Behavior +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Overview + +This document outlines how to develop a behavior for ZMK and prepare the changes for a pull request. + +Behaviors are assigned to key positions and determine what happens when they are pressed and released. They are implemented in Zephyr as "devices": they consist of a devicetree binding file, which specifies the properties of the behavior, and a driver written in C code. This allows for the ability to create unique instances of these behaviors in [keymaps](../features/keymaps.md) or devicetree-source-include files (`.dtsi`). While instances of behaviors stored in keymaps are created by end-users for their personal needs, the instances that live in the .dtsi files are stored and documented in ZMK directly, which removes the need for end-users to set up common use-cases of these behaviors in their personal keymaps. + +The general process for developing behaviors is: + +1. [Create the behavior](#creating-the-behavior) + 1. [Create the devicetree binding (`.yaml`)](#creating-the-devicetree-binding-yaml) + 1. [Create the driver (`.c`)](#creating-the-driver-c) + 1. [Update `app/CmakeLists.txt` to include the new driver](#updating-appcmakeliststxt-to-include-the-new-driver) + 1. [Define common use-cases for the behavior (`.dtsi`) (Optional)](#defining-common-use-cases-for-the-behavior-dtsi-optional) +1. [Test changes locally](#testing-changes-locally) +1. [Document behavior functionality](#documenting-behavior-functionality) +1. [Create a pull request for review and inclusion into the ZMK sources](#submitting-a-pull-request) + +:::info +Before developing new behaviors, developers should have a working knowledge of the Embedded Linux Devicetree. +The following resources are provided for those seeking further understanding: + +- [Embedded Linux Wiki - Device Tree Usage](https://elinux.org/Device_Tree_Usage) +- [Zephyr Devicetree API](https://docs.zephyrproject.org/latest/build/dts/api/api.html) +- [Zephyr Device Driver Model](https://docs.zephyrproject.org/latest/kernel/drivers/index.html) + +::: + +## Creating the Behavior + +### Creating the devicetree binding (`.yaml`) + +The properties of the behavior are listed in the behavior's devicetree binding, which comes in the form of a `.yaml` file. Devicetree bindings are stored in the directory `app/dts/bindings/behaviors/` and are labelled in lowercase, beginning with the prefix `zmk,behavior-`, and ending with the behavior's name, using dashes to separate multiple words. For example, the directory for the hold-tap's devicetree binding would be located at `app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml`, which is shown below as a reference: + +```yaml title="app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml" +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +// highlight-next-line +description: Hold or Tap behavior + +// highlight-next-line +compatible: "zmk,behavior-hold-tap" + +// highlight-next-line +include: two_param.yaml + +// highlight-next-line +properties: + bindings: + type: phandles + required: true + tapping-term-ms: + type: int + tapping_term_ms: # deprecated + type: int + quick-tap-ms: + type: int + default: -1 + quick_tap_ms: # deprecated + type: int + flavor: + type: string + required: false + default: "hold-preferred" + enum: + - "hold-preferred" + - "balanced" + - "tap-preferred" + - "tap-unless-interrupted" + retro-tap: + type: boolean + hold-trigger-key-positions: + type: array + required: false + default: [] +``` + +We see that the `.yaml` files used for new behaviors' devicetree bindings consist of the following properties: + +#### `description` + +A brief statement of what the behavior is. The value of this property is not seen by end-users; as such, the `description` value should be kept less than a sentence long, leaving explanations for end-users of how the behavior works for its documentation. + +#### `compatible` + +Allows ZMK to assign the correct driver to the behavior extracted from the keymap or `.dtsi`. The value of the `compatible` property is equal to the name of the [devicetree binding file](#creating-the-devicetree-binding-yaml) as a `string`. + +As shown in the example above, `compatible: "zmk,behavior-hold-tap"` is the value of the `compatible` property of `zmk,behavior-hold-tap.yaml`. + +#### `include` + +Choose between `zero_param.yaml`, `one_param.yaml`, or `two_param.yaml` depending on how many additional parameters are required to complete the behavior's binding in a keymap. For example, we `include: two_param.yaml` in `zmk,behavior-hold-tap.yaml` because any user-defined or pre-defined instances of the hold-tap behavior take in two cells as inputs: one for the hold behavior and one for the tap behavior. + +#### `properties` (Optional) + +These are additional variables required to configure a particular instance of a behavior. `properties` can be of the following types: + +- `path` +- `compound` +- `array` +- `string` +- `string-array` +- `boolean` +- `int` +- `uint8-array` +- `phandle`. +- `phandle-array` +- `phandles` + +:::info +For more information on additional `properties`, refer to [Zephyr's documentation on Devicetree bindings](https://docs.zephyrproject.org/latest/build/dts/bindings.html#properties). +::: + +### Creating the driver (`.c`) + +:::info +Developing drivers for behaviors in ZMK makes extensive use of the Zephyr Devicetree API and Device Driver Model. Links to the Zephyr Project Documentation for both of these concepts can be found below: + +- [Zephyr Devicetree API](https://docs.zephyrproject.org/latest/build/dts/api/api.html) +- [Zephyr Device Driver Model](https://docs.zephyrproject.org/latest/kernel/drivers/index.html) + +::: + +Driver files are stored in `app/src/behaviors/` and are labelled in lowercase, beginning with the prefix `behavior_`, and ending with the behavior's name, using underscores to separate multiple words. For example, the directory for the hold-tap's driver would be located at `app/src/behaviors/behavior_hold_tap.c`. + +The code snippet below shows the essential components of a new driver. + +```c +#define DT_DRV_COMPAT zmk_ + +// Dependencies +#include +#include +#include + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +// Instance-Unique Data Struct (Optional) +struct behavior__data { + bool example_data_param1; + bool example_data_param2; + bool example_data_param3; +}; + +// Instance-Unique Config Struct (Optional) +struct behavior__config { + bool example_config_param1; + bool example_config_param2; + bool example_config_param3; +}; + +// Initialization Function +static int _init(const struct device *dev) { + return 0; +}; + +// API Structure +static const struct behavior_driver_api _driver_api = { + +}; + +BEHAVIOR_DT_INST_DEFINE(0, // Instance Number (Equal to 0 for behaviors that don't require multiple instances, + // Equal to n for behaviors that do make use of multiple instances) + _init, NULL, // Initialization Function, Power Management Device Pointer + &_data, &_config, // Behavior Data Pointer, Behavior Configuration Pointer (Both Optional) + APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, // Initialization Level, Device Priority + &_driver_api); // API Structure + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ + +``` + +#### `DT_DRV_COMPAT` + +Replace `zmk_` in the `#define DT_DRV_COMPAT` statement with the name of your behavior. (e.g. `zmk_behavior_caps_word`) + +#### Dependencies + +The dependencies required for any ZMK behavior are: + +- `device.h`: [Zephyr Device APIs](https://docs.zephyrproject.org/apidoc/latest/group__device__model.html) +- `drivers/behavior.h`: ZMK Behavior Functions (e.g. [`locality`](#api-structure), `behavior_keymap_binding_pressed`, `behavior_keymap_binding_released`, `behavior_sensor_keymap_binding_triggered`) +- `logging/log.h`: [Zephyr Logging APIs](https://docs.zephyrproject.org/latest/services/logging/index.html) (for more information on USB Logging in ZMK, see [USB Logging](usb-logging.md)). +- `zmk/behavior.h`: ZMK Behavior Information (e.g. parameters, position and timestamp of events) + - `return` values: + - `ZMK_BEHAVIOR_OPAQUE`: Used to terminate `on__binding_pressed` and `on__binding_released` functions that accept `(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event)` as parameters + - `ZMK_BEHAVIOR_TRANSPARENT`: Used in the `binding_pressed` and `binding_released` functions for the transparent (`&trans`) behavior + - `struct`s: + - `zmk_behavior_binding`: Stores the name of the behavior device (`char *behavior_dev`) as a `string` and up to two additional parameters (`uint32_t param1`, `uint32_t param2`) + - `zmk_behavior_binding_event`: Contains layer, position, and timestamp data for an active `zmk_behavior_binding` + +Other common dependencies include `zmk/keymap.h`, which allows behaviors to access layer information and extract behavior bindings from keymaps, and `zmk/event_manager.h` which is detailed below. + +##### ZMK Event Manager + +Including `zmk/event_manager.h` is required for the following dependencies to function properly. + +- `zmk/events/position_state_changed.h`: Position events' state (on/off), source, position, and timestamps +- `zmk/events/keycode_state_changed.h`: Keycode events' state (on/off), usage page, keycode value, modifiers, and timestamps +- `zmk/events/modifiers_state_changed.h`: Modifier events' state (on/off) and modifier value + +Events can be used similarly to hardware interrupts, through the use of [listeners](#listeners-and-subscriptions). + +###### Listeners and Subscriptions + +The condensed form of lines 192-225 of the tap-dance driver, shown below, does an excellent job of showcasing the function of listeners and subscriptions with respect to the [ZMK Event Manager](#zmk-event-manager). + +```c title="app/src/behaviors/behavior_tap_dance.c (Lines 192-197, 225)" +static int tap_dance_position_state_changed_listener(const zmk_event_t *eh); + +ZMK_LISTENER(behavior_tap_dance, tap_dance_position_state_changed_listener); +ZMK_SUBSCRIPTION(behavior_tap_dance, zmk_position_state_changed); + +static int tap_dance_position_state_changed_listener(const zmk_event_t *eh){ + // Do stuff... +} +``` + +Listeners, defined by the `ZMK_LISTENER(mod, cb)` function, take in a listener name (`mod`) and a callback function (`cb`) as their parameters. On the other hand subscriptions are defined by the `ZMK_SUBSCRIPTION(mod, ev_type)`, and determine what kind of event (`ev_type`) should invoke the callback function from the listener. In the tap-dance example, this listener executes code depending on a `zmk_position_state_changed` event, or simply, a change in key position. Other types of ZMK events can be found as the name of the `struct` inside each of the files located at `app/include/zmk/events/.h`. All control paths in a listener should `return` one of the [`ZMK_EV_EVENT_*` values](#return-values), which are shown below. + +###### `return` values: + +- `ZMK_EV_EVENT_BUBBLE`: Keep propagating the event `struct` to the next listener. +- `ZMK_EV_EVENT_HANDLED`: Stop propagating the event `struct` to the next listener. The event manager still owns the `struct`'s memory, so it will be `free`d automatically. Do **not** free the memory in this function. +- `ZMK_EV_EVENT_CAPTURED`: Stop propagating the event `struct` to the next listener. The event `struct`'s memory is now owned by your code, so the event manager will not free the event `struct` memory. Make sure your code will release or free the event at some point in the future. (Use the [`ZMK_EVENT_*` macros](#macros) described below.) + +###### Macros: + +- `ZMK_EVENT_RAISE(ev)`: Start handling this event (`ev`) with the first registered event listener. +- `ZMK_EVENT_RAISE_AFTER(ev, mod)`: Start handling this event (`ev`) after the event is captured by the named [event listener](#listeners-and-subscriptions) (`mod`). The named event listener will be skipped as well. +- `ZMK_EVENT_RAISE_AT(ev, mod)`: Start handling this event (`ev`) at the named [event listener](#listeners-and-subscriptions) (`mod`). The named event listener is the first handler to be invoked. +- `ZMK_EVENT_RELEASE(ev)`: Continue handling this event (`ev`) at the next registered event listener. +- `ZMK_EVENT_FREE(ev)`: Free the memory associated with the event (`ev`). + +#### `BEHAVIOR_DT_INST_DEFINE` + +`BEHAVIOR_DT_INST_DEFINE` is a special ZMK macro. It forwards all the parameters to Zephyr's `DEVICE_DT_INST_DEFINE` macro to define the driver instance, then it adds the driver to a list of ZMK behaviors so they can be found by `zmk_behavior_get_binding()`. + +:::info +For more information on this function, refer to [Zephyr's documentation on the Device Driver Model](https://docs.zephyrproject.org/latest/kernel/drivers/index.html#c.DEVICE_DT_INST_DEFINE). +::: + +The example `BEHAVIOR_DT_INST_DEFINE` call can be left as is with the first parameter, the instance number, equal to `0` for behaviors that only require a single instance (e.g. external power, backlighting, accessing layers). For behaviors that can have multiple instances (e.g. hold-taps, tap-dances, sticky-keys), `BEHAVIOR_DT_INST_DEFINE` can be placed inside a `#define` statement, usually formatted as `#define _INST(n)`, that sets up any [data pointers](#data-pointers-optional) and/or [configuration pointers](#configuration-pointers-optional) that are unique to each instance. + +An example of this can be seen below, taking the `#define KP_INST(n)` from the hold-tap driver. + +```c +#define KP_INST(n) \ + static struct behavior_hold_tap_config behavior_hold_tap_config_##n = { \ + .tapping_term_ms = DT_INST_PROP(n, tapping_term_ms), \ + .hold_behavior_dev = DT_PROP(DT_INST_PHANDLE_BY_IDX(n, bindings, 0), label), \ + .tap_behavior_dev = DT_PROP(DT_INST_PHANDLE_BY_IDX(n, bindings, 1), label), \ + .quick_tap_ms = DT_INST_PROP(n, quick_tap_ms), \ + .flavor = DT_ENUM_IDX(DT_DRV_INST(n), flavor), \ + .retro_tap = DT_INST_PROP(n, retro_tap), \ + .hold_trigger_key_positions = DT_INST_PROP(n, hold_trigger_key_positions), \ + .hold_trigger_key_positions_len = DT_INST_PROP_LEN(n, hold_trigger_key_positions), \ + }; \ + BEHAVIOR_DT_INST_DEFINE(n, behavior_hold_tap_init, NULL, NULL, &behavior_hold_tap_config_##n, \ + APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + &behavior_hold_tap_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KP_INST) +``` + +Note that in the hold-tap example, the instance number, `0`, has been replaced by `n`, signifying the unique `node_id` of each instance of a behavior. Furthermore, the DT_INST_FOREACH_STATUS_OKAY(KP_INST) macro iterates through each compatible, non-disabled devicetree node, creating and applying the proper values to any instance-specific configurations or data by invoking the KP_INST macro for each instance of the new behavior. + +Behaviors also require the following parameters of `BEHAVIOR_DT_INST_DEFINE` to be changed: + +##### Initialization Function + +Comes in the form `static int _init(const struct device *dev)`. Initialization functions preconfigure any data, like resetting timers and position for hold-taps and tap-dances. All initialization functions `return 0;` once complete. + +##### API Structure + +Comes in the form `static const struct behavior_driver_api _driver_api)`. Common items to include in the API Structure are: + +- `.binding_pressed`: Used for behaviors that invoke an action on its keybind press. Set `.binding_pressed` equal to the function typically named [`on__binding_pressed`](#dependencies). +- `.binding_released`: Same as above, except for activating on keybind release events. Set `.binding_released` equal to the function typically named [`on__binding_released`](#dependencies). +- `.locality`: Defined in ``. Describes how the behavior affects parts of a _split_ keyboard. + - `BEHAVIOR_LOCALITY_CENTRAL`: Behavior only affects the central half, which is the case for most keymap-related behavior. + - `BEHAVIOR_LOCALITY_EVENT_SOURCE`: Behavior affects only the central _or_ peripheral half depending on which side invoked the behavior binding, such as [reset behaviors](../behaviors/reset.md). + - `BEHAVIOR_LOCALITY_GLOBAL`: Behavior affects the entire keyboard, such as [external power](../behaviors/power.md) and lighting-related behaviors that need to be synchronized across halves. + :::note + For unibody keyboards, all locality values perform the same as `BEHAVIOR_LOCALITY_GLOBAL`. + ::: + +##### Data Pointers (Optional) + +The data `struct` stores additional data required for **each new instance** of the behavior. Regardless of the instance number, `n`, `behavior__data_##n` is typically initialized as an empty `struct`. The data respective to each instance of the behavior can be accessed in functions like [`on__binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event)`](#dependencies) by extracting the behavior device from the keybind like so: + +```c +const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); +struct behavior__data *data = dev->data; +``` + +The variables stored inside the data `struct`, `data`, can be then modified as necessary. + +The fourth cell of `BEHAVIOR_DT_INST_DEFINE` can be set to `NULL` instead if instance-specific data is not required. + +##### Configuration Pointers (Optional) + +The configuration `struct` stores the properties declared from the behavior's `.yaml` for **each new instance** of the behavior. As seen in the `#define KP_INST(n)` of the hold-tap example, the configuration `struct`, `behavior__config_##n`, for each instance number, `n`, can be initialized using the [Zephyr Devicetree Instance-based APIs](https://docs.zephyrproject.org/latest/build/dts/api/api.html#instance-based-apis), which extract the values from the `properties` of each instance of the [devicetree binding](#creating-the-devicetree-binding-yaml) from a user's keymap or [predefined use-case `.dtsi` files](#defining-common-use-cases-for-the-behavior-dtsi-optional) stored in `app/dts/behaviors/`. We illustrate this further by comparing the [`#define KP_INST(n)` from the hold-tap driver](#behavior_dt_inst_define) and the [`properties` of the hold-tap devicetree binding.](#creating-the-devicetree-binding-yaml) + +The fifth cell of `BEHAVIOR_DT_INST_DEFINE` can be set to `NULL` instead if instance-specific configurations are not required. + +:::caution +Remember that `.c` files should be formatted according to `clang-format` to ensure that checks run smoothly once the pull request is submitted. +::: + +### Updating `app/CmakeLists.txt` to include the new driver + +Most behavior drivers' are invoked according to the central half's [locality](#api-structure), and are therefore stored after the line `if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)` in the form, `target_sources(app PRIVATE src/behaviors/.c)`, as shown below. + +```txt title="app/CmakeLists.txt" +if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL) + target_sources(app PRIVATE src/behaviors/behavior_key_press.c) + target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c) + target_sources(app PRIVATE src/behaviors/behavior_sticky_key.c) + target_sources(app PRIVATE src/behaviors/behavior_caps_word.c) + target_sources(app PRIVATE src/behaviors/behavior_key_repeat.c) + target_sources(app PRIVATE src/behaviors/behavior_momentary_layer.c) + target_sources(app PRIVATE src/behaviors/behavior_mod_morph.c) + target_sources(app PRIVATE src/behaviors/behavior_outputs.c) + target_sources(app PRIVATE src/behaviors/behavior_tap_dance.c) + target_sources(app PRIVATE src/behaviors/behavior_toggle_layer.c) + target_sources(app PRIVATE src/behaviors/behavior_to_layer.c) + target_sources(app PRIVATE src/behaviors/behavior_transparent.c) + target_sources(app PRIVATE src/behaviors/behavior_none.c) + target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c) + target_sources(app PRIVATE src/combo.c) + target_sources(app PRIVATE src/conditional_layer.c) + target_sources(app PRIVATE src/keymap.c) +endif() +``` + +For behaviors that do not require central locality, the following options for updating `app/CmakeLists.txt` also exist: + +- Behavior applies to unibody, or central or peripheral half of keyboard: place `target_sources(app PRIVATE .c)` line _before_ `if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)` +- Behavior applies to _only_ central half of split keyboard: place `target_sources(app PRIVATE .c)` after `if (CONFIG_ZMK_SPLIT AND CONFIG_ZMK_SPLIT_ROLE_CENTRAL)` +- Behavior applies to _only_ peripheral half of split keyboard: place `target_sources(app PRIVATE .c)` after `if (CONFIG_ZMK_SPLIT AND (NOT CONFIG_ZMK_SPLIT_ROLE_CENTRAL))` +- Behavior requires certain condition in a keyboard's `.conf` file to be met: use `target_sources_ifdef(CONFIG_ app PRIVATE .c)` instead of `target_sources(.c)` + +### Defining common use-cases for the behavior (`.dtsi`) (Optional) + +`.dtsi` files, found in the directory `app/dts/behaviors/`, are only necessary for behaviors with more common use-cases. A common example is the mod-tap (`&mt`), which is a predefined type of hold-tap that takes a modifier key as the hold parameter and another key as the tap parameter. + +For the purpose of this section, we will discuss the structure of `app/dts/behaviors/gresc.dtsi` below. + +```dts title="app/dts/behaviors/gresc.dtsi" +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + behaviors { + /omit-if-no-ref/ gresc: grave_escape { + compatible = "zmk,behavior-mod-morph"; + #binding-cells = <0>; + bindings = <&kp ESC>, <&kp GRAVE>; + mods = <(MOD_LGUI|MOD_LSFT|MOD_RGUI|MOD_RSFT)>; + }; + }; +}; +``` + +The format of a behavior's `.dtsi` file is identical to declaring an instance of the behavior in a user's keymap. The only major difference is that the value `/omit-if-no-ref/` should be placed adjacent to the label and name of the behavior, as seen in line 11 of the `gresc` example. + +:::caution + +If your behavior has its [`locality`](#api-structure) property set to anything other than `BEHAVIOR_LOCALITY_CENTRAL`, then the name of the node must be at most 8 characters long, or it will fail to be invoked on the peripheral half of a split keyboard. + +In the above example, `grave_escape` is too long, so it would need to be shortened, e.g. + +```dts +// Behavior can be invoked on peripherals, so name must be <= 8 characters. +/omit-if-no-ref/ gresc: gresc { ... }; +``` + +::: + +After creating the `.dtsi` from above, update `app/dts/behaviors.dtsi` to include your newly predefined behavior instance, making it accessible by the devicetree. + +```dts title="app/dts/behaviors.dtsi" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// highlight-next-line +#include +``` + +## Testing changes locally + +Create a new folder in `app/tests/` to develop virtual test sets for all common use cases of the behavior. Behaviors should be tested thoroughly on both virtual testing environments using `west test` and real hardware. + +:::note +Zephyr currently does not support logging over Bluetooth, so any use of the serial monitor for hardware testing must be done over hardware UART or USB virtual UART. +::: + +:::info + +- See [Tests](tests.md) for more information on how to create virtual test sets. +- For hardware-based testing, see [USB Logging](usb-logging.md). + +::: + +## Documenting behavior functionality + +Consider the following prompts when writing documentation for new behaviors: + +- What does it do? Describe some general use-cases for the behavior. +- Which properties included in the [devicetree binding](#creating-the-devicetree-binding-yaml) should be configured manually by the user? What do they do, and if applicable, what are their default values? +- What does an example implementation in a keymap look like? Include a code-snippet of the example implementation in the keymap file's `behaviors` node. + - Are there any [common use-cases of the behavior](#defining-common-use-cases-for-the-behavior-dtsi-optional)? Consider making a separate documentation page for these predefined variations, like how the [mod-tap](../behaviors/mod-tap.md) has a separate page from the [hold-tap](../behaviors/hold-tap.md). +- How does the behavior perform in edge cases? For example, tap-dances invoke the last binding in its list of `bindings` once the maximum number of keypresses has been reached. + +Consider also including visual aids alongside written documentation if it adds clarity. + +:::info +See [Documentation](documentation.md) for more information on writing, testing, and formatting ZMK documentation. +::: + +## Submitting a pull request + +Once the above sections are complete, the behavior is almost ready to submit as a pull request. New [devicetree bindings](#creating-the-devicetree-binding-yaml), new [drivers](#creating-the-driver-c), and [predefined use-cases](#defining-common-use-cases-for-the-behavior-dtsi-optional) of the new behavior must contain the appropriate copyright headers, which can be copied and pasted from the tabs below. + + + + +```yaml +// highlight-next-line +# Copyright (c) XXXX The ZMK Contributors +# SPDX-License-Identifier: MIT +``` + + + + +```c +/* +// highlight-next-line + * Copyright (c) XXXX The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ +``` + + + + +:::caution +Remember to change the copyright year (`XXXX`) to the current year when adding the copyright headers to your newly created files. +::: + +While you wait for your PR to become approved and merged into the main repository, please stay up to date for any code reviews and check in with users testing your new behavior. For more detailed information on contributing to ZMK, it is recommended to thoroughly review the [documentation for contributors](https://github.com/zmkfirmware/zmk/blob/main/CONTRIBUTING.md). diff --git a/docs/docs/development/new-shield.md b/docs/docs/development/new-shield.md new file mode 100644 index 000000000000..dd63fa9b8806 --- /dev/null +++ b/docs/docs/development/new-shield.md @@ -0,0 +1,589 @@ +--- +title: New Keyboard Shield +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import KeymapExampleFile from '../keymap-example-file.md'; + +import InterconnectTabs from "@site/src/components/interconnect-tabs"; +import Metadata from "@site/src/data/hardware-metadata.json"; + +## Overview + +This guide will walk through the steps necessary to add ZMK support for a keyboard that uses an add-on MCU board (e.g. Pro Micro compatible) to provide the microprocessor. + +The high level steps are: + +- From a template, create a new [Zephyr module](https://docs.zephyrproject.org/3.2.0/develop/modules.html) housed in a git repository containing one or more custom shields. +- Create a new shield directory. +- Add the base Kconfig files. +- Add the shield overlay file to define the KSCAN driver for detecting key press/release. +- (Optional) Add the matrix transform for mapping KSCAN row/column values to sane key positions. This is needed for non-rectangular keyboards, or where the underlying row/column pin arrangement does not map one to one with logical locations on the keyboard. +- Add a default keymap, which users can override in their own configs as needed. +- Add a `.zmk.yml` metadata file to document the high level details of your shield, and the features it supports. +- Update the `build.yaml` file from the repository template to have some sample builds of the firmware to test. +- Add support for features such as encoders, OLED displays, or RGB underglow. + +It may be helpful to review the upstream [shields documentation](https://docs.zephyrproject.org/3.2.0/guides/porting/shields.html#shields) to get a proper understanding of the underlying system before continuing. + +:::note +ZMK support for split keyboards requires a few more files than single boards to ensure proper connectivity between the central and peripheral units. Check the following guides thoroughly to ensure that all the files are in place. +::: + +## New Zephyr Module Repository + +The first step to creating the shield is to create a new Zephyr module repository from a template. + +:::note +This guide assumes you already have a configured GitHub account. If you don't yet have one, go ahead and [sign up](https://github.com/join) before continuing. +::: + +Follow these steps to create your new repository: + +- Visit https://github.com/zmkfirmware/unified-zmk-config-template +- Click the green "Use this template" button +- In the drop down that opens, click "Use this template". +- In the following screen, provide the following information: + - A repository name, e.g. `my-shield-module`. + - A brief description, e.g. `ZMK Support For MyShield Keyboard`. + - Select Public or Private, depending on your preference. +- Click the green "Create repository" button + +## New Shield Directory + +:::note +This guide describes how to add a shield to an independently managed Zephyr module repository. This is the +preferred way to handle boards and shields moving forward in ZMK, although the tooling to make this easier +for users is still improving. ZMK does have a collection of boards/shields in the ZMK main repository, which are planned to be phased out, but until that is complete, there _may_ be a few select scenarios where adding your keyboard to ZMK itself is preferred. Due the volume of PRs and the focus of ZMK development not being merging of keyboard PRs, you are highly encouraged to use an out-of-tree Zephyr module repository to manage your definitions. Should you choose to try to get your keyboard included in ZMK main repository, the paths in the rest of the guide would be nested under the `app/` folder there instead. For example, `boards/shields/` should now be +`app/boards/shields/`. +::: + +Shields in Zephyr module "board root" go into the `boards/shields/` directory; that means the new shield directory in your module repository should be: + +```bash +mkdir boards/shields/ +``` + +## Base Kconfig Files + +There are two required Kconfig files that need to be created for your new keyboard +shield to get it picked up for ZMK, `Kconfig.shield` and `Kconfig.defconfig`. + +### Kconfig.shield + +The `Kconfig.shield` file defines any additional Kconfig settings that may be relevant when using this keyboard. For most keyboards, there is just one additional configuration value for the shield itself. + +```kconfig +config SHIELD_MY_BOARD + def_bool $(shields_list_contains,my_board) +``` + +This will make sure that a new configuration value named `SHIELD_MY_BOARD` is set to true whenever `my_board` is used as the shield name, either as the `SHIELD` variable [in a local build](build-flash.md) or in your `build.yaml` file [when using Github Actions](../customization). Note that this configuration value will be used in `Kconfig.defconfig` to set other properties about your shield, so make sure that they match. + +**For split boards**, you will need to add configurations for the left and right sides. For example, if your split halves are named `my_board_left` and `my_board_right`, it would look like this: + +```kconfig +config SHIELD_MY_BOARD_LEFT + def_bool $(shields_list_contains,my_board_left) + +config SHIELD_MY_BOARD_RIGHT + def_bool $(shields_list_contains,my_board_right) +``` + +### Kconfig.defconfig + +The `Kconfig.defconfig` file is where overrides for various configuration settings +that make sense to have different defaults when this shield is used. One main item +that usually has a new default value set here is the `ZMK_KEYBOARD_NAME` value, +which controls the display name of the device over USB and BLE. + +The updated new default values should always be wrapped inside a conditional on the shield config name defined in the `Kconfig.shield` file. Here's the simplest example file. + +:::warning +The keyboard name must be less than or equal to 16 characters in length, otherwise the bluetooth advertising might fail and you will not be able to find your keyboard from your device. +::: + +```kconfig +if SHIELD_MY_BOARD + +config ZMK_KEYBOARD_NAME + default "My Board" + +endif +``` + +For split keyboards, `Kconfig.defconfig` needs to specify a few more options. +Which side is central (usually the left) is determined via the configuration in this file. +For that side, the keyboard name is assigned and the central config is set. +The peripheral side is typically not assigned a name since only the central will be advertising for connections to other devices. +Finally, the split config needs to be set for both sides: + +```kconfig +if SHIELD_MY_BOARD_LEFT + +config ZMK_KEYBOARD_NAME + default "My Board" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_MY_BOARD_LEFT || SHIELD_MY_BOARD_RIGHT + +config ZMK_SPLIT + default y + +endif +``` + +## Shield Overlays + + + +To use GPIO pins that are not part of the interconnects as described above, you can use the GPIO labels that are specific to each controller type. +For instance, pins numbered `PX.Y` in nRF52840-based boards can be referred to via `&gpioX Y` labels. +An example is `&gpio1 7` for the `P1.07` pin that the nice!nano exposes in the middle of the board. + + + + + +The `.overlay` is the devicetree description of the keyboard shield that is merged with the primary board devicetree description before the build. For ZMK, this file at a minimum should include the chosen node named `zmk,kscan` that references a KSCAN driver instance. For a simple 3x3 macropad matrix, +this might look something like: + +```dts +/ { + chosen { + zmk,kscan = &kscan0; + }; + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + + col-gpios + = <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; +``` + +See the [Keyboard Scan configuration documentation](../config/kscan.md) for details on configuring the KSCAN driver. + + + + + +### .dtsi files and Shield Overlays (Split Shields) + +Unlike unibody keyboards, split keyboards have a core .dtsi file with shield overlays for each half of the keyboard. +It is preferred to define only the `col-gpios` or `row-gpios` in the common shield .dtsi, depending on the `diode-direction` value. +For `col2row` directed boards like the iris, the shared .dtsi file may look like this: + +```dts +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <16>; + rows = <4>; +// | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | +// | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | +// | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | +// | SW24 | SW23 | SW22 | SW21 | SW20 | SW19 | SW25 | | SW25 | SW19 | SW20 | SW21 | SW22 | SW23 | SW24 | +// | SW29 | SW28 | SW27 | SW26 | | SW26 | SW27 | SW28 | SW29 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,2) RC(4,9) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) + RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // Row A from the schematic file + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // Row B from the schematic file + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // Row C from the schematic file + , <&pro_micro 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // Row D from the schematic file + , <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // Row E from the schematic file + ; + + }; +}; +``` + +:::note +Notice that in addition to the common `row-gpios` that are declared in the kscan, the [matrix transform](#optional-matrix-transform) is defined in the .dtsi. +::: + +The missing `col-gpios` would be defined in your `_left.overlay` and `_right.overlay` files. +Keep in mind that the mirrored position of the GPIOs means that the `col-gpios` will appear reversed when the .overlay files are compared to one another. +Furthermore, the column offset for the [matrix transform](#optional-matrix-transform) should be added to the right half of the keyboard's overlay +because the keyboard's switch matrix is read from left to right, top to bottom. +This is exemplified with the iris .overlay files. + +```dts title=iris_left.overlay +#include "iris.dtsi" // Notice that the main dtsi files are included in the overlay. + +&kscan0 { + col-gpios + = <&pro_micro 19 GPIO_ACTIVE_HIGH> // col1 in the schematic + , <&pro_micro 18 GPIO_ACTIVE_HIGH> // col2 in the schematic + , <&pro_micro 15 GPIO_ACTIVE_HIGH> // col3 in the schematic + , <&pro_micro 14 GPIO_ACTIVE_HIGH> // col4 in the schematic + , <&pro_micro 16 GPIO_ACTIVE_HIGH> // col5 in the schematic + , <&pro_micro 10 GPIO_ACTIVE_HIGH> // col6 in the schematic + ; +}; +``` + +```dts title=iris_right.overlay +#include "iris.dtsi" + +&default_transform { // The matrix transform for this board is 6 columns over because the left half is 6 columns wide according to the matrix. + col-offset = <6>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 10 GPIO_ACTIVE_HIGH> // col6 in the schematic + , <&pro_micro 16 GPIO_ACTIVE_HIGH> // col5 in the schematic + , <&pro_micro 14 GPIO_ACTIVE_HIGH> // col4 in the schematic + , <&pro_micro 15 GPIO_ACTIVE_HIGH> // col3 in the schematic + , <&pro_micro 18 GPIO_ACTIVE_HIGH> // col2 in the schematic + , <&pro_micro 19 GPIO_ACTIVE_HIGH> // col1 in the schematic + ; +}; + +``` + +See the [Keyboard Scan configuration documentation](../config/kscan.md) for details on configuring the KSCAN driver. + +### .conf files (Split Shields) + +While unibody boards only have one .conf file that applies configuration characteristics to the entire keyboard, +split keyboards are unique in that they contain multiple .conf files with different scopes. +For example, a split board called `my_awesome_split_board` would have the following files: + +- `my_awesome_split_board.conf` - Configuration elements affect both halves +- `my_awesome_split_board_left.conf` - Configuration elements only affect left half +- `my_awesome_split_board_right.conf` - Configuration elements only affect right half + +In most case you'll only need to use the .conf file that affects both halves of a split board. It's used for adding features like deep-sleep or rotary encoders. + +```ini title=my_awesome_split_board.conf +CONFIG_ZMK_SLEEP=y +``` + +:::note +The shared configuration in `my_awesome_split_board.conf` is only applied when you are building with a [`zmk-config` folder](build-flash#building-from-zmk-config-folder) and when it is present at `config/my_awesome_split_board.conf`. If you are not using a `zmk-config` folder, you will need to include the shared configuration in both `my_awesome_split_board_left.conf` and `my_awesome_split_board_right.conf` files. +::: + + + + +## (Optional) Matrix Transform + +Internally ZMK translates all row/column events into "key position" events to maintain a consistent model that works no matter what any possible GPIO matrix may look like for a certain keyboard. This is particularly helpful when: + +1. To reduce the used pins, an "efficient" number of rows/columns for the GPIO matrix is used, that does _not_ match the physical layout of rows/columns of the actual key switches. +1. For non rectangular keyboards with thumb clusters, non `1u` locations, etc. + +A "key position" is the numeric index (zero-based) of a given key, which identifies +the logical key location as perceived by the end user. All _keymap_ mappings actually bind behaviors to _key positions_, not to row/column values. + +_Without_ a matrix transform, that intentionally map each key position to the row/column pair that position corresponds to, the default equation to determine that is: + +```c +($row * NUMBER_OF_COLUMNS) + $column +``` + +Which effectively amounts to numbering the key positions by traversing each row from top to bottom and assigning numerically incrementing key positions. + +Whenever that default key position mapping is insufficient, the `.overlay` file should _also_ include a matrix transform. + +Here is an example for the [nice60](https://github.com/Nicell/nice60), which uses an efficient 8x8 GPIO matrix, and uses a transform: + +```dts +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <8>; + rows = <8>; +// | MX1 | MX2 | MX3 | MX4 | MX5 | MX6 | MX7 | MX8 | MX9 | MX10 | MX11 | MX12 | MX13 | MX14 | +// | MX15 | MX16 | MX17 | MX18 | MX19 | MX20 | MX21 | MX22 | MX23 | MX34 | MX25 | MX26 | MX27 | MX28 | +// | MX29 | MX30 | MX31 | MX32 | MX33 | MX34 | MX35 | MX36 | MX37 | MX38 | MX39 | MX40 | MX41 | +// | MX42 | MX43 | MX44 | MX45 | MX46 | MX47 | MX48 | MX49 | MX50 | MX51 | MX52 | MX53 | +// | MX54 | MX55 | MX56 | MX57 | MX58 | MX59 | MX60 | MX61 | + map = < +RC(3,0) RC(2,0) RC(1,0) RC(0,0) RC(1,1) RC(0,1) RC(0,2) RC(1,3) RC(0,3) RC(1,4) RC(0,4) RC(0,5) RC(1,6) RC(1,7) +RC(4,0) RC(4,1) RC(3,1) RC(2,1) RC(2,2) RC(1,2) RC(2,3) RC(3,4) RC(2,4) RC(2,5) RC(1,5) RC(2,6) RC(2,7) RC(3,7) +RC(5,0) RC(5,1) RC(5,2) RC(4,2) RC(3,2) RC(4,3) RC(3,3) RC(4,4) RC(4,5) RC(3,5) RC(4,6) RC(3,6) RC(4,7) +RC(6,0) RC(6,1) RC(6,2) RC(6,3) RC(5,3) RC(6,4) RC(5,4) RC(6,5) RC(5,5) RC(6,6) RC(5,6) RC(5,7) +RC(7,0) RC(7,1) RC(7,2) RC(7,3) RC(7,5) RC(7,6) RC(6,7) RC(7,7) + >; + }; +``` + +Some important things to note: + +- The `#include ` is critical. The `RC` macro is used to generate the internal storage in the matrix transform, and is actually replaced by a C preprocessor before the final devicetree is compiled into ZMK. +- `RC(row, column)` is placed sequentially to define what row and column values that position corresponds to. +- If you have a keyboard with options for `2u` keys in certain positions, or break away portions, it is a good idea to set the chosen `zmk,matrix_transform` to the default arrangement, and include _other_ possible matrix transform nodes in the devicetree that users can select in their user config by overriding the chosen node. + +See the [matrix transform section](../config/kscan.md#matrix-transform) in the Keyboard Scan configuration documentation for details and more examples of matrix transforms. + +## Default Keymap + +Each keyboard should provide a default keymap to be used when building the firmware, which can be overridden and customized by user configs. For "shield keyboards", this should be placed in the `boards/shields//.keymap` file. The keymap is configured as an additional devicetree overlay that includes the following: + +- A node with `compatible = "zmk,keymap"` where each child node is a layer with a `bindings` array that binds each key position to a given behavior (e.g. key press, momentary layer, etc). + +Here is an example simple keymap for the Kyria, with only one layer: + + + +:::note +The two `#include` lines at the top of the keymap are required in order to bring in the default set of behaviors to make them available to bind, and to import a set of defines for the key codes, so keymaps can use parameters like `N2` or `K` instead of the raw keycode numeric values. +::: + +### Keymap Behaviors + +For the full documentation on the available behaviors for use in keymaps, start with reviewing [`kp`](../behaviors/key-press.md) and then use the sidebar to review the others available within ZMK. + +## Metadata + +ZMK makes use of an additional metadata YAML file for all boards and shields to provide high level information about the hardware to be incorporated into setup scripts/utilities, website hardware list, etc. + +The naming convention for metadata files is `{item_id}.zmk.yml`, where the `item_id` is the board/shield identifier, including version information but excluding any optional split `_left`/`_right` suffix, e.g. `corne.zmk.yml` or `nrfmicro_11.zmk.yml`. + +Here is a sample `corne.zmk.yml` file from the repository: + +```yaml +file_format: "1" +id: corne +name: Corne +type: shield +url: https://github.com/foostan/crkbd/ +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display +siblings: + - corne_left + - corne_right +``` + +You should place a properly named `foo.zmk.yml` file in the directory next to your other shield values, and fill it out completely and accurately. See [Hardware Metadata Files](/docs/development/hardware-metadata-files) for the full details. + +## Build File + +To help you test/verify your firmware, update the `build.yaml` to list your particular board/shield combinations you want built whenever changes are published to GitHub. Open `build.yaml` with your editor and add a combination, e.g.: + +```yaml +# This file generates the GitHub Actions matrix +# For simple board + shield combinations, add them +# to the top level board and shield arrays, for more +# control, add individual board + shield combinations to +# the `include` property, e.g: +# +# board: [ "nice_nano_v2" ] +# shield: [ "corne_left", "corne_right" ] +# include: +# - board: bdn9_rev2 +# - board: nice_nano_v2 +# shield: reviung41 +# +--- +include: + - board: nice_nano_v2 + shield: +``` + +For split keyboards, you will need to specify the halves/siblings separately, e.g.: + +```yaml +include: + - board: mikoto_520 + shield: _left + - board: mikoto_520 + shield: _right +``` + +## Adding Features + +### Encoders + +EC11 encoder support can be added to your board or shield by adding the appropriate lines to your board/shield's configuration (.conf), device tree (.dtsi), overlay (.overlay), and keymap (.keymap) files. + + + + +In your configuration file you will need to add the following lines so that the encoders can be enabled/disabled: + +```ini +# Uncomment to enable encoder +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y +``` + +These should be commented by default for encoders that are optional/can be swapped with switches, but can be uncommented if encoders are part of the default design. + +:::note +If building locally for split boards, you may need to add these lines to the specific half's configuration file as well as the combined configuration file. +::: + + + +In your device tree file you will need to add the following lines to define the encoder sensor: + +```dts + left_encoder: encoder_left { + compatible = "alps,ec11"; + a-gpios = ; + b-gpios = ; + steps = <80>; + status = "disabled"; + }; +``` + +Here you need to replace `PIN_A` and `PIN_B` with the appropriate pins that your PCB utilizes for the encoder(s). See [shield overlays section above](#shield-overlays) on the appropriate node label and pin number to use for GPIOs. + +The `steps` property should corresponded to the documented pulses per rotation for the encoders used on the keyboard, typically found on the datasheet of the component. If users use different encoders when they build, the value can be overridden in their keymap. + +Add additional encoders as necessary by duplicating the above lines, replacing `left` with whatever you would like to call your encoder, and updating the pins. Note that support for peripheral (right) side sensors over BLE is still in progress. + +Once you have defined the encoder sensors, you will have to add them to the list of sensors: + +```dts + sensors: sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + triggers-per-rotation = <20>; + }; +``` + +In this example, a left_encoder and right_encoder are both added. Additional encoders can be added with spaces separating each, and the order they are added here determines the order in which you define their behavior in your keymap. + +In addition, a default value for the number of times the sensors trigger the bound behavior per full rotation is set via the `triggers-per-rotation` property. See [Encoders Config](../config/encoders.md#devicetree) for more details. + + + +Add the following lines to your overlay file(s) to enable the encoder: + +```dts +&left_encoder { + status = "okay"; +}; +``` + +:::note +For split keyboards, make sure to add left hand encoders to the left .overlay file and right hand encoders to the right .overlay file. +::: + + + +Add the following line to your keymap file to add default encoder behavior bindings: + +```dts +sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; +``` + +Add additional bindings as necessary to match the default number of encoders on your board. See the [Encoders](../features/encoders.md) and [Keymap](../features/keymaps.md) feature documentation for more details. + + + + +## Testing + +### GitHub Actions + +Using GitHub Actions to build your new firmware can save you from doing any local [development setup](./setup.md), +at the expense of a longer feedback loop if there are issues. To push your changes and trigger a build: + +- Add all your pending changes with `git add .` +- Commit your changes with `git commit -m "Initial shield"` +- Push the changes to GitHub with `git push` + +Once pushed, click on the "Actions" tab of the repo you created in the first step, and you should see a new build running. If the build is successful, there will be a new `firmware.zip` artifact shown on the summary screen you can download that will contain the new `.uf2` files that can be flashed to the device. + +### Local Build + +:::note +To build locally, be sure you've followed the [development setup](./setup.md) guide first. +::: + +Once you've fully created the new keyboard shield definition, +you should be able to test with a build command like: + +```sh +west build --pristine -b nice_nano_v2 -- -DSHIELD= -DZMK_EXTRA_MODULES=/full/path/to/your/module +# replace with e.g. _left for split keyboards, then repeat for _right +``` + +The above build command generates a `build/zephyr/zmk.uf2` file that you can flash using the steps from the following section. See the dedicated [building and flashing page](build-flash.md) for more details. + +### Flashing + +If your board +supports USB Flashing Format (UF2), copy that file onto the root of the USB mass +storage device for your board. The controller should flash your built firmware +and automatically restart once flashing is complete. If you need to flash an updated +UF2 file with fixes, you can re-enter the bootloader by double tapping the reset button. + +Alternatively, if your board supports flashing and you're not developing from +within a Dockerized environment, enable Device Firmware Upgrade (DFU) mode on +your board and run the following command to test your build: + +```sh +west flash +``` + +Please have a look at documentation specific to +[building and flashing](build-flash.md) for additional information. + +:::note +Further testing your keyboard shield without altering the root keymap file can be done with the use of `-DZMK_CONFIG` in your `west build` command, +shown [here](build-flash.md#building-from-zmk-config-folder) +::: diff --git a/docs/docs/development/posix-board.md b/docs/docs/development/posix-board.md new file mode 100644 index 000000000000..5a809c02cca0 --- /dev/null +++ b/docs/docs/development/posix-board.md @@ -0,0 +1,38 @@ +--- +title: Native Posix board target +--- + +In order to iterate quickly on firmware features, it can +be helpful to build and run the firmware on your local +workstation, with generated virtual press/release events +flowing into the handler functions. + +## Prerequisites + +In order to build targeting the `native_posix` board, you need to setup your system +with a compiler that can target 32-bit POSIX. + +On Debian, you can do this with: + +```sh +apt install -y gcc-multilib +``` + +## Building + +To do this, you can build ZMK targeting the +`native_posix_64` board. + +```sh +west build --pristine --board native_posix_64 -- -DZMK_CONFIG=tests/none/normal/ +``` + +Once built, you can run the firmware locally: + +``` +./build/zephyr/zmk.exe +``` + +## Virtual Key Events + +The virtual key presses are hardcoded in `boards/native_posix_64.overlay` file, should you want to change the sequence to test various actions like Mod-Tap, etc. diff --git a/docs/docs/development/pre-commit.md b/docs/docs/development/pre-commit.md new file mode 100644 index 000000000000..b4306fc95217 --- /dev/null +++ b/docs/docs/development/pre-commit.md @@ -0,0 +1,37 @@ +--- +title: Pre-commit +--- + +ZMK uses [pre-commit](https://pre-commit.com/) to check for common errors and make sure the codebase is formatted consistently. + +Pre-commit is run on every pull request. You can also install it locally to get the same checks run on every commit you make _before_ you submit a pull request. + +## Installing pre-commit + +Open a terminal and run: + +```bash +pip3 install pre-commit +``` + +If this doesn't work, make sure [Python](https://www.python.org/) is installed and try again. + +## Enabling Commit Hooks + +Now that pre-commit is installed on your PC, you need to install it into the ZMK repo to enable it. Open a terminal to the ZMK repo directory and run: + +```bash +pre-commit install +``` + +This should print a message such as + +``` +pre-commit installed at .git\hooks\pre-commit +``` + +Pre-commit will now automatically check your changes whenever you run `git commit`. If it detects a problem, it will describe the problem and cancel the commit. For simple problems such as incorrect formatting, it will also automatically fix the files so you can just `git add` them and try again. + +## Automatically Enabling pre-commit + +Pre-commit can be configured to automatically install itself into any newly cloned repository, so you don't have to remember to run `pre-commit install`. See the [pre-commit documentation](https://pre-commit.com/#automatically-enabling-pre-commit-on-repositories) for instructions. diff --git a/docs/docs/development/setup.md b/docs/docs/development/setup.md new file mode 100644 index 000000000000..8ce5ffdee9a9 --- /dev/null +++ b/docs/docs/development/setup.md @@ -0,0 +1,317 @@ +--- +title: Toolchain Setup +sidebar_label: Toolchain Setup +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +export const OsTabs = (props) => ({props.children}); + +This guide will show you how to set up a development environment for building ZMK locally. + +## Install Dependencies + +Click the operating system you are using. (The VS Code & Docker option can be used on any OS.) + + + + +This option use the same [Docker image which is used by the GitHub action](https://github.com/zmkfirmware/zmk-docker) for local development. Beyond the benefits of [dev/prod parity](https://12factor.net/dev-prod-parity), this approach is also the easiest to set up. No toolchain or dependencies are necessary when using Docker; the container image you'll be using already has the toolchain installed and set up to use. + +1. Install [Docker Desktop](https://www.docker.com/products/docker-desktop) for your operating system. +2. Install [Visual Studio Code](https://code.visualstudio.com/) +3. Install the [Remote - Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) + +:::info +The docker container already includes `west`. Skip past the following section to [Get Source Code](#get-source-code). +::: + + + + +Open Zephyr's [Getting Started Guide](https://docs.zephyrproject.org/3.2.0/develop/getting_started/index.html) and follow the instructions under these sections: + +- [Select and Update OS](https://docs.zephyrproject.org/3.2.0/develop/getting_started/index.html#select-and-update-os) +- [Install Dependencies](https://docs.zephyrproject.org/3.2.0/develop/getting_started/index.html#install-dependencies) +- [Install Zephyr SDK](https://docs.zephyrproject.org/3.2.0/develop/getting_started/index.html#install-zephyr-sdk) + +Return to this guide once you are finished with each section. + + + + +Open Zephyr's [Getting Started Guide](https://docs.zephyrproject.org/3.2.0/develop/getting_started/index.html) and follow the instructions under these sections: + +- [Select and Update OS](https://docs.zephyrproject.org/3.2.0/develop/getting_started/index.html#select-and-update-os) +- [Install Dependencies](https://docs.zephyrproject.org/3.2.0/develop/getting_started/index.html#install-dependencies) +- [Install Zephyr SDK](https://docs.zephyrproject.org/3.2.0/develop/getting_started/index.html#install-zephyr-sdk) + +Return to this guide once you are finished with each section. + +`dfu-util` is required to flash devices that use DFU, but there is currently no maintained package for it on Chocolatey. [QMK Toolbox](https://github.com/qmk/qmk_toolbox) contains a working version of it though. + + + + +Open Zephyr's [Getting Started Guide](https://docs.zephyrproject.org/3.2.0/develop/getting_started/index.html) and follow the instructions under these sections: + +- [Select and Update OS](https://docs.zephyrproject.org/3.2.0/develop/getting_started/index.html#select-and-update-os) +- [Install Dependencies](https://docs.zephyrproject.org/3.2.0/develop/getting_started/index.html#install-dependencies) +- [Install Zephyr SDK](https://docs.zephyrproject.org/3.2.0/develop/getting_started/index.html#install-zephyr-sdk) + +Return to this guide once you are finished with each section. + + + + +#### Install Base Dependencies + +Open Zephyr's [Getting Started Guide](https://docs.zephyrproject.org/3.2.0/develop/getting_started/index.html) and follow the instructions for Ubuntu under these sections: + +- [Select and Update OS](https://docs.zephyrproject.org/3.2.0/develop/getting_started/index.html#select-and-update-os) +- [Install Dependencies](https://docs.zephyrproject.org/3.2.0/develop/getting_started/index.html#install-dependencies) + +Return to this guide once you are finished with each section. + +#### Install Cross-Compile Toolchain + +Because Raspberry OS runs on the same architecture (but different ABI) as ARM keyboard MCUs, the operating system's installed [cross compilers](https://docs.zephyrproject.org/3.2.0/develop/toolchains/other_x_compilers.html) can be used to target the different ABI. Building for non-ARM MCUs has not been tested. + +First, the cross compiler should be installed: + +```sh +sudo apt install gcc-arm-none-eabi +``` + +Next, we'll configure Zephyr with some [environment variables](https://docs.zephyrproject.org/3.2.0/develop/env_vars.html#env-vars) needed to find the cross compiler. Create a file named `~/.zephyrrc` if it doesn't exist, and add these lines to it: + +```sh +export ZEPHYR_TOOLCHAIN_VARIANT=cross-compile +export CROSS_COMPILE=/usr/bin/arm-none-eabi- +``` + + + + +Follow Zephyr's [Install Linux Host Dependencies](https://docs.zephyrproject.org/3.2.0/develop/getting_started/installation_linux.html) documentation for Fedora. + + + + +### Install West + +`west` is the [Zephyr® Project's meta-tool](https://docs.zephyrproject.org/3.2.0/develop/west/index.html) used to configure and build Zephyr OS applications. + +West can be installed by using the `pip` python package manager. The [Zephyr™ instructions](https://docs.zephyrproject.org/3.2.0/develop/west/install.html) are summarized here: + + + + +Install west: + +```sh +pip3 install --user -U west +``` + +Verify that west is installed: + +```sh +west --version +``` + +This should print a message like "West version: v0.14.0". If it prints an error instead, make sure `~/.local/bin` is on your `PATH` environment variable. You can add it with these commands: + +```sh +echo 'export PATH=~/.local/bin:"$PATH"' >> ~/.bashrc +source ~/.bashrc +``` + + + + +Install west: + +```sh +pip3 install -U west +``` + +Verify that west is installed: + +```sh +west --version +``` + +This should print a message like "West version: v0.14.0". If it prints an error instead, make sure that the Python scripts directory is on your `PATH` environment variable. You can add it by opening a PowerShell window and running the following commands: + +```powershell +$Scripts = python -c "import sysconfig; print(sysconfig.get_path('scripts'))" +$Path = [Environment]::GetEnvironmentVariable('PATH', 'User') +[Environment]::SetEnvironmentVariable('PATH', "$Path;$Scripts", 'User') +$env:PATH += ";$Scripts" +``` + + + + +Install west: + +```sh +pip3 install -U west +``` + + + + +## Get Source Code + +Next, you'll need to clone the ZMK source repository if you haven't already. Navigate to the folder you would like to place your `zmk` directory in and run the following command: + +``` +git clone https://github.com/zmkfirmware/zmk.git +``` + +## Initialize & Update Zephyr Workspace + +Since ZMK is built as a Zephyr™ application, the next step is +to use `west` to initialize and update your workspace. The ZMK +Zephyr™ application is in the `app/` source directory: + +### Step into the repository + + + + +```sh +cd zmk +``` + + + + +```sh +cd zmk +``` + + + + +```sh +cd zmk +``` + + + + +```sh +cd zmk +``` + + + + +```sh +cd zmk +``` + + + + + +Open the `zmk` checkout folder in VS Code. The repository includes a configuration for containerized development, so an alert will pop up: + +![VS Code Dev Container Configuration Alert](../assets/dev-setup/vscode_devcontainer.png) + +Click `Reopen in Container` in order to reopen the VS Code with the running container. + +The first time you do this on your machine, it will pull the docker image down from the registry and build the container. Subsequent launches are much faster! + +:::caution +All subsequent steps must be performed from the VS Code terminal _inside_ the container. +::: + + + + +### Initialize the Application + +```sh +west init -l app/ +``` + +### Update to Fetch Modules + +```sh +west update +``` + +:::tip +This step pulls down quite a bit of tooling. Go grab a cup of coffee, it can take 10-15 minutes even on a good internet connection! +::: + +:::info +If you're using Docker, you're done with setup! You must restart the container at this point. The easiest way to do so is to close the VS Code window, verify that the container has stopped in Docker Dashboard, and reopen the container with VS Code. + +Once your container is restarted, proceed to [Building and Flashing](development/build-flash.md). +::: + +### Export Zephyr CMake package + +This allows CMake to load the code needed to build ZMK. + +```sh +west zephyr-export +``` + +### Install Zephyr Python Dependencies + +Some additional Python dependencies are listed in Zephyr's `scripts/requirements.txt` file. + + + + +```sh +pip3 install --user -r zephyr/scripts/requirements.txt +``` + + + + +```sh +pip3 install -r zephyr/scripts/requirements.txt +``` + + + + +```sh +pip3 install -r zephyr/scripts/requirements.txt +``` + + + diff --git a/docs/docs/development/tests.md b/docs/docs/development/tests.md new file mode 100644 index 000000000000..37b52bdd1996 --- /dev/null +++ b/docs/docs/development/tests.md @@ -0,0 +1,22 @@ +--- +title: Tests +sidebar_label: Tests +--- + +- Running tests requires [native posix support](posix-board.md). +- Any folder under `/app/tests` containing `native_posix_64.keymap` will be selected when running `west test`. +- Run tests from within the `/zmk/app` directory. +- Run a single test with `west test `, like `west test tests/toggle-layer/normal`. + +## Creating a New Test Set + +1. Copy the test set that most closely resembles the tests you will be creating. +2. Rename the newly created test set to the behavior you're testing e.g, toggle-layer +3. Modify `behavior_keymap.dtsi` to create a keymap using the behavior and related behaviors +4. Modify `test_case/native_posix_64.keymap` for a simulated use case +5. Modify `test_case/events.patterns` to collect relevant logs to the test + - See: [sed manual](https://www.gnu.org/software/sed/manual/sed.html) and + [tutorial](https://www.digitalocean.com/community/tutorials/the-basics-of-using-the-sed-stream-editor-to-manipulate-text-in-linux) +6. Modify `test_case/keycode_events.snapshot` for to include the expected output +7. Rename the `test_case` folder to describe the test. +8. Repeat steps 4 to 7 for every test case diff --git a/docs/docs/development/usb-logging.md b/docs/docs/development/usb-logging.md new file mode 100644 index 000000000000..6a8f8564b049 --- /dev/null +++ b/docs/docs/development/usb-logging.md @@ -0,0 +1,114 @@ +--- +title: USB Logging +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Overview + +If you are developing ZMK on a device that does not have a built in UART for debugging and log/console output, +Zephyr can be configured to create a USB CDC ACM device and the direct all `printk`, console output, and log +messages to that device instead. + +:::warning Battery Life Impact + +Enabling logging increases the power usage of your keyboard, and can have a non-trivial impact to your time on battery. +It is recommended to only enable logging when needed, and not leaving it on by default. + +::: + +## Kconfig + +The `CONFIG_ZMK_USB_LOGGING` Kconfig enables USB logging. This can be set at the keyboard level, typically in the `config/.conf` +file if you are using a [user config repository](user-setup.md). It can also be enabled at the ZMK level using the `app/prj.conf` file, or other +search locations described in the [configuration overview](config/index.md#config-file-locations). + +Logging can be further configured using Kconfig described in [the Zephyr documentation](https://docs.zephyrproject.org/3.2.0/services/logging/index.html). +For instance, setting `CONFIG_LOG_PROCESS_THREAD_STARTUP_DELAY_MS` to a large value such as `8000` might help catch issues that happen near keyboard +boot, before you can connect to view the logs. + +:::note +In Github Actions, you can check the ` Kconfig file` step output to verify the options above have been enabled +for you successfully. +::: + +```ini +# Turn on logging, and set ZMK logging to debug output +CONFIG_ZMK_USB_LOGGING=y +``` + +## Viewing Logs + +After flashing the updated ZMK image, the board should expose a USB CDC ACM device that you can connect to and view the logs. + + + + +On Linux, this should be a device like `/dev/ttyACM0` and you can connect with `minicom` or `tio` as usual, e.g.: + +```sh +sudo tio /dev/ttyACM0 +``` + + + + +On Windows, you can use [PuTTY](https://www.putty.org/). Once installed, use Device Manager to figure out which COM port your controller is communicating on (listed under 'Ports (COM & LPT)') and specify that as the 'Serial line' in PuTTY. + +![Controller COM port](../assets/usb-logging/com.jpg) + +![PuTTY settings](../assets/usb-logging/putty.jpg) + +If you already have the Ardunio IDE installed you can also use its built-in Serial Monitor. + + + + +On macOS, the device name is something like `/dev/tty.usbmodemXXXXX` where `XXXXX` is some numerical ID. +You can connect to the device with [tio](https://tio.github.io/) (can be installed via [Homebrew](https://formulae.brew.sh/formula/tio)): + +```sh +sudo tio /dev/tty.usbmodem14401 +``` + +You should see tio printing `Disconnected` or `Connected` when you disconnect or reconnect the USB cable. + + + +From there, you should see the various log messages from ZMK and Zephyr, depending on which systems you have set to what log levels. + +## Adding USB Logging to a Board + +Standard boards such as the nice!nano and Seeeduino XIAO family have the necessary configuration for logging already added, however if you are developing your own standalone board you may wish to add the ability to use USB logging in the future. + +To add USB logging to a board you need to define the USB CDC ACM device that the serial output gets piped to, as well as adding the console in the `chosen` node inside `.dts`. + +Inside the USB device (`&usbd`), add the CDC ACM node: + +```dts +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; +``` + +Then you can add the `zephyr,console` binding in the `chosen` node: + +```dts +/ { + chosen { + ... + zephyr,console = &cdc_acm_uart; + }; + ... +}; +``` diff --git a/docs/docs/faq.md b/docs/docs/faq.md new file mode 100644 index 000000000000..edb41f3b697c --- /dev/null +++ b/docs/docs/faq.md @@ -0,0 +1,121 @@ +--- +title: FAQs +sidebar_label: FAQs +--- + +### Why Zephyr™? + +As a best-in-class RTOS, Zephyr™ brings many [benefits](https://www.zephyrproject.org/benefits) to ZMK, such as: + +- A _single_ platform [supporting](https://docs.zephyrproject.org/latest/boards/index.html) many architectures, processors and boards. +- Optimization for low-powered, small memory footprint devices. +- Powerful hardware abstraction and configuration using [DeviceTree](https://docs.zephyrproject.org/latest/guides/dts/index.html) and [Kconfig](https://docs.zephyrproject.org/latest/build/kconfig/index.html). +- A BLE stack that periodically obtains [qualification](https://docs.zephyrproject.org/latest/connectivity/bluetooth/bluetooth-qual.html) listings, making it easier for final products to obtain qualification from the Bluetooth® SIG. +- Multi-processor support, which is critical for power efficiency in upcoming MCUs. +- Permissive licensing with its Apache 2.0 open source [license](https://www.apache.org/licenses/LICENSE-2.0). +- A buzzing developer [community](https://github.com/zephyrproject-rtos/zephyr) including many leading [embedded technology](https://www.zephyrproject.org/project-members) companies. +- Long term support (LTS) with security updates. + +### Why yet another keyboard firmware? + +That’s an excellent question! There are already great keyboard firmwares available, but ZMK has some advantages: + +- Zephyr™ + - See [Why Zephyr™?](#why-zephyr) +- Licensing + - Just like other open source firmware, ZMK is all about the free and the sharing. However, some other projects use the GPL license which prevents integration of libraries and drivers whose licenses are not GPL-compatible (such as some embedded BLE drivers). ZMK uses the permissive [MIT](https://github.com/zmkfirmware/zmk/blob/main/LICENSE) license which doesn’t have this limitation. +- Wireless First + - ZMK is designed for the future, and we believe the future is wireless. So power efficiency plays a critical role in every design decision, just like in Zephyr™. + +The ZMK contributors firmly believe that a keyboard firmware built on Zephyr™ will provide more long term benefits. + +### What license does ZMK use? + +ZMK uses the MIT [license](https://github.com/zmkfirmware/zmk/blob/main/LICENSE). + +### What hardware/platforms does ZMK support? + +ZMK has the potential to run on any platform supported by Zephyr™. However, it’s impractical for the ZMK contributors to test all possible hardware. + +The Zephyr™ [documentation](https://docs.zephyrproject.org/latest/boards/index.html) describes which hardware is currently natively supported by the Zephyr™ platform. _Similar documentation covering which keyboards have been integrated into ZMK is currently being planned._ + +### Does ZMK compile for AVR? + +Sorry, Zephyr™ only supports 32-bit and 64-bit platforms. + +### How do I get started? + +ZMK is still in its infancy, so there’s a learning curve involved. But if you’d like to try it out, please check out the development [documentation](/docs) and the other FAQs. Please keep in mind that the project team is still small, so our support capability is limited whilst we focus on development. But we’ll try our best! Interested developers are also very welcome to contribute! + +### What is a “board”? + +In ZMK, a _board_ defines the _PCB_ that _includes the MCU_. +For keyboards, this is one of two options: + +- Complete keyboard PCBs that include the MCU (e.g. the Planck or Preonic). +- Small MCU boards (e.g. the Proton-C or nice!nano) that expose pins and are designed to be combined with larger keyboard PCBs, or hand wired to switches to create the final keyboard. + +### What is a “shield”? + +In ZMK, a _shield_ is a _PCB_ or _hardwired set of components_ that when combined with a MCU only [board](#what-is-a-board) like the Proton-C or nice!nano, results in a complete usable keyboard. Examples would be keyboard PCBs like the Kyria or Corne. The _shield_ is usually the big PCB containing all the keys. + +### Why _boards_ and _shields_? Why not just “keyboard”? + +If you haven't already done so, please read these FAQs first: + +- [What is a “board”?](#what-is-a-board) +- [What is a "shield"?](#what-is-a-shield) + +When a keyboard accepts a small “PCB MCU module” (e.g. _Arduino Pro Micro_) for its “brains”, then it's important to conceptually separate the hardware into a [board](#what-is-a-board) PCB and a [shield](#what-is-a-shield) PCB. + +The [shield](#what-is-a-shield) is a brainless shell containing all the keys, RGB LEDs, encoders etc. It maps all of these features to a standard pin footprint, such as the Pro Micro pinout. + +To bring this brainless [shield](#what-is-a-shield) to life, you attach any MCU [board](#what-is-a-board) matching the footprint. For instance, the _nice!nano_ is _pin-compatible_ with the _Arduino Pro Micro_, so you can substitute either [board](#what-is-a-board) onto the [shield](#what-is-a-shield). But each [board](#what-is-a-board) comes with its own features (MCU, flash, BLE, etc.) which must also be handled. + +Therefore in ZMK, [board](#what-is-a-board) and [shield](#what-is-a-shield) are considered two different (but related) entities so that it’s easier to mix and match them. They are combined during a ZMK build. + +Please note, many keyboards only have a single PCB which includes the “brains” (MCU) onboard. In ZMK, these have no [shield](#what-is-a-shield), only a [board](#what-is-a-board). + +### Does ZMK support wired split? + +Currently, ZMK only supports wireless split, but wired split is possible and we welcome contributions! + +### How is the latency? + +The latency of ZMK is comparable to other firmware offerings. ZMK is equipped with a variety of scanning methods and [debounce algorithms](features/debouncing.md) that can affect the final measured latency. [This video](https://www.youtube.com/watch?v=jWL4nU-vtWs) shows a latency comparison of ZMK and other keyboard firmwares. + +### Any chance for 2.4GHz dongle implementation? + +At this time, there are no current plans to implement 2.4GHz dongle mode. This is because utilizing Nordic's proprietary 2.4GHz low level protocols requires use of the Nordic Connect SDK, which is licensed with a more restrictive license than ZMK's MIT license. However, ZMK does plan to implement dongle mode using BLE (with encryption). This will result in a 3.75ms average latency from the protocol itself. + +### What bootloader does ZMK use? + +ZMK isn’t designed for any particular bootloader, and supports flashing different boards with different flash utilities (e.g. OpenOCD, nrfjprog, etc.). So if you have any difficulties, please let us know on [Discord](https://zmk.dev/community/discord/invite)! + +### Can I contribute? + +Of course! Please use the developer [documentation](/docs) to get started! + +### I have an idea! What should I do? + +Please join us on [Discord](https://zmk.dev/community/discord/invite) and discuss it with us! + +### I want to add a new keyboard! What should I do? + +The exact process for the management of all the possible hardware is still being finalized, but any developer looking to contribute new keyboard definitions should chat with us on [Discord](https://zmk.dev/community/discord/invite) to get started. + +### Does ZMK have a Code of Conduct? + +Yes, it does have a [Code of Conduct](https://github.com/zmkfirmware/zmk/blob/main/CODE_OF_CONDUCT.md)! Please give it a read! + +### What does “ZMK” mean? + +ZMK was originally coined as a quasi-acronym of “Zephyr Mechanical Keyboard” and also taking inspiration from the amazing keyboard firmware projects, TMK and QMK. + +### Is ZMK related to TMK or QMK? + +No. But inspired by, of course! + +### Who created ZMK? + +ZMK was created by Pete Johanson. It is developed and maintained by the open source community. diff --git a/docs/docs/features/backlight.md b/docs/docs/features/backlight.md new file mode 100644 index 000000000000..eae4d2f9a2ec --- /dev/null +++ b/docs/docs/features/backlight.md @@ -0,0 +1,255 @@ +--- +title: Backlight +sidebar_label: Backlight +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +Backlight is a feature used to control an array of LEDs, usually placed through or under switches. + +:::info +Unlike [RGB Underglow](underglow.md), backlight can only control single color LEDs. Additionally, because backlight LEDs all receive the same power, it's not possible to dim individual LEDs. +::: + +## Enabling Backlight + +To enable backlight on your board or shield, add the following line to your `.conf` file of your user config directory as such: + +```ini +CONFIG_ZMK_BACKLIGHT=y +``` + +If your board or shield does not have backlight configured, refer to [Adding Backlight to a board or a shield](#adding-backlight-to-a-board-or-a-shield). + +## Configuring Backlight + +There are various Kconfig options used to configure the backlight feature. These can all be set in the `.conf` file. + +| Option | Description | Default | +| ------------------------------------ | ----------------------------------------------------- | ------- | +| `CONFIG_ZMK_BACKLIGHT_BRT_STEP` | Brightness step in percent | 20 | +| `CONFIG_ZMK_BACKLIGHT_BRT_START` | Default brightness in percent | 40 | +| `CONFIG_ZMK_BACKLIGHT_ON_START` | Default backlight state | y | +| `CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE` | Turn off backlight when keyboard goes into idle state | n | +| `CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB` | Turn off backlight when USB is disconnected | n | + +## Adding Backlight to a board or a shield + + + + + +First, you must enable PWM by adding the following lines to your `Kconfig.defconfig` file: + +```kconfig +if ZMK_BACKLIGHT + +config PWM + default y + +config LED_PWM + default y + +endif # ZMK_BACKLIGHT +``` + +Create a `-pinctrl.dtsi` file if it does not already exist, and include it at the beginning of the `.dts` file. `CONFIG_PINCTRL=y` must be added to to `_defconfig` if it isn't already enabled. + +The pinctrl file has a `&pinctrl` node that encompasses all pinctrl settings, including I2C or SPI peripherals (e.g. WS2812 LEDs, Battery fuel gauges): + +```dts +&pinctrl { + // Other pinctrl definitions for other hardware + pwm0_default: pwm0_default { + group1 { + psels = ; + }; + }; + pwm0_sleep: pwm0_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; +``` + +Pin numbers are handled differently depending on the MCU. On nRF MCUs pins are configured using `(PWM_OUTX, Y, Z)`, where `X` is the PWM channel used (usually 0), `Y` is the first part of the hardware port (_PY.01_) and `Z` is the second part of the hardware port (_P1.Z_). + +For example, _P1.13_ would give you `(PWM_OUT0, 1, 13)` and _P0.15_ would give you `(PWM_OUT0, 0, 15)`. + +Add the PWM device to the `board.dts` file and assign the pinctrl definitions to it: + +```dts +&pwm0 { + status = "okay"; + pinctrl-0 = <&pwm0_default>; + pinctrl-1 = <&pwm0_sleep>; + pinctrl-names = "default", "sleep"; +}; +``` + +Then add the following lines to the same `.dts` file, but inside the root devicetree node: + +```dts +/ { + backlight: pwmleds { + compatible = "pwm-leds"; + pwm_led_0 { + pwms = <&pwm0 0 PWM_MSEC(10) PWM_POLARITY_NORMAL>; + }; + }; +}; +``` + +The value inside `pwm_led_0` after `&pwm0` must be the channel number. Since `PWM_OUT0` is defined in the pinctrl node, the channel in this example is 0. + +In this example, `PWM_MSEC(10)` is the period of the PWM waveform. This period can be altered if your drive circuitry requires different values or the frequency is audible. + +If your board uses a P-channel MOSFET to control backlight instead of a N-channel MOSFET, you may want to change `PWM_POLARITY_NORMAL` for `PWM_POLARITY_INVERTED`. + +Finally you need to add backlight to the `chosen` element of the root devicetree node: + +```dts +/ { + chosen { + zmk,backlight = &backlight; + }; +}; +``` + + + + +You must first add a `boards/` directory within your shield folder. For each board that supports the shield you must create a `.defconfig` file and a `.overlay` file inside the `boards/` folder. + +Inside your `.defconfig` file, add the following lines: + +```kconfig +if ZMK_BACKLIGHT + +config PWM + default y + +config LED_PWM + default y + +endif # ZMK_BACKLIGHT +``` + +Then add the following lines to your `.overlay` file: + +```dts +&pinctrl { + // Other pinctrl definitions for other hardware + pwm0_default: pwm0_default { + group1 { + psels = ; + }; + }; + pwm0_sleep: pwm0_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; +``` + +Pin numbers are handled differently depending on the MCU. On nRF MCUs pins are configured using `(PWM_OUTX, Y, Z)`, where `X` is the PWM channel used (usually 0), `Y` is the first part of the hardware port (_PY.01_) and `Z` is the second part of the hardware port (_P1.Z_). + +For example, _P1.13_ would give you `(PWM_OUT0, 1, 13)` and _P0.15_ would give you `(PWM_OUT0, 0, 15)`. + +Add the PWM device to the `.overlay` file and assign the pinctrl definitions to it: + +```dts +&pwm0 { + status = "okay"; + pinctrl-0 = <&pwm0_default>; + pinctrl-1 = <&pwm0_sleep>; + pinctrl-names = "default", "sleep"; +}; +``` + +Then add the following lines to the same `.overlay` file, but inside the root devicetree node: + +``` +/ { + backlight: pwmleds { + compatible = "pwm-leds"; + pwm_led_0 { + pwms = <&pwm0 0 PWM_MSEC(10) PWM_POLARITY_NORMAL>; + }; + }; +}; +``` + +In this example, `PWM_MSEC(10)` is the period of the PWM waveform. This period can be altered if your drive circuitry requires different values or the frequency is audible. + +If your board uses a P-channel MOSFET to control backlight instead of a N-channel MOSFET, you may want to change `PWM_POLARITY_NORMAL` for `PWM_POLARITY_INVERTED`. + +The value inside `pwm_led_0` after `&pwm0` must be the channel number. Since `PWM_OUT0` is defined in the pinctrl node, the channel in this example is 0. + +Finally you need to add backlight to the `chosen` element of the root devicetree node: + +```dts +/ { + chosen { + zmk,backlight = &backlight; + }; +}; +``` + + + + +### Multiple backlight LEDs + +It is possible to control multiple backlight LEDs at the same time. This is useful if, for example, you have a Caps Lock LED connected to a different pin and you want it to be part of the backlight. + +In order to do that, first configure PWM for each pin in the pinctrl node: + +```dts +&pinctrl { + // Other Pinctrl definitions go here + pwm0_default: pwm0_default { + group1 { + psels = , // LED 0 + , // LED 1 + ; // LED 2 + }; + }; + pwm0_sleep: pwm0_sleep { + group1 { + psels = , // LED 0 + , // LED 1 + ; // LED 2 + low-power-enable; + }; + }; +}; +``` + +This part will vary based on your MCU as different MCUs have a different number of modules, channels and configuration options. + +Add each of your LEDs to the backlight node in the same manner as for one LED, using the channel number definitions in the pinctrl node: + +```dts +backlight: pwmleds { + compatible = "pwm-leds"; + pwm_led_0: pwm_led_0 { + pwms = <&pwm0 0 PWM_MSEC(10) PWM_POLARITY_NORMAL>; + }; + pwm_led_1: pwm_led_1 { + pwms = <&pwm0 1 PWM_MSEC(10) PWM_POLARITY_NORMAL>; + }; + pwm_led_2: pwm_led_2 { + pwms = <&pwm0 2 PWM_MSEC(10) PWM_POLARITY_NORMAL>; + }; +}; +``` diff --git a/docs/docs/features/battery.md b/docs/docs/features/battery.md new file mode 100644 index 000000000000..4bfeb129994c --- /dev/null +++ b/docs/docs/features/battery.md @@ -0,0 +1,39 @@ +--- +title: Battery Level +sidebar_label: Battery Level +--- + +If your keyboard has a battery sensor, ZMK will report its battery level to the connected bluetooth host and show it on the keyboard's display, if it has one. + +For split keyboards, only the battery level of the central (usually left) side is reported over bluetooth. + +:::note + +Windows may not properly ask the keyboard to notify it of changes in battery level, so the level shown may be out of date. + +::: + +## Adding a Battery Sensor to a Board + +To enable a battery sensor on a new board, add the driver for the sensor to your board's `.dts` file. ZMK provides two drivers for estimating the battery level using its voltage: + +- `zmk,battery-voltage-divider`: Reads the voltage on an analog input pin. +- `zmk,battery-nrf-vddh`: Reads the power supply voltage on a Nordic nRF52's VDDH pin. + +See the [battery level configuration page](../config/battery.md) for the configuration supported by each driver provided by ZMK. + +Zephyr also provides some drivers for fuel gauge ICs such as the TI bq274xx series and Maxim MAX17xxx series. If you use a battery sensor that does not have an existing driver, you will need to write a new driver that supports the `SENSOR_CHAN_GAUGE_STATE_OF_CHARGE` sensor channel and contribute it to Zephyr or ZMK. + +Once you have the sensor driver defined, add a `zmk,battery` property to the `chosen` node and set it to reference the sensor node. For example: + +```dts +/ { + chosen { + zmk,battery = &vbatt; + }; + + vbatt: vbatt { + compatible = "zmk,battery-nrf-vddh"; + }; +} +``` diff --git a/docs/docs/features/beta-testing.md b/docs/docs/features/beta-testing.md new file mode 100644 index 000000000000..4a159362f13c --- /dev/null +++ b/docs/docs/features/beta-testing.md @@ -0,0 +1,100 @@ +--- +title: Beta Testing +sidebar_label: Beta Testing +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +You may find that ZMK does not support a feature or keyboard that you are interesting in using. You may find that someone +has already taken the time to submit the feature you need as a [Pull Request](https://github.com/zmkfirmware/zmk/pulls). If you find the feature you need as a pull request, +this page is for you! + +## Developer Repositories and Branches + +For a developer to submit a pull request to ZMK, they must first clone the original ZMK repository. After they have a copy +of the source code, they may create a feature branch to work within. When they have finished, they will publish the feature +branch and create the pull request. + +### Finding the Repository Page from the Pull Request + +![PR Repository](../assets/features/beta-testing/pr-repo-branch.png) + +### Finding the Repository URL + +![Repository URL](../assets/features/beta-testing/repo-url.png) + +### Finding the Repository Branch + +![Repository URL](../assets/features/beta-testing/repo-branch.png) + +## Testing features + +Testing features will require you to modify the `west.yml` file. You will need to add a new remote for the pull request you +would like to test, and change the selected remote and revision (or branch) for the `zmk` project. + +### Examples + + + + +```yaml +manifest: + remotes: + - name: zmkfirmware + url-base: https://github.com/zmkfirmware + projects: + - name: zmk + remote: zmkfirmware + revision: main + import: app/west.yml + self: + path: config +``` + + + + +```yaml +manifest: + remotes: + - name: zmkfirmware + url-base: https://github.com/zmkfirmware + - name: okke-formsma + url-base: https://github.com/okke-formsma + projects: + - name: zmk + remote: okke-formsma + revision: macros + import: app/west.yml + self: + path: config +``` + + + + +```yaml +manifest: + remotes: + - name: zmkfirmware + url-base: https://github.com/zmkfirmware + - name: mcrosson + url-base: https://github.com/mcrosson + projects: + - name: zmk + remote: mcrosson + revision: feat-behavior-sleep + import: app/west.yml + self: + path: config +``` + + + diff --git a/docs/docs/features/bluetooth.md b/docs/docs/features/bluetooth.md new file mode 100644 index 000000000000..e58e16735ef0 --- /dev/null +++ b/docs/docs/features/bluetooth.md @@ -0,0 +1,92 @@ +--- +title: Bluetooth +sidebar_label: Bluetooth +--- + +ZMK's bluetooth functionality allows users to connect their keyboards to hosts using Bluetooth Low Energy (BLE) technology. It also is used for split keyboards to connect the two halves wirelessly. + +:::note + +Bluetooth 4.2 or newer is required in order to connect to a ZMK keyboard. ZMK implements advanced security using BLE's Secure Connection feature, which requires Bluetooth 4.2 at a minimum. To avoid well-known security vulnerabilities, we disallow using Legacy pairing. + +::: + +## Security + +BLE connections between keyboards and hosts are secured by an initial pairing/bonding process that establishes long term keys (LTK) shared between the two sides, using Elliptic Curve Diffie Hellman (ECDH) for key generation. The same security is used to secure the communication between the two sides of split keyboards running ZMK. + +The only known vulnerability in the protocol is a risk of an active man-in-the-middle (MITM) attack exactly during the initial pairing, which can be mitigated in the future using the Numeric Comparison association model. Support for that in ZMK is still experimental, so if you have serious concerns about an active attacker with physical proximity to your device, consider only pairing/bonding your keyboards in a controlled environment. + +## Profiles + +By default, ZMK supports five "profiles" for selecting which bonded host +device should receive the keyboard input. + +:::note Connection Management + +When pairing to a host device ZMK saves bond information to the selected profile. It will not replace this automatically when you initiate pairing with another device. To pair with a new device select an unused profile with or clearing the current profile, using the [`&bt` behavior](../behaviors/bluetooth.md) on your keyboard. + +A ZMK device may show as "connected" on multiple hosts at the same time. This is working as intended, and only the host associated with the active profile will receive keystrokes. + +::: + +Failure to manage the profiles can result in unexpected/broken behavior with hosts due to bond key mismatches, so it is an important aspect of ZMK to understand. + +## Bluetooth Behavior + +Management of the bluetooth in ZMK is accomplished using the [`&bt` behavior](../behaviors/bluetooth.md). Be sure to refer to that documentation to learn how to manage profiles, switch between connected hosts, etc. + +## Troubleshooting + +### Connectivity Issues + +Some users may experience a poor connection between the keyboard and the host. This might be due to poor quality BLE hardware, a metal enclosure on the keyboard or host, or the distance between them. Increasing the transmit power of the keyboard's BLE radio may reduce the severity of this problem. To do this, set the `CONFIG_BT_CTLR_TX_PWR_PLUS_8` configuration value in the `.conf` file of your user config directory as such: + +```ini +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y +``` + +For the `nRF52840`, the value `PLUS_8` can be set to any multiple of four between `MINUS_20` and `PLUS_8`. The default value for this config is `0`, but if you are having connection issues it is recommended to set it to `PLUS_8` because the power consumption difference is negligible. For more information on changing the transmit power of your BLE device, please refer to [the Zephyr docs.](https://docs.zephyrproject.org/latest/kconfig.html#CONFIG_BT_CTLR_TX_PWR) + +:::info +This setting can also improve the connection strength between the keyboard halves for split keyboards. +::: + +### Using bluetooth output with USB power + +If you want to test bluetooth output on your keyboard and are powering it through the USB connection rather than a battery, you will be able to pair with a host device but may not see keystrokes sent. In this case you need to use the [output selection behavior](../behaviors/outputs.md) to prefer sending keystrokes over bluetooth rather than USB. This might be necessary even if you are not powering from a device capable of receiving USB inputs, such as a USB charger. + +## Known Issues + +There are a few known issues related to BLE and ZMK: + +### Windows Battery Reporting + +There is a known issue with Windows failing to update the battery information after connecting to a ZMK keyboard. You can work around this Windows bug by overriding a [Bluetooth config variable](../config/bluetooth.md) to force battery notifications even if a host neglects to subscribe to them: + +```ini +CONFIG_BT_GATT_ENFORCE_SUBSCRIPTION=n +``` + +### macOS Connected But Not Working + +If you attempt to pair a ZMK keyboard from macOS in a way that causes a bonding issue, macOS may report the keyboard as connected, but fail to actually work. If this occurs: + +1. Remove the keyboard from macOS using the Bluetooth control panel. +1. Invoke `&bt BT_CLR` on the keyboard while the profile associated with the macOS device is active, by pressing the correct keys for your particular keymap. +1. Try connecting again from macOS. + +### Windows Connected But Not Working + +Occasionally pairing the keyboard to a Windows device might result in a state where the keyboard is connected but does not send any key strokes. +If this occurs: + +1. Remove the keyboard from Windows using the Bluetooth settings. +1. Invoke `&bt BT_CLR` on the keyboard while the profile associated with the Windows device is active, by pressing the correct keys for your particular keymap. +1. Turn off Bluetooth from Windows settings, then turn it back on. +1. Pair the keyboard to the Windows device. + +If this doesn't help, try following the procedure above but replace step 3 with one of the following: + +- Restart the Windows device +- Open "Device Manager," turn on "Show hidden devices" from the "View" menu, then find and delete the keyboard under the "Bluetooth" item diff --git a/docs/docs/features/combos.md b/docs/docs/features/combos.md new file mode 100644 index 000000000000..f4664c546f13 --- /dev/null +++ b/docs/docs/features/combos.md @@ -0,0 +1,51 @@ +--- +title: Combos +--- + +## Summary + +Combo keys are a way to combine multiple keypresses to output a different key. For example, you can hit the Q and W keys on your keyboard to output escape. + +### Configuration + +Combos configured in your `.keymap` file, but are separate from the `keymap` node found there, since they are processed before the normal keymap. They are specified like this: + +```dts +/ { + combos { + compatible = "zmk,combos"; + combo_esc { + timeout-ms = <50>; + key-positions = <0 1>; + bindings = <&kp ESC>; + }; + }; +}; +``` + +- The name of the combo doesn't really matter, but convention is to start the node name with `combo_`. +- The `compatible` property should always be `"zmk,combos"` for combos. +- All the keys in `key-positions` must be pressed within `timeout-ms` milliseconds to trigger the combo. +- `key-positions` is an array of key positions. See the info section below about how to figure out the positions on your board. +- `layers = <0 1...>` will allow limiting a combo to specific layers. This is an _optional_ parameter, when omitted it defaults to global scope. +- `bindings` is the behavior that is activated when the behavior is pressed. +- (advanced) you can specify `slow-release` if you want the combo binding to be released when all key-positions are released. The default is to release the combo as soon as any of the keys in the combo is released. +- (advanced) you can specify a `require-prior-idle-ms` value much like for [hold-taps](behaviors/hold-tap.md#require-prior-idle-ms). If any non-modifier key is pressed within `require-prior-idle-ms` before a key in the combo, the combo will not trigger. + +:::info + +Key positions are numbered like the keys in your keymap, starting at 0. So, if the first key in your keymap is `Q`, this key is in position `0`. The next key (possibly `W`) will have position 1, etcetera. + +::: + +### Advanced usage + +- Partially overlapping combos like `0 1` and `0 2` are supported. +- Fully overlapping combos like `0 1` and `0 1 2` are supported. +- You are not limited to `&kp` bindings. You can use all ZMK behaviors there, like `&mo`, `&bt`, `&mt`, `<` etc. + +:::note Source-specific behaviors on split keyboards +Invoking a source-specific behavior such as one of the [reset behaviors](behaviors/reset.md) using a combo will always trigger it on the central side of the keyboard, regardless of the side that the keys corresponding to `key-positions` are on. +::: + +See [combo configuration](/docs/config/combos) for advanced configuration options. diff --git a/docs/docs/features/conditional-layers.md b/docs/docs/features/conditional-layers.md new file mode 100644 index 000000000000..7ccfdf2338ac --- /dev/null +++ b/docs/docs/features/conditional-layers.md @@ -0,0 +1,56 @@ +--- +title: Conditional Layers +--- + +Conditional layers support activating a particular layer (called the `then-layer`) when all layers +in a specified set (called the `if-layers`) are active. This feature generalizes what's commonly +known as tri-layer support, allowing activation of two layers (usually called "lower" and "raise") +to trigger a third (usually called "adjust"). + +Another way to think of this feature is as a simple combo system for layers, just like the usual +[combos for behaviors](combos.md). + +## Configuration + +Conditional layers are configured via a `conditional_layers` node in your `.keymap` file as follows: + +```dts +/ { + conditional_layers { + compatible = "zmk,conditional-layers"; + tri_layer { + if-layers = <1 2>; + then-layer = <3>; + }; + }; +}; +``` + +Each conditional layer configuration may have whatever name you like, but it's helpful to choose +something self explanatory like `tri_layer`. The following properties are supported: + +- `if-layers` specifies a set of layer numbers, all of which must be active for the conditional + layer to trigger. +- `then-layer` specifies a layer number that should be activated if and only if all the layers + specified in the `if-layers` property are active. + +Therefore, in this example, layer 3 ("adjust") will be activated if and only if both layers 1 +("lower") and 2 ("raise") are active. + +:::tip +Since higher-numbered layers are processed first, a `then-layer` should generally have a higher +number than its associated `if-layers` so the `then-layer` can be accessed when active. +::: + +:::info +Activating a `then-layer` in one conditional layer configuration can trigger the `if-layers` +condition in another configuration, possibly repeatedly. +::: + +:::caution +When configured as a `then-layer`, a layer's activation status is entirely controlled by the +conditional layers feature. Even if the layer is activated for another reason (such as a [momentary +layer](../behaviors/layers.md#momentary-layer) behavior), it will be immediately deactivated if the +associated `then-layers` configuration is not met. As such, we recommend avoiding using regular +layer behaviors for `then-layer` targets. +::: diff --git a/docs/docs/features/debouncing.md b/docs/docs/features/debouncing.md new file mode 100644 index 000000000000..38ded2d7952c --- /dev/null +++ b/docs/docs/features/debouncing.md @@ -0,0 +1,104 @@ +--- +title: Debouncing +sidebar_label: Debouncing +--- + +To prevent contact bounce (also known as chatter) and noise spikes from causing +unwanted key presses, ZMK uses a [cycle-based debounce algorithm](https://www.kennethkuhn.com/electronics/debounce.c), +with each key debounced independently. + +By default the debounce algorithm decides that a key is pressed or released after +the input is stable for 5 milliseconds. You can decrease this to improve latency +or increase it to improve reliability. + +If you are having problems with a single key press registering multiple inputs, +you can try increasing the debounce press and/or release times to compensate. +You should also check for mechanical issues that might be causing the bouncing, +such as hot swap sockets that are making poor contact. You can try replacing the +socket or using some sharp tweezers to bend the contacts back together. + +## Debounce Configuration + +:::note +Currently the `zmk,kscan-gpio-matrix` and `zmk,kscan-gpio-direct` [drivers](../config/kscan.md) supports these options, while `zmk,kscan-gpio-demux` driver does not. +::: + +### Global Options + +You can set these options in your `.conf` file to control debouncing globally. +Values must be <= 16383. + +- `CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS`: Debounce time for key press in milliseconds. Default = 5. +- `CONFIG_ZMK_KSCAN_DEBOUNCE_RELEASE_MS`: Debounce time for key release in milliseconds. Default = 5. + +If one of these options is set, it overrides the matching per-driver option described below. + +For example, this would shorten the debounce time for both press and release: + +```ini +CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS=3 +CONFIG_ZMK_KSCAN_DEBOUNCE_RELEASE_MS=3 +``` + +### Per-driver Options + +You can add these Devicetree properties to a kscan node to control debouncing for +that instance of the driver. Values must be <= 16383. + +- `debounce-press-ms`: Debounce time for key press in milliseconds. Default = 5. +- `debounce-release-ms`: Debounce time for key release in milliseconds. Default = 5. +- ~~`debounce-period`~~: Deprecated. Sets both press and release debounce times. +- `debounce-scan-period-ms`: Time between reads in milliseconds when any key is pressed. Default = 1. + +If one of the global options described above is set, it overrides the corresponding +per-driver option. + +For example, if your board/shield has a kscan driver labeled `kscan0` in its +`.overlay`, `.dts`, or `.dtsi` files, + +```dts +kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + ... +}; +``` + +then you could add this to your `.keymap`: + +```dts +&kscan0 { + debounce-press-ms = <3>; + debounce-release-ms = <3>; +}; +``` + +This must be placed outside of any blocks surrounded by curly braces (`{...}`). + +`debounce-scan-period-ms` determines how often the keyboard scans while debouncing. It defaults to 1 ms, but it can be increased to reduce power use. Note that the debounce press/release timers are rounded up to the next multiple of the scan period. For example, if the scan period is 2 ms and debounce timer is 5 ms, key presses will take 6 ms to register instead of 5. + +## Eager Debouncing + +Eager debouncing means reporting a key change immediately and then ignoring +further changes for the debounce time. This eliminates latency but it is not +noise-resistant. + +ZMK does not currently support true eager debouncing, but you can get something +very close by setting the time to detect a key press to zero and the time to detect +a key release to a larger number. This will detect a key press immediately, then +debounce the key release. + +```ini +CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS=0 +CONFIG_ZMK_KSCAN_DEBOUNCE_RELEASE_MS=5 +``` + +Also consider setting `CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS=1` instead, which adds +one millisecond of latency but protects against short noise spikes. + +## Comparison With QMK + +ZMK's default debouncing is similar to QMK's `sym_defer_pk` algorithm. + +Setting `CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS=0` for eager debouncing would be similar to QMK's `asym_eager_defer_pk`. + +See [QMK's Debounce API documentation](https://docs.qmk.fm/#/feature_debounce_type) for more information. diff --git a/docs/docs/features/displays.md b/docs/docs/features/displays.md new file mode 100644 index 000000000000..283bf8806718 --- /dev/null +++ b/docs/docs/features/displays.md @@ -0,0 +1,10 @@ +--- +title: Displays +sidebar_label: Displays +--- + +Displays in ZMK are currently a proof of concept and official support is coming soon. + +:::info +Although ZMK-powered keyboards _are_ capable of utilizing OLED and ePaper displays, the Displays feature is not yet considered production-ready due to an issue where the display remains blank after resuming from [external power cutoff](../behaviors/power.md#external-power-control). This issue can be tracked on GitHub at [zmkfirmware/zmk #674](https://github.com/zmkfirmware/zmk/issues/674). +::: diff --git a/docs/docs/features/encoders.md b/docs/docs/features/encoders.md new file mode 100644 index 000000000000..105757634b18 --- /dev/null +++ b/docs/docs/features/encoders.md @@ -0,0 +1,44 @@ +--- +title: Encoders +sidebar_label: Encoders +--- + +Existing support for encoders in ZMK is focused around the five pin EC11 rotary encoder with push button design used in the majority of current keyboard and macropad designs. + +## Enabling EC11 Encoders + +To enable encoders for boards that have existing encoder support, uncomment the `CONFIG_EC11=y` and `CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y` lines in your board's .conf file in your `zmk-config/config` folder. Save and push your changes, then download and flash the new firmware. + +## Customizing EC11 Encoder Behavior + +Encoder behavior in ZMK is configured in two different locations as the push button and rotation behaviors are handled in two separate ways. + +### Push Button + +Keyboards and macropads with encoder support will typically take the two EC11 pins responsible for the push button and include them as part of the matrix for the keys. To configure what is sent by the push button, find the encoder's position in the keyboard matrix and assign it a behavior the same as you would any other key. + +### Rotation + +Rotation is handled separately as a type of sensor. The behavior for this is set in `sensor-bindings`. See [Sensor Rotation](../behaviors/sensor-rotate.md) for customizing this behavior. + +```dts +sensor-bindings = ; +``` + +- `BINDING` is either a user-defined behavior, or `&inc_dec_kp` for key presses (see [Key Press](../behaviors/key-press.md) for details on available keycodes). +- `CW_KEY` is the keycode activated by a clockwise turn. +- `CCW_KEY` is the keycode activated by a counter-clockwise turn. + +Additional encoders can be configured by adding more bindings immediately after the first. + +As an example, a complete `sensor-bindings` for a Kyria with two encoders could look like: + +```dts +sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; +``` + +Here, the left encoder is configured to control volume up and down while the right encoder sends either Page Up or Page Down. + +## Adding Encoder Support + +See the [New Keyboard Shield](../development/new-shield.md#encoders) documentation for how to add or modify additional encoders to your shield. diff --git a/docs/docs/features/keymaps.md b/docs/docs/features/keymaps.md new file mode 100644 index 000000000000..9778ecbab185 --- /dev/null +++ b/docs/docs/features/keymaps.md @@ -0,0 +1,140 @@ +--- +title: Keymaps & Behaviors +sidebar_label: Keymaps +--- + +import KeymapExample from '../keymap-example.md'; +import KeymapExampleFile from '../keymap-example-file.md'; + +ZMK uses a declarative approach to keymaps instead of using C code for all keymap configuration. +Right now, ZMK uses the devicetree syntax to declare those keymaps; future work is envisioned for +supporting dynamic loading of declarative keymaps, e.g. over USB Mass Storage or via a custom BLE +service. + +:::note +For advanced users looking to implement custom behaviors for their keymaps, this will be possible +in the future by allowing user configs to add to the CMake application built by Zephyr. +::: + +## Big Picture + +All keyboard definitions (complete boards or shields) include the _default_ keymap for that keyboard, +so ZMK can produce a "stock" firmware for that keyboard without any further modifications. For users +looking to customize their keyboard's behavior, they can copy the stock `.keymap` file into their +user config directory, and customize the keymap to their liking. + +## Behaviors + +ZMK implements the concept of "behaviors", which can be bound to a certain key position, sensor (encoder), +or layer, to perform certain actions when events occur for that binding (e.g. when a certain key position +is pressed or released, or an encoder triggers a rotation event). + +For example, the simplest behavior in ZMK is the "key press" behavior, which responds to key position +(a certain spot on the keyboard), and when that position is pressed, send a keycode to the host, and +when the key position is released, updates the host to notify of the keycode being released. + +For the full set of possible behaviors, start at the [Key Press](../behaviors/key-press.md) behavior. + +## Layers + +Like many mechanical keyboard firmwares, ZMK keymaps are composed of a collection of layers, with a +minimum of at least one layer that is the default, usually near the bottom of the "stack". Each layer +in ZMK contains a set of bindings that bind a certain behavior to a certain key position in that layer. + +| ![Diagram of three layers](../assets/features/keymaps/layer-diagram.png) | +| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +| _A simplified diagram showing three layers. The layout of each layer is the same (they all contain four keys), but the behavior bindings within each layer can be different._ | + +In addition to the base default layer (which can be changed), certain bound behaviors may also +enable/disable additional layers "on top" of the default layer. + +When a key location is pressed/released, the stack of all active layers from "top to bottom" is used, +and the event is sent to the behavior bound at that position in each layer, for it to perform whatever +actions it wants to in reaction to the event. Those behaviors can choose to "handle" the event, and stop +it from being passed to any lower layers, or may choose to "pass it along", and let the next layer +in the stack _also_ get the event. + +## Behavior Bindings + +Binding a behavior at a certain key position may include up to two extra parameters that are used to +alter the behavior when that specific key position is activated/deactivated. For example, when binding +the "key press" (`kp`) behavior at a certain key position, you must specify _which_ keycode should +be used for that key position. + +```dts +&kp A +``` + +In this case, the `A` is actually a define for the raw HID keycode, to make keymaps easier to read and write. + +For example of a binding that uses two parameters, you can see how "mod-tap" (`mt`) is bound: + +```dts +&mt LSHIFT D +``` + +Here, the first parameter is the set of modifiers that should be used for the "hold" behavior, and the second +parameter is the keycode that should be sent when triggering the "tap" behavior. + +## Keymap File + +A keymap file is composed of several sections, that together make up a valid devicetree file for describing the keymap and its layers. + +### Includes + +The devicetree files are actually preprocessed before being finally leveraged by Zephyr. This allows using standard C defines to create meaningful placeholders +for what would otherwise be cryptic integer keycodes, etc. This also allows bringing in _other_ devicetree nodes from separate files. + +The top two lines of most keymaps should include: + +```dts +#include +#include +``` + +The first defines the nodes for all the available behaviors in ZMK, which will be referenced in the behavior bindings. This is how bindings like `&kp` can reference the key press behavior defined with an anchor name of `kp`. + +The second include brings in the defines for all the keycodes (e.g. `A`, `N1`, `C_PLAY`) and the modifiers (e.g. `LSHIFT`) used for various behavior bindings. + +### Root devicetree Node + +All the remaining keymap nodes will be nested inside of the root devicetree node, like so: + +```dts +/ { + // Everything else goes here! +}; +``` + +### Keymap Node + +Nested under the devicetree root, is the keymap node. The node _name_ itself is not critical, but the node **MUST** have a property +`compatible = "zmk,keymap"` in order to be used by ZMK. + +```dts + keymap { + compatible = "zmk,keymap"; + + // Layer nodes go here! + }; +``` + +### Layers + +Each layer of your keymap will be nested under the keymap node. Here is a sample +that defines just one layer for this keymap: + + + +Each layer should have: + +1. A `bindings` property this will be a list of behavior bindings, one for each key position for the keyboard. +1. (Optional) A `sensor-bindings` property that will be a list of behavior bindings for each sensor on the keyboard. (Currently, only encoders are supported as sensor hardware, but in the future devices like trackpoints would be supported the same way) + +For the full set of possible behaviors, start at the [Key Press](../behaviors/key-press.md) behavior. + +### Complete Example + +Putting this all together, a complete [`kyria.keymap`](https://github.com/zmkfirmware/zmk/blob/main/app/boards/shields/kyria/kyria.keymap) looks like: + + diff --git a/docs/docs/features/underglow.md b/docs/docs/features/underglow.md new file mode 100644 index 000000000000..13f0d8c71e6e --- /dev/null +++ b/docs/docs/features/underglow.md @@ -0,0 +1,176 @@ +--- +title: RGB Underglow +sidebar_label: RGB Underglow +--- + +RGB underglow is a feature used to control "strips" of RGB LEDs. Most of the time this is called underglow and creates a glow underneath the board using a ring of LEDs around the edge, hence the name. However, this can be extended to be used to control anything from a single LED to a long string of LEDs anywhere on the keyboard. + +:::info +RGB underglow can also be used for under-key lighting. If you have RGB LEDs on your keyboard, this is what you want. For PWM/single color LEDs, see [Backlight](backlight.md). +::: + +ZMK supports all the RGB LEDs supported by Zephyr. Here's the current list supported: + +- WS2812-ish (WS2812B, WS2813, SK6812, or compatible) +- APA102 +- LPD880x (LPD8803, LPD8806, or compatible) + +Of the compatible types, the WS2812 LED family is by far the most popular type. Currently each of these types of LEDs are expected to be run using SPI with a couple of exceptions. + +Here you can see the RGB underglow feature in action using WS2812 LEDs. + +
+ +
+ +## Enabling RGB Underglow + +To enable RGB underglow on your board or shield, simply enable the `CONFIG_ZMK_RGB_UNDERGLOW` and `CONFIG_*_STRIP` configuration values in the `.conf` file for your board or shield. +For example: + +```ini +CONFIG_ZMK_RGB_UNDERGLOW=y +# Use the STRIP config specific to the LEDs you're using +CONFIG_WS2812_STRIP=y +``` + +See [Configuration Overview](/docs/config) for more instructions on how to +use Kconfig. + +If your board or shield does not have RGB underglow configured, refer to [Adding RGB Underglow to a Board](#adding-rgb-underglow-to-a-board). + +### Modifying the number of LEDs + +A common issue when enabling underglow is that some of the installed LEDs do not illuminate. This can happen when a board's default underglow configuration accounts only for either the downward facing LEDs or the upward facing LEDs under each key. On a split keyboard, a good sign that this may be the problem is that the unilluminated LEDs on each half are symmetrical. + +The number of underglow LEDs is controlled by the `chain-length` property in the `led_strip` node. You can [change the value of this property](../config/index.md#changing-devicetree-properties) in the `.keymap` file by adding a stanza like this one outside of any other node (i.e. above or below the `/` node): + +```dts +&led_strip { + chain-length = <21>; +}; +``` + +where the value is the total count of LEDs (per half, for split keyboards). + +## Configuring RGB Underglow + +See [RGB underglow configuration](/docs/config/underglow). + +## Adding RGB Underglow to a Board + +RGB underglow is always added to a board, not a shield. This is a consequence of needing to configure SPI to control the LEDs. +If you have a shield with RGB underglow, you must add a `boards/` directory within your shield folder to define the RGB underglow individually for each board that supports the shield. +Inside the `boards/` folder, you define a `.overlay` for each different board. +For example, the Kyria shield has a `boards/nice_nano.overlay` file that defines the RGB underglow for the `nice_nano` board specifically. + +### nRF52-based boards + +With nRF52 boards, you can just use `&spi3` and define the pins you want to use. + +Here's an example on a definition that uses P0.06: + +```dts +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* number of LEDs */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + color-mapping = ; + }; +}; +``` + +:::info + +If you are configuring SPI for an nRF52 based board, double check that you are using pins that aren't restricted to low frequency I/O. +Ignoring these restrictions may result in poor wireless performance. You can find the list of low frequency I/O pins for the nRF52840 [here](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf52840%2Fpin.html&cp=4_0_0_6_0). + +::: + +:::note + +Standard WS2812 LEDs use a wire protocol where the bits for the colors green, red, and blue values are sent in that order. +If your board/shield uses LEDs that require the data sent in a different order, the `color-mapping` property ordering should be changed to match. + +::: + +### Other boards + +For other boards, you must select an SPI definition that has the `MOSI` pin as your data pin going to your LED strip. + +Here's another example for a non-nRF52 board on `spi3`: + +```dts +#include + +&spi3 { + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; + spi-max-frequency = <5250000>; + + /* WS2812 */ + chain-length = <10>; /* number of LEDs */ + spi-one-frame = <0x70>; /* make sure to configure this properly for your SOC */ + spi-zero-frame = <0x40>; /* make sure to configure this properly for your SOC */ + color-mapping = ; + }; +}; +``` + +Once you have your `led_strip` properly defined you need to add it to the root devicetree node `chosen` element: + +```dts +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; +``` + +Finally you need to enable the `CONFIG_ZMK_RGB_UNDERGLOW` and `CONFIG_*_STRIP` configuration values in the `.conf` file of your board (or set a default in the `Kconfig.defconfig`): + +```ini +CONFIG_ZMK_RGB_UNDERGLOW=y +# Use the STRIP config specific to the LEDs you're using +CONFIG_WS2812_STRIP=y +``` diff --git a/docs/docs/hardware.mdx b/docs/docs/hardware.mdx new file mode 100644 index 000000000000..7bc98f961052 --- /dev/null +++ b/docs/docs/hardware.mdx @@ -0,0 +1,59 @@ +--- +title: Supported Hardware +sidebar_label: Supported Hardware +--- + +import HardwareList from "@site/src/components/hardware-list"; +import Metadata from "@site/src/data/hardware-metadata.json"; + +import Heading from "@theme/Heading"; + +import { groupedMetadata } from "@site/src/components/hardware-utils"; + +export const toc = [ + { + value: "Onboard Controller Keyboards", + id: "onboard", + level: 2, + }, + { + value: "Composite Keyboards", + id: "composite", + level: 2, + }, + ...Object.values(groupedMetadata(Metadata).interconnects) + .filter((ic) => ic.interconnect !== undefined) + .map(({ interconnect }) => ({ + value: `${interconnect.name} Interconnect`, + id: interconnect.id, + level: 3, + })), + { + value: "Other Hardware", + id: "other-hardware", + level: 2, + }, + { + value: "Contributing", + id: "contributing", + level: 2, + }, +]; + +With the solid technical foundation of Zephyr™ RTOS, ZMK can support a wide diversity of hardware targets. +That being said, there are specific [boards](faq.md#what-is-a-board)/[shields](faq.md#what-is-a-shield) that have been implemented and tested by the ZMK contributors, listed below. + + + + + Other Hardware + + +In addition to the basic keyboard functionality, there is also support for additional keyboard hardware such as encoders, RGB underglow, backlight and displays. +Please see pages under the "Features" header in the sidebar for details. + + + Contributing + + +If you'd like to add support for a new keyboard shield, head over to the [New Keyboard Shield](development/new-shield.md) documentation and note the [clean room design requirements](development/clean-room.md). diff --git a/docs/docs/intro.md b/docs/docs/intro.md new file mode 100644 index 000000000000..d65ac46e405b --- /dev/null +++ b/docs/docs/intro.md @@ -0,0 +1,53 @@ +--- +title: Introduction to ZMK +sidebar_label: Introduction +slug: / +--- + +ZMK Firmware is an open source (MIT) keyboard +firmware built on the [Zephyr™ Project](https://zephyrproject.org/) Real Time Operating System (RTOS). ZMK's goal is to provide a modern, wireless, and powerful firmware free of licensing issues. + +## Features + +ZMK is currently missing some features found in other popular firmware. This table compares the features supported by ZMK, BlueMicro and QMK: + +| Legend: | ✅ Supported | 🚧 Under Development | 💡 Planned | +| :------ | :----------- | :------------------- | :--------- | + +| **Feature** | ZMK | BlueMicro | QMK | +| ---------------------------------------------------------------------------------------------------------------------------------- | :-: | :-------: | :-: | +| Low Latency BLE Support | ✅ | ✅ | | +| Multi-Device BLE Support | ✅ | | | +| [USB Connectivity](behaviors/outputs.md) | ✅ | ✅ | ✅ | +| User Configuration Repositories | ✅ | | | +| Split Keyboard Support | ✅ | ✅ | ✅ | +| [Keymaps and Layers](behaviors/layers.md) | ✅ | ✅ | ✅ | +| [Hold-Tap](behaviors/hold-tap.md) (which includes [Mod-Tap](behaviors/mod-tap.md) and [Layer-Tap](behaviors/layers.md/#layer-tap)) | ✅ | ✅ | ✅ | +| [Tap-Dance](behaviors/tap-dance.md) | ✅ | ✅[^2] | ✅ | +| [Keyboard Codes](codes/index.mdx#keyboard) | ✅ | ✅ | ✅ | +| [Media](codes/index.mdx#media-controls) & [Consumer](codes/index.mdx#consumer-controls) Codes | ✅ | ✅ | ✅ | +| [Encoders](features/encoders.md) | ✅ | ✅ | ✅ | +| [Display Support](features/displays.md)[^1] | 🚧 | 🚧 | ✅ | +| [RGB Underglow](features/underglow.md) | ✅ | ✅ | ✅ | +| [Backlight](features/backlight.md) | ✅ | ✅ | ✅ | +| One Shot Keys | ✅ | ✅ | ✅ | +| [Combo Keys](features/combos.md) | ✅ | | ✅ | +| [Macros](behaviors/macros.md) | ✅ | ✅ | ✅ | +| Mouse Keys | 🚧 | ✅ | ✅ | +| Low Active Power Usage | ✅ | | | +| Low Power Sleep States | ✅ | ✅ | | +| [Low Power Mode (VCC Shutoff)](behaviors/power.md) | ✅ | ✅ | | +| Battery Reporting | ✅ | ✅ | | +| Shell over BLE | 💡 | | | +| Realtime Keymap Updating | 💡 | | ✅ | +| AVR/8 Bit | | | ✅ | +| [Wide Range of ARM Chips Supported](https://docs.zephyrproject.org/latest/boards/index.html) | ✅ | | | + +[^2]: Tap-Dances are limited to single and double-tap on BlueMicro +[^1]: OLEDs are currently proof of concept in ZMK. + +## Code Of Conduct + +Please note that this project is released with a +[Contributor Code of Conduct](https://www.contributor-covenant.org/version/2/0/code_of_conduct/). +By participating in this project you agree to abide by its terms. diff --git a/docs/docs/keymap-example-file.md b/docs/docs/keymap-example-file.md new file mode 100644 index 000000000000..91213f1510bf --- /dev/null +++ b/docs/docs/keymap-example-file.md @@ -0,0 +1,26 @@ +```dts +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// -------------------------------------------------------------------------------------------------------------------------------------------------------------------- +// | ESC | Q | W | E | R | T | | Y | U | I | O | P | \ | +// | TAB | A | S | D | F | G | | H | J | K | L | ; | ' | +// | SHIFT | Z | X | C | V | B | CTRL+A | CTRL+C | | CTRL+V | CTRL+X | N | M | , | . | / | R CTRL | +// | GUI | DEL | RETURN | SPACE | ESCAPE | | RETURN | SPACE | TAB | BSPC | R ALT | + bindings = < + &kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSLH + &kp TAB &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LSHIFT &kp Z &kp X &kp C &kp V &kp B &kp LC(A) &kp LC(C) &kp LC(V) &kp LC(X) &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RCTRL + &kp LGUI &kp DEL &kp RET &kp SPACE &kp ESC &kp RET &kp SPACE &kp TAB &kp BSPC &kp RALT + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + }; +}; +``` diff --git a/docs/docs/keymap-example.md b/docs/docs/keymap-example.md new file mode 100644 index 000000000000..e526d5427a90 --- /dev/null +++ b/docs/docs/keymap-example.md @@ -0,0 +1,21 @@ +```dts + keymap { + compatible = "zmk,keymap"; + + default_layer { +// -------------------------------------------------------------------------------------------------------------------------------------------------------------------- +// | ESC | Q | W | E | R | T | | Y | U | I | O | P | \ | +// | TAB | A | S | D | F | G | | H | J | K | L | ; | ' | +// | SHIFT | Z | X | C | V | B | CTRL+A | CTRL+C | | CTRL+V | CTRL+X | N | M | , | . | / | R CTRL | +// | GUI | DEL | RETURN | SPACE | ESCAPE | | RETURN | SPACE | TAB | BSPC | R ALT | + bindings = < + &kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSLH + &kp TAB &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LSHIFT &kp Z &kp X &kp C &kp V &kp B &kp LC(A) &kp LC(C) &kp LC(V) &kp LC(X) &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RCTRL + &kp LGUI &kp DEL &kp RET &kp SPACE &kp ESC &kp RET &kp SPACE &kp TAB &kp BSPC &kp RALT + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + }; +``` diff --git a/docs/docs/troubleshooting.md b/docs/docs/troubleshooting.md new file mode 100644 index 000000000000..1418f327febf --- /dev/null +++ b/docs/docs/troubleshooting.md @@ -0,0 +1,108 @@ +--- +title: Troubleshooting +sidebar_title: Troubleshooting +--- + +The following page provides suggestions for common errors that may occur during firmware compilation or other issues with keyboard usage. If the information provided is insufficient to resolve the issue, feel free to seek out help from the [ZMK Discord](https://zmk.dev/community/discord/invite). + +Please also see [the troubleshooting section](features/bluetooth.md#troubleshooting) under the Bluetooth feature page for issues related to bluetooth. + +### File Transfer Error + +Variations of the warnings shown below occur when flashing the `.uf2` onto the microcontroller. This is because the microcontroller resets itself before the OS receives confirmation that the file transfer is complete. Errors like this are normal and can generally be ignored. Verification of a functional board can be done by attempting to pair your newly flashed keyboard to your computer via Bluetooth or plugging in a USB cable if `ZMK_USB` is enabled in your Kconfig.defconfig. + +| ![Example Error Screen](../docs/assets/troubleshooting/filetransfer/windows.png) | +| :------------------------------------------------------------------------------: | +| An example of the file transfer error on Windows 10 | + +| ![Example Error Screen](../docs/assets/troubleshooting/filetransfer/linux.png) | +| :----------------------------------------------------------------------------: | +| An example of the file transfer error on Linux | + +| ![Example Error Screen](../docs/assets/troubleshooting/filetransfer/mac.png) | +| :--------------------------------------------------------------------------: | +| An example of the file transfer error on macOS | + +### macOS Ventura error + +macOS 13.0 (Ventura) Finder may report an error code 100093 when copying `.uf2` files into microcontrollers. This bug is limited to the operating system's Finder. You can work around it by copying on Terminal command line or use a third party file manager. Issue is fixed in macOS version 13.1. + +### CMake Error + +An error along the lines of `CMake Error at (zmk directory)/zephyr/cmake/generic_toolchain.cmake:64 (include): include could not find load file:` during firmware compilation indicates that the Zephyr Environment Variables are not properly defined. +For more information, click [here](../docs/development/setup.md#environment-variables). + +### West Build Errors + +West build errors usually indicate syntax problems in the `.keymap` file during the compilation process. The following are some examples and root causes. + +:::note +If you are reviewing these errors in the GitHub Actions tab, they can be found in the `West Build` step of the build process. +::: + +#### devicetree error + +A `devicetree error` followed by a reference to the line number on `.keymap` refers to an issue at the exact line position in that file. For example, below error message indicates a missing `;` at line 109 of the `cradio.keymap` file: + +``` +devicetree error: /__w/zmk-config/zmk-config/config/cradio.keymap:109 (column 4): parse error: expected ';' or ',' +``` + +#### devicetree_unfixed.h error + +A `devicetree_unfixed.h` error that follows with an "undeclared here" string indicates a problem with key bindings, like behavior nodes (e.g. `&kp` or `&mt`) with incorrect number of parameters: + +``` +/__w/zmk-config/zmk-config/build/zephyr/include/generated/devicetree_unfixed.h:3756:145: error: 'DT_N_S_keymap_S_symbol_layer_P_bindings_IDX_12_PH_P_label' undeclared here (not in a function); did you mean 'DT_N_S_keymap_S_symbol_layer_P_bindings_IDX_16_PH'? +``` + +In this example, the error string `DT_N_S_keymap_S_symbol_layer_P_bindings_IDX_12_PH_P_label` indicates a problem with the key binding in position `12` in the `symbol_layer` of the keymap. + +:::info +Key positions are numbered starting from `0` at the top left key on the keymap, incrementing horizontally, row by row. +::: + +:::tip +A common mistake that leads to this error is to use [key press keycodes](behaviors/key-press.md) without the leading `&kp` binding. That is, having entries such as `SPACE` that should have been `&kp SPACE`. +::: + +### Split Keyboard Halves Unable to Pair + +Split keyboard halves pairing issue can be resolved by flashing a settings reset firmware to both controllers. You will first need to acquire the reset UF2 image file with one of the following options: + +#### Option 1: Build Reset UF2 in 'zmk-config' + +Find the `build.yaml` file in your `zmk-config` folder and add an additional settings reset build for the board used by your split keyboard. For example assuming that the config repo is setup for nice!nano v2 with Corne, append the `settings_reset` shield to the `build.yaml` file as follows: + +```yml +include: + - board: nice_nano_v2 + shield: corne_left + - board: nice_nano_v2 + shield: corne_right + - board: nice_nano_v2 + shield: settings_reset +``` + +Save the file, commit the changes and push them to GitHub. Download the new firmware zip file build by the latest GitHub Actions job. In it you will find an additional `settings_reset` UF2 image file. + +#### Option 2: Download Reset UF2 from ZMK's Workflow + +1. [Open the GitHub `Actions` tab and select the `Build` workflow](https://github.com/zmkfirmware/zmk/actions?query=workflow%3ABuild+branch%3Amain+event%3Apush). +1. Find one of the 'results' for which the core-coverage job was successfully run, indicated by a green checkmark in the core-coverage bubble like the image example below. +1. From the next page under "Artifacts", download and unzip the `-settings_reset-zmk` zip file for the UF2 image. + +| ![Successful core-coverage Job](../docs/assets/troubleshooting/splitpairing/corecoverage.png) | +| :-------------------------------------------------------------------------------------------: | +| An example of a successful core-coverage job which will produce a settings_reset firmware. | + +#### Reset Split Keyboard Procedure + +Perform the following steps to reset both halves of your split keyboard: + +1. Put each half of the split keyboard into bootloader mode. +1. Flash one of the halves of the split with the downloaded settings reset UF2 image. Immediately after flashing the chosen half, put it into bootloader mode to avoid accidental bonding between the halves. +1. Repeat step 2 with the other half of the split keyboard. +1. Flash the actual image for each half of the split keyboard (e.g `my_board_left.uf2` to the left half, `my_board_right.uf2` to the right half). + +After completing these steps, pair the halves of the split keyboard together by resetting them at the same time. Most commonly, this is done by grounding the reset pins for each of your keyboard's microcontrollers or pressing the reset buttons at the same time. diff --git a/docs/docs/user-setup.md b/docs/docs/user-setup.md new file mode 100644 index 000000000000..2532fe8b128c --- /dev/null +++ b/docs/docs/user-setup.md @@ -0,0 +1,229 @@ +--- +title: Installing ZMK +sidebar_label: Installing ZMK +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +Unlike other keyboard firmwares, ZMK Firmware has been built from the ground up to allow users to manage +their own keyboard configurations, including keymaps, specific hardware details, etc. all outside of the +core ZMK Firmware source repository. + +In addition to this, most users will not need to install any complicated toolchains or tools to build ZMK. GitHub Actions is used instead to automatically build the user's configured firmware for them. + +## Summary + +The following steps can be taken to obtain an installable firmware image for your device, without the need +to install any compiler or specialized toolchain. This is possible by leveraging [GitHub Actions](https://github.com/features/actions) +to build your firmware for you in the cloud, which you can then download and flash to your device. + +Following the steps in this guide, you will: + +1. Create a new repository in GitHub that will contain your user config. +1. Download and run a small shell script that will automate most of the setup. The script will: + 1. Prompt you for which board (e.g. nice!nano) and shield (e.g. Lily58 or Kyria) you want to create a configuration for. + 1. Prompt you for your GitHub username and repo where the config should be pushed. + 1. Use `git` to clone a template repository that will be the basis for your user's config repository. + 1. Use the given board and shield to update the included GitHub Action to build for the correct hardware. + 1. Commit the initial version. + 1. (If info was provided) Push the local repo to your GitHub repository. +1. Add your own keymap overlay (`keymap.overlay`) file to the repository, and change your keymap. +1. Update the configuration flags for your user config, to enable/disable any ZMK features you would like to include. +1. Commit and push the updates to trigger a new GitHub Action run. + +## Prerequisites + +The remainder of this guide assumes the following prerequisites: + +1. You have an active, working [GitHub](https://github.com/) account. +1. You have installed and configured the [`git`](https://git-scm.com/) version control tool. +1. You have locally configured git to access your github account. If using [personal access tokens](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token), please be sure it was created with the "workflow" scope option selected. + +:::note +If you need to, a quick read of [Learn The Basics Of Git In Under 10 Minutes](https://www.freecodecamp.org/news/learn-the-basics-of-git-in-under-10-minutes-da548267cc91/) will help you get started. +::: + +## GitHub Repo + +Before running the setup script, you will first need to create a new GitHub repository to host the config. + +1. Navigate to [https://github.com/new](https://github.com/new) +1. When prompted for the repo name, enter `zmk-config`. +1. The repository can be public or private +1. Do **not** check any of the options to initialize the repository with a README or other files. +1. Click "Create repository" + +## User Config Setup Script + +To start the setup process, run the following from your command line prompt: + + + + +```bash +bash -c "$(curl -fsSL https://zmk.dev/setup.sh)" +``` + + + + +```bash +bash -c "$(wget https://zmk.dev/setup.sh -O -)" '' --wget +``` + + + + +```powershell +powershell -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://zmk.dev/setup.ps1'))" +``` + + + + +### Keyboard Selection + +When prompted, enter the number for the corresponding keyboard you would like to target: + +``` +Keyboard Selection: + 1) 2% Milk 19) Ferris 0.2 37) Nibble + 2) A. Dux 20) Fourier Rev. 1 38) nice!60 + 3) BAT43 21) Helix 39) Osprette + 4) BDN9 Rev2 22) Hummingbird 40) Pancake + 5) BFO-9000 23) Iris 41) Planck Rev6 + 6) Boardsource 3x4 Macropad 24) etc... +Pick an keyboard: +``` + +:::note For a keyboard not in the included list: +If you are building firmware for a new keyboard that is not included in the built-in +list of keyboards, you can choose any keyboard from the list that is similar to yours (e.g. in terms of unibody/split and [onboard controller](hardware.mdx#onboard)/[composite](hardware.mdx#composite)) to generate the repository, +and edit / add necessary files. You can follow the [new shield guide](development/new-shield.md) if you are adding support for a composite keyboard. +::: + +### MCU Board Selection + +If the keyboard selected uses an onboard controller you will skip this step. +When prompted, enter the number for the corresponding MCU board you would like to target: + +``` +MCU Board Selection: +1) BlueMicro840 v1 5) nRF52840 M.2 Module 9) QMK Proton-C +2) Mikoto 5.20 6) nRFMicro 1.1 (flipped) 10) Seeeduino XIAO +3) nice!nano v1 7) nRFMicro 1.1/1.2 11) Seeeduino XIAO BLE +4) nice!nano v2 8) nRFMicro 1.3/1.4 12) Quit +Pick an MCU board: +``` + +### Keymap Customization + +At the next prompt, you have an opportunity to decide if you want the stock keymap file copied in +for further customization: + +``` +Copy in the stock keymap for customization? [Yn]: +``` + +Hit `Enter` or type `yes`/`y` to accept this. If you want to keep the stock keymap, or write a keymap +from scratch, type in `no`/`n`. + +### GitHub Details + +In order to have your new configuration automatically pushed, and then built using GitHub Actions, enter +some information about your particular GitHub info: + +``` +GitHub Username (leave empty to skip GitHub repo creation): petejohanson +GitHub Repo Name: zmk-config +GitHub Repo: https://github.com/petejohanson/zmk-config.git +``` + +Only the GitHub username is required; if you are happy with the defaults offered in the square brackets, you can simply hit `Enter`. + +:::note +If you are using SSH keys for git push, change GitHub Repo field to the SSH scheme, e.g. `git@github.com:petejohanson/zmk-config.git`. +::: + +### Confirming Selections + +The setup script will confirm all of your selections one last time, before performing the setup: + +``` +Preparing a user config for: +* MCU Board: nice_nano +* Shield: kyria +* GitHub Repo To Push (please create this in GH first!): https://github.com/petejohanson/zmk-config.git + +Continue? [Yn]: +``` + +After hitting `Enter` or typing `y`, the script will create an initial config in a directory named after the repo name, +update the GitHub Action YAML file, commit the initial version, and then push to your repo. + +:::info + +If you used the default GitHub repo URL using the `https://` scheme, you may be prompted for your username + password in order to +push the initial commit. + +::: + +## Installing The Firmware + +### Download The Archive + +Once the setup script is complete and the new user config repository has been pushed, GitHub will automatically run the action +to build your keyboard firmware files. You can view the actions by clicking on the "Actions" tab on your GitHub repository. + +![](./assets/user-setup/github-actions-link.png) + +Once you have loaded the Actions tab, select the top build from the list. Once you load it, the right side panel will include +a link to download the `firmware` upload: + +![](./assets/user-setup/firmware-archive.png) + +Once downloaded, extract the zip and you can verify it should contain one or more `uf2` files, which will be copied to +your keyboard. + +### Flashing UF2 Files + +To flash the firmware, first put your board into bootloader mode by double clicking the reset button (either on the MCU board itself, +or the one that is part of your keyboard). The controller should appear in your OS as a new USB storage device. + +Once this happens, copy the correct UF2 file (e.g. left or right if working on a split), and paste it onto the root of that USB mass +storage device. Once the flash is complete, the controller should unmount the USB storage, automatically restart and load your newly +flashed firmware. It is recommended that you test your keyboard works over USB first to rule out hardware issues, before trying to +connect to it wirelessly. + +:::caution Split keyboards + +For split keyboards, only the central half (typically the left side) will send keyboard outputs over USB or advertise to other devices +over bluetooth. Peripheral half will only send keystrokes to the central once they are paired and connected. For this reason it is +recommended to test the left half of a split keyboard first. + +::: + +## Wirelessly Connecting Your Keyboard + +ZMK will automatically advertise itself as connectable if it is not currently connected to a device. You should be able to see your keyboard from the bluetooth scanning view of your computer or phone / tablet. It is reported by some users that the connections with Android / iOS devices are generally smoother than with laptops, so if you have trouble connecting, you could try to connect from your phone or tablet first to eliminate any potential hardware issues with bluetooth receivers. + +ZMK supports multiple BLE “profiles”, which allows you to connect to and switch among multiple devices. Please refer to the [Bluetooth behavior](behaviors/bluetooth.md) section for detailed explanations on how to use them. If you don't make use of the mentioned behaviors you will have issues pairing your keyboard to other devices. + +### Connecting Split Keyboard Halves + +For split keyboards, after flashing each half individually you can connect them together by resetting them at the same time. Within a few seconds of resetting, both halves should automatically connect to each other. + +:::note + +If you have issues connecting the halves, make sure that both sides are getting powered properly through USB or batteries, then follow the +[recommended troubleshooting procedure](troubleshooting.md#split-keyboard-halves-unable-to-pair). This is typically necessary if you +swapped firmware sides between controllers, like flashing left side firmware to the same controller after flashing the right, or vice versa. + +::: diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js new file mode 100644 index 000000000000..20e6a75c90fb --- /dev/null +++ b/docs/docusaurus.config.js @@ -0,0 +1,160 @@ +const path = require("path"); +const theme = require("./src/theme/prism/themes/github"); +const darkTheme = require("./src/theme/prism/themes/github-dark-dimmed"); + +module.exports = { + title: "ZMK Firmware", + tagline: "Modern, open source keyboard firmware", + url: "https://zmk.dev", + baseUrl: "/", + favicon: "img/favicon.ico", + trailingSlash: "false", + organizationName: "zmkfirmware", // Usually your GitHub org/user name. + projectName: "zmk", // Usually your repo name. + plugins: [ + path.resolve(__dirname, "src/docusaurus-tree-sitter-plugin"), + path.resolve(__dirname, "src/hardware-metadata-collection-plugin"), + path.resolve(__dirname, "src/hardware-metadata-static-plugin"), + path.resolve(__dirname, "src/hardware-schema-typescript-plugin"), + path.resolve(__dirname, "src/setup-script-generation-plugin"), + ], + themeConfig: { + colorMode: { + respectPrefersColorScheme: true, + }, + prism: { + additionalLanguages: [ + "bash", + "c", + "cmake", + "ini", + "linker-script", + "log", + "powershell", + ], + theme, + darkTheme, + }, + // sidebarCollapsible: false, + navbar: { + title: "ZMK Firmware", + logo: { + alt: "ZMK Logo", + src: "img/zmk_logo.svg", + }, + items: [ + { + to: "docs", + activeBasePath: "docs", + label: "Docs", + position: "left", + }, + { to: "blog", label: "Blog", position: "left" }, + { + to: "power-profiler", + label: "Power Profiler", + position: "left", + }, + { + href: "https://github.com/zmkfirmware/zmk", + label: "GitHub", + position: "right", + }, + ], + }, + footer: { + style: "dark", + links: [ + { + title: "Docs", + items: [ + { + label: "Getting Started", + to: "docs/", + }, + { + label: "Development", + to: "docs/development/setup/", + }, + ], + }, + { + title: "Community", + items: [ + // { + // label: "Stack Overflow", + // href: "https://stackoverflow.com/questions/tagged/docusaurus", + // }, + { + label: "Discord", + href: + (process.env.URL || "https://zmk.dev") + + "/community/discord/invite", + }, + { + label: "Twitter", + href: "https://twitter.com/ZMKFirmware", + }, + ], + }, + { + title: "More", + items: [ + { + label: "Blog", + to: "blog", + }, + { + label: "GitHub", + href: "https://github.com/zmkfirmware/zmk", + }, + { + html: ` + + Deploys by Netlify + + `, + }, + ], + }, + ], + copyright: `Copyright © ${new Date().getFullYear()} ZMK Project Contributors. Creative Commons License`, + }, + algolia: { + appId: "USXLDJ14JE", + apiKey: "384a3bd2d50136c9dc8c8ddfe1b3a4b2", + indexName: "zmkfirmware", + }, + }, + presets: [ + [ + "@docusaurus/preset-classic", + { + googleAnalytics: { + trackingID: "UA-145201102-2", + anonymizeIP: true, + }, + docs: { + // Removed (for now) until we have content for each level of the generated breadcrumbs + breadcrumbs: false, + // It is recommended to set document id as docs home page (`docs/` path). + sidebarPath: require.resolve("./sidebars.js"), + // Please change this to your repo. + editUrl: "https://github.com/zmkfirmware/zmk/edit/main/docs/", + }, + blog: { + showReadingTime: true, + // Please change this to your repo. + editUrl: "https://github.com/zmkfirmware/zmk/edit/main/docs/", + blogSidebarCount: "ALL", + }, + theme: { + customCss: [ + require.resolve("./src/css/custom.css"), + require.resolve("./src/css/codes.css"), + ], + }, + }, + ], + ], +}; diff --git a/docs/netlify.toml b/docs/netlify.toml new file mode 100644 index 000000000000..874620061e5f --- /dev/null +++ b/docs/netlify.toml @@ -0,0 +1,22 @@ +[build] + ignore = "git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF . ../app/boards/" + +[[redirects]] + from = "/community/discord/invite" + to = "https://discord.gg/sycytVQ" + status = 302 + +[[redirects]] + from = "https://zmkfirmware.dev/*" + to = "https://zmk.dev/:splat" + force = true + +[[redirects]] + from = "https://www.zmkfirmware.dev/*" + to = "https://www.zmk.dev/:splat" + force = true + +[[headers]] + for = "/hardware-metadata.json" + [headers.values] + Access-Control-Allow-Origin = "*" \ No newline at end of file diff --git a/docs/package-lock.json b/docs/package-lock.json new file mode 100644 index 000000000000..6e5973726bf9 --- /dev/null +++ b/docs/package-lock.json @@ -0,0 +1,28300 @@ +{ + "name": "docs", + "version": "0.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "docs", + "version": "0.0.0", + "dependencies": { + "@docusaurus/core": "^2.4.0", + "@docusaurus/preset-classic": "^2.4.0", + "@fortawesome/fontawesome-svg-core": "^6.4.2", + "@fortawesome/free-solid-svg-icons": "^6.4.0", + "@fortawesome/react-fontawesome": "^0.2.0", + "@mdx-js/react": "^1.6.22", + "classnames": "^2.2.6", + "js-yaml": "^4.1.0", + "react": "^17.0.2", + "react-async": "^10.0.1", + "react-copy-to-clipboard": "^5.0.3", + "react-dom": "^17.0.2", + "react-toastify": "^7.0.4", + "web-tree-sitter": "^0.20.8" + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "^2.4.0", + "@docusaurus/types": "^2.4.0", + "@tsconfig/docusaurus": "^1.0.7", + "@types/js-yaml": "^4.0.5", + "@types/react": "^17.0.58", + "@types/react-helmet": "^6.1.6", + "@types/react-router-dom": "^5.1.7", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-mdx": "^2.0.5", + "eslint-plugin-react": "^7.33.2", + "json-schema-to-typescript": "^13.1.1", + "mustache": "^4.2.0", + "null-loader": "^4.0.0", + "prebuild-webpack-plugin": "^1.1.1", + "prettier": "^2.8.7", + "string-replace-loader": "^3.1.0", + "typescript": "^5.0.4", + "webpack": "^5.86.0" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.7.4.tgz", + "integrity": "sha512-daoLpQ3ps/VTMRZDEBfU8ixXd+amZcNJ4QSP3IERGyzqnL5Ch8uSRFt/4G8pUvW9c3o6GA4vtVv4I4lmnkdXyg==", + "dependencies": { + "@algolia/autocomplete-shared": "1.7.4" + } + }, + "node_modules/@algolia/autocomplete-preset-algolia": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.7.4.tgz", + "integrity": "sha512-s37hrvLEIfcmKY8VU9LsAXgm2yfmkdHT3DnA3SgHaY93yjZ2qL57wzb5QweVkYuEBZkT2PIREvRoLXC2sxTbpQ==", + "dependencies": { + "@algolia/autocomplete-shared": "1.7.4" + }, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.7.4.tgz", + "integrity": "sha512-2VGCk7I9tA9Ge73Km99+Qg87w0wzW4tgUruvWAn/gfey1ZXgmxZtyIRBebk35R1O8TbK77wujVtCnpsGpRy1kg==" + }, + "node_modules/@algolia/cache-browser-local-storage": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.17.0.tgz", + "integrity": "sha512-myRSRZDIMYB8uCkO+lb40YKiYHi0fjpWRtJpR/dgkaiBlSD0plRyB6lLOh1XIfmMcSeBOqDE7y9m8xZMrXYfyQ==", + "dependencies": { + "@algolia/cache-common": "4.17.0" + } + }, + "node_modules/@algolia/cache-common": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.17.0.tgz", + "integrity": "sha512-g8mXzkrcUBIPZaulAuqE7xyHhLAYAcF2xSch7d9dABheybaU3U91LjBX6eJTEB7XVhEsgK4Smi27vWtAJRhIKQ==" + }, + "node_modules/@algolia/cache-in-memory": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.17.0.tgz", + "integrity": "sha512-PT32ciC/xI8z919d0oknWVu3kMfTlhQn3MKxDln3pkn+yA7F7xrxSALysxquv+MhFfNAcrtQ/oVvQVBAQSHtdw==", + "dependencies": { + "@algolia/cache-common": "4.17.0" + } + }, + "node_modules/@algolia/client-account": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.17.0.tgz", + "integrity": "sha512-sSEHx9GA6m7wrlsSMNBGfyzlIfDT2fkz2u7jqfCCd6JEEwmxt8emGmxAU/0qBfbhRSuGvzojoLJlr83BSZAKjA==", + "dependencies": { + "@algolia/client-common": "4.17.0", + "@algolia/client-search": "4.17.0", + "@algolia/transporter": "4.17.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.17.0.tgz", + "integrity": "sha512-84ooP8QA3mQ958hQ9wozk7hFUbAO+81CX1CjAuerxBqjKIInh1fOhXKTaku05O/GHBvcfExpPLIQuSuLYziBXQ==", + "dependencies": { + "@algolia/client-common": "4.17.0", + "@algolia/client-search": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.17.0.tgz", + "integrity": "sha512-jHMks0ZFicf8nRDn6ma8DNNsdwGgP/NKiAAL9z6rS7CymJ7L0+QqTJl3rYxRW7TmBhsUH40wqzmrG6aMIN/DrQ==", + "dependencies": { + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.17.0.tgz", + "integrity": "sha512-RMzN4dZLIta1YuwT7QC9o+OeGz2cU6eTOlGNE/6RcUBLOU3l9tkCOdln5dPE2jp8GZXPl2yk54b2nSs1+pAjqw==", + "dependencies": { + "@algolia/client-common": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.17.0.tgz", + "integrity": "sha512-x4P2wKrrRIXszT8gb7eWsMHNNHAJs0wE7/uqbufm4tZenAp+hwU/hq5KVsY50v+PfwM0LcDwwn/1DroujsTFoA==", + "dependencies": { + "@algolia/client-common": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" + } + }, + "node_modules/@algolia/events": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz", + "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==" + }, + "node_modules/@algolia/logger-common": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.17.0.tgz", + "integrity": "sha512-DGuoZqpTmIKJFDeyAJ7M8E/LOenIjWiOsg1XJ1OqAU/eofp49JfqXxbfgctlVZVmDABIyOz8LqEoJ6ZP4DTyvw==" + }, + "node_modules/@algolia/logger-console": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.17.0.tgz", + "integrity": "sha512-zMPvugQV/gbXUvWBCzihw6m7oxIKp48w37QBIUu/XqQQfxhjoOE9xyfJr1KldUt5FrYOKZJVsJaEjTsu+bIgQg==", + "dependencies": { + "@algolia/logger-common": "4.17.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.17.0.tgz", + "integrity": "sha512-aSOX/smauyTkP21Pf52pJ1O2LmNFJ5iHRIzEeTh0mwBeADO4GdG94cAWDILFA9rNblq/nK3EDh3+UyHHjplZ1A==", + "dependencies": { + "@algolia/requester-common": "4.17.0" + } + }, + "node_modules/@algolia/requester-common": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.17.0.tgz", + "integrity": "sha512-XJjmWFEUlHu0ijvcHBoixuXfEoiRUdyzQM6YwTuB8usJNIgShua8ouFlRWF8iCeag0vZZiUm4S2WCVBPkdxFgg==" + }, + "node_modules/@algolia/requester-node-http": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.17.0.tgz", + "integrity": "sha512-bpb/wDA1aC6WxxM8v7TsFspB7yBN3nqCGs2H1OADolQR/hiAIjAxusbuMxVbRFOdaUvAIqioIIkWvZdpYNIn8w==", + "dependencies": { + "@algolia/requester-common": "4.17.0" + } + }, + "node_modules/@algolia/transporter": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.17.0.tgz", + "integrity": "sha512-6xL6H6fe+Fi0AEP3ziSgC+G04RK37iRb4uUUqVAH9WPYFI8g+LYFq6iv5HS8Cbuc5TTut+Bwj6G+dh/asdb9uA==", + "dependencies": { + "@algolia/cache-common": "4.17.0", + "@algolia/logger-common": "4.17.0", + "@algolia/requester-common": "4.17.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.4.tgz", + "integrity": "sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", + "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.6", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helpers": "^7.19.4", + "@babel/parser": "^7.19.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.6.tgz", + "integrity": "sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA==", + "dependencies": { + "@babel/types": "^7.19.4", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "dependencies": { + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz", + "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==", + "dependencies": { + "@babel/compat-data": "^7.19.3", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz", + "integrity": "sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", + "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", + "dependencies": { + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz", + "integrity": "sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.19.4", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", + "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", + "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", + "dependencies": { + "@babel/types": "^7.19.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz", + "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", + "dependencies": { + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", + "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", + "dependencies": { + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.4.tgz", + "integrity": "sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw==", + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.4", + "@babel/types": "^7.19.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz", + "integrity": "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.1.tgz", + "integrity": "sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-static-block": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", + "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-proposal-dynamic-import": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-json-strings": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.19.4.tgz", + "integrity": "sha512-wHmj6LDxVDnL+3WhXteUBaoM1aVILZODAUjg11kHqG4cOlfgMQGxw6aCgvrXrmaJR3Bn14oZhImyCPZzRpC93Q==", + "dependencies": { + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.18.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", + "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz", + "integrity": "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", + "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", + "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.19.4.tgz", + "integrity": "sha512-934S2VLLlt2hRJwPf4MczaOr4hYF0z+VKPwqTNxyKX7NthTiPfhuKFWQZHXRM0vh/wo/VyXB3s4bZUNA08l+tQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz", + "integrity": "sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.19.0", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.19.4.tgz", + "integrity": "sha512-t0j0Hgidqf0aM86dF8U+vXYReUgJnlv4bZLsyoPnwZNrGY+7/38o8YjaELrvHeVfTZao15kjR0PVv0nju2iduA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.19.6.tgz", + "integrity": "sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg==", + "dependencies": { + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.19.6.tgz", + "integrity": "sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==", + "dependencies": { + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-simple-access": "^7.19.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.6.tgz", + "integrity": "sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==", + "dependencies": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-identifier": "^7.19.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "dependencies": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", + "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz", + "integrity": "sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.18.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.18.12.tgz", + "integrity": "sha512-Q99U9/ttiu+LMnRU8psd23HhvwXmKWDQIpocm0JKaICcZHnw+mdQbHm6xnSy7dOl8I5PELakYtNBubNQlBXbZw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz", + "integrity": "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.19.0.tgz", + "integrity": "sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/plugin-syntax-jsx": "^7.18.6", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz", + "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz", + "integrity": "sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", + "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "regenerator-transform": "^0.15.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz", + "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==", + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", + "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.19.3.tgz", + "integrity": "sha512-z6fnuK9ve9u/0X0rRvI9MY0xg+DOUaABDYOe+/SQTxtlptaBB/V9JIUxJn6xp3lMBeb9qe8xSFmHU35oZDXD+w==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/plugin-syntax-typescript": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.4.tgz", + "integrity": "sha512-5QVOTXUdqTCjQuh2GGtdd7YEhoRXBMVGROAtsBeLGIbIz3obCBIfRMT1I3ZKkMgNzwkyCkftDXSSkHxnfVf4qg==", + "dependencies": { + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.19.1", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.19.4", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.19.4", + "@babel/plugin-transform-classes": "^7.19.0", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.19.4", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.19.0", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.8", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.19.0", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.19.4", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "core-js-compat": "^3.25.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.18.6.tgz", + "integrity": "sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-react-display-name": "^7.18.6", + "@babel/plugin-transform-react-jsx": "^7.18.6", + "@babel/plugin-transform-react-jsx-development": "^7.18.6", + "@babel/plugin-transform-react-pure-annotations": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz", + "integrity": "sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-typescript": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "dependencies": { + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.6.tgz", + "integrity": "sha512-oWNn1ZlGde7b4i/3tnixpH9qI0bOAACiUs+KEES4UUCnsPjVWFlWdLV/iwJuPC2qp3EowbAqsm+0XqNwnwYhxA==", + "dependencies": { + "core-js-pure": "^3.25.1", + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.6.tgz", + "integrity": "sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ==", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.19.6", + "@babel/types": "^7.19.4", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcherny/json-schema-ref-parser": { + "version": "10.0.5-fork", + "resolved": "https://registry.npmjs.org/@bcherny/json-schema-ref-parser/-/json-schema-ref-parser-10.0.5-fork.tgz", + "integrity": "sha512-E/jKbPoca1tfUPj3iSbitDZTGnq6FUFjkH6L8U2oDwSuwK1WhnnVtCG7oFOTg/DDnyoXbQYUiUiGOibHqaGVnw==", + "dev": true, + "dependencies": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.6", + "call-me-maybe": "^1.0.1", + "js-yaml": "^4.1.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/philsturgeon" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@docsearch/css": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.3.3.tgz", + "integrity": "sha512-6SCwI7P8ao+se1TUsdZ7B4XzL+gqeQZnBc+2EONZlcVa0dVrk0NjETxozFKgMv0eEGH8QzP1fkN+A1rH61l4eg==" + }, + "node_modules/@docsearch/react": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.3.3.tgz", + "integrity": "sha512-pLa0cxnl+G0FuIDuYlW+EBK6Rw2jwLw9B1RHIeS4N4s2VhsfJ/wzeCi3CWcs5yVfxLd5ZK50t//TMA5e79YT7Q==", + "dependencies": { + "@algolia/autocomplete-core": "1.7.4", + "@algolia/autocomplete-preset-algolia": "1.7.4", + "@docsearch/css": "3.3.3", + "algoliasearch": "^4.0.0" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 19.0.0", + "react": ">= 16.8.0 < 19.0.0", + "react-dom": ">= 16.8.0 < 19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@docusaurus/core": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.4.0.tgz", + "integrity": "sha512-J55/WEoIpRcLf3afO5POHPguVZosKmJEQWKBL+K7TAnfuE7i+Y0NPLlkKtnWCehagGsgTqClfQEexH/UT4kELA==", + "dependencies": { + "@babel/core": "^7.18.6", + "@babel/generator": "^7.18.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.18.6", + "@babel/preset-env": "^7.18.6", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.18.6", + "@babel/runtime": "^7.18.6", + "@babel/runtime-corejs3": "^7.18.6", + "@babel/traverse": "^7.18.8", + "@docusaurus/cssnano-preset": "2.4.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/react-loadable": "5.5.2", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-common": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "@slorber/static-site-generator-webpack-plugin": "^4.0.7", + "@svgr/webpack": "^6.2.1", + "autoprefixer": "^10.4.7", + "babel-loader": "^8.2.5", + "babel-plugin-dynamic-import-node": "^2.3.3", + "boxen": "^6.2.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "clean-css": "^5.3.0", + "cli-table3": "^0.6.2", + "combine-promises": "^1.1.0", + "commander": "^5.1.0", + "copy-webpack-plugin": "^11.0.0", + "core-js": "^3.23.3", + "css-loader": "^6.7.1", + "css-minimizer-webpack-plugin": "^4.0.0", + "cssnano": "^5.1.12", + "del": "^6.1.1", + "detect-port": "^1.3.0", + "escape-html": "^1.0.3", + "eta": "^2.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^10.1.0", + "html-minifier-terser": "^6.1.0", + "html-tags": "^3.2.0", + "html-webpack-plugin": "^5.5.0", + "import-fresh": "^3.3.0", + "leven": "^3.1.0", + "lodash": "^4.17.21", + "mini-css-extract-plugin": "^2.6.1", + "postcss": "^8.4.14", + "postcss-loader": "^7.0.0", + "prompts": "^2.4.2", + "react-dev-utils": "^12.0.1", + "react-helmet-async": "^1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@5.5.2", + "react-loadable-ssr-addon-v5-slorber": "^1.0.1", + "react-router": "^5.3.3", + "react-router-config": "^5.1.1", + "react-router-dom": "^5.3.3", + "rtl-detect": "^1.0.4", + "semver": "^7.3.7", + "serve-handler": "^6.1.3", + "shelljs": "^0.8.5", + "terser-webpack-plugin": "^5.3.3", + "tslib": "^2.4.0", + "update-notifier": "^5.1.0", + "url-loader": "^4.1.1", + "wait-on": "^6.0.1", + "webpack": "^5.73.0", + "webpack-bundle-analyzer": "^4.5.0", + "webpack-dev-server": "^4.9.3", + "webpack-merge": "^5.8.0", + "webpackbar": "^5.0.2" + }, + "bin": { + "docusaurus": "bin/docusaurus.mjs" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/cssnano-preset": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.4.0.tgz", + "integrity": "sha512-RmdiA3IpsLgZGXRzqnmTbGv43W4OD44PCo+6Q/aYjEM2V57vKCVqNzuafE94jv0z/PjHoXUrjr69SaRymBKYYw==", + "dependencies": { + "cssnano-preset-advanced": "^5.3.8", + "postcss": "^8.4.14", + "postcss-sort-media-queries": "^4.2.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + } + }, + "node_modules/@docusaurus/logger": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-2.4.0.tgz", + "integrity": "sha512-T8+qR4APN+MjcC9yL2Es+xPJ2923S9hpzDmMtdsOcUGLqpCGBbU1vp3AAqDwXtVgFkq+NsEk7sHdVsfLWR/AXw==", + "dependencies": { + "chalk": "^4.1.2", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + } + }, + "node_modules/@docusaurus/mdx-loader": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.4.0.tgz", + "integrity": "sha512-GWoH4izZKOmFoC+gbI2/y8deH/xKLvzz/T5BsEexBye8EHQlwsA7FMrVa48N063bJBH4FUOiRRXxk5rq9cC36g==", + "dependencies": { + "@babel/parser": "^7.18.8", + "@babel/traverse": "^7.18.8", + "@docusaurus/logger": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@mdx-js/mdx": "^1.6.22", + "escape-html": "^1.0.3", + "file-loader": "^6.2.0", + "fs-extra": "^10.1.0", + "image-size": "^1.0.1", + "mdast-util-to-string": "^2.0.0", + "remark-emoji": "^2.2.0", + "stringify-object": "^3.3.0", + "tslib": "^2.4.0", + "unified": "^9.2.2", + "unist-util-visit": "^2.0.3", + "url-loader": "^4.1.1", + "webpack": "^5.73.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/module-type-aliases": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-2.4.0.tgz", + "integrity": "sha512-YEQO2D3UXs72qCn8Cr+RlycSQXVGN9iEUyuHwTuK4/uL/HFomB2FHSU0vSDM23oLd+X/KibQ3Ez6nGjQLqXcHg==", + "dependencies": { + "@docusaurus/react-loadable": "5.5.2", + "@docusaurus/types": "2.4.0", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "@types/react-router-dom": "*", + "react-helmet-async": "*", + "react-loadable": "npm:@docusaurus/react-loadable@5.5.2" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/@docusaurus/plugin-content-blog": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.4.0.tgz", + "integrity": "sha512-YwkAkVUxtxoBAIj/MCb4ohN0SCtHBs4AS75jMhPpf67qf3j+U/4n33cELq7567hwyZ6fMz2GPJcVmctzlGGThQ==", + "dependencies": { + "@docusaurus/core": "2.4.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-common": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "cheerio": "^1.0.0-rc.12", + "feed": "^4.2.2", + "fs-extra": "^10.1.0", + "lodash": "^4.17.21", + "reading-time": "^1.5.0", + "tslib": "^2.4.0", + "unist-util-visit": "^2.0.3", + "utility-types": "^3.10.0", + "webpack": "^5.73.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-docs": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.4.0.tgz", + "integrity": "sha512-ic/Z/ZN5Rk/RQo+Io6rUGpToOtNbtPloMR2JcGwC1xT2riMu6zzfSwmBi9tHJgdXH6CB5jG+0dOZZO8QS5tmDg==", + "dependencies": { + "@docusaurus/core": "2.4.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/module-type-aliases": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "@types/react-router-config": "^5.0.6", + "combine-promises": "^1.1.0", + "fs-extra": "^10.1.0", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "tslib": "^2.4.0", + "utility-types": "^3.10.0", + "webpack": "^5.73.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-pages": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.4.0.tgz", + "integrity": "sha512-Pk2pOeOxk8MeU3mrTU0XLIgP9NZixbdcJmJ7RUFrZp1Aj42nd0RhIT14BGvXXyqb8yTQlk4DmYGAzqOfBsFyGw==", + "dependencies": { + "@docusaurus/core": "2.4.0", + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "fs-extra": "^10.1.0", + "tslib": "^2.4.0", + "webpack": "^5.73.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/plugin-debug": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.4.0.tgz", + "integrity": "sha512-KC56DdYjYT7Txyux71vXHXGYZuP6yYtqwClvYpjKreWIHWus5Zt6VNi23rMZv3/QKhOCrN64zplUbdfQMvddBQ==", + "dependencies": { + "@docusaurus/core": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "fs-extra": "^10.1.0", + "react-json-view": "^1.21.3", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-analytics": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.4.0.tgz", + "integrity": "sha512-uGUzX67DOAIglygdNrmMOvEp8qG03X20jMWadeqVQktS6nADvozpSLGx4J0xbkblhJkUzN21WiilsP9iVP+zkw==", + "dependencies": { + "@docusaurus/core": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-gtag": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.4.0.tgz", + "integrity": "sha512-adj/70DANaQs2+TF/nRdMezDXFAV/O/pjAbUgmKBlyOTq5qoMe0Tk4muvQIwWUmiUQxFJe+sKlZGM771ownyOg==", + "dependencies": { + "@docusaurus/core": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-tag-manager": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.4.0.tgz", + "integrity": "sha512-E66uGcYs4l7yitmp/8kMEVQftFPwV9iC62ORh47Veqzs6ExwnhzBkJmwDnwIysHBF1vlxnzET0Fl2LfL5fRR3A==", + "dependencies": { + "@docusaurus/core": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/plugin-sitemap": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.4.0.tgz", + "integrity": "sha512-pZxh+ygfnI657sN8a/FkYVIAmVv0CGk71QMKqJBOfMmDHNN1FeDeFkBjWP49ejBqpqAhjufkv5UWq3UOu2soCw==", + "dependencies": { + "@docusaurus/core": "2.4.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-common": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "fs-extra": "^10.1.0", + "sitemap": "^7.1.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/preset-classic": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.4.0.tgz", + "integrity": "sha512-/5z5o/9bc6+P5ool2y01PbJhoGddEGsC0ej1MF6mCoazk8A+kW4feoUd68l7Bnv01rCnG3xy7kHUQP97Y0grUA==", + "dependencies": { + "@docusaurus/core": "2.4.0", + "@docusaurus/plugin-content-blog": "2.4.0", + "@docusaurus/plugin-content-docs": "2.4.0", + "@docusaurus/plugin-content-pages": "2.4.0", + "@docusaurus/plugin-debug": "2.4.0", + "@docusaurus/plugin-google-analytics": "2.4.0", + "@docusaurus/plugin-google-gtag": "2.4.0", + "@docusaurus/plugin-google-tag-manager": "2.4.0", + "@docusaurus/plugin-sitemap": "2.4.0", + "@docusaurus/theme-classic": "2.4.0", + "@docusaurus/theme-common": "2.4.0", + "@docusaurus/theme-search-algolia": "2.4.0", + "@docusaurus/types": "2.4.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/react-loadable": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", + "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", + "dependencies": { + "@types/react": "*", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/@docusaurus/theme-classic": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.4.0.tgz", + "integrity": "sha512-GMDX5WU6Z0OC65eQFgl3iNNEbI9IMJz9f6KnOyuMxNUR6q0qVLsKCNopFUDfFNJ55UU50o7P7o21yVhkwpfJ9w==", + "dependencies": { + "@docusaurus/core": "2.4.0", + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/module-type-aliases": "2.4.0", + "@docusaurus/plugin-content-blog": "2.4.0", + "@docusaurus/plugin-content-docs": "2.4.0", + "@docusaurus/plugin-content-pages": "2.4.0", + "@docusaurus/theme-common": "2.4.0", + "@docusaurus/theme-translations": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-common": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "@mdx-js/react": "^1.6.22", + "clsx": "^1.2.1", + "copy-text-to-clipboard": "^3.0.1", + "infima": "0.2.0-alpha.43", + "lodash": "^4.17.21", + "nprogress": "^0.2.0", + "postcss": "^8.4.14", + "prism-react-renderer": "^1.3.5", + "prismjs": "^1.28.0", + "react-router-dom": "^5.3.3", + "rtlcss": "^3.5.0", + "tslib": "^2.4.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/theme-common": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.4.0.tgz", + "integrity": "sha512-IkG/l5f/FLY6cBIxtPmFnxpuPzc5TupuqlOx+XDN+035MdQcAh8wHXXZJAkTeYDeZ3anIUSUIvWa7/nRKoQEfg==", + "dependencies": { + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/module-type-aliases": "2.4.0", + "@docusaurus/plugin-content-blog": "2.4.0", + "@docusaurus/plugin-content-docs": "2.4.0", + "@docusaurus/plugin-content-pages": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-common": "2.4.0", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "clsx": "^1.2.1", + "parse-numeric-range": "^1.3.0", + "prism-react-renderer": "^1.3.5", + "tslib": "^2.4.0", + "use-sync-external-store": "^1.2.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/theme-search-algolia": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.4.0.tgz", + "integrity": "sha512-pPCJSCL1Qt4pu/Z0uxBAuke0yEBbxh0s4fOvimna7TEcBLPq0x06/K78AaABXrTVQM6S0vdocFl9EoNgU17hqA==", + "dependencies": { + "@docsearch/react": "^3.1.1", + "@docusaurus/core": "2.4.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/plugin-content-docs": "2.4.0", + "@docusaurus/theme-common": "2.4.0", + "@docusaurus/theme-translations": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "algoliasearch": "^4.13.1", + "algoliasearch-helper": "^3.10.0", + "clsx": "^1.2.1", + "eta": "^2.0.0", + "fs-extra": "^10.1.0", + "lodash": "^4.17.21", + "tslib": "^2.4.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/theme-translations": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.4.0.tgz", + "integrity": "sha512-kEoITnPXzDPUMBHk3+fzEzbopxLD3fR5sDoayNH0vXkpUukA88/aDL1bqkhxWZHA3LOfJ3f0vJbOwmnXW5v85Q==", + "dependencies": { + "fs-extra": "^10.1.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + } + }, + "node_modules/@docusaurus/types": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-2.4.0.tgz", + "integrity": "sha512-xaBXr+KIPDkIaef06c+i2HeTqVNixB7yFut5fBXPGI2f1rrmEV2vLMznNGsFwvZ5XmA3Quuefd4OGRkdo97Dhw==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.6.0", + "react-helmet-async": "^1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.73.0", + "webpack-merge": "^5.8.0" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.4.0.tgz", + "integrity": "sha512-89hLYkvtRX92j+C+ERYTuSUK6nF9bGM32QThcHPg2EDDHVw6FzYQXmX6/p+pU5SDyyx5nBlE4qXR92RxCAOqfg==", + "dependencies": { + "@docusaurus/logger": "2.4.0", + "@svgr/webpack": "^6.2.1", + "escape-string-regexp": "^4.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^10.1.0", + "github-slugger": "^1.4.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.4.0", + "url-loader": "^4.1.1", + "webpack": "^5.73.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "@docusaurus/types": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } + } + }, + "node_modules/@docusaurus/utils-common": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.4.0.tgz", + "integrity": "sha512-zIMf10xuKxddYfLg5cS19x44zud/E9I7lj3+0bv8UIs0aahpErfNrGhijEfJpAfikhQ8tL3m35nH3hJ3sOG82A==", + "dependencies": { + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "@docusaurus/types": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } + } + }, + "node_modules/@docusaurus/utils-validation": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.4.0.tgz", + "integrity": "sha512-IrBsBbbAp6y7mZdJx4S4pIA7dUyWSA0GNosPk6ZJ0fX3uYIEQgcQSGIgTeSC+8xPEx3c16o03en1jSDpgQgz/w==", + "dependencies": { + "@docusaurus/logger": "2.4.0", + "@docusaurus/utils": "2.4.0", + "joi": "^17.6.0", + "js-yaml": "^4.1.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "devOptional": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", + "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", + "devOptional": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", + "devOptional": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.5.1", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "devOptional": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "devOptional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", + "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", + "devOptional": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz", + "integrity": "sha512-HNii132xfomg5QVZw0HwXXpN22s7VBHQBv9CeOu9tfJnhsWQNd2lmTNi8CSrnw5B+5YOmzu1UoPAyxaXsJ6RgQ==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.2.tgz", + "integrity": "sha512-gjYDSKv3TrM2sLTOKBc5rH9ckje8Wrwgx1CxAPbN5N3Fm4prfi7NsJVWd1jklp7i5uSCVwhZS5qlhMXqLrpAIg==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.4.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core/node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.2.tgz", + "integrity": "sha512-1DgP7f+XQIJbLFCTX1V2QnxVmpLdKdzzo2k8EmvDOePfchaIGQ9eCHj2up3/jNEbZuBqel5OxiaOJf37TWauRA==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.4.0.tgz", + "integrity": "sha512-kutPeRGWm8V5dltFP1zGjQOEAzaLZj4StdQhWVZnfGFCvAPVvHh8qk5bRrU4KXnRRRNni5tKQI9PBAdI6MP8nQ==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.4.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", + "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react": ">=16.3" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "devOptional": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "devOptional": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "devOptional": true + }, + "node_modules/@jest/schemas": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", + "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.2.1.tgz", + "integrity": "sha512-O/QNDQODLnINEPAI0cl9U6zUIDXEWXt6IC1o2N2QENuos7hlGUIthlKyV4p6ki3TvXFX071blj8HUhgLGquPjw==", + "dependencies": { + "@jest/schemas": "^29.0.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", + "dev": true + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" + }, + "node_modules/@mdx-js/mdx": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-1.6.22.tgz", + "integrity": "sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA==", + "dependencies": { + "@babel/core": "7.12.9", + "@babel/plugin-syntax-jsx": "7.12.1", + "@babel/plugin-syntax-object-rest-spread": "7.8.3", + "@mdx-js/util": "1.6.22", + "babel-plugin-apply-mdx-type-prop": "1.6.22", + "babel-plugin-extract-import-names": "1.6.22", + "camelcase-css": "2.0.1", + "detab": "2.0.4", + "hast-util-raw": "6.0.1", + "lodash.uniq": "4.5.0", + "mdast-util-to-hast": "10.0.1", + "remark-footnotes": "2.0.0", + "remark-mdx": "1.6.22", + "remark-parse": "8.0.3", + "remark-squeeze-paragraphs": "4.0.0", + "style-to-object": "0.3.0", + "unified": "9.2.0", + "unist-builder": "2.0.3", + "unist-util-visit": "2.0.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/@babel/core": { + "version": "7.12.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", + "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.5", + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helpers": "^7.12.5", + "@babel/parser": "^7.12.7", + "@babel/template": "^7.12.7", + "@babel/traverse": "^7.12.9", + "@babel/types": "^7.12.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@mdx-js/mdx/node_modules/@babel/plugin-syntax-jsx": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", + "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@mdx-js/mdx/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@mdx-js/mdx/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@mdx-js/mdx/node_modules/unified": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", + "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", + "dependencies": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^2.0.0", + "trough": "^1.0.0", + "vfile": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/vfile": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", + "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-message": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/react": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-1.6.22.tgz", + "integrity": "sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + } + }, + "node_modules/@mdx-js/util": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz", + "integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgr/utils": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz", + "integrity": "sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "is-glob": "^4.0.3", + "open": "^8.4.0", + "picocolors": "^1.0.0", + "tiny-glob": "^0.2.9", + "tslib": "^2.4.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.21", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", + "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==" + }, + "node_modules/@sideway/address": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + }, + "node_modules/@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + }, + "node_modules/@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@slorber/static-site-generator-webpack-plugin": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.7.tgz", + "integrity": "sha512-Ug7x6z5lwrz0WqdnNFOMYrDQNTPAprvHLSh6+/fmml3qUiz6l5eq+2MzLKWtn/q5K5NpSiFsZTP/fck/3vjSxA==", + "dependencies": { + "eval": "^0.1.8", + "p-map": "^4.0.0", + "webpack-sources": "^3.2.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.5.0.tgz", + "integrity": "sha512-Cp1JR1IPrQNvPRbkfcPmax52iunBC+eQDyBce8feOIIbVH6ZpVhErYoJtPWRBj2rKi4Wi9HvCm1+L1UD6QlBmg==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-6.5.0.tgz", + "integrity": "sha512-8zYdkym7qNyfXpWvu4yq46k41pyNM9SOstoWhKlm+IfdCE1DdnRKeMUPsWIEO/DEkaWxJ8T9esNdG3QwQ93jBA==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-6.5.0.tgz", + "integrity": "sha512-NFdxMq3xA42Kb1UbzCVxplUc0iqSyM9X8kopImvFnB+uSDdzIHOdbs1op8ofAvVRtbg4oZiyRl3fTYeKcOe9Iw==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.5.0.tgz", + "integrity": "sha512-XWm64/rSPUCQ+MFyA9lhMO+w8bOZvkTvovRIU1lpIy63ysPaVAFtxjQiZj+S7QaLaLGUXkSkf8WZsaN+QPo/gA==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.5.0.tgz", + "integrity": "sha512-JIF2D2ltiWFGlTw2fJ9jJg1fNT9rWjOD2Cf0/xzeW6Z2LIRQTHcRHxpZq359+SRWtEPsCXEWV2Xmd+DMBj6dBw==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.5.0.tgz", + "integrity": "sha512-uuo0FfLP4Nu2zncOcoUFDzZdXWma2bxkTGk0etRThs4/PghvPIGaW8cPhCg6yJ8zpaauWcKV0wZtzKlJRCtVzg==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.5.0.tgz", + "integrity": "sha512-VMRWyOmrV+DaEFPgP3hZMsFgs2g87ojs3txw0Rx8iz6Nf/E3UoHUwTqpkSCWd3Hsnc9gMOY9+wl6+/Ycleh1sw==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.5.0.tgz", + "integrity": "sha512-b67Ul3SelaqvGEEG/1B3VJ03KUtGFgRQjRLCCjdttMQLcYa9l/izQFEclNFx53pNqhijUMNKHPhGMY/CWGVKig==", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-6.5.0.tgz", + "integrity": "sha512-UWM98PKVuMqw2UZo8YO3erI6nF1n7/XBYTXBqR0QhZP7HTjYK6QxFNvPfIshddy1hBdzhVpkf148Vg8xiVOtyg==", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "^6.5.0", + "@svgr/babel-plugin-remove-jsx-attribute": "^6.5.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "^6.5.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^6.5.0", + "@svgr/babel-plugin-svg-dynamic-title": "^6.5.0", + "@svgr/babel-plugin-svg-em-dimensions": "^6.5.0", + "@svgr/babel-plugin-transform-react-native-svg": "^6.5.0", + "@svgr/babel-plugin-transform-svg-component": "^6.5.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-6.5.0.tgz", + "integrity": "sha512-jIbu36GMjfK8HCCQitkfVVeQ2vSXGfq0ef0GO9HUxZGjal6Kvpkk4PwpkFP+OyCzF+skQFT9aWrUqekT3pKF8w==", + "dependencies": { + "@babel/core": "^7.18.5", + "@svgr/babel-preset": "^6.5.0", + "@svgr/plugin-jsx": "^6.5.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.5.0.tgz", + "integrity": "sha512-PPy94U/EiPQ2dY0b4jEqj4QOdDRq6DG7aTHjpGaL8HlKSHkpU1DpjfywCXTJqtOdCo2FywjWvg0U2FhqMeUJaA==", + "dependencies": { + "@babel/types": "^7.18.4", + "entities": "^4.3.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-6.5.0.tgz", + "integrity": "sha512-1CHMqOBKoNk/ZPU+iGXKcQPC6q9zaD7UOI99J+BaGY5bdCztcf5bZyi0QZSDRJtCQpdofeVv7XfBYov2mtl0Pw==", + "dependencies": { + "@babel/core": "^7.18.5", + "@svgr/babel-preset": "^6.5.0", + "@svgr/hast-util-to-babel-ast": "^6.5.0", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "^6.0.0" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-6.5.0.tgz", + "integrity": "sha512-8Zv1Yyv6I7HlIqrqGFM0sDKQrhjbfNZJawR8UjIaVWSb0tKZP1Ra6ymhqIFu6FT6kDRD0Ct5NlQZ10VUujSspw==", + "dependencies": { + "cosmiconfig": "^7.0.1", + "deepmerge": "^4.2.2", + "svgo": "^2.8.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "^6.0.0" + } + }, + "node_modules/@svgr/webpack": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-6.5.0.tgz", + "integrity": "sha512-rM/Z4pwMhqvAXEHoHIlE4SeTb0ToQNmJuBdiHwhP2ZtywyX6XqrgCv2WX7K/UCgNYJgYbekuylgyjnuLUHTcZQ==", + "dependencies": { + "@babel/core": "^7.18.5", + "@babel/plugin-transform-react-constant-elements": "^7.17.12", + "@babel/preset-env": "^7.18.2", + "@babel/preset-react": "^7.17.12", + "@babel/preset-typescript": "^7.17.12", + "@svgr/core": "^6.5.0", + "@svgr/plugin-jsx": "^6.5.0", + "@svgr/plugin-svgo": "^6.5.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@tsconfig/docusaurus": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@tsconfig/docusaurus/-/docusaurus-1.0.7.tgz", + "integrity": "sha512-ffTXxGIP/IRMCjuzHd6M4/HdIrw1bMfC7Bv8hMkTadnePkpe0lG0oDSdbRpSDZb2rQMAgpbWiR10BvxvNYwYrg==", + "dev": true + }, + "node_modules/@types/acorn": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", + "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", + "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "dev": true, + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.4.8", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.8.tgz", + "integrity": "sha512-zUCKQI1bUCTi+0kQs5ZQzQ/XILWRLIlh15FXWNykJ+NG3TMKMVvwwC6GP3DR1Ylga15fB7iAExSzc4PNlR5i3w==", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", + "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.0.tgz", + "integrity": "sha512-3qvGd0z8F2ENTGr/GG1yViqfiKmRfrXVx5sJyHGFu3z7m5g5utCQtGp/g29JnjflhtQJBv1WDQukHiT58xPcYQ==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", + "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.31", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", + "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/hast": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", + "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", + "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/js-yaml": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.5.tgz", + "integrity": "sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" + }, + "node_modules/@types/lodash": { + "version": "4.14.186", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.186.tgz", + "integrity": "sha512-eHcVlLXP0c2FlMPm56ITode2AgLMSa6aJ05JTTbYbI+7EMkCEE5qk2E41d5g2lCVTqRe0GnnRFurmlCsDODrPw==", + "dev": true + }, + "node_modules/@types/mdast": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", + "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "node_modules/@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.11.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.5.tgz", + "integrity": "sha512-3JRwhbjI+cHLAkUorhf8RnqUbFXajvzX4q6fMn5JwkgtuwfYtRQYI3u4V92vI6NJuTsbBQWWh3RZjFsuevyMGQ==" + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + }, + "node_modules/@types/parse5": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz", + "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==" + }, + "node_modules/@types/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", + "dev": true + }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + }, + "node_modules/@types/react": { + "version": "17.0.58", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.58.tgz", + "integrity": "sha512-c1GzVY97P0fGxwGxhYq989j4XwlcHQoto6wQISOC2v6wm3h0PORRWJFHlkRjfGsiG3y1609WdQ+J+tKxvrEd6A==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-helmet": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/@types/react-helmet/-/react-helmet-6.1.6.tgz", + "integrity": "sha512-ZKcoOdW/Tg+kiUbkFCBtvDw0k3nD4HJ/h/B9yWxN4uDO8OkRksWTO+EL+z/Qu3aHTeTll3Ro0Cc/8UhwBCMG5A==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-router": { + "version": "5.1.19", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.19.tgz", + "integrity": "sha512-Fv/5kb2STAEMT3wHzdKQK2z8xKq38EDIGVrutYLmQVVLe+4orDFquU52hQrULnEHinMKv9FSA6lf9+uNT1ITtA==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-config": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.6.tgz", + "integrity": "sha512-db1mx37a1EJDf1XeX8jJN7R3PZABmJQXR8r28yUjVMFSjkmnQo6X6pOEEmNl+Tp2gYQOGPdYbFIipBtdElZ3Yg==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + }, + "node_modules/@types/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-pSAff4IAxJjfAXUG6tFkO7dsSbTmf8CtUpfhhZ5VhkRpC4628tJhh3+V6H1E+/Gs9piSzYKT5yzHO5M4GG9jkw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "node_modules/@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/unist": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", + "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" + }, + "node_modules/@types/ws": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", + "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.5.tgz", + "integrity": "sha512-LHY/GSAZZRpsNQH+/oHqhRQ5FT7eoULcBqgfyTB5nQHogFnK3/7QoN7dLnwSE/JkUAF0SrRuclT7ODqMFtWxxQ==", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.5.tgz", + "integrity": "sha512-1j1zTIC5EZOtCplMBG/IEwLtUojtwFVwdyVMbL/hwWqbzlQoJsWCOavrdnLkemwNoC/EOwtUFch3fuo+cbcXYQ==" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.5.tgz", + "integrity": "sha512-L65bDPmfpY0+yFrsgz8b6LhXmbbs38OnwDCf6NpnMUYqa+ENfE5Dq9E42ny0qz/PdR0LJyq/T5YijPnU8AXEpA==" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.5.tgz", + "integrity": "sha512-fDKo1gstwFFSfacIeH5KfwzjykIE6ldh1iH9Y/8YkAZrhmu4TctqYjSh7t0K2VyDSXOZJ1MLhht/k9IvYGcIxg==" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.5.tgz", + "integrity": "sha512-DhykHXM0ZABqfIGYNv93A5KKDw/+ywBFnuWybZZWcuzWHfbp21wUfRkbtz7dMGwGgT4iXjWuhRMA2Mzod6W4WA==", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.5", + "@webassemblyjs/helper-api-error": "1.11.5", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.5.tgz", + "integrity": "sha512-oC4Qa0bNcqnjAowFn7MPCETQgDYytpsfvz4ujZz63Zu/a/v71HeCAAmZsgZ3YVKec3zSPYytG3/PrRCqbtcAvA==" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.5.tgz", + "integrity": "sha512-uEoThA1LN2NA+K3B9wDo3yKlBfVtC6rh0i4/6hvbz071E8gTNZD/pT0MsBf7MeD6KbApMSkaAK0XeKyOZC7CIA==", + "dependencies": { + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-buffer": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5", + "@webassemblyjs/wasm-gen": "1.11.5" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.5.tgz", + "integrity": "sha512-37aGq6qVL8A8oPbPrSGMBcp38YZFXcHfiROflJn9jxSdSMMM5dS5P/9e2/TpaJuhE+wFrbukN2WI6Hw9MH5acg==", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.5.tgz", + "integrity": "sha512-ajqrRSXaTJoPW+xmkfYN6l8VIeNnR4vBOTQO9HzR7IygoCcKWkICbKFbVTNMjMgMREqXEr0+2M6zukzM47ZUfQ==", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.5.tgz", + "integrity": "sha512-WiOhulHKTZU5UPlRl53gHR8OxdGsSOxqfpqWeA2FmcwBMaoEdz6b2x2si3IwC9/fSPLfe8pBMRTHVMk5nlwnFQ==" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.5.tgz", + "integrity": "sha512-C0p9D2fAu3Twwqvygvf42iGCQ4av8MFBLiTb+08SZ4cEdwzWx9QeAHDo1E2k+9s/0w1DM40oflJOpkZ8jW4HCQ==", + "dependencies": { + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-buffer": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5", + "@webassemblyjs/helper-wasm-section": "1.11.5", + "@webassemblyjs/wasm-gen": "1.11.5", + "@webassemblyjs/wasm-opt": "1.11.5", + "@webassemblyjs/wasm-parser": "1.11.5", + "@webassemblyjs/wast-printer": "1.11.5" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.5.tgz", + "integrity": "sha512-14vteRlRjxLK9eSyYFvw1K8Vv+iPdZU0Aebk3j6oB8TQiQYuO6hj9s4d7qf6f2HJr2khzvNldAFG13CgdkAIfA==", + "dependencies": { + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5", + "@webassemblyjs/ieee754": "1.11.5", + "@webassemblyjs/leb128": "1.11.5", + "@webassemblyjs/utf8": "1.11.5" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.5.tgz", + "integrity": "sha512-tcKwlIXstBQgbKy1MlbDMlXaxpucn42eb17H29rawYLxm5+MsEmgPzeCP8B1Cl69hCice8LeKgZpRUAPtqYPgw==", + "dependencies": { + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-buffer": "1.11.5", + "@webassemblyjs/wasm-gen": "1.11.5", + "@webassemblyjs/wasm-parser": "1.11.5" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.5.tgz", + "integrity": "sha512-SVXUIwsLQlc8srSD7jejsfTU83g7pIGr2YYNb9oHdtldSxaOhvA5xwvIiWIfcX8PlSakgqMXsLpLfbbJ4cBYew==", + "dependencies": { + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-api-error": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5", + "@webassemblyjs/ieee754": "1.11.5", + "@webassemblyjs/leb128": "1.11.5", + "@webassemblyjs/utf8": "1.11.5" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.5.tgz", + "integrity": "sha512-f7Pq3wvg3GSPUPzR0F6bmI89Hdb+u9WXrSKc4v+N0aV0q6r42WoF92Jp2jEorBEBRoRNXgjp53nBniDXcqZYPA==", + "dependencies": { + "@webassemblyjs/ast": "1.11.5", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "devOptional": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.1.tgz", + "integrity": "sha512-B+6bi5D34+fDYENiH5qOlA0cV2rAGKuWZ9LeyUUehbXy8e0VS9e498yO0Jeeh+iM+6KbfudHTFjXw2MmJD4QRA==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/algoliasearch": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.17.0.tgz", + "integrity": "sha512-JMRh2Mw6sEnVMiz6+APsi7lx9a2jiDFF+WUtANaUVCv6uSU9UOLdo5h9K3pdP6frRRybaM2fX8b1u0nqICS9aA==", + "dependencies": { + "@algolia/cache-browser-local-storage": "4.17.0", + "@algolia/cache-common": "4.17.0", + "@algolia/cache-in-memory": "4.17.0", + "@algolia/client-account": "4.17.0", + "@algolia/client-analytics": "4.17.0", + "@algolia/client-common": "4.17.0", + "@algolia/client-personalization": "4.17.0", + "@algolia/client-search": "4.17.0", + "@algolia/logger-common": "4.17.0", + "@algolia/logger-console": "4.17.0", + "@algolia/requester-browser-xhr": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/requester-node-http": "4.17.0", + "@algolia/transporter": "4.17.0" + } + }, + "node_modules/algoliasearch-helper": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.12.0.tgz", + "integrity": "sha512-/j1U3PEwdan0n6P/QqSnSpNSLC5+cEMvyljd5CnmNmUjDlGrys+vFEOwjVEnqELIiAGMHEA/Nl3CiKVFBUYqyQ==", + "dependencies": { + "@algolia/events": "^4.0.1" + }, + "peerDependencies": { + "algoliasearch": ">= 3.1 < 6" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "node_modules/array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", + "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz", + "integrity": "sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + }, + "node_modules/asynciterator.prototype": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", + "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + } + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.14", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", + "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "dependencies": { + "browserslist": "^4.21.5", + "caniuse-lite": "^1.0.30001464", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axios": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", + "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "dependencies": { + "follow-redirects": "^1.14.7" + } + }, + "node_modules/babel-loader": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-plugin-apply-mdx-type-prop": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.22.tgz", + "integrity": "sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ==", + "dependencies": { + "@babel/helper-plugin-utils": "7.10.4", + "@mdx-js/util": "1.6.22" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@babel/core": "^7.11.6" + } + }, + "node_modules/babel-plugin-apply-mdx-type-prop/node_modules/@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-extract-import-names": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz", + "integrity": "sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ==", + "dependencies": { + "@babel/helper-plugin-utils": "7.10.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/babel-plugin-extract-import-names/node_modules/@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "dependencies": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/bail": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", + "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base16": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz", + "integrity": "sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==" + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/bonjour-service": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.14.tgz", + "integrity": "sha512-HIMbgLnk1Vqvs6B4Wq5ep7mxvj9sGz5d1JJyDNSGNIdA/w2MCz6GTjWTdjqOJV1bEPj+6IkxDvWNFKEBxNt4kQ==", + "dependencies": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "node_modules/boxen": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-6.2.1.tgz", + "integrity": "sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^6.2.0", + "chalk": "^4.1.2", + "cli-boxes": "^3.0.0", + "string-width": "^5.0.1", + "type-fest": "^2.5.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-me-maybe": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", + "dev": true + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001481", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001481.tgz", + "integrity": "sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/ccount": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz", + "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz", + "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==" + }, + "node_modules/classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + }, + "node_modules/clean-css": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.1.tgz", + "integrity": "sha512-lCr8OHhiWCTw4v8POJovCoh4T7I9U11yVsPjMWWnnMmp9ZowCxyad1Pathle/9HjaDp+fdQKjO9fQydE6RHTZg==", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-color": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.3.tgz", + "integrity": "sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.61", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.15", + "timers-ext": "^0.1.7" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cli-table3": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-table3/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/cli-table3/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/collapse-white-space": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", + "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" + }, + "node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==" + }, + "node_modules/combine-promises": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/combine-promises/-/combine-promises-1.1.0.tgz", + "integrity": "sha512-ZI9jvcLDxqwaXEixOhArm3r7ReIivsXkpbyEWyeOhzz1QS0iSgBPnWvEqvIQtYyamGCYA88gFhmUrs9hrrQ0pg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compressible/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/consola": { + "version": "2.15.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", + "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" + }, + "node_modules/content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/copy-text-to-clipboard": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.1.0.tgz", + "integrity": "sha512-PFM6BnjLnOON/lB3ta/Jg7Ywsv+l9kQGD4TWDCSlRBGmqnnTM5MrDkhAFgw+8HZt0wW6Q2BBE4cmy9sq+s9Qng==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-to-clipboard": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.2.tgz", + "integrity": "sha512-Vme1Z6RUDzrb6xAI7EZlVZ5uvOk2F//GaxKUxajDqm9LhOVM1inxNAD2vy+UZDYsd0uyA9s7b3/FVZPSxqrCfg==", + "dependencies": { + "toggle-selection": "^1.0.6" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/copy-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/globby": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz", + "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==", + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/copy-webpack-plugin/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/core-js": { + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.26.0.tgz", + "integrity": "sha512-+DkDrhoR4Y0PxDz6rurahuB+I45OsEUv8E1maPTB6OuHRohMMcznBq9TMpdpDMm/hUPob/mJJS3PqgbHpMTQgw==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.26.0.tgz", + "integrity": "sha512-piOX9Go+Z4f9ZiBFLnZ5VrOpBl0h7IGCkiFUN11QTe6LjAvOT3ifL/5TdoizMh99hcGy5SoLyWbapIY/PIb/3A==", + "dependencies": { + "browserslist": "^4.21.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-pure": { + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.26.0.tgz", + "integrity": "sha512-LiN6fylpVBVwT8twhhluD9TzXmZQQsr2I2eIKtWNbZI1XMfBT7CV18itaN6RA7EtQd/SDdRx/wzvAShX2HvhQA==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "dependencies": { + "node-fetch": "2.6.7" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/css-declaration-sorter": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz", + "integrity": "sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w==", + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-loader": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", + "integrity": "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.7", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.5" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/css-minimizer-webpack-plugin": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-4.2.2.tgz", + "integrity": "sha512-s3Of/4jKfw1Hj9CxEO1E5oXhQAxlayuHO2y/ML+C6I9sQ7FdzfEV6QgMLN3vI+qFsjJGIAFLKtQK7t8BOXAIyA==", + "dependencies": { + "cssnano": "^5.1.8", + "jest-worker": "^29.1.2", + "postcss": "^8.4.17", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "@swc/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "lightningcss": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "5.1.13", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.13.tgz", + "integrity": "sha512-S2SL2ekdEz6w6a2epXn4CmMKU4K3KpcyXLKfAYc9UQQqJRkD/2eLUG0vJ3Db/9OvO5GuAdgXw3pFbR6abqghDQ==", + "dependencies": { + "cssnano-preset-default": "^5.2.12", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-advanced": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.10.tgz", + "integrity": "sha512-fnYJyCS9jgMU+cmHO1rPSPf9axbQyD7iUhLO5Df6O4G+fKIOMps+ZbU0PdGFejFBBZ3Pftf18fn1eG7MAPUSWQ==", + "dependencies": { + "autoprefixer": "^10.4.12", + "cssnano-preset-default": "^5.2.14", + "postcss-discard-unused": "^5.1.0", + "postcss-merge-idents": "^5.1.1", + "postcss-reduce-idents": "^5.2.0", + "postcss-zindex": "^5.1.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-default": { + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "dependencies": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "dev": true, + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/decode-named-character-reference/node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "devOptional": true + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "dependencies": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detab": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detab/-/detab-2.0.4.tgz", + "integrity": "sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g==", + "dependencies": { + "repeat-string": "^1.5.4" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "node_modules/detect-port": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", + "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", + "dependencies": { + "address": "^1.0.1", + "debug": "4" + }, + "bin": { + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" + } + }, + "node_modules/detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "dependencies": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "bin": { + "detect": "bin/detect-port", + "detect-port": "bin/detect-port" + }, + "engines": { + "node": ">= 4.2.1" + } + }, + "node_modules/detect-port-alt/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/detect-port-alt/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==" + }, + "node_modules/dns-packet": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", + "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "devOptional": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", + "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.1" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dot-prop/node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, + "node_modules/duplexer3": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", + "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/emoticon": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-3.2.0.tgz", + "integrity": "sha512-SNujglcLTTg+lDAcApPNgEdudaqQFiAbJCqzjNxJkvN9vAwCGi0uu8IUVvx+f16h+V44KCY6Y2yboroc9pilHg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.14.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz", + "integrity": "sha512-Vklwq2vDKtl0y/vtwjSesgJ5MYS7Etuk5txS8VdKL4AOS1aUlD96zqIfsOSLQsdv3xgMRbtkWM8eG9XDfKUPow==", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", + "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", + "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.1", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.1", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "safe-array-concat": "^1.0.0", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.14.tgz", + "integrity": "sha512-JgtVnwiuoRuzLvqelrvN3Xu7H9bu2ap/kQ2CrM62iidP8SKuD99rWU3CJy++s7IVL2qb/AjXPGR/E7i9ngd/Cw==", + "dev": true, + "dependencies": { + "asynciterator.prototype": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-set-tostringtag": "^2.0.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.2.1", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "iterator.prototype": "^1.1.0", + "safe-array-concat": "^1.0.0" + } + }, + "node_modules/es-module-lexer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.2.1.tgz", + "integrity": "sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==" + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", + "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", + "devOptional": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.39.0", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.0", + "espree": "^9.5.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", + "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-mdx": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/eslint-mdx/-/eslint-mdx-2.0.5.tgz", + "integrity": "sha512-1ZzcJwJNfladtuK+uuG/MdC0idc1e3d1vCI2STOq/pLcJBGuao2biWh90vEh2M93zDiNoHJGUIU7UAxupiiHFw==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "cosmiconfig": "^7.0.1", + "espree": "^9.4.0", + "estree-util-visit": "^1.2.0", + "remark-mdx": "^2.1.3", + "remark-parse": "^10.0.1", + "remark-stringify": "^10.0.2", + "synckit": "^0.8.4", + "tslib": "^2.4.0", + "unified": "^10.1.2", + "unist-util-visit": "^4.1.1", + "uvu": "^0.5.6", + "vfile": "^5.3.4" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "eslint": ">=8.0.0" + } + }, + "node_modules/eslint-mdx/node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/eslint-mdx/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-mdx/node_modules/mdast-util-from-markdown": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz", + "integrity": "sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==", + "dev": true, + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/eslint-mdx/node_modules/mdast-util-to-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz", + "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/eslint-mdx/node_modules/micromark": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.1.0.tgz", + "integrity": "sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/eslint-mdx/node_modules/remark-mdx": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-2.1.5.tgz", + "integrity": "sha512-A8vw5s+BgOa968Irt8BO7DfWJTE0Fe7Ge3hX8zzDB1DnwMZTNdK6qF2IcFao+/7nzk1vSysKcFp+3ku4vhMpaQ==", + "dev": true, + "dependencies": { + "mdast-util-mdx": "^2.0.0", + "micromark-extension-mdxjs": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/eslint-mdx/node_modules/remark-parse": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz", + "integrity": "sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==", + "dev": true, + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/eslint-mdx/node_modules/trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/eslint-mdx/node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/eslint-mdx/node_modules/unist-util-is": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.1.1.tgz", + "integrity": "sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/eslint-mdx/node_modules/unist-util-stringify-position": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", + "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/eslint-mdx/node_modules/unist-util-visit": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.1.tgz", + "integrity": "sha512-n9KN3WV9k4h1DxYR1LoajgN93wpEi/7ZplVe02IoB4gH5ctI1AaF2670BLHQYbwj+pY83gFtyeySFiyMHJklrg==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/eslint-mdx/node_modules/unist-util-visit-parents": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.1.tgz", + "integrity": "sha512-gks4baapT/kNRaWxuGkl5BIhoanZo7sC/cUT/JToSRNL1dYoXRFl75d++NkjYk4TAu2uv2Px+l8guMajogeuiw==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/eslint-plugin-markdown": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-markdown/-/eslint-plugin-markdown-3.0.0.tgz", + "integrity": "sha512-hRs5RUJGbeHDLfS7ELanT0e29Ocyssf/7kBM+p7KluY5AwngGkDf8Oyu4658/NZSGTTq05FZeWbkxXtbVyHPwg==", + "dev": true, + "dependencies": { + "mdast-util-from-markdown": "^0.8.5" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-mdx": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-mdx/-/eslint-plugin-mdx-2.0.5.tgz", + "integrity": "sha512-j2xN97jSlc5IoH94rJTHqYMztl46+hHzyC8Zqjx+OI1Rvv33isyf8xSSBHN6f0z8IJmgPgGsb/fH90JbvKplXg==", + "dev": true, + "dependencies": { + "eslint-mdx": "^2.0.5", + "eslint-plugin-markdown": "^3.0.0", + "remark-mdx": "^2.1.3", + "remark-parse": "^10.0.1", + "remark-stringify": "^10.0.2", + "tslib": "^2.4.0", + "unified": "^10.1.2", + "vfile": "^5.3.4" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "eslint": ">=8.0.0" + } + }, + "node_modules/eslint-plugin-mdx/node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/eslint-plugin-mdx/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-mdx/node_modules/mdast-util-from-markdown": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz", + "integrity": "sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==", + "dev": true, + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/eslint-plugin-mdx/node_modules/mdast-util-to-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz", + "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/eslint-plugin-mdx/node_modules/micromark": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.1.0.tgz", + "integrity": "sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/eslint-plugin-mdx/node_modules/remark-mdx": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-2.1.5.tgz", + "integrity": "sha512-A8vw5s+BgOa968Irt8BO7DfWJTE0Fe7Ge3hX8zzDB1DnwMZTNdK6qF2IcFao+/7nzk1vSysKcFp+3ku4vhMpaQ==", + "dev": true, + "dependencies": { + "mdast-util-mdx": "^2.0.0", + "micromark-extension-mdxjs": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/eslint-plugin-mdx/node_modules/remark-parse": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz", + "integrity": "sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==", + "dev": true, + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/eslint-plugin-mdx/node_modules/trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/eslint-plugin-mdx/node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/eslint-plugin-mdx/node_modules/unist-util-stringify-position": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", + "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.33.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", + "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.12", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.8" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "devOptional": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "devOptional": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "devOptional": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "devOptional": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "devOptional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", + "devOptional": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "devOptional": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-2.0.1.tgz", + "integrity": "sha512-rxZj1GkQhY4x1j/CSnybK9cGuMFQYFPLq0iNyopqf14aOVLFtMv7Esika+ObJWPWiOHuMOAHz3YkWoLYYRnzWQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-visit": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-1.2.0.tgz", + "integrity": "sha512-wdsoqhWueuJKsh5hqLw3j8lwFqNStm92VcwtAOAny8g/KS/l5Y8RISjR4k5W6skCj3Nirag/WUCMS0Nfy3sgsg==", + "dev": true, + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eta": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/eta/-/eta-2.0.1.tgz", + "integrity": "sha512-46E2qDPDm7QA+usjffUWz9KfXsxVZclPOuKsXs4ZWZdI/X1wpDF7AO424pt7fdYohCzWsIkXAhNGXSlwo5naAg==", + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "url": "https://github.com/eta-dev/eta?sponsor=1" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eval": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eval/-/eval-0.1.8.tgz", + "integrity": "sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==", + "dependencies": { + "@types/node": "*", + "require-like": ">= 0.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/express/node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/express/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "devOptional": true + }, + "node_modules/fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", + "dependencies": { + "punycode": "^1.3.2" + } + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fbemitter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-3.0.0.tgz", + "integrity": "sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==", + "dependencies": { + "fbjs": "^3.0.0" + } + }, + "node_modules/fbjs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.4.tgz", + "integrity": "sha512-ucV0tDODnGV3JCnnkmoszb5lf4bNpzjv80K41wd4k798Etq+UYD0y0TIfalLjZoKgjive6/adkRnszwapiDgBQ==", + "dependencies": { + "cross-fetch": "^3.1.5", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.30" + } + }, + "node_modules/fbjs-css-vars": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", + "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==" + }, + "node_modules/feed": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", + "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", + "dependencies": { + "xml-js": "^1.6.11" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "devOptional": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/file-loader/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/filesize": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", + "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "devOptional": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "devOptional": true + }, + "node_modules/flux": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.4.tgz", + "integrity": "sha512-NCj3XlayA2UsapRpM7va6wU1+9rE5FIL7qoMcmxWHRzbp0yujihMBm9BBHZ1MDIk5h5o2Bl6eGiCe8rYELAmYw==", + "dependencies": { + "fbemitter": "^3.0.0", + "fbjs": "^3.0.1" + }, + "peerDependencies": { + "react": "^15.0.2 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.2.tgz", + "integrity": "sha512-m5cUmF30xkZ7h4tWUgTAcEaKmUW7tfyUyTqNNOz7OxWJ0v1VWKTcOvH8FWHUwSjlW/356Ijc9vi3XfcPstpQKA==", + "dependencies": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=10", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "eslint": ">= 6", + "typescript": ">= 2.7", + "vue-template-compiler": "*", + "webpack": ">= 4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dependencies": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" + }, + "node_modules/get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/github-slugger": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz", + "integrity": "sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==" + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-promise": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/glob-promise/-/glob-promise-4.2.2.tgz", + "integrity": "sha512-xcUzJ8NWN5bktoTIX7eOclO1Npxd/dyVqUJxlLIDasT4C7KZyqlPIwkdJ0Ypiy3p2ZKahTjK4M9uC3sNSfNMzw==", + "dev": true, + "dependencies": { + "@types/glob": "^7.1.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/ahmadnassri" + }, + "peerDependencies": { + "glob": "^7.1.6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "node_modules/global-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-dirs/node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globalyzer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", + "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", + "dev": true + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dependencies": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "devOptional": true + }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/hast-to-hyperscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz", + "integrity": "sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==", + "dependencies": { + "@types/unist": "^2.0.3", + "comma-separated-tokens": "^1.0.0", + "property-information": "^5.3.0", + "space-separated-tokens": "^1.0.0", + "style-to-object": "^0.3.0", + "unist-util-is": "^4.0.0", + "web-namespaces": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-6.0.1.tgz", + "integrity": "sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA==", + "dependencies": { + "@types/parse5": "^5.0.0", + "hastscript": "^6.0.0", + "property-information": "^5.0.0", + "vfile": "^4.0.0", + "vfile-location": "^3.2.0", + "web-namespaces": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5/node_modules/vfile": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", + "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-message": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5/node_modules/vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-6.0.1.tgz", + "integrity": "sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig==", + "dependencies": { + "@types/hast": "^2.0.0", + "hast-util-from-parse5": "^6.0.0", + "hast-util-to-parse5": "^6.0.0", + "html-void-elements": "^1.0.0", + "parse5": "^6.0.0", + "unist-util-position": "^3.0.0", + "vfile": "^4.0.0", + "web-namespaces": "^1.0.0", + "xtend": "^4.0.0", + "zwitch": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "node_modules/hast-util-raw/node_modules/vfile": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", + "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-message": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw/node_modules/vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-parse5": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz", + "integrity": "sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ==", + "dependencies": { + "hast-to-hyperscript": "^9.0.0", + "property-information": "^5.0.0", + "web-namespaces": "^1.0.0", + "xtend": "^4.0.0", + "zwitch": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==" + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-tags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz", + "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/html-void-elements": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz", + "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", + "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==", + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "webpack": "^5.20.0" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz", + "integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==", + "dependencies": { + "queue": "6.0.2" + }, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/immer": { + "version": "9.0.16", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.16.tgz", + "integrity": "sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/infima": { + "version": "0.2.0-alpha.43", + "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.43.tgz", + "integrity": "sha512-2uw57LvUqW0rK/SWYnd/2rRfxNA5DDNOh33jxF7fy46VWoNhGxiUQyVZHbBMjQ33mQem0cjdDVwgWVAmlRfgyQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" + }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", + "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "dependencies": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-ci/node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-npm": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "node_modules/is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-whitespace-character": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", + "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-word-character": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz", + "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.1.tgz", + "integrity": "sha512-9E+nePc8C9cnQldmNl6bgpTY6zI4OPRZd97fhJ/iVZ1GifIUDVV5F6x1nEDqpe8KaMEZGT4xgrwKQDxXnjOIZQ==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.0", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.3" + } + }, + "node_modules/jest-util": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.2.1.tgz", + "integrity": "sha512-P5VWDj25r7kj7kl4pN2rG/RN2c1TLfYYYZYULnS/35nFDjBai+hBeo3MDrYZS7p6IoY3YHZnt2vq4L6mKnLk0g==", + "dependencies": { + "@jest/types": "^29.2.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.2.1.tgz", + "integrity": "sha512-ROHTZ+oj7sBrgtv46zZ84uWky71AoYi0vEV9CdEtc1FQunsoAGe5HbQmW76nI5QWdvECVPrSi1MCVUmizSavMg==", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.2.1", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/joi": { + "version": "17.6.4", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.4.tgz", + "integrity": "sha512-tPzkTJHZQjSFCc842QpdVpOZ9LI2txApboNUbW70qgnRB14Lzl+oWQOPdF2N4yqyiY14wBGe8lc7f/2hZxbGmw==", + "dependencies": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.3", + "@sideway/formula": "^3.0.0", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/js-sdsl": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", + "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", + "devOptional": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema-to-typescript": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-13.1.1.tgz", + "integrity": "sha512-F3CYhtA7F3yPbb8vF7sFchk/2dnr1/yTKf8RcvoNpjnh67ZS/ZMH1ElLt5KHAtf2/bymiejLQQszszPWEeTdSw==", + "dev": true, + "dependencies": { + "@bcherny/json-schema-ref-parser": "10.0.5-fork", + "@types/json-schema": "^7.0.11", + "@types/lodash": "^4.14.182", + "@types/prettier": "^2.6.1", + "cli-color": "^2.0.2", + "get-stdin": "^8.0.0", + "glob": "^7.1.6", + "glob-promise": "^4.2.2", + "is-glob": "^4.0.3", + "lodash": "^4.17.21", + "minimist": "^1.2.6", + "mkdirp": "^1.0.4", + "mz": "^2.7.0", + "prettier": "^2.6.2" + }, + "bin": { + "json2ts": "dist/src/cli.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "devOptional": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", + "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.5", + "object.assign": "^4.1.3" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dependencies": { + "json-buffer": "3.0.0" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "engines": { + "node": ">=6" + } + }, + "node_modules/klona": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", + "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dependencies": { + "package-json": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "devOptional": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", + "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.curry": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", + "integrity": "sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "node_modules/lodash.flow": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", + "integrity": "sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "devOptional": true + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + }, + "node_modules/longest-streak": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.0.1.tgz", + "integrity": "sha512-cHlYSUpL2s7Fb3394mYxwTYj8niTaNHUCLr0qdiCXQfSjfuA7CKofpX2uSwEfFDQ0EB7JcnMnm+GjbqqoinYYg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", + "dev": true, + "dependencies": { + "es5-ext": "~0.10.2" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/markdown-escapes": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz", + "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-squeeze-paragraphs": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz", + "integrity": "sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ==", + "dependencies": { + "unist-util-remove": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-definitions": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz", + "integrity": "sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==", + "dependencies": { + "unist-util-visit": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz", + "integrity": "sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==", + "dev": true, + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-to-string": "^2.0.0", + "micromark": "~2.11.0", + "parse-entities": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-2.0.0.tgz", + "integrity": "sha512-M09lW0CcBT1VrJUaF/PYxemxxHa7SLDHdSn94Q9FhxjCQfuW7nMAWKWimTmA3OyDMSTH981NN1csW1X+HPSluw==", + "dev": true, + "dependencies": { + "mdast-util-mdx-expression": "^1.0.0", + "mdast-util-mdx-jsx": "^2.0.0", + "mdast-util-mdxjs-esm": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-1.3.1.tgz", + "integrity": "sha512-TTb6cKyTA1RD+1su1iStZ5PAv3rFfOUKcoU5EstUpv/IZo63uDX03R8+jXjMEhcobXnNOiG6/ccekvVl4eV1zQ==", + "dev": true, + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "mdast-util-to-markdown": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression/node_modules/mdast-util-from-markdown": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz", + "integrity": "sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==", + "dev": true, + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression/node_modules/mdast-util-to-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz", + "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression/node_modules/micromark": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.1.0.tgz", + "integrity": "sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/mdast-util-mdx-expression/node_modules/unist-util-stringify-position": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", + "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-2.1.0.tgz", + "integrity": "sha512-KzgzfWMhdteDkrY4mQtyvTU5bc/W4ppxhe9SzelO6QUUiwLAM+Et2Dnjjprik74a336kHdo0zKm7Tp+n6FFeRg==", + "dev": true, + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "ccount": "^2.0.0", + "mdast-util-to-markdown": "^1.3.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-remove-position": "^4.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx/node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-mdx-jsx/node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-mdx-jsx/node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-mdx-jsx/node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-mdx-jsx/node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-mdx-jsx/node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "dev": true, + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-mdx-jsx/node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-mdx-jsx/node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-mdx-jsx/node_modules/parse-entities": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.0.tgz", + "integrity": "sha512-5nk9Fn03x3rEhGaX1FU6IDwG/k+GxLXlFAkgrbM1asuAFl3BhdQWvASaIsmwWypRNcZKHPYnIuOSfIWEyEQnPQ==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-mdx-jsx/node_modules/unist-util-is": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.1.1.tgz", + "integrity": "sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx/node_modules/unist-util-remove-position": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-4.0.1.tgz", + "integrity": "sha512-0yDkppiIhDlPrfHELgB+NLQD5mfjup3a8UYclHruTJWmY74je8g+CIFr79x5f6AkmzSwlvKLbs63hC0meOMowQ==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-visit": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx/node_modules/unist-util-stringify-position": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", + "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx/node_modules/unist-util-visit": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.1.tgz", + "integrity": "sha512-n9KN3WV9k4h1DxYR1LoajgN93wpEi/7ZplVe02IoB4gH5ctI1AaF2670BLHQYbwj+pY83gFtyeySFiyMHJklrg==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx/node_modules/unist-util-visit-parents": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.1.tgz", + "integrity": "sha512-gks4baapT/kNRaWxuGkl5BIhoanZo7sC/cUT/JToSRNL1dYoXRFl75d++NkjYk4TAu2uv2Px+l8guMajogeuiw==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-1.3.0.tgz", + "integrity": "sha512-7N5ihsOkAEGjFotIX9p/YPdl4TqUoMxL4ajNz7PbT89BqsdWJuBC9rvgt6wpbwTZqWWR0jKWqQbwsOWDBUZv4g==", + "dev": true, + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "mdast-util-to-markdown": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm/node_modules/mdast-util-from-markdown": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz", + "integrity": "sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==", + "dev": true, + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm/node_modules/mdast-util-to-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz", + "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm/node_modules/micromark": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.1.0.tgz", + "integrity": "sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/mdast-util-mdxjs-esm/node_modules/unist-util-stringify-position": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", + "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz", + "integrity": "sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA==", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "mdast-util-definitions": "^4.0.0", + "mdurl": "^1.0.0", + "unist-builder": "^2.0.0", + "unist-util-generated": "^1.0.0", + "unist-util-position": "^3.0.0", + "unist-util-visit": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.3.0.tgz", + "integrity": "sha512-6tUSs4r+KK4JGTTiQ7FfHmVOaDrLQJPmpjD6wPMlHGUVXoG9Vjc3jIeP+uyBWRf8clwB2blM+W7+KrlMYQnftA==", + "dev": true, + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "longest-streak": "^3.0.0", + "mdast-util-to-string": "^3.0.0", + "micromark-util-decode-string": "^1.0.0", + "unist-util-visit": "^4.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown/node_modules/mdast-util-to-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz", + "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown/node_modules/unist-util-is": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.1.1.tgz", + "integrity": "sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown/node_modules/unist-util-visit": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.1.tgz", + "integrity": "sha512-n9KN3WV9k4h1DxYR1LoajgN93wpEi/7ZplVe02IoB4gH5ctI1AaF2670BLHQYbwj+pY83gFtyeySFiyMHJklrg==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown/node_modules/unist-util-visit-parents": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.1.tgz", + "integrity": "sha512-gks4baapT/kNRaWxuGkl5BIhoanZo7sC/cUT/JToSRNL1dYoXRFl75d++NkjYk4TAu2uv2Px+l8guMajogeuiw==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown/node_modules/zwitch": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.2.tgz", + "integrity": "sha512-JZxotl7SxAJH0j7dN4pxsTV6ZLXoLdGME+PsjkL/DaBrVryK9kTGq06GfKrwcSOqypP+fdXGoCHE36b99fWVoA==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-to-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", + "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.7.tgz", + "integrity": "sha512-ygaiUSNalBX85388uskeCyhSAoOSgzBbtVCr9jA2RROssFL9Q19/ZXFqS+2Th2sr1ewNIWgFdLzLC3Yl1Zv+lw==", + "dependencies": { + "fs-monkey": "^1.0.3" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/memoizee": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", + "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromark": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz", + "integrity": "sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "debug": "^4.0.0", + "parse-entities": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz", + "integrity": "sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-factory-destination": "^1.0.0", + "micromark-factory-label": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-factory-title": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-html-tag-name": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-extension-mdx-expression": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-1.0.3.tgz", + "integrity": "sha512-TjYtjEMszWze51NJCZmhv7MEBcgYRgb3tJeMAJ+HQCAaZHHRBaDCccqQzGizR/H4ODefP44wRTgOn2vE5I6nZA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-mdx-expression": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-events-to-acorn": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-extension-mdx-jsx": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-1.0.3.tgz", + "integrity": "sha512-VfA369RdqUISF0qGgv2FfV7gGjHDfn9+Qfiv5hEwpyr1xscRj/CiVRkU7rywGFCO7JwJ5L0e7CJz60lY52+qOA==", + "dev": true, + "dependencies": { + "@types/acorn": "^4.0.0", + "estree-util-is-identifier-name": "^2.0.0", + "micromark-factory-mdx-expression": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-md": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-1.0.0.tgz", + "integrity": "sha512-xaRAMoSkKdqZXDAoSgp20Azm0aRQKGOl0RrS81yGu8Hr/JhMsBmfs4wR7m9kgVUIO36cMUQjNyiyDKPrsv8gOw==", + "dev": true, + "dependencies": { + "micromark-util-types": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-1.0.0.tgz", + "integrity": "sha512-TZZRZgeHvtgm+IhtgC2+uDMR7h8eTKF0QUX9YsgoL9+bADBpBY6SiLvWqnBlLbCEevITmTqmEuY3FoxMKVs1rQ==", + "dev": true, + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^1.0.0", + "micromark-extension-mdx-jsx": "^1.0.0", + "micromark-extension-mdx-md": "^1.0.0", + "micromark-extension-mdxjs-esm": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-types": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-1.0.3.tgz", + "integrity": "sha512-2N13ol4KMoxb85rdDwTAC6uzs8lMX0zeqpcyx7FhS7PxXomOnLactu8WI8iBNXW8AVyea3KIJd/1CKnUmwrK9A==", + "dev": true, + "dependencies": { + "micromark-core-commonmark": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-events-to-acorn": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-position-from-estree": "^1.1.0", + "uvu": "^0.5.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz", + "integrity": "sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz", + "integrity": "sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-factory-mdx-expression": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-1.0.6.tgz", + "integrity": "sha512-WRQIc78FV7KrCfjsEf/sETopbYjElh3xAmNpLkd1ODPqxEngP42eVRGbiPEQWpRV27LzqW+XVTvQAMIIRLPnNA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-events-to-acorn": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-position-from-estree": "^1.0.0", + "uvu": "^0.5.0", + "vfile-message": "^3.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz", + "integrity": "sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz", + "integrity": "sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz", + "integrity": "sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.1.0.tgz", + "integrity": "sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz", + "integrity": "sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz", + "integrity": "sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz", + "integrity": "sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz", + "integrity": "sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz", + "integrity": "sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz", + "integrity": "sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-events-to-acorn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-1.2.0.tgz", + "integrity": "sha512-WWp3bf7xT9MppNuw3yPjpnOxa8cj5ACivEzXJKu0WwnjBYfzaBvIAT9KfeyI0Qkll+bfQtfftSwdgTH6QhTOKw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "estree-util-visit": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0", + "vfile-location": "^4.0.0", + "vfile-message": "^3.0.0" + } + }, + "node_modules/micromark-util-events-to-acorn/node_modules/vfile-location": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-4.0.1.tgz", + "integrity": "sha512-JDxPlTbZrZCQXogGheBHjbRWjESSPEak770XwWPfw5mTc1v1nWGLB/apzZxsx8a0SJVfF8HK8ql8RD308vXRUw==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-util-html-tag-name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.1.0.tgz", + "integrity": "sha512-BKlClMmYROy9UiV03SwNmckkjn8QHVaWkqoAqzivabvdGcwNGMMMH/5szAnywmsTBUzDsU57/mFi0sp4BQO6dA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz", + "integrity": "sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz", + "integrity": "sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.1.0.tgz", + "integrity": "sha512-RoxtuSCX6sUNtxhbmsEFQfWzs8VN7cTctmBPvYivo98xb/kDEoTCtJQX5wyzIYEmk/lvNFTat4hL8oW0KndFpg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz", + "integrity": "sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz", + "integrity": "sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-types": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.0.2.tgz", + "integrity": "sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dependencies": { + "mime-db": "~1.33.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz", + "integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==", + "dependencies": { + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/mrmime": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "dev": true, + "bin": { + "mustache": "bin/mustache" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "devOptional": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/null-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/null-loader/-/null-loader-4.0.1.tgz", + "integrity": "sha512-pxqVbi4U6N26lq+LmgIbB5XATP0VdZKOG25DhHi8btMmJJefGArFyDg1yc4U3hWCJbMqSrw0qyrz1UQX+qYXqg==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/null-loader/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", + "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.hasown": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", + "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "devOptional": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dependencies": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "dependencies": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-numeric-range": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", + "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==" + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dependencies": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "dependencies": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-colormin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-unused": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-5.1.0.tgz", + "integrity": "sha512-KwLWymI9hbwXmJa0dkrzpRbSJEh0vVUd7r8t0yOGPcfKzyJJxFM8kLyC5Ev9avji6nY95pOp1W6HqIrfT+0VGw==", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-loader": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.1.tgz", + "integrity": "sha512-VRviFEyYlLjctSM93gAZtcJJ/iSkPZ79zWbN/1fSH+NisBByEiVLqpdVDrPLVSi8DX0oJo12kL/GppTBdKVXiQ==", + "dependencies": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.7" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-merge-idents": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-5.1.1.tgz", + "integrity": "sha512-pCijL1TREiCoog5nQp7wUe+TUonA2tC2sQ54UGeMmryK3UFGIYKqDyjnqd6RcuI4znFn9hWSLNN8xKE/vWcUQw==", + "dependencies": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-rules": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "dependencies": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "dependencies": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "dependencies": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "dependencies": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-idents": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-5.2.0.tgz", + "integrity": "sha512-BTrLjICoSB6gxbc58D5mdBK8OhXRDqud/zodYfdSi52qvDHdMwk+9kB9xsM8yJThH/sZU5A6QVSmMmaN001gIg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-sort-media-queries": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.4.1.tgz", + "integrity": "sha512-QDESFzDDGKgpiIh4GYXsSy6sek2yAwQx1JASl5AxBtU1Lq2JfKBljIPNdil989NcSKRQX1ToiaKphImtBuhXWw==", + "dependencies": { + "sort-css-media-queries": "2.1.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.4.16" + } + }, + "node_modules/postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/postcss-zindex": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-5.1.0.tgz", + "integrity": "sha512-fgFMf0OtVSBR1va1JNHYgMxYk73yhn/qb4uQDq1DLGYolz8gHCyr/sesEuGUaYs58E3ZJRcpoGuPVoB7Meiq9A==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/prebuild-webpack-plugin": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/prebuild-webpack-plugin/-/prebuild-webpack-plugin-1.1.1.tgz", + "integrity": "sha512-H5/VnSl7KZm3NCGj1+8BrBHu0Bn9xzLREdpeE4TRYyp4t4qFnYPExzozk2sfD/CLJRGIuyOFrXbXgJJ4ETdz/g==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "glob": "^7.1.5", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "devOptional": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/prettier": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz", + "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", + "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/prism-react-renderer": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.3.5.tgz", + "integrity": "sha512-IJ+MSwBWKG+SM3b2SUfdrhC+gu01QkV2KmRQgREThBfSQRoufqRfxfHUxpG1WcaFjP+kojcFyO9Qqtpgt3qLCg==", + "peerDependencies": { + "react": ">=0.14.9" + } + }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dependencies": { + "asap": "~2.0.3" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "dependencies": { + "xtend": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" + }, + "node_modules/pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dependencies": { + "escape-goat": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pure-color": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz", + "integrity": "sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA==" + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "dependencies": { + "inherits": "~2.0.3" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-async": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/react-async/-/react-async-10.0.1.tgz", + "integrity": "sha512-ORUz5ca0B57QgBIzEZM5SuhJ6xFjkvEEs0gylLNlWf06vuVcLZsjIw3wx58jJkZG38p+0nUAxRgFW2b7mnVZzA==", + "peerDependencies": { + "react": ">=16.3.1" + } + }, + "node_modules/react-base16-styling": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.6.0.tgz", + "integrity": "sha512-yvh/7CArceR/jNATXOKDlvTnPKPmGZz7zsenQ3jUwLzHkNUR0CvY3yGYJbWJ/nnxsL8Sgmt5cO3/SILVuPO6TQ==", + "dependencies": { + "base16": "^1.0.0", + "lodash.curry": "^4.0.1", + "lodash.flow": "^3.3.0", + "pure-color": "^1.2.0" + } + }, + "node_modules/react-copy-to-clipboard": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz", + "integrity": "sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==", + "dependencies": { + "copy-to-clipboard": "^3.3.1", + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "react": "^15.3.0 || 16 || 17 || 18" + } + }, + "node_modules/react-dev-utils": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", + "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", + "dependencies": { + "@babel/code-frame": "^7.16.0", + "address": "^1.1.2", + "browserslist": "^4.18.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "detect-port-alt": "^1.1.6", + "escape-string-regexp": "^4.0.0", + "filesize": "^8.0.6", + "find-up": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^6.5.0", + "global-modules": "^2.0.0", + "globby": "^11.0.4", + "gzip-size": "^6.0.0", + "immer": "^9.0.7", + "is-root": "^2.1.0", + "loader-utils": "^3.2.0", + "open": "^8.4.0", + "pkg-up": "^3.1.0", + "prompts": "^2.4.2", + "react-error-overlay": "^6.0.11", + "recursive-readdir": "^2.2.2", + "shell-quote": "^1.7.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/react-dev-utils/node_modules/loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + }, + "peerDependencies": { + "react": "17.0.2" + } + }, + "node_modules/react-error-overlay": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" + }, + "node_modules/react-fast-compare": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", + "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" + }, + "node_modules/react-helmet-async": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.3.0.tgz", + "integrity": "sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "invariant": "^2.2.4", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.2.0", + "shallowequal": "^1.1.0" + }, + "peerDependencies": { + "react": "^16.6.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-json-view": { + "version": "1.21.3", + "resolved": "https://registry.npmjs.org/react-json-view/-/react-json-view-1.21.3.tgz", + "integrity": "sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw==", + "dependencies": { + "flux": "^4.0.1", + "react-base16-styling": "^0.6.0", + "react-lifecycles-compat": "^3.0.4", + "react-textarea-autosize": "^8.3.2" + }, + "peerDependencies": { + "react": "^17.0.0 || ^16.3.0 || ^15.5.4", + "react-dom": "^17.0.0 || ^16.3.0 || ^15.5.4" + } + }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "node_modules/react-loadable": { + "name": "@docusaurus/react-loadable", + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", + "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", + "dependencies": { + "@types/react": "*", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-loadable-ssr-addon-v5-slorber": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz", + "integrity": "sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A==", + "dependencies": { + "@babel/runtime": "^7.10.3" + }, + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "react-loadable": "*", + "webpack": ">=4.41.1 || 5.x" + } + }, + "node_modules/react-router": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", + "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/react-router-config": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/react-router-config/-/react-router-config-5.1.1.tgz", + "integrity": "sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==", + "dependencies": { + "@babel/runtime": "^7.1.2" + }, + "peerDependencies": { + "react": ">=15", + "react-router": ">=5" + } + }, + "node_modules/react-router-dom": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz", + "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.3.4", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/react-textarea-autosize": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.4.1.tgz", + "integrity": "sha512-aD2C+qK6QypknC+lCMzteOdIjoMbNlgSFmJjCV+DrfTPwp59i/it9mMNf2HDzvRjQgKAyBDPyLJhcrzElf2U4Q==", + "dependencies": { + "@babel/runtime": "^7.20.13", + "use-composed-ref": "^1.3.0", + "use-latest": "^1.2.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-toastify": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-7.0.4.tgz", + "integrity": "sha512-Rol7+Cn39hZp5hQ/k6CbMNE2CKYV9E5OQdC/hBLtIQU2xz7DdAm7xil4NITQTHR6zEbE5RVFbpgSwTD7xRGLeQ==", + "dependencies": { + "clsx": "^1.1.1" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reading-time": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", + "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==" + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", + "integrity": "sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.1.tgz", + "integrity": "sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsgen": "^0.7.1", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/registry-auth-token": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", + "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/regjsgen": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", + "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==" + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remark-emoji": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-2.2.0.tgz", + "integrity": "sha512-P3cj9s5ggsUvWw5fS2uzCHJMGuXYRb0NnZqYlNecewXt8QBU9n5vW3DUUKOhepS8F9CwdMx9B8a3i7pqFWAI5w==", + "dependencies": { + "emoticon": "^3.2.0", + "node-emoji": "^1.10.0", + "unist-util-visit": "^2.0.3" + } + }, + "node_modules/remark-footnotes": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-2.0.0.tgz", + "integrity": "sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-1.6.22.tgz", + "integrity": "sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==", + "dependencies": { + "@babel/core": "7.12.9", + "@babel/helper-plugin-utils": "7.10.4", + "@babel/plugin-proposal-object-rest-spread": "7.12.1", + "@babel/plugin-syntax-jsx": "7.12.1", + "@mdx-js/util": "1.6.22", + "is-alphabetical": "1.0.4", + "remark-parse": "8.0.3", + "unified": "9.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx/node_modules/@babel/core": { + "version": "7.12.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", + "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.5", + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helpers": "^7.12.5", + "@babel/parser": "^7.12.7", + "@babel/template": "^7.12.7", + "@babel/traverse": "^7.12.9", + "@babel/types": "^7.12.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/remark-mdx/node_modules/@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + }, + "node_modules/remark-mdx/node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", + "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-transform-parameters": "^7.12.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/remark-mdx/node_modules/@babel/plugin-syntax-jsx": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", + "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/remark-mdx/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/remark-mdx/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/remark-mdx/node_modules/unified": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", + "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", + "dependencies": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^2.0.0", + "trough": "^1.0.0", + "vfile": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx/node_modules/vfile": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", + "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-message": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx/node_modules/vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz", + "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==", + "dependencies": { + "ccount": "^1.0.0", + "collapse-white-space": "^1.0.2", + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-whitespace-character": "^1.0.0", + "is-word-character": "^1.0.0", + "markdown-escapes": "^1.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.5.4", + "state-toggle": "^1.0.0", + "trim": "0.0.1", + "trim-trailing-lines": "^1.0.0", + "unherit": "^1.0.4", + "unist-util-remove-position": "^2.0.0", + "vfile-location": "^3.0.0", + "xtend": "^4.0.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-squeeze-paragraphs": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-4.0.0.tgz", + "integrity": "sha512-8qRqmL9F4nuLPIgl92XUuxI3pFxize+F1H0e/W3llTk0UsjJaj01+RrirkMw7P21RKe4X6goQhYRSvNWX+70Rw==", + "dependencies": { + "mdast-squeeze-paragraphs": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-10.0.2.tgz", + "integrity": "sha512-6wV3pvbPvHkbNnWB0wdDvVFHOe1hBRAx1Q/5g/EpH4RppAII6J8Gnwe7VbHuXaoKIF6LAg6ExTel/+kNqSQ7lw==", + "dev": true, + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify/node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/remark-stringify/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/remark-stringify/node_modules/trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/remark-stringify/node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/renderkid/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/renderkid/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-like": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", + "integrity": "sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==", + "engines": { + "node": "*" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, + "node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", + "dependencies": { + "lowercase-keys": "^1.0.0" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rtl-detect": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.0.4.tgz", + "integrity": "sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ==" + }, + "node_modules/rtlcss": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-3.5.0.tgz", + "integrity": "sha512-wzgMaMFHQTnyi9YOwsx9LjOxYXJPzS8sYnFaKm6R5ysvTkwzHiB0vxnbHwchHQT65PTdBjDG21/kQBWI7q9O7A==", + "dependencies": { + "find-up": "^5.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.3.11", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "rtlcss": "bin/rtlcss.js" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", + "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "node_modules/scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" + }, + "node_modules/selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "dependencies": { + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dependencies": { + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semver-diff/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/send/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-handler": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz", + "integrity": "sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==", + "dependencies": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "fast-url-parser": "1.1.3", + "mime-types": "2.1.18", + "minimatch": "3.1.2", + "path-is-inside": "1.0.2", + "path-to-regexp": "2.2.1", + "range-parser": "1.2.0" + } + }, + "node_modules/serve-handler/node_modules/path-to-regexp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", + "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==" + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.4.tgz", + "integrity": "sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/sirv": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", + "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==", + "dependencies": { + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", + "totalist": "^1.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "node_modules/sitemap": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-7.1.1.tgz", + "integrity": "sha512-mK3aFtjz4VdJN0igpIJrinf3EO8U8mxOPsTBzSsy06UtjZQJ3YY3o3Xa7zSc5nMqcMrRwlChHZ18Kxg0caiPBg==", + "dependencies": { + "@types/node": "^17.0.5", + "@types/sax": "^1.2.1", + "arg": "^5.0.0", + "sax": "^1.2.4" + }, + "bin": { + "sitemap": "dist/cli.js" + }, + "engines": { + "node": ">=12.0.0", + "npm": ">=5.6.0" + } + }, + "node_modules/sitemap/node_modules/@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/sort-css-media-queries": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.1.0.tgz", + "integrity": "sha512-IeWvo8NkNiY2vVYdPa27MCQiR0MN0M80johAYFVxWWXQ44KU84WNxjslwBHmc/7ZL2ccwkM7/e6S5aiKZXm7jA==", + "engines": { + "node": ">= 6.3.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility" + }, + "node_modules/state-toggle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz", + "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.3.0.tgz", + "integrity": "sha512-cNNS+VYsXIs5gI6gJipO4qZ8YYT274JHvNnQ1/R/x8Q8mdP0qj0zoMchRXmBNPqp/0eOEhX+3g7g6Fgb7meLIQ==" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-replace-loader": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-replace-loader/-/string-replace-loader-3.1.0.tgz", + "integrity": "sha512-5AOMUZeX5HE/ylKDnEa/KKBqvlnFmRZudSOjVJHxhoJg9QYTwl1rECx7SLR8BBH7tfxb4Rp7EM2XVfQFxIhsbQ==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "peerDependencies": { + "webpack": "^5" + } + }, + "node_modules/string-replace-loader/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", + "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.3.tgz", + "integrity": "sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==", + "dev": true, + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stringify-entities/node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-to-object": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", + "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", + "dependencies": { + "inline-style-parser": "0.1.1" + } + }, + "node_modules/stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + }, + "node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/svgo/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/svgo/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/svgo/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/synckit": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.4.tgz", + "integrity": "sha512-Dn2ZkzMdSX827QbowGbU/4yjWuvNaCoScLLoMo/yKbu+P4GBR6cRGKZH27k6a9bRzdqcyd1DE96pQtQ6uNkmyw==", + "dev": true, + "dependencies": { + "@pkgr/utils": "^2.3.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.1.tgz", + "integrity": "sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw==", + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz", + "integrity": "sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.5" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "node_modules/timers-ext": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "dev": true, + "dependencies": { + "es5-ext": "~0.10.46", + "next-tick": "1" + } + }, + "node_modules/tiny-glob": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", + "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", + "dev": true, + "dependencies": { + "globalyzer": "0.1.0", + "globrex": "^0.1.2" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", + "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", + "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==", + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/trim": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", + "integrity": "sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ==", + "deprecated": "Use String.prototype.trim() instead" + }, + "node_modules/trim-trailing-lines": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz", + "integrity": "sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", + "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "devOptional": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/ua-parser-js": { + "version": "0.7.35", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.35.tgz", + "integrity": "sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unherit": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz", + "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==", + "dependencies": { + "inherits": "^2.0.0", + "xtend": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unified": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz", + "integrity": "sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ==", + "dependencies": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^2.0.0", + "trough": "^1.0.0", + "vfile": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unified/node_modules/vfile": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", + "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-message": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unified/node_modules/vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/unist-builder": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-2.0.3.tgz", + "integrity": "sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-generated": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.6.tgz", + "integrity": "sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.1.0.tgz", + "integrity": "sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position-from-estree": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-1.1.1.tgz", + "integrity": "sha512-xtoY50b5+7IH8tFbkw64gisG9tMSpxDjhX9TmaJJae/XuxQ9R/Kc8Nv1eOsf43Gt4KV/LkriMy9mptDr7XLcaw==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-2.1.0.tgz", + "integrity": "sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q==", + "dependencies": { + "unist-util-is": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz", + "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==", + "dependencies": { + "unist-util-visit": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", + "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", + "dependencies": { + "@types/unist": "^2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", + "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/update-notifier": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "dependencies": { + "boxen": "^5.0.0", + "chalk": "^4.1.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-notifier/node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-notifier/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/update-notifier/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-notifier/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-notifier/node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-notifier/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uri-js/node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "dependencies": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "file-loader": "*", + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "file-loader": { + "optional": true + } + } + }, + "node_modules/url-loader/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/url-loader/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/url-loader/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", + "dependencies": { + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/use-composed-ref": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.3.0.tgz", + "integrity": "sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-latest": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.1.tgz", + "integrity": "sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==", + "dependencies": { + "use-isomorphic-layout-effect": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" + }, + "node_modules/utility-types": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", + "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/uvu": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", + "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", + "dev": true, + "dependencies": { + "dequal": "^2.0.0", + "diff": "^5.0.0", + "kleur": "^4.0.3", + "sade": "^1.7.3" + }, + "bin": { + "uvu": "bin.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/uvu/node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vfile": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.5.tgz", + "integrity": "sha512-U1ho2ga33eZ8y8pkbQLH54uKqGhFJ6GYIHnnG5AhRpAh3OWjkrRHKa/KogbmQn8We+c0KVV3rTOgR9V/WowbXQ==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.2.0.tgz", + "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.2.tgz", + "integrity": "sha512-QjSNP6Yxzyycd4SVOtmKKyTsSvClqBPJcd00Z0zuPj3hOIjg0rUPG6DbFGPvUKRgYyaIWLPKpuEclcuvb3H8qA==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message/node_modules/unist-util-stringify-position": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", + "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile/node_modules/unist-util-stringify-position": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", + "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/wait-on": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz", + "integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==", + "dependencies": { + "axios": "^0.25.0", + "joi": "^17.6.0", + "lodash": "^4.17.21", + "minimist": "^1.2.5", + "rxjs": "^7.5.4" + }, + "bin": { + "wait-on": "bin/wait-on" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/web-namespaces": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz", + "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/web-tree-sitter": { + "version": "0.20.8", + "resolved": "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.20.8.tgz", + "integrity": "sha512-weOVgZ3aAARgdnb220GqYuh7+rZU0Ka9k9yfKtGAzEYMa6GgiCzW9JjQRJyCJakvibQW+dfjJdihjInKuuCAUQ==" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/webpack": { + "version": "5.86.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.86.0.tgz", + "integrity": "sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==", + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.14.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.2", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.6.1.tgz", + "integrity": "sha512-oKz9Oz9j3rUciLNfpGFjOb49/jEpXNmWdVH8Ls//zNcnLlQdTGXQQMsBbb/gR7Zl8WNLxVCq+0Hqbx3zv6twBw==", + "dependencies": { + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "chalk": "^4.1.0", + "commander": "^7.2.0", + "gzip-size": "^6.0.0", + "lodash": "^4.17.20", + "opener": "^1.5.2", + "sirv": "^1.0.7", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/webpack-dev-middleware/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-middleware/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz", + "integrity": "sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==", + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.4.2" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.10.0.tgz", + "integrity": "sha512-+s49uSmZpvtAsd2h37vIPy1RBusaLawVe8of+GyEPsaJTCMpj/2v8NpeK1SHXjBlQ95lQTmQofOJnFiLoaN3yw==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/webpack/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", + "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpackbar": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-5.0.2.tgz", + "integrity": "sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==", + "dependencies": { + "chalk": "^4.1.0", + "consola": "^2.15.3", + "pretty-time": "^1.1.0", + "std-env": "^3.0.1" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "webpack": "3 || 4 || 5" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==" + }, + "node_modules/word-wrap": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.0.1.tgz", + "integrity": "sha512-QFF+ufAqhoYHvoHdajT/Po7KoXVBPXS2bgjIam5isfWJPfIOnQZ50JtUiVvCv/sjgacf3yRrt2ZKUZ/V4itN4g==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zwitch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", + "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + }, + "dependencies": { + "@algolia/autocomplete-core": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.7.4.tgz", + "integrity": "sha512-daoLpQ3ps/VTMRZDEBfU8ixXd+amZcNJ4QSP3IERGyzqnL5Ch8uSRFt/4G8pUvW9c3o6GA4vtVv4I4lmnkdXyg==", + "requires": { + "@algolia/autocomplete-shared": "1.7.4" + } + }, + "@algolia/autocomplete-preset-algolia": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.7.4.tgz", + "integrity": "sha512-s37hrvLEIfcmKY8VU9LsAXgm2yfmkdHT3DnA3SgHaY93yjZ2qL57wzb5QweVkYuEBZkT2PIREvRoLXC2sxTbpQ==", + "requires": { + "@algolia/autocomplete-shared": "1.7.4" + } + }, + "@algolia/autocomplete-shared": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.7.4.tgz", + "integrity": "sha512-2VGCk7I9tA9Ge73Km99+Qg87w0wzW4tgUruvWAn/gfey1ZXgmxZtyIRBebk35R1O8TbK77wujVtCnpsGpRy1kg==" + }, + "@algolia/cache-browser-local-storage": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.17.0.tgz", + "integrity": "sha512-myRSRZDIMYB8uCkO+lb40YKiYHi0fjpWRtJpR/dgkaiBlSD0plRyB6lLOh1XIfmMcSeBOqDE7y9m8xZMrXYfyQ==", + "requires": { + "@algolia/cache-common": "4.17.0" + } + }, + "@algolia/cache-common": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.17.0.tgz", + "integrity": "sha512-g8mXzkrcUBIPZaulAuqE7xyHhLAYAcF2xSch7d9dABheybaU3U91LjBX6eJTEB7XVhEsgK4Smi27vWtAJRhIKQ==" + }, + "@algolia/cache-in-memory": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.17.0.tgz", + "integrity": "sha512-PT32ciC/xI8z919d0oknWVu3kMfTlhQn3MKxDln3pkn+yA7F7xrxSALysxquv+MhFfNAcrtQ/oVvQVBAQSHtdw==", + "requires": { + "@algolia/cache-common": "4.17.0" + } + }, + "@algolia/client-account": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.17.0.tgz", + "integrity": "sha512-sSEHx9GA6m7wrlsSMNBGfyzlIfDT2fkz2u7jqfCCd6JEEwmxt8emGmxAU/0qBfbhRSuGvzojoLJlr83BSZAKjA==", + "requires": { + "@algolia/client-common": "4.17.0", + "@algolia/client-search": "4.17.0", + "@algolia/transporter": "4.17.0" + } + }, + "@algolia/client-analytics": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.17.0.tgz", + "integrity": "sha512-84ooP8QA3mQ958hQ9wozk7hFUbAO+81CX1CjAuerxBqjKIInh1fOhXKTaku05O/GHBvcfExpPLIQuSuLYziBXQ==", + "requires": { + "@algolia/client-common": "4.17.0", + "@algolia/client-search": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" + } + }, + "@algolia/client-common": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.17.0.tgz", + "integrity": "sha512-jHMks0ZFicf8nRDn6ma8DNNsdwGgP/NKiAAL9z6rS7CymJ7L0+QqTJl3rYxRW7TmBhsUH40wqzmrG6aMIN/DrQ==", + "requires": { + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" + } + }, + "@algolia/client-personalization": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.17.0.tgz", + "integrity": "sha512-RMzN4dZLIta1YuwT7QC9o+OeGz2cU6eTOlGNE/6RcUBLOU3l9tkCOdln5dPE2jp8GZXPl2yk54b2nSs1+pAjqw==", + "requires": { + "@algolia/client-common": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" + } + }, + "@algolia/client-search": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.17.0.tgz", + "integrity": "sha512-x4P2wKrrRIXszT8gb7eWsMHNNHAJs0wE7/uqbufm4tZenAp+hwU/hq5KVsY50v+PfwM0LcDwwn/1DroujsTFoA==", + "requires": { + "@algolia/client-common": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" + } + }, + "@algolia/events": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz", + "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==" + }, + "@algolia/logger-common": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.17.0.tgz", + "integrity": "sha512-DGuoZqpTmIKJFDeyAJ7M8E/LOenIjWiOsg1XJ1OqAU/eofp49JfqXxbfgctlVZVmDABIyOz8LqEoJ6ZP4DTyvw==" + }, + "@algolia/logger-console": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.17.0.tgz", + "integrity": "sha512-zMPvugQV/gbXUvWBCzihw6m7oxIKp48w37QBIUu/XqQQfxhjoOE9xyfJr1KldUt5FrYOKZJVsJaEjTsu+bIgQg==", + "requires": { + "@algolia/logger-common": "4.17.0" + } + }, + "@algolia/requester-browser-xhr": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.17.0.tgz", + "integrity": "sha512-aSOX/smauyTkP21Pf52pJ1O2LmNFJ5iHRIzEeTh0mwBeADO4GdG94cAWDILFA9rNblq/nK3EDh3+UyHHjplZ1A==", + "requires": { + "@algolia/requester-common": "4.17.0" + } + }, + "@algolia/requester-common": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.17.0.tgz", + "integrity": "sha512-XJjmWFEUlHu0ijvcHBoixuXfEoiRUdyzQM6YwTuB8usJNIgShua8ouFlRWF8iCeag0vZZiUm4S2WCVBPkdxFgg==" + }, + "@algolia/requester-node-http": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.17.0.tgz", + "integrity": "sha512-bpb/wDA1aC6WxxM8v7TsFspB7yBN3nqCGs2H1OADolQR/hiAIjAxusbuMxVbRFOdaUvAIqioIIkWvZdpYNIn8w==", + "requires": { + "@algolia/requester-common": "4.17.0" + } + }, + "@algolia/transporter": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.17.0.tgz", + "integrity": "sha512-6xL6H6fe+Fi0AEP3ziSgC+G04RK37iRb4uUUqVAH9WPYFI8g+LYFq6iv5HS8Cbuc5TTut+Bwj6G+dh/asdb9uA==", + "requires": { + "@algolia/cache-common": "4.17.0", + "@algolia/logger-common": "4.17.0", + "@algolia/requester-common": "4.17.0" + } + }, + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/compat-data": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.4.tgz", + "integrity": "sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==" + }, + "@babel/core": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", + "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.6", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helpers": "^7.19.4", + "@babel/parser": "^7.19.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/generator": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.6.tgz", + "integrity": "sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA==", + "requires": { + "@babel/types": "^7.19.4", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "requires": { + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz", + "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==", + "requires": { + "@babel/compat-data": "^7.19.3", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz", + "integrity": "sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", + "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.1.0" + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "requires": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "requires": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", + "requires": { + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-transforms": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz", + "integrity": "sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==", + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.19.4", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-replace-supers": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", + "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-simple-access": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", + "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", + "requires": { + "@babel/types": "^7.19.4" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz", + "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", + "requires": { + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" + }, + "@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==" + }, + "@babel/helper-wrap-function": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", + "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", + "requires": { + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + } + }, + "@babel/helpers": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.4.tgz", + "integrity": "sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw==", + "requires": { + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.4", + "@babel/types": "^7.19.4" + } + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz", + "integrity": "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==" + }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" + } + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.1.tgz", + "integrity": "sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q==", + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-class-static-block": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", + "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.19.4.tgz", + "integrity": "sha512-wHmj6LDxVDnL+3WhXteUBaoM1aVILZODAUjg11kHqG4cOlfgMQGxw6aCgvrXrmaJR3Bn14oZhImyCPZzRpC93Q==", + "requires": { + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.18.8" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", + "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz", + "integrity": "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", + "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", + "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.19.4.tgz", + "integrity": "sha512-934S2VLLlt2hRJwPf4MczaOr4hYF0z+VKPwqTNxyKX7NthTiPfhuKFWQZHXRM0vh/wo/VyXB3s4bZUNA08l+tQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz", + "integrity": "sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.19.0", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.19.4.tgz", + "integrity": "sha512-t0j0Hgidqf0aM86dF8U+vXYReUgJnlv4bZLsyoPnwZNrGY+7/38o8YjaELrvHeVfTZao15kjR0PVv0nju2iduA==", + "requires": { + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "requires": { + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.19.6.tgz", + "integrity": "sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg==", + "requires": { + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.19.6.tgz", + "integrity": "sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==", + "requires": { + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-simple-access": "^7.19.4" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.6.tgz", + "integrity": "sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==", + "requires": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-identifier": "^7.19.1" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "requires": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", + "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz", + "integrity": "sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-react-constant-elements": { + "version": "7.18.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.18.12.tgz", + "integrity": "sha512-Q99U9/ttiu+LMnRU8psd23HhvwXmKWDQIpocm0JKaICcZHnw+mdQbHm6xnSy7dOl8I5PELakYtNBubNQlBXbZw==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-react-display-name": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz", + "integrity": "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-react-jsx": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.19.0.tgz", + "integrity": "sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/plugin-syntax-jsx": "^7.18.6", + "@babel/types": "^7.19.0" + } + }, + "@babel/plugin-transform-react-jsx-development": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz", + "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==", + "requires": { + "@babel/plugin-transform-react-jsx": "^7.18.6" + } + }, + "@babel/plugin-transform-react-pure-annotations": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz", + "integrity": "sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", + "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "regenerator-transform": "^0.15.0" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz", + "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==", + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", + "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", + "requires": { + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.19.3.tgz", + "integrity": "sha512-z6fnuK9ve9u/0X0rRvI9MY0xg+DOUaABDYOe+/SQTxtlptaBB/V9JIUxJn6xp3lMBeb9qe8xSFmHU35oZDXD+w==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/plugin-syntax-typescript": "^7.18.6" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/preset-env": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.4.tgz", + "integrity": "sha512-5QVOTXUdqTCjQuh2GGtdd7YEhoRXBMVGROAtsBeLGIbIz3obCBIfRMT1I3ZKkMgNzwkyCkftDXSSkHxnfVf4qg==", + "requires": { + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.19.1", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.19.4", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.19.4", + "@babel/plugin-transform-classes": "^7.19.0", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.19.4", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.19.0", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.8", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.19.0", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.19.4", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "core-js-compat": "^3.25.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/preset-react": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.18.6.tgz", + "integrity": "sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-react-display-name": "^7.18.6", + "@babel/plugin-transform-react-jsx": "^7.18.6", + "@babel/plugin-transform-react-jsx-development": "^7.18.6", + "@babel/plugin-transform-react-pure-annotations": "^7.18.6" + } + }, + "@babel/preset-typescript": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz", + "integrity": "sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-typescript": "^7.18.6" + } + }, + "@babel/runtime": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "requires": { + "regenerator-runtime": "^0.13.11" + } + }, + "@babel/runtime-corejs3": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.6.tgz", + "integrity": "sha512-oWNn1ZlGde7b4i/3tnixpH9qI0bOAACiUs+KEES4UUCnsPjVWFlWdLV/iwJuPC2qp3EowbAqsm+0XqNwnwYhxA==", + "requires": { + "core-js-pure": "^3.25.1", + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + } + }, + "@babel/traverse": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.6.tgz", + "integrity": "sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ==", + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.19.6", + "@babel/types": "^7.19.4", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", + "requires": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + } + }, + "@bcherny/json-schema-ref-parser": { + "version": "10.0.5-fork", + "resolved": "https://registry.npmjs.org/@bcherny/json-schema-ref-parser/-/json-schema-ref-parser-10.0.5-fork.tgz", + "integrity": "sha512-E/jKbPoca1tfUPj3iSbitDZTGnq6FUFjkH6L8U2oDwSuwK1WhnnVtCG7oFOTg/DDnyoXbQYUiUiGOibHqaGVnw==", + "dev": true, + "requires": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.6", + "call-me-maybe": "^1.0.1", + "js-yaml": "^4.1.0" + } + }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "optional": true + }, + "@docsearch/css": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.3.3.tgz", + "integrity": "sha512-6SCwI7P8ao+se1TUsdZ7B4XzL+gqeQZnBc+2EONZlcVa0dVrk0NjETxozFKgMv0eEGH8QzP1fkN+A1rH61l4eg==" + }, + "@docsearch/react": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.3.3.tgz", + "integrity": "sha512-pLa0cxnl+G0FuIDuYlW+EBK6Rw2jwLw9B1RHIeS4N4s2VhsfJ/wzeCi3CWcs5yVfxLd5ZK50t//TMA5e79YT7Q==", + "requires": { + "@algolia/autocomplete-core": "1.7.4", + "@algolia/autocomplete-preset-algolia": "1.7.4", + "@docsearch/css": "3.3.3", + "algoliasearch": "^4.0.0" + } + }, + "@docusaurus/core": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.4.0.tgz", + "integrity": "sha512-J55/WEoIpRcLf3afO5POHPguVZosKmJEQWKBL+K7TAnfuE7i+Y0NPLlkKtnWCehagGsgTqClfQEexH/UT4kELA==", + "requires": { + "@babel/core": "^7.18.6", + "@babel/generator": "^7.18.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.18.6", + "@babel/preset-env": "^7.18.6", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.18.6", + "@babel/runtime": "^7.18.6", + "@babel/runtime-corejs3": "^7.18.6", + "@babel/traverse": "^7.18.8", + "@docusaurus/cssnano-preset": "2.4.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/react-loadable": "5.5.2", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-common": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "@slorber/static-site-generator-webpack-plugin": "^4.0.7", + "@svgr/webpack": "^6.2.1", + "autoprefixer": "^10.4.7", + "babel-loader": "^8.2.5", + "babel-plugin-dynamic-import-node": "^2.3.3", + "boxen": "^6.2.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "clean-css": "^5.3.0", + "cli-table3": "^0.6.2", + "combine-promises": "^1.1.0", + "commander": "^5.1.0", + "copy-webpack-plugin": "^11.0.0", + "core-js": "^3.23.3", + "css-loader": "^6.7.1", + "css-minimizer-webpack-plugin": "^4.0.0", + "cssnano": "^5.1.12", + "del": "^6.1.1", + "detect-port": "^1.3.0", + "escape-html": "^1.0.3", + "eta": "^2.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^10.1.0", + "html-minifier-terser": "^6.1.0", + "html-tags": "^3.2.0", + "html-webpack-plugin": "^5.5.0", + "import-fresh": "^3.3.0", + "leven": "^3.1.0", + "lodash": "^4.17.21", + "mini-css-extract-plugin": "^2.6.1", + "postcss": "^8.4.14", + "postcss-loader": "^7.0.0", + "prompts": "^2.4.2", + "react-dev-utils": "^12.0.1", + "react-helmet-async": "^1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@5.5.2", + "react-loadable-ssr-addon-v5-slorber": "^1.0.1", + "react-router": "^5.3.3", + "react-router-config": "^5.1.1", + "react-router-dom": "^5.3.3", + "rtl-detect": "^1.0.4", + "semver": "^7.3.7", + "serve-handler": "^6.1.3", + "shelljs": "^0.8.5", + "terser-webpack-plugin": "^5.3.3", + "tslib": "^2.4.0", + "update-notifier": "^5.1.0", + "url-loader": "^4.1.1", + "wait-on": "^6.0.1", + "webpack": "^5.73.0", + "webpack-bundle-analyzer": "^4.5.0", + "webpack-dev-server": "^4.9.3", + "webpack-merge": "^5.8.0", + "webpackbar": "^5.0.2" + } + }, + "@docusaurus/cssnano-preset": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.4.0.tgz", + "integrity": "sha512-RmdiA3IpsLgZGXRzqnmTbGv43W4OD44PCo+6Q/aYjEM2V57vKCVqNzuafE94jv0z/PjHoXUrjr69SaRymBKYYw==", + "requires": { + "cssnano-preset-advanced": "^5.3.8", + "postcss": "^8.4.14", + "postcss-sort-media-queries": "^4.2.1", + "tslib": "^2.4.0" + } + }, + "@docusaurus/logger": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-2.4.0.tgz", + "integrity": "sha512-T8+qR4APN+MjcC9yL2Es+xPJ2923S9hpzDmMtdsOcUGLqpCGBbU1vp3AAqDwXtVgFkq+NsEk7sHdVsfLWR/AXw==", + "requires": { + "chalk": "^4.1.2", + "tslib": "^2.4.0" + } + }, + "@docusaurus/mdx-loader": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.4.0.tgz", + "integrity": "sha512-GWoH4izZKOmFoC+gbI2/y8deH/xKLvzz/T5BsEexBye8EHQlwsA7FMrVa48N063bJBH4FUOiRRXxk5rq9cC36g==", + "requires": { + "@babel/parser": "^7.18.8", + "@babel/traverse": "^7.18.8", + "@docusaurus/logger": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@mdx-js/mdx": "^1.6.22", + "escape-html": "^1.0.3", + "file-loader": "^6.2.0", + "fs-extra": "^10.1.0", + "image-size": "^1.0.1", + "mdast-util-to-string": "^2.0.0", + "remark-emoji": "^2.2.0", + "stringify-object": "^3.3.0", + "tslib": "^2.4.0", + "unified": "^9.2.2", + "unist-util-visit": "^2.0.3", + "url-loader": "^4.1.1", + "webpack": "^5.73.0" + } + }, + "@docusaurus/module-type-aliases": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-2.4.0.tgz", + "integrity": "sha512-YEQO2D3UXs72qCn8Cr+RlycSQXVGN9iEUyuHwTuK4/uL/HFomB2FHSU0vSDM23oLd+X/KibQ3Ez6nGjQLqXcHg==", + "requires": { + "@docusaurus/react-loadable": "5.5.2", + "@docusaurus/types": "2.4.0", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "@types/react-router-dom": "*", + "react-helmet-async": "*", + "react-loadable": "npm:@docusaurus/react-loadable@5.5.2" + } + }, + "@docusaurus/plugin-content-blog": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.4.0.tgz", + "integrity": "sha512-YwkAkVUxtxoBAIj/MCb4ohN0SCtHBs4AS75jMhPpf67qf3j+U/4n33cELq7567hwyZ6fMz2GPJcVmctzlGGThQ==", + "requires": { + "@docusaurus/core": "2.4.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-common": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "cheerio": "^1.0.0-rc.12", + "feed": "^4.2.2", + "fs-extra": "^10.1.0", + "lodash": "^4.17.21", + "reading-time": "^1.5.0", + "tslib": "^2.4.0", + "unist-util-visit": "^2.0.3", + "utility-types": "^3.10.0", + "webpack": "^5.73.0" + } + }, + "@docusaurus/plugin-content-docs": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.4.0.tgz", + "integrity": "sha512-ic/Z/ZN5Rk/RQo+Io6rUGpToOtNbtPloMR2JcGwC1xT2riMu6zzfSwmBi9tHJgdXH6CB5jG+0dOZZO8QS5tmDg==", + "requires": { + "@docusaurus/core": "2.4.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/module-type-aliases": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "@types/react-router-config": "^5.0.6", + "combine-promises": "^1.1.0", + "fs-extra": "^10.1.0", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "tslib": "^2.4.0", + "utility-types": "^3.10.0", + "webpack": "^5.73.0" + } + }, + "@docusaurus/plugin-content-pages": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.4.0.tgz", + "integrity": "sha512-Pk2pOeOxk8MeU3mrTU0XLIgP9NZixbdcJmJ7RUFrZp1Aj42nd0RhIT14BGvXXyqb8yTQlk4DmYGAzqOfBsFyGw==", + "requires": { + "@docusaurus/core": "2.4.0", + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "fs-extra": "^10.1.0", + "tslib": "^2.4.0", + "webpack": "^5.73.0" + } + }, + "@docusaurus/plugin-debug": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.4.0.tgz", + "integrity": "sha512-KC56DdYjYT7Txyux71vXHXGYZuP6yYtqwClvYpjKreWIHWus5Zt6VNi23rMZv3/QKhOCrN64zplUbdfQMvddBQ==", + "requires": { + "@docusaurus/core": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "fs-extra": "^10.1.0", + "react-json-view": "^1.21.3", + "tslib": "^2.4.0" + } + }, + "@docusaurus/plugin-google-analytics": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.4.0.tgz", + "integrity": "sha512-uGUzX67DOAIglygdNrmMOvEp8qG03X20jMWadeqVQktS6nADvozpSLGx4J0xbkblhJkUzN21WiilsP9iVP+zkw==", + "requires": { + "@docusaurus/core": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "tslib": "^2.4.0" + } + }, + "@docusaurus/plugin-google-gtag": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.4.0.tgz", + "integrity": "sha512-adj/70DANaQs2+TF/nRdMezDXFAV/O/pjAbUgmKBlyOTq5qoMe0Tk4muvQIwWUmiUQxFJe+sKlZGM771ownyOg==", + "requires": { + "@docusaurus/core": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "tslib": "^2.4.0" + } + }, + "@docusaurus/plugin-google-tag-manager": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.4.0.tgz", + "integrity": "sha512-E66uGcYs4l7yitmp/8kMEVQftFPwV9iC62ORh47Veqzs6ExwnhzBkJmwDnwIysHBF1vlxnzET0Fl2LfL5fRR3A==", + "requires": { + "@docusaurus/core": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "tslib": "^2.4.0" + } + }, + "@docusaurus/plugin-sitemap": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.4.0.tgz", + "integrity": "sha512-pZxh+ygfnI657sN8a/FkYVIAmVv0CGk71QMKqJBOfMmDHNN1FeDeFkBjWP49ejBqpqAhjufkv5UWq3UOu2soCw==", + "requires": { + "@docusaurus/core": "2.4.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-common": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "fs-extra": "^10.1.0", + "sitemap": "^7.1.1", + "tslib": "^2.4.0" + } + }, + "@docusaurus/preset-classic": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.4.0.tgz", + "integrity": "sha512-/5z5o/9bc6+P5ool2y01PbJhoGddEGsC0ej1MF6mCoazk8A+kW4feoUd68l7Bnv01rCnG3xy7kHUQP97Y0grUA==", + "requires": { + "@docusaurus/core": "2.4.0", + "@docusaurus/plugin-content-blog": "2.4.0", + "@docusaurus/plugin-content-docs": "2.4.0", + "@docusaurus/plugin-content-pages": "2.4.0", + "@docusaurus/plugin-debug": "2.4.0", + "@docusaurus/plugin-google-analytics": "2.4.0", + "@docusaurus/plugin-google-gtag": "2.4.0", + "@docusaurus/plugin-google-tag-manager": "2.4.0", + "@docusaurus/plugin-sitemap": "2.4.0", + "@docusaurus/theme-classic": "2.4.0", + "@docusaurus/theme-common": "2.4.0", + "@docusaurus/theme-search-algolia": "2.4.0", + "@docusaurus/types": "2.4.0" + } + }, + "@docusaurus/react-loadable": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", + "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", + "requires": { + "@types/react": "*", + "prop-types": "^15.6.2" + } + }, + "@docusaurus/theme-classic": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.4.0.tgz", + "integrity": "sha512-GMDX5WU6Z0OC65eQFgl3iNNEbI9IMJz9f6KnOyuMxNUR6q0qVLsKCNopFUDfFNJ55UU50o7P7o21yVhkwpfJ9w==", + "requires": { + "@docusaurus/core": "2.4.0", + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/module-type-aliases": "2.4.0", + "@docusaurus/plugin-content-blog": "2.4.0", + "@docusaurus/plugin-content-docs": "2.4.0", + "@docusaurus/plugin-content-pages": "2.4.0", + "@docusaurus/theme-common": "2.4.0", + "@docusaurus/theme-translations": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-common": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "@mdx-js/react": "^1.6.22", + "clsx": "^1.2.1", + "copy-text-to-clipboard": "^3.0.1", + "infima": "0.2.0-alpha.43", + "lodash": "^4.17.21", + "nprogress": "^0.2.0", + "postcss": "^8.4.14", + "prism-react-renderer": "^1.3.5", + "prismjs": "^1.28.0", + "react-router-dom": "^5.3.3", + "rtlcss": "^3.5.0", + "tslib": "^2.4.0", + "utility-types": "^3.10.0" + } + }, + "@docusaurus/theme-common": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.4.0.tgz", + "integrity": "sha512-IkG/l5f/FLY6cBIxtPmFnxpuPzc5TupuqlOx+XDN+035MdQcAh8wHXXZJAkTeYDeZ3anIUSUIvWa7/nRKoQEfg==", + "requires": { + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/module-type-aliases": "2.4.0", + "@docusaurus/plugin-content-blog": "2.4.0", + "@docusaurus/plugin-content-docs": "2.4.0", + "@docusaurus/plugin-content-pages": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-common": "2.4.0", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "clsx": "^1.2.1", + "parse-numeric-range": "^1.3.0", + "prism-react-renderer": "^1.3.5", + "tslib": "^2.4.0", + "use-sync-external-store": "^1.2.0", + "utility-types": "^3.10.0" + } + }, + "@docusaurus/theme-search-algolia": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.4.0.tgz", + "integrity": "sha512-pPCJSCL1Qt4pu/Z0uxBAuke0yEBbxh0s4fOvimna7TEcBLPq0x06/K78AaABXrTVQM6S0vdocFl9EoNgU17hqA==", + "requires": { + "@docsearch/react": "^3.1.1", + "@docusaurus/core": "2.4.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/plugin-content-docs": "2.4.0", + "@docusaurus/theme-common": "2.4.0", + "@docusaurus/theme-translations": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "algoliasearch": "^4.13.1", + "algoliasearch-helper": "^3.10.0", + "clsx": "^1.2.1", + "eta": "^2.0.0", + "fs-extra": "^10.1.0", + "lodash": "^4.17.21", + "tslib": "^2.4.0", + "utility-types": "^3.10.0" + } + }, + "@docusaurus/theme-translations": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.4.0.tgz", + "integrity": "sha512-kEoITnPXzDPUMBHk3+fzEzbopxLD3fR5sDoayNH0vXkpUukA88/aDL1bqkhxWZHA3LOfJ3f0vJbOwmnXW5v85Q==", + "requires": { + "fs-extra": "^10.1.0", + "tslib": "^2.4.0" + } + }, + "@docusaurus/types": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-2.4.0.tgz", + "integrity": "sha512-xaBXr+KIPDkIaef06c+i2HeTqVNixB7yFut5fBXPGI2f1rrmEV2vLMznNGsFwvZ5XmA3Quuefd4OGRkdo97Dhw==", + "requires": { + "@types/history": "^4.7.11", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.6.0", + "react-helmet-async": "^1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.73.0", + "webpack-merge": "^5.8.0" + } + }, + "@docusaurus/utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.4.0.tgz", + "integrity": "sha512-89hLYkvtRX92j+C+ERYTuSUK6nF9bGM32QThcHPg2EDDHVw6FzYQXmX6/p+pU5SDyyx5nBlE4qXR92RxCAOqfg==", + "requires": { + "@docusaurus/logger": "2.4.0", + "@svgr/webpack": "^6.2.1", + "escape-string-regexp": "^4.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^10.1.0", + "github-slugger": "^1.4.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.4.0", + "url-loader": "^4.1.1", + "webpack": "^5.73.0" + } + }, + "@docusaurus/utils-common": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.4.0.tgz", + "integrity": "sha512-zIMf10xuKxddYfLg5cS19x44zud/E9I7lj3+0bv8UIs0aahpErfNrGhijEfJpAfikhQ8tL3m35nH3hJ3sOG82A==", + "requires": { + "tslib": "^2.4.0" + } + }, + "@docusaurus/utils-validation": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.4.0.tgz", + "integrity": "sha512-IrBsBbbAp6y7mZdJx4S4pIA7dUyWSA0GNosPk6ZJ0fX3uYIEQgcQSGIgTeSC+8xPEx3c16o03en1jSDpgQgz/w==", + "requires": { + "@docusaurus/logger": "2.4.0", + "@docusaurus/utils": "2.4.0", + "joi": "^17.6.0", + "js-yaml": "^4.1.0", + "tslib": "^2.4.0" + } + }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "devOptional": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", + "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", + "devOptional": true + }, + "@eslint/eslintrc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", + "devOptional": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.5.1", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "devOptional": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "devOptional": true + } + } + }, + "@eslint/js": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", + "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", + "devOptional": true + }, + "@fortawesome/fontawesome-common-types": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz", + "integrity": "sha512-HNii132xfomg5QVZw0HwXXpN22s7VBHQBv9CeOu9tfJnhsWQNd2lmTNi8CSrnw5B+5YOmzu1UoPAyxaXsJ6RgQ==" + }, + "@fortawesome/fontawesome-svg-core": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.2.tgz", + "integrity": "sha512-gjYDSKv3TrM2sLTOKBc5rH9ckje8Wrwgx1CxAPbN5N3Fm4prfi7NsJVWd1jklp7i5uSCVwhZS5qlhMXqLrpAIg==", + "requires": { + "@fortawesome/fontawesome-common-types": "6.4.2" + }, + "dependencies": { + "@fortawesome/fontawesome-common-types": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.2.tgz", + "integrity": "sha512-1DgP7f+XQIJbLFCTX1V2QnxVmpLdKdzzo2k8EmvDOePfchaIGQ9eCHj2up3/jNEbZuBqel5OxiaOJf37TWauRA==" + } + } + }, + "@fortawesome/free-solid-svg-icons": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.4.0.tgz", + "integrity": "sha512-kutPeRGWm8V5dltFP1zGjQOEAzaLZj4StdQhWVZnfGFCvAPVvHh8qk5bRrU4KXnRRRNni5tKQI9PBAdI6MP8nQ==", + "requires": { + "@fortawesome/fontawesome-common-types": "6.4.0" + } + }, + "@fortawesome/react-fontawesome": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", + "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", + "requires": { + "prop-types": "^15.8.1" + } + }, + "@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" + }, + "@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "devOptional": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "devOptional": true + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "devOptional": true + }, + "@jest/schemas": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", + "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", + "requires": { + "@sinclair/typebox": "^0.24.1" + } + }, + "@jest/types": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.2.1.tgz", + "integrity": "sha512-O/QNDQODLnINEPAI0cl9U6zUIDXEWXt6IC1o2N2QENuos7hlGUIthlKyV4p6ki3TvXFX071blj8HUhgLGquPjw==", + "requires": { + "@jest/schemas": "^29.0.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", + "dev": true + }, + "@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" + }, + "@mdx-js/mdx": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-1.6.22.tgz", + "integrity": "sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA==", + "requires": { + "@babel/core": "7.12.9", + "@babel/plugin-syntax-jsx": "7.12.1", + "@babel/plugin-syntax-object-rest-spread": "7.8.3", + "@mdx-js/util": "1.6.22", + "babel-plugin-apply-mdx-type-prop": "1.6.22", + "babel-plugin-extract-import-names": "1.6.22", + "camelcase-css": "2.0.1", + "detab": "2.0.4", + "hast-util-raw": "6.0.1", + "lodash.uniq": "4.5.0", + "mdast-util-to-hast": "10.0.1", + "remark-footnotes": "2.0.0", + "remark-mdx": "1.6.22", + "remark-parse": "8.0.3", + "remark-squeeze-paragraphs": "4.0.0", + "style-to-object": "0.3.0", + "unified": "9.2.0", + "unist-builder": "2.0.3", + "unist-util-visit": "2.0.3" + }, + "dependencies": { + "@babel/core": { + "version": "7.12.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", + "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.5", + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helpers": "^7.12.5", + "@babel/parser": "^7.12.7", + "@babel/template": "^7.12.7", + "@babel/traverse": "^7.12.9", + "@babel/types": "^7.12.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", + "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" + }, + "unified": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", + "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", + "requires": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^2.0.0", + "trough": "^1.0.0", + "vfile": "^4.0.0" + } + }, + "vfile": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", + "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", + "requires": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-message": "^2.0.0" + } + }, + "vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + } + } + } + }, + "@mdx-js/react": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-1.6.22.tgz", + "integrity": "sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==", + "requires": {} + }, + "@mdx-js/util": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz", + "integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==" + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@pkgr/utils": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz", + "integrity": "sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "is-glob": "^4.0.3", + "open": "^8.4.0", + "picocolors": "^1.0.0", + "tiny-glob": "^0.2.9", + "tslib": "^2.4.0" + } + }, + "@polka/url": { + "version": "1.0.0-next.21", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", + "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==" + }, + "@sideway/address": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" + }, + "@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + }, + "@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" + }, + "@slorber/static-site-generator-webpack-plugin": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.7.tgz", + "integrity": "sha512-Ug7x6z5lwrz0WqdnNFOMYrDQNTPAprvHLSh6+/fmml3qUiz6l5eq+2MzLKWtn/q5K5NpSiFsZTP/fck/3vjSxA==", + "requires": { + "eval": "^0.1.8", + "p-map": "^4.0.0", + "webpack-sources": "^3.2.2" + } + }, + "@svgr/babel-plugin-add-jsx-attribute": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.5.0.tgz", + "integrity": "sha512-Cp1JR1IPrQNvPRbkfcPmax52iunBC+eQDyBce8feOIIbVH6ZpVhErYoJtPWRBj2rKi4Wi9HvCm1+L1UD6QlBmg==", + "requires": {} + }, + "@svgr/babel-plugin-remove-jsx-attribute": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-6.5.0.tgz", + "integrity": "sha512-8zYdkym7qNyfXpWvu4yq46k41pyNM9SOstoWhKlm+IfdCE1DdnRKeMUPsWIEO/DEkaWxJ8T9esNdG3QwQ93jBA==", + "requires": {} + }, + "@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-6.5.0.tgz", + "integrity": "sha512-NFdxMq3xA42Kb1UbzCVxplUc0iqSyM9X8kopImvFnB+uSDdzIHOdbs1op8ofAvVRtbg4oZiyRl3fTYeKcOe9Iw==", + "requires": {} + }, + "@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.5.0.tgz", + "integrity": "sha512-XWm64/rSPUCQ+MFyA9lhMO+w8bOZvkTvovRIU1lpIy63ysPaVAFtxjQiZj+S7QaLaLGUXkSkf8WZsaN+QPo/gA==", + "requires": {} + }, + "@svgr/babel-plugin-svg-dynamic-title": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.5.0.tgz", + "integrity": "sha512-JIF2D2ltiWFGlTw2fJ9jJg1fNT9rWjOD2Cf0/xzeW6Z2LIRQTHcRHxpZq359+SRWtEPsCXEWV2Xmd+DMBj6dBw==", + "requires": {} + }, + "@svgr/babel-plugin-svg-em-dimensions": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.5.0.tgz", + "integrity": "sha512-uuo0FfLP4Nu2zncOcoUFDzZdXWma2bxkTGk0etRThs4/PghvPIGaW8cPhCg6yJ8zpaauWcKV0wZtzKlJRCtVzg==", + "requires": {} + }, + "@svgr/babel-plugin-transform-react-native-svg": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.5.0.tgz", + "integrity": "sha512-VMRWyOmrV+DaEFPgP3hZMsFgs2g87ojs3txw0Rx8iz6Nf/E3UoHUwTqpkSCWd3Hsnc9gMOY9+wl6+/Ycleh1sw==", + "requires": {} + }, + "@svgr/babel-plugin-transform-svg-component": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.5.0.tgz", + "integrity": "sha512-b67Ul3SelaqvGEEG/1B3VJ03KUtGFgRQjRLCCjdttMQLcYa9l/izQFEclNFx53pNqhijUMNKHPhGMY/CWGVKig==", + "requires": {} + }, + "@svgr/babel-preset": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-6.5.0.tgz", + "integrity": "sha512-UWM98PKVuMqw2UZo8YO3erI6nF1n7/XBYTXBqR0QhZP7HTjYK6QxFNvPfIshddy1hBdzhVpkf148Vg8xiVOtyg==", + "requires": { + "@svgr/babel-plugin-add-jsx-attribute": "^6.5.0", + "@svgr/babel-plugin-remove-jsx-attribute": "^6.5.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "^6.5.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^6.5.0", + "@svgr/babel-plugin-svg-dynamic-title": "^6.5.0", + "@svgr/babel-plugin-svg-em-dimensions": "^6.5.0", + "@svgr/babel-plugin-transform-react-native-svg": "^6.5.0", + "@svgr/babel-plugin-transform-svg-component": "^6.5.0" + } + }, + "@svgr/core": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-6.5.0.tgz", + "integrity": "sha512-jIbu36GMjfK8HCCQitkfVVeQ2vSXGfq0ef0GO9HUxZGjal6Kvpkk4PwpkFP+OyCzF+skQFT9aWrUqekT3pKF8w==", + "requires": { + "@babel/core": "^7.18.5", + "@svgr/babel-preset": "^6.5.0", + "@svgr/plugin-jsx": "^6.5.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.1" + } + }, + "@svgr/hast-util-to-babel-ast": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.5.0.tgz", + "integrity": "sha512-PPy94U/EiPQ2dY0b4jEqj4QOdDRq6DG7aTHjpGaL8HlKSHkpU1DpjfywCXTJqtOdCo2FywjWvg0U2FhqMeUJaA==", + "requires": { + "@babel/types": "^7.18.4", + "entities": "^4.3.0" + } + }, + "@svgr/plugin-jsx": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-6.5.0.tgz", + "integrity": "sha512-1CHMqOBKoNk/ZPU+iGXKcQPC6q9zaD7UOI99J+BaGY5bdCztcf5bZyi0QZSDRJtCQpdofeVv7XfBYov2mtl0Pw==", + "requires": { + "@babel/core": "^7.18.5", + "@svgr/babel-preset": "^6.5.0", + "@svgr/hast-util-to-babel-ast": "^6.5.0", + "svg-parser": "^2.0.4" + } + }, + "@svgr/plugin-svgo": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-6.5.0.tgz", + "integrity": "sha512-8Zv1Yyv6I7HlIqrqGFM0sDKQrhjbfNZJawR8UjIaVWSb0tKZP1Ra6ymhqIFu6FT6kDRD0Ct5NlQZ10VUujSspw==", + "requires": { + "cosmiconfig": "^7.0.1", + "deepmerge": "^4.2.2", + "svgo": "^2.8.0" + } + }, + "@svgr/webpack": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-6.5.0.tgz", + "integrity": "sha512-rM/Z4pwMhqvAXEHoHIlE4SeTb0ToQNmJuBdiHwhP2ZtywyX6XqrgCv2WX7K/UCgNYJgYbekuylgyjnuLUHTcZQ==", + "requires": { + "@babel/core": "^7.18.5", + "@babel/plugin-transform-react-constant-elements": "^7.17.12", + "@babel/preset-env": "^7.18.2", + "@babel/preset-react": "^7.17.12", + "@babel/preset-typescript": "^7.17.12", + "@svgr/core": "^6.5.0", + "@svgr/plugin-jsx": "^6.5.0", + "@svgr/plugin-svgo": "^6.5.0" + } + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==" + }, + "@tsconfig/docusaurus": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@tsconfig/docusaurus/-/docusaurus-1.0.7.tgz", + "integrity": "sha512-ffTXxGIP/IRMCjuzHd6M4/HdIrw1bMfC7Bv8hMkTadnePkpe0lG0oDSdbRpSDZb2rQMAgpbWiR10BvxvNYwYrg==", + "dev": true + }, + "@types/acorn": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", + "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", + "dev": true, + "requires": { + "@types/estree": "*" + } + }, + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "requires": { + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "requires": { + "@types/node": "*" + } + }, + "@types/connect-history-api-fallback": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", + "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "requires": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "@types/debug": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "dev": true, + "requires": { + "@types/ms": "*" + } + }, + "@types/eslint": { + "version": "8.4.8", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.8.tgz", + "integrity": "sha512-zUCKQI1bUCTi+0kQs5ZQzQ/XILWRLIlh15FXWNykJ+NG3TMKMVvwwC6GP3DR1Ylga15fB7iAExSzc4PNlR5i3w==", + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", + "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==" + }, + "@types/estree-jsx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.0.tgz", + "integrity": "sha512-3qvGd0z8F2ENTGr/GG1yViqfiKmRfrXVx5sJyHGFu3z7m5g5utCQtGp/g29JnjflhtQJBv1WDQukHiT58xPcYQ==", + "dev": true, + "requires": { + "@types/estree": "*" + } + }, + "@types/express": { + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", + "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.31", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", + "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/hast": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", + "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", + "requires": { + "@types/unist": "*" + } + }, + "@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" + }, + "@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" + }, + "@types/http-proxy": { + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", + "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", + "requires": { + "@types/node": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/js-yaml": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.5.tgz", + "integrity": "sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" + }, + "@types/lodash": { + "version": "4.14.186", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.186.tgz", + "integrity": "sha512-eHcVlLXP0c2FlMPm56ITode2AgLMSa6aJ05JTTbYbI+7EMkCEE5qk2E41d5g2lCVTqRe0GnnRFurmlCsDODrPw==", + "dev": true + }, + "@types/mdast": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", + "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==", + "requires": { + "@types/unist": "*" + } + }, + "@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" + }, + "@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==", + "dev": true + }, + "@types/node": { + "version": "18.11.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.5.tgz", + "integrity": "sha512-3JRwhbjI+cHLAkUorhf8RnqUbFXajvzX4q6fMn5JwkgtuwfYtRQYI3u4V92vI6NJuTsbBQWWh3RZjFsuevyMGQ==" + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + }, + "@types/parse5": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz", + "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==" + }, + "@types/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", + "dev": true + }, + "@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + }, + "@types/react": { + "version": "17.0.58", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.58.tgz", + "integrity": "sha512-c1GzVY97P0fGxwGxhYq989j4XwlcHQoto6wQISOC2v6wm3h0PORRWJFHlkRjfGsiG3y1609WdQ+J+tKxvrEd6A==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-helmet": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/@types/react-helmet/-/react-helmet-6.1.6.tgz", + "integrity": "sha512-ZKcoOdW/Tg+kiUbkFCBtvDw0k3nD4HJ/h/B9yWxN4uDO8OkRksWTO+EL+z/Qu3aHTeTll3Ro0Cc/8UhwBCMG5A==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/react-router": { + "version": "5.1.19", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.19.tgz", + "integrity": "sha512-Fv/5kb2STAEMT3wHzdKQK2z8xKq38EDIGVrutYLmQVVLe+4orDFquU52hQrULnEHinMKv9FSA6lf9+uNT1ITtA==", + "requires": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "@types/react-router-config": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.6.tgz", + "integrity": "sha512-db1mx37a1EJDf1XeX8jJN7R3PZABmJQXR8r28yUjVMFSjkmnQo6X6pOEEmNl+Tp2gYQOGPdYbFIipBtdElZ3Yg==", + "requires": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "requires": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + }, + "@types/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-pSAff4IAxJjfAXUG6tFkO7dsSbTmf8CtUpfhhZ5VhkRpC4628tJhh3+V6H1E+/Gs9piSzYKT5yzHO5M4GG9jkw==", + "requires": { + "@types/node": "*" + } + }, + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "requires": { + "@types/express": "*" + } + }, + "@types/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "requires": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "requires": { + "@types/node": "*" + } + }, + "@types/unist": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", + "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" + }, + "@types/ws": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "requires": { + "@types/node": "*" + } + }, + "@types/yargs": { + "version": "17.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", + "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" + }, + "@webassemblyjs/ast": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.5.tgz", + "integrity": "sha512-LHY/GSAZZRpsNQH+/oHqhRQ5FT7eoULcBqgfyTB5nQHogFnK3/7QoN7dLnwSE/JkUAF0SrRuclT7ODqMFtWxxQ==", + "requires": { + "@webassemblyjs/helper-numbers": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.5.tgz", + "integrity": "sha512-1j1zTIC5EZOtCplMBG/IEwLtUojtwFVwdyVMbL/hwWqbzlQoJsWCOavrdnLkemwNoC/EOwtUFch3fuo+cbcXYQ==" + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.5.tgz", + "integrity": "sha512-L65bDPmfpY0+yFrsgz8b6LhXmbbs38OnwDCf6NpnMUYqa+ENfE5Dq9E42ny0qz/PdR0LJyq/T5YijPnU8AXEpA==" + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.5.tgz", + "integrity": "sha512-fDKo1gstwFFSfacIeH5KfwzjykIE6ldh1iH9Y/8YkAZrhmu4TctqYjSh7t0K2VyDSXOZJ1MLhht/k9IvYGcIxg==" + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.5.tgz", + "integrity": "sha512-DhykHXM0ZABqfIGYNv93A5KKDw/+ywBFnuWybZZWcuzWHfbp21wUfRkbtz7dMGwGgT4iXjWuhRMA2Mzod6W4WA==", + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.5", + "@webassemblyjs/helper-api-error": "1.11.5", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.5.tgz", + "integrity": "sha512-oC4Qa0bNcqnjAowFn7MPCETQgDYytpsfvz4ujZz63Zu/a/v71HeCAAmZsgZ3YVKec3zSPYytG3/PrRCqbtcAvA==" + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.5.tgz", + "integrity": "sha512-uEoThA1LN2NA+K3B9wDo3yKlBfVtC6rh0i4/6hvbz071E8gTNZD/pT0MsBf7MeD6KbApMSkaAK0XeKyOZC7CIA==", + "requires": { + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-buffer": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5", + "@webassemblyjs/wasm-gen": "1.11.5" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.5.tgz", + "integrity": "sha512-37aGq6qVL8A8oPbPrSGMBcp38YZFXcHfiROflJn9jxSdSMMM5dS5P/9e2/TpaJuhE+wFrbukN2WI6Hw9MH5acg==", + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.5.tgz", + "integrity": "sha512-ajqrRSXaTJoPW+xmkfYN6l8VIeNnR4vBOTQO9HzR7IygoCcKWkICbKFbVTNMjMgMREqXEr0+2M6zukzM47ZUfQ==", + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.5.tgz", + "integrity": "sha512-WiOhulHKTZU5UPlRl53gHR8OxdGsSOxqfpqWeA2FmcwBMaoEdz6b2x2si3IwC9/fSPLfe8pBMRTHVMk5nlwnFQ==" + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.5.tgz", + "integrity": "sha512-C0p9D2fAu3Twwqvygvf42iGCQ4av8MFBLiTb+08SZ4cEdwzWx9QeAHDo1E2k+9s/0w1DM40oflJOpkZ8jW4HCQ==", + "requires": { + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-buffer": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5", + "@webassemblyjs/helper-wasm-section": "1.11.5", + "@webassemblyjs/wasm-gen": "1.11.5", + "@webassemblyjs/wasm-opt": "1.11.5", + "@webassemblyjs/wasm-parser": "1.11.5", + "@webassemblyjs/wast-printer": "1.11.5" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.5.tgz", + "integrity": "sha512-14vteRlRjxLK9eSyYFvw1K8Vv+iPdZU0Aebk3j6oB8TQiQYuO6hj9s4d7qf6f2HJr2khzvNldAFG13CgdkAIfA==", + "requires": { + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5", + "@webassemblyjs/ieee754": "1.11.5", + "@webassemblyjs/leb128": "1.11.5", + "@webassemblyjs/utf8": "1.11.5" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.5.tgz", + "integrity": "sha512-tcKwlIXstBQgbKy1MlbDMlXaxpucn42eb17H29rawYLxm5+MsEmgPzeCP8B1Cl69hCice8LeKgZpRUAPtqYPgw==", + "requires": { + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-buffer": "1.11.5", + "@webassemblyjs/wasm-gen": "1.11.5", + "@webassemblyjs/wasm-parser": "1.11.5" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.5.tgz", + "integrity": "sha512-SVXUIwsLQlc8srSD7jejsfTU83g7pIGr2YYNb9oHdtldSxaOhvA5xwvIiWIfcX8PlSakgqMXsLpLfbbJ4cBYew==", + "requires": { + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-api-error": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5", + "@webassemblyjs/ieee754": "1.11.5", + "@webassemblyjs/leb128": "1.11.5", + "@webassemblyjs/utf8": "1.11.5" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.5.tgz", + "integrity": "sha512-f7Pq3wvg3GSPUPzR0F6bmI89Hdb+u9WXrSKc4v+N0aV0q6r42WoF92Jp2jEorBEBRoRNXgjp53nBniDXcqZYPA==", + "requires": { + "@webassemblyjs/ast": "1.11.5", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "dependencies": { + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + } + } + }, + "acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==" + }, + "acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "requires": {} + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "devOptional": true, + "requires": {} + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" + }, + "address": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.1.tgz", + "integrity": "sha512-B+6bi5D34+fDYENiH5qOlA0cV2rAGKuWZ9LeyUUehbXy8e0VS9e498yO0Jeeh+iM+6KbfudHTFjXw2MmJD4QRA==" + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "requires": { + "ajv": "^8.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + } + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "requires": {} + }, + "algoliasearch": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.17.0.tgz", + "integrity": "sha512-JMRh2Mw6sEnVMiz6+APsi7lx9a2jiDFF+WUtANaUVCv6uSU9UOLdo5h9K3pdP6frRRybaM2fX8b1u0nqICS9aA==", + "requires": { + "@algolia/cache-browser-local-storage": "4.17.0", + "@algolia/cache-common": "4.17.0", + "@algolia/cache-in-memory": "4.17.0", + "@algolia/client-account": "4.17.0", + "@algolia/client-analytics": "4.17.0", + "@algolia/client-common": "4.17.0", + "@algolia/client-personalization": "4.17.0", + "@algolia/client-search": "4.17.0", + "@algolia/logger-common": "4.17.0", + "@algolia/logger-console": "4.17.0", + "@algolia/requester-browser-xhr": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/requester-node-http": "4.17.0", + "@algolia/transporter": "4.17.0" + } + }, + "algoliasearch-helper": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.12.0.tgz", + "integrity": "sha512-/j1U3PEwdan0n6P/QqSnSpNSLC5+cEMvyljd5CnmNmUjDlGrys+vFEOwjVEnqELIiAGMHEA/Nl3CiKVFBUYqyQ==", + "requires": { + "@algolia/events": "^4.0.1" + } + }, + "ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "requires": { + "string-width": "^4.1.0" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + } + } + }, + "ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==" + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + } + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + }, + "array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.tosorted": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", + "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + } + }, + "arraybuffer.prototype.slice": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz", + "integrity": "sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + } + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + }, + "asynciterator.prototype": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", + "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.3" + } + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" + }, + "autoprefixer": { + "version": "10.4.14", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", + "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", + "requires": { + "browserslist": "^4.21.5", + "caniuse-lite": "^1.0.30001464", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + } + }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, + "axios": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", + "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "requires": { + "follow-redirects": "^1.14.7" + } + }, + "babel-loader": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "requires": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + } + }, + "babel-plugin-apply-mdx-type-prop": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.22.tgz", + "integrity": "sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ==", + "requires": { + "@babel/helper-plugin-utils": "7.10.4", + "@mdx-js/util": "1.6.22" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + } + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-extract-import-names": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz", + "integrity": "sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ==", + "requires": { + "@babel/helper-plugin-utils": "7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + } + } + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "requires": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + } + }, + "bail": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", + "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base16": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz", + "integrity": "sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==" + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, + "body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "bonjour-service": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.14.tgz", + "integrity": "sha512-HIMbgLnk1Vqvs6B4Wq5ep7mxvj9sGz5d1JJyDNSGNIdA/w2MCz6GTjWTdjqOJV1bEPj+6IkxDvWNFKEBxNt4kQ==", + "requires": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "boxen": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-6.2.1.tgz", + "integrity": "sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==", + "requires": { + "ansi-align": "^3.0.1", + "camelcase": "^6.2.0", + "chalk": "^4.1.2", + "cli-boxes": "^3.0.0", + "string-width": "^5.0.1", + "type-fest": "^2.5.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "requires": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==" + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" + }, + "normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==" + } + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "call-me-maybe": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", + "dev": true + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "requires": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + }, + "camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==" + }, + "caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "requires": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001481", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001481.tgz", + "integrity": "sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ==" + }, + "ccount": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz", + "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==" + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==" + }, + "character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "dev": true + }, + "character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==" + }, + "character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==" + }, + "cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "requires": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + } + }, + "cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "requires": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" + }, + "ci-info": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz", + "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==" + }, + "classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + }, + "clean-css": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.1.tgz", + "integrity": "sha512-lCr8OHhiWCTw4v8POJovCoh4T7I9U11yVsPjMWWnnMmp9ZowCxyad1Pathle/9HjaDp+fdQKjO9fQydE6RHTZg==", + "requires": { + "source-map": "~0.6.0" + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" + }, + "cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==" + }, + "cli-color": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.3.tgz", + "integrity": "sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==", + "dev": true, + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.61", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.15", + "timers-ext": "^0.1.7" + } + }, + "cli-table3": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "requires": { + "@colors/colors": "1.5.0", + "string-width": "^4.2.0" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + } + } + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" + }, + "collapse-white-space": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", + "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==" + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" + }, + "colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==" + }, + "combine-promises": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/combine-promises/-/combine-promises-1.1.0.tgz", + "integrity": "sha512-ZI9jvcLDxqwaXEixOhArm3r7ReIivsXkpbyEWyeOhzz1QS0iSgBPnWvEqvIQtYyamGCYA88gFhmUrs9hrrQ0pg==" + }, + "comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==" + }, + "commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==" + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "requires": { + "mime-db": ">= 1.43.0 < 2" + }, + "dependencies": { + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + } + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + } + }, + "connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==" + }, + "consola": { + "version": "2.15.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", + "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "copy-text-to-clipboard": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.1.0.tgz", + "integrity": "sha512-PFM6BnjLnOON/lB3ta/Jg7Ywsv+l9kQGD4TWDCSlRBGmqnnTM5MrDkhAFgw+8HZt0wW6Q2BBE4cmy9sq+s9Qng==" + }, + "copy-to-clipboard": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.2.tgz", + "integrity": "sha512-Vme1Z6RUDzrb6xAI7EZlVZ5uvOk2F//GaxKUxajDqm9LhOVM1inxNAD2vy+UZDYsd0uyA9s7b3/FVZPSxqrCfg==", + "requires": { + "toggle-selection": "^1.0.6" + } + }, + "copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "requires": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "requires": { + "is-glob": "^4.0.3" + } + }, + "globby": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz", + "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==", + "requires": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + }, + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==" + } + } + }, + "core-js": { + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.26.0.tgz", + "integrity": "sha512-+DkDrhoR4Y0PxDz6rurahuB+I45OsEUv8E1maPTB6OuHRohMMcznBq9TMpdpDMm/hUPob/mJJS3PqgbHpMTQgw==" + }, + "core-js-compat": { + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.26.0.tgz", + "integrity": "sha512-piOX9Go+Z4f9ZiBFLnZ5VrOpBl0h7IGCkiFUN11QTe6LjAvOT3ifL/5TdoizMh99hcGy5SoLyWbapIY/PIb/3A==", + "requires": { + "browserslist": "^4.21.4" + } + }, + "core-js-pure": { + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.26.0.tgz", + "integrity": "sha512-LiN6fylpVBVwT8twhhluD9TzXmZQQsr2I2eIKtWNbZI1XMfBT7CV18itaN6RA7EtQd/SDdRx/wzvAShX2HvhQA==" + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "requires": { + "node-fetch": "2.6.7" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" + }, + "css-declaration-sorter": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz", + "integrity": "sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w==", + "requires": {} + }, + "css-loader": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", + "integrity": "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==", + "requires": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.7", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.5" + } + }, + "css-minimizer-webpack-plugin": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-4.2.2.tgz", + "integrity": "sha512-s3Of/4jKfw1Hj9CxEO1E5oXhQAxlayuHO2y/ML+C6I9sQ7FdzfEV6QgMLN3vI+qFsjJGIAFLKtQK7t8BOXAIyA==", + "requires": { + "cssnano": "^5.1.8", + "jest-worker": "^29.1.2", + "postcss": "^8.4.17", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + } + }, + "css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" + }, + "cssnano": { + "version": "5.1.13", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.13.tgz", + "integrity": "sha512-S2SL2ekdEz6w6a2epXn4CmMKU4K3KpcyXLKfAYc9UQQqJRkD/2eLUG0vJ3Db/9OvO5GuAdgXw3pFbR6abqghDQ==", + "requires": { + "cssnano-preset-default": "^5.2.12", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + } + }, + "cssnano-preset-advanced": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.10.tgz", + "integrity": "sha512-fnYJyCS9jgMU+cmHO1rPSPf9axbQyD7iUhLO5Df6O4G+fKIOMps+ZbU0PdGFejFBBZ3Pftf18fn1eG7MAPUSWQ==", + "requires": { + "autoprefixer": "^10.4.12", + "cssnano-preset-default": "^5.2.14", + "postcss-discard-unused": "^5.1.0", + "postcss-merge-idents": "^5.1.1", + "postcss-reduce-idents": "^5.2.0", + "postcss-zindex": "^5.1.0" + } + }, + "cssnano-preset-default": { + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "requires": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + } + }, + "cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "requires": {} + }, + "csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "requires": { + "css-tree": "^1.1.2" + } + }, + "csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "dev": true, + "requires": { + "character-entities": "^2.0.0" + }, + "dependencies": { + "character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "dev": true + } + } + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "devOptional": true + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" + }, + "default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "requires": { + "execa": "^5.0.0" + } + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==" + }, + "define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "requires": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + } + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "detab": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detab/-/detab-2.0.4.tgz", + "integrity": "sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g==", + "requires": { + "repeat-string": "^1.5.4" + } + }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "detect-port": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", + "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", + "requires": { + "address": "^1.0.1", + "debug": "4" + } + }, + "detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "requires": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "requires": { + "path-type": "^4.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==" + }, + "dns-packet": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", + "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", + "requires": { + "@leichtgewicht/ip-codec": "^2.0.1" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "devOptional": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "requires": { + "utila": "~0.4" + } + }, + "dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" + }, + "domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "requires": { + "domelementtype": "^2.3.0" + } + }, + "domutils": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", + "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "requires": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.1" + } + }, + "dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "requires": { + "is-obj": "^2.0.0" + }, + "dependencies": { + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" + } + } + }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, + "duplexer3": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", + "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==" + }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "electron-to-chromium": { + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" + }, + "emoticon": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-3.2.0.tgz", + "integrity": "sha512-SNujglcLTTg+lDAcApPNgEdudaqQFiAbJCqzjNxJkvN9vAwCGi0uu8IUVvx+f16h+V44KCY6Y2yboroc9pilHg==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "5.14.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz", + "integrity": "sha512-Vklwq2vDKtl0y/vtwjSesgJ5MYS7Etuk5txS8VdKL4AOS1aUlD96zqIfsOSLQsdv3xgMRbtkWM8eG9XDfKUPow==", + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "entities": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", + "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==" + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", + "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.1", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.1", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "safe-array-concat": "^1.0.0", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.10" + } + }, + "es-iterator-helpers": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.14.tgz", + "integrity": "sha512-JgtVnwiuoRuzLvqelrvN3Xu7H9bu2ap/kQ2CrM62iidP8SKuD99rWU3CJy++s7IVL2qb/AjXPGR/E7i9ngd/Cw==", + "dev": true, + "requires": { + "asynciterator.prototype": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-set-tostringtag": "^2.0.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.2.1", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "iterator.prototype": "^1.1.0", + "safe-array-concat": "^1.0.0" + } + }, + "es-module-lexer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.2.1.tgz", + "integrity": "sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==" + }, + "es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + } + }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "requires": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + }, + "eslint": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", + "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", + "devOptional": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.39.0", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.0", + "espree": "^9.5.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "devOptional": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "devOptional": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "devOptional": true + } + } + }, + "eslint-config-prettier": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", + "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", + "dev": true, + "requires": {} + }, + "eslint-mdx": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/eslint-mdx/-/eslint-mdx-2.0.5.tgz", + "integrity": "sha512-1ZzcJwJNfladtuK+uuG/MdC0idc1e3d1vCI2STOq/pLcJBGuao2biWh90vEh2M93zDiNoHJGUIU7UAxupiiHFw==", + "dev": true, + "requires": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "cosmiconfig": "^7.0.1", + "espree": "^9.4.0", + "estree-util-visit": "^1.2.0", + "remark-mdx": "^2.1.3", + "remark-parse": "^10.0.1", + "remark-stringify": "^10.0.2", + "synckit": "^0.8.4", + "tslib": "^2.4.0", + "unified": "^10.1.2", + "unist-util-visit": "^4.1.1", + "uvu": "^0.5.6", + "vfile": "^5.3.4" + }, + "dependencies": { + "bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "dev": true + }, + "is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true + }, + "mdast-util-from-markdown": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz", + "integrity": "sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==", + "dev": true, + "requires": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + } + }, + "mdast-util-to-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz", + "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==", + "dev": true + }, + "micromark": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.1.0.tgz", + "integrity": "sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==", + "dev": true, + "requires": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "remark-mdx": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-2.1.5.tgz", + "integrity": "sha512-A8vw5s+BgOa968Irt8BO7DfWJTE0Fe7Ge3hX8zzDB1DnwMZTNdK6qF2IcFao+/7nzk1vSysKcFp+3ku4vhMpaQ==", + "dev": true, + "requires": { + "mdast-util-mdx": "^2.0.0", + "micromark-extension-mdxjs": "^1.0.0" + } + }, + "remark-parse": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz", + "integrity": "sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==", + "dev": true, + "requires": { + "@types/mdast": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "unified": "^10.0.0" + } + }, + "trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "dev": true + }, + "unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + } + }, + "unist-util-is": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.1.1.tgz", + "integrity": "sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ==", + "dev": true + }, + "unist-util-stringify-position": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", + "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0" + } + }, + "unist-util-visit": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.1.tgz", + "integrity": "sha512-n9KN3WV9k4h1DxYR1LoajgN93wpEi/7ZplVe02IoB4gH5ctI1AaF2670BLHQYbwj+pY83gFtyeySFiyMHJklrg==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + } + }, + "unist-util-visit-parents": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.1.tgz", + "integrity": "sha512-gks4baapT/kNRaWxuGkl5BIhoanZo7sC/cUT/JToSRNL1dYoXRFl75d++NkjYk4TAu2uv2Px+l8guMajogeuiw==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + } + } + } + }, + "eslint-plugin-markdown": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-markdown/-/eslint-plugin-markdown-3.0.0.tgz", + "integrity": "sha512-hRs5RUJGbeHDLfS7ELanT0e29Ocyssf/7kBM+p7KluY5AwngGkDf8Oyu4658/NZSGTTq05FZeWbkxXtbVyHPwg==", + "dev": true, + "requires": { + "mdast-util-from-markdown": "^0.8.5" + } + }, + "eslint-plugin-mdx": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-mdx/-/eslint-plugin-mdx-2.0.5.tgz", + "integrity": "sha512-j2xN97jSlc5IoH94rJTHqYMztl46+hHzyC8Zqjx+OI1Rvv33isyf8xSSBHN6f0z8IJmgPgGsb/fH90JbvKplXg==", + "dev": true, + "requires": { + "eslint-mdx": "^2.0.5", + "eslint-plugin-markdown": "^3.0.0", + "remark-mdx": "^2.1.3", + "remark-parse": "^10.0.1", + "remark-stringify": "^10.0.2", + "tslib": "^2.4.0", + "unified": "^10.1.2", + "vfile": "^5.3.4" + }, + "dependencies": { + "bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "dev": true + }, + "is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true + }, + "mdast-util-from-markdown": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz", + "integrity": "sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==", + "dev": true, + "requires": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + } + }, + "mdast-util-to-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz", + "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==", + "dev": true + }, + "micromark": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.1.0.tgz", + "integrity": "sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==", + "dev": true, + "requires": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "remark-mdx": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-2.1.5.tgz", + "integrity": "sha512-A8vw5s+BgOa968Irt8BO7DfWJTE0Fe7Ge3hX8zzDB1DnwMZTNdK6qF2IcFao+/7nzk1vSysKcFp+3ku4vhMpaQ==", + "dev": true, + "requires": { + "mdast-util-mdx": "^2.0.0", + "micromark-extension-mdxjs": "^1.0.0" + } + }, + "remark-parse": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz", + "integrity": "sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==", + "dev": true, + "requires": { + "@types/mdast": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "unified": "^10.0.0" + } + }, + "trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "dev": true + }, + "unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + } + }, + "unist-util-stringify-position": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", + "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0" + } + } + } + }, + "eslint-plugin-react": { + "version": "7.33.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", + "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==", + "dev": true, + "requires": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.12", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.8" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "eslint-scope": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "devOptional": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-visitor-keys": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "devOptional": true + }, + "espree": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", + "devOptional": true, + "requires": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "devOptional": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + }, + "estree-util-is-identifier-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-2.0.1.tgz", + "integrity": "sha512-rxZj1GkQhY4x1j/CSnybK9cGuMFQYFPLq0iNyopqf14aOVLFtMv7Esika+ObJWPWiOHuMOAHz3YkWoLYYRnzWQ==", + "dev": true + }, + "estree-util-visit": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-1.2.0.tgz", + "integrity": "sha512-wdsoqhWueuJKsh5hqLw3j8lwFqNStm92VcwtAOAny8g/KS/l5Y8RISjR4k5W6skCj3Nirag/WUCMS0Nfy3sgsg==", + "dev": true, + "requires": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^2.0.0" + } + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "eta": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/eta/-/eta-2.0.1.tgz", + "integrity": "sha512-46E2qDPDm7QA+usjffUWz9KfXsxVZclPOuKsXs4ZWZdI/X1wpDF7AO424pt7fdYohCzWsIkXAhNGXSlwo5naAg==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "eval": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eval/-/eval-0.1.8.tgz", + "integrity": "sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==", + "requires": { + "@types/node": "*", + "require-like": ">= 0.1.1" + } + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "dependencies": { + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" + } + } + }, + "express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + } + } + }, + "ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "requires": { + "type": "^2.7.2" + }, + "dependencies": { + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "devOptional": true + }, + "fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", + "requires": { + "punycode": "^1.3.2" + } + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "requires": { + "reusify": "^1.0.4" + } + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fbemitter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-3.0.0.tgz", + "integrity": "sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==", + "requires": { + "fbjs": "^3.0.0" + } + }, + "fbjs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.4.tgz", + "integrity": "sha512-ucV0tDODnGV3JCnnkmoszb5lf4bNpzjv80K41wd4k798Etq+UYD0y0TIfalLjZoKgjive6/adkRnszwapiDgBQ==", + "requires": { + "cross-fetch": "^3.1.5", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.30" + } + }, + "fbjs-css-vars": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", + "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==" + }, + "feed": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", + "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", + "requires": { + "xml-js": "^1.6.11" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "devOptional": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "filesize": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", + "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "devOptional": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "devOptional": true + }, + "flux": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.4.tgz", + "integrity": "sha512-NCj3XlayA2UsapRpM7va6wU1+9rE5FIL7qoMcmxWHRzbp0yujihMBm9BBHZ1MDIk5h5o2Bl6eGiCe8rYELAmYw==", + "requires": { + "fbemitter": "^3.0.0", + "fbjs": "^3.0.1" + } + }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, + "fork-ts-checker-webpack-plugin": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.2.tgz", + "integrity": "sha512-m5cUmF30xkZ7h4tWUgTAcEaKmUW7tfyUyTqNNOz7OxWJ0v1VWKTcOvH8FWHUwSjlW/356Ijc9vi3XfcPstpQKA==", + "requires": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "dependencies": { + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + } + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "requires": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" + } + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + }, + "get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + } + }, + "get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" + }, + "get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "github-slugger": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz", + "integrity": "sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==" + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-promise": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/glob-promise/-/glob-promise-4.2.2.tgz", + "integrity": "sha512-xcUzJ8NWN5bktoTIX7eOclO1Npxd/dyVqUJxlLIDasT4C7KZyqlPIwkdJ0Ypiy3p2ZKahTjK4M9uC3sNSfNMzw==", + "dev": true, + "requires": { + "@types/glob": "^7.1.3" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "global-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "requires": { + "ini": "2.0.0" + }, + "dependencies": { + "ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==" + } + } + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "requires": { + "global-prefix": "^3.0.0" + } + }, + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "dependencies": { + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, + "globalyzer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", + "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", + "dev": true + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "devOptional": true + }, + "gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "requires": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } + } + }, + "gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "requires": { + "duplexer": "^0.1.2" + } + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==" + }, + "hast-to-hyperscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz", + "integrity": "sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==", + "requires": { + "@types/unist": "^2.0.3", + "comma-separated-tokens": "^1.0.0", + "property-information": "^5.3.0", + "space-separated-tokens": "^1.0.0", + "style-to-object": "^0.3.0", + "unist-util-is": "^4.0.0", + "web-namespaces": "^1.0.0" + } + }, + "hast-util-from-parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-6.0.1.tgz", + "integrity": "sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA==", + "requires": { + "@types/parse5": "^5.0.0", + "hastscript": "^6.0.0", + "property-information": "^5.0.0", + "vfile": "^4.0.0", + "vfile-location": "^3.2.0", + "web-namespaces": "^1.0.0" + }, + "dependencies": { + "vfile": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", + "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", + "requires": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-message": "^2.0.0" + } + }, + "vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + } + } + } + }, + "hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==" + }, + "hast-util-raw": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-6.0.1.tgz", + "integrity": "sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig==", + "requires": { + "@types/hast": "^2.0.0", + "hast-util-from-parse5": "^6.0.0", + "hast-util-to-parse5": "^6.0.0", + "html-void-elements": "^1.0.0", + "parse5": "^6.0.0", + "unist-util-position": "^3.0.0", + "vfile": "^4.0.0", + "web-namespaces": "^1.0.0", + "xtend": "^4.0.0", + "zwitch": "^1.0.0" + }, + "dependencies": { + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "vfile": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", + "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", + "requires": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-message": "^2.0.0" + } + }, + "vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + } + } + } + }, + "hast-util-to-parse5": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz", + "integrity": "sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ==", + "requires": { + "hast-to-hyperscript": "^9.0.0", + "property-information": "^5.0.0", + "web-namespaces": "^1.0.0", + "xtend": "^4.0.0", + "zwitch": "^1.0.0" + } + }, + "hastscript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "requires": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, + "history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "requires": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==" + }, + "html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "requires": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "dependencies": { + "commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" + } + } + }, + "html-tags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz", + "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==" + }, + "html-void-elements": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz", + "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==" + }, + "html-webpack-plugin": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", + "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==", + "requires": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + } + }, + "htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "requires": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "dependencies": { + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==" + } + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "requires": {} + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" + }, + "image-size": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz", + "integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==", + "requires": { + "queue": "6.0.2" + } + }, + "immer": { + "version": "9.0.16", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.16.tgz", + "integrity": "sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==" + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==" + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + }, + "infima": { + "version": "0.2.0-alpha.43", + "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.43.tgz", + "integrity": "sha512-2uw57LvUqW0rK/SWYnd/2rRfxNA5DDNOh33jxF7fy46VWoNhGxiUQyVZHbBMjQ33mQem0cjdDVwgWVAmlRfgyQ==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" + }, + "internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "ipaddr.js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", + "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==" + }, + "is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==" + }, + "is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "requires": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + } + }, + "is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "requires": { + "ci-info": "^2.0.0" + }, + "dependencies": { + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + } + } + }, + "is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==" + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + }, + "is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==" + }, + "is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "requires": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + } + }, + "is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-npm": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==" + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==" + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==" + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==" + }, + "is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==" + }, + "is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "requires": { + "which-typed-array": "^1.1.11" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "dev": true + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "is-whitespace-character": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", + "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==" + }, + "is-word-character": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz", + "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==" + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "requires": { + "is-docker": "^2.0.0" + } + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" + }, + "iterator.prototype": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.1.tgz", + "integrity": "sha512-9E+nePc8C9cnQldmNl6bgpTY6zI4OPRZd97fhJ/iVZ1GifIUDVV5F6x1nEDqpe8KaMEZGT4xgrwKQDxXnjOIZQ==", + "dev": true, + "requires": { + "define-properties": "^1.2.0", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.3" + } + }, + "jest-util": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.2.1.tgz", + "integrity": "sha512-P5VWDj25r7kj7kl4pN2rG/RN2c1TLfYYYZYULnS/35nFDjBai+hBeo3MDrYZS7p6IoY3YHZnt2vq4L6mKnLk0g==", + "requires": { + "@jest/types": "^29.2.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, + "jest-worker": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.2.1.tgz", + "integrity": "sha512-ROHTZ+oj7sBrgtv46zZ84uWky71AoYi0vEV9CdEtc1FQunsoAGe5HbQmW76nI5QWdvECVPrSi1MCVUmizSavMg==", + "requires": { + "@types/node": "*", + "jest-util": "^29.2.1", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "joi": { + "version": "17.6.4", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.4.tgz", + "integrity": "sha512-tPzkTJHZQjSFCc842QpdVpOZ9LI2txApboNUbW70qgnRB14Lzl+oWQOPdF2N4yqyiY14wBGe8lc7f/2hZxbGmw==", + "requires": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.3", + "@sideway/formula": "^3.0.0", + "@sideway/pinpoint": "^2.0.0" + } + }, + "js-sdsl": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", + "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", + "devOptional": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==" + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "json-schema-to-typescript": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-13.1.1.tgz", + "integrity": "sha512-F3CYhtA7F3yPbb8vF7sFchk/2dnr1/yTKf8RcvoNpjnh67ZS/ZMH1ElLt5KHAtf2/bymiejLQQszszPWEeTdSw==", + "dev": true, + "requires": { + "@bcherny/json-schema-ref-parser": "10.0.5-fork", + "@types/json-schema": "^7.0.11", + "@types/lodash": "^4.14.182", + "@types/prettier": "^2.6.1", + "cli-color": "^2.0.2", + "get-stdin": "^8.0.0", + "glob": "^7.1.6", + "glob-promise": "^4.2.2", + "is-glob": "^4.0.3", + "lodash": "^4.17.21", + "minimist": "^1.2.6", + "mkdirp": "^1.0.4", + "mz": "^2.7.0", + "prettier": "^2.6.2" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "devOptional": true + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsx-ast-utils": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", + "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", + "dev": true, + "requires": { + "array-includes": "^3.1.5", + "object.assign": "^4.1.3" + } + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "requires": { + "json-buffer": "3.0.0" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + }, + "klona": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", + "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==" + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "requires": { + "package-json": "^6.3.0" + } + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "devOptional": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lilconfig": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", + "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==" + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==" + }, + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.curry": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", + "integrity": "sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==" + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "lodash.flow": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", + "integrity": "sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==" + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "devOptional": true + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + }, + "longest-streak": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.0.1.tgz", + "integrity": "sha512-cHlYSUpL2s7Fb3394mYxwTYj8niTaNHUCLr0qdiCXQfSjfuA7CKofpX2uSwEfFDQ0EB7JcnMnm+GjbqqoinYYg==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "requires": { + "tslib": "^2.0.3" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", + "dev": true, + "requires": { + "es5-ext": "~0.10.2" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "markdown-escapes": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz", + "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==" + }, + "mdast-squeeze-paragraphs": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz", + "integrity": "sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ==", + "requires": { + "unist-util-remove": "^2.0.0" + } + }, + "mdast-util-definitions": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz", + "integrity": "sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==", + "requires": { + "unist-util-visit": "^2.0.0" + } + }, + "mdast-util-from-markdown": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz", + "integrity": "sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==", + "dev": true, + "requires": { + "@types/mdast": "^3.0.0", + "mdast-util-to-string": "^2.0.0", + "micromark": "~2.11.0", + "parse-entities": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + } + }, + "mdast-util-mdx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-2.0.0.tgz", + "integrity": "sha512-M09lW0CcBT1VrJUaF/PYxemxxHa7SLDHdSn94Q9FhxjCQfuW7nMAWKWimTmA3OyDMSTH981NN1csW1X+HPSluw==", + "dev": true, + "requires": { + "mdast-util-mdx-expression": "^1.0.0", + "mdast-util-mdx-jsx": "^2.0.0", + "mdast-util-mdxjs-esm": "^1.0.0" + } + }, + "mdast-util-mdx-expression": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-1.3.1.tgz", + "integrity": "sha512-TTb6cKyTA1RD+1su1iStZ5PAv3rFfOUKcoU5EstUpv/IZo63uDX03R8+jXjMEhcobXnNOiG6/ccekvVl4eV1zQ==", + "dev": true, + "requires": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "mdast-util-to-markdown": "^1.0.0" + }, + "dependencies": { + "mdast-util-from-markdown": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz", + "integrity": "sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==", + "dev": true, + "requires": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + } + }, + "mdast-util-to-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz", + "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==", + "dev": true + }, + "micromark": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.1.0.tgz", + "integrity": "sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==", + "dev": true, + "requires": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "unist-util-stringify-position": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", + "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0" + } + } + } + }, + "mdast-util-mdx-jsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-2.1.0.tgz", + "integrity": "sha512-KzgzfWMhdteDkrY4mQtyvTU5bc/W4ppxhe9SzelO6QUUiwLAM+Et2Dnjjprik74a336kHdo0zKm7Tp+n6FFeRg==", + "dev": true, + "requires": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "ccount": "^2.0.0", + "mdast-util-to-markdown": "^1.3.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-remove-position": "^4.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "dependencies": { + "ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true + }, + "character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "dev": true + }, + "character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true + }, + "character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "dev": true + }, + "is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "dev": true + }, + "is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "dev": true, + "requires": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + } + }, + "is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "dev": true + }, + "is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "dev": true + }, + "parse-entities": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.0.tgz", + "integrity": "sha512-5nk9Fn03x3rEhGaX1FU6IDwG/k+GxLXlFAkgrbM1asuAFl3BhdQWvASaIsmwWypRNcZKHPYnIuOSfIWEyEQnPQ==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "character-entities": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + } + }, + "unist-util-is": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.1.1.tgz", + "integrity": "sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ==", + "dev": true + }, + "unist-util-remove-position": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-4.0.1.tgz", + "integrity": "sha512-0yDkppiIhDlPrfHELgB+NLQD5mfjup3a8UYclHruTJWmY74je8g+CIFr79x5f6AkmzSwlvKLbs63hC0meOMowQ==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "unist-util-visit": "^4.0.0" + } + }, + "unist-util-stringify-position": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", + "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0" + } + }, + "unist-util-visit": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.1.tgz", + "integrity": "sha512-n9KN3WV9k4h1DxYR1LoajgN93wpEi/7ZplVe02IoB4gH5ctI1AaF2670BLHQYbwj+pY83gFtyeySFiyMHJklrg==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + } + }, + "unist-util-visit-parents": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.1.tgz", + "integrity": "sha512-gks4baapT/kNRaWxuGkl5BIhoanZo7sC/cUT/JToSRNL1dYoXRFl75d++NkjYk4TAu2uv2Px+l8guMajogeuiw==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + } + } + } + }, + "mdast-util-mdxjs-esm": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-1.3.0.tgz", + "integrity": "sha512-7N5ihsOkAEGjFotIX9p/YPdl4TqUoMxL4ajNz7PbT89BqsdWJuBC9rvgt6wpbwTZqWWR0jKWqQbwsOWDBUZv4g==", + "dev": true, + "requires": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "mdast-util-to-markdown": "^1.0.0" + }, + "dependencies": { + "mdast-util-from-markdown": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz", + "integrity": "sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==", + "dev": true, + "requires": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + } + }, + "mdast-util-to-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz", + "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==", + "dev": true + }, + "micromark": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.1.0.tgz", + "integrity": "sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==", + "dev": true, + "requires": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "unist-util-stringify-position": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", + "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0" + } + } + } + }, + "mdast-util-to-hast": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz", + "integrity": "sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA==", + "requires": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "mdast-util-definitions": "^4.0.0", + "mdurl": "^1.0.0", + "unist-builder": "^2.0.0", + "unist-util-generated": "^1.0.0", + "unist-util-position": "^3.0.0", + "unist-util-visit": "^2.0.0" + } + }, + "mdast-util-to-markdown": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.3.0.tgz", + "integrity": "sha512-6tUSs4r+KK4JGTTiQ7FfHmVOaDrLQJPmpjD6wPMlHGUVXoG9Vjc3jIeP+uyBWRf8clwB2blM+W7+KrlMYQnftA==", + "dev": true, + "requires": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "longest-streak": "^3.0.0", + "mdast-util-to-string": "^3.0.0", + "micromark-util-decode-string": "^1.0.0", + "unist-util-visit": "^4.0.0", + "zwitch": "^2.0.0" + }, + "dependencies": { + "mdast-util-to-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz", + "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==", + "dev": true + }, + "unist-util-is": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.1.1.tgz", + "integrity": "sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ==", + "dev": true + }, + "unist-util-visit": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.1.tgz", + "integrity": "sha512-n9KN3WV9k4h1DxYR1LoajgN93wpEi/7ZplVe02IoB4gH5ctI1AaF2670BLHQYbwj+pY83gFtyeySFiyMHJklrg==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + } + }, + "unist-util-visit-parents": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.1.tgz", + "integrity": "sha512-gks4baapT/kNRaWxuGkl5BIhoanZo7sC/cUT/JToSRNL1dYoXRFl75d++NkjYk4TAu2uv2Px+l8guMajogeuiw==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + } + }, + "zwitch": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.2.tgz", + "integrity": "sha512-JZxotl7SxAJH0j7dN4pxsTV6ZLXoLdGME+PsjkL/DaBrVryK9kTGq06GfKrwcSOqypP+fdXGoCHE36b99fWVoA==", + "dev": true + } + } + }, + "mdast-util-to-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", + "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==" + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + }, + "memfs": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.7.tgz", + "integrity": "sha512-ygaiUSNalBX85388uskeCyhSAoOSgzBbtVCr9jA2RROssFL9Q19/ZXFqS+2Th2sr1ewNIWgFdLzLC3Yl1Zv+lw==", + "requires": { + "fs-monkey": "^1.0.3" + } + }, + "memoizee": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", + "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", + "dev": true, + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + }, + "micromark": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz", + "integrity": "sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==", + "dev": true, + "requires": { + "debug": "^4.0.0", + "parse-entities": "^2.0.0" + } + }, + "micromark-core-commonmark": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz", + "integrity": "sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==", + "dev": true, + "requires": { + "decode-named-character-reference": "^1.0.0", + "micromark-factory-destination": "^1.0.0", + "micromark-factory-label": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-factory-title": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-html-tag-name": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "micromark-extension-mdx-expression": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-1.0.3.tgz", + "integrity": "sha512-TjYtjEMszWze51NJCZmhv7MEBcgYRgb3tJeMAJ+HQCAaZHHRBaDCccqQzGizR/H4ODefP44wRTgOn2vE5I6nZA==", + "dev": true, + "requires": { + "micromark-factory-mdx-expression": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-events-to-acorn": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-extension-mdx-jsx": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-1.0.3.tgz", + "integrity": "sha512-VfA369RdqUISF0qGgv2FfV7gGjHDfn9+Qfiv5hEwpyr1xscRj/CiVRkU7rywGFCO7JwJ5L0e7CJz60lY52+qOA==", + "dev": true, + "requires": { + "@types/acorn": "^4.0.0", + "estree-util-is-identifier-name": "^2.0.0", + "micromark-factory-mdx-expression": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0", + "vfile-message": "^3.0.0" + } + }, + "micromark-extension-mdx-md": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-1.0.0.tgz", + "integrity": "sha512-xaRAMoSkKdqZXDAoSgp20Azm0aRQKGOl0RrS81yGu8Hr/JhMsBmfs4wR7m9kgVUIO36cMUQjNyiyDKPrsv8gOw==", + "dev": true, + "requires": { + "micromark-util-types": "^1.0.0" + } + }, + "micromark-extension-mdxjs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-1.0.0.tgz", + "integrity": "sha512-TZZRZgeHvtgm+IhtgC2+uDMR7h8eTKF0QUX9YsgoL9+bADBpBY6SiLvWqnBlLbCEevITmTqmEuY3FoxMKVs1rQ==", + "dev": true, + "requires": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^1.0.0", + "micromark-extension-mdx-jsx": "^1.0.0", + "micromark-extension-mdx-md": "^1.0.0", + "micromark-extension-mdxjs-esm": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-extension-mdxjs-esm": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-1.0.3.tgz", + "integrity": "sha512-2N13ol4KMoxb85rdDwTAC6uzs8lMX0zeqpcyx7FhS7PxXomOnLactu8WI8iBNXW8AVyea3KIJd/1CKnUmwrK9A==", + "dev": true, + "requires": { + "micromark-core-commonmark": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-events-to-acorn": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-position-from-estree": "^1.1.0", + "uvu": "^0.5.0", + "vfile-message": "^3.0.0" + } + }, + "micromark-factory-destination": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz", + "integrity": "sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw==", + "dev": true, + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-factory-label": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz", + "integrity": "sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg==", + "dev": true, + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-factory-mdx-expression": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-1.0.6.tgz", + "integrity": "sha512-WRQIc78FV7KrCfjsEf/sETopbYjElh3xAmNpLkd1ODPqxEngP42eVRGbiPEQWpRV27LzqW+XVTvQAMIIRLPnNA==", + "dev": true, + "requires": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-events-to-acorn": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-position-from-estree": "^1.0.0", + "uvu": "^0.5.0", + "vfile-message": "^3.0.0" + } + }, + "micromark-factory-space": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz", + "integrity": "sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew==", + "dev": true, + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-factory-title": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz", + "integrity": "sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A==", + "dev": true, + "requires": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-factory-whitespace": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz", + "integrity": "sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A==", + "dev": true, + "requires": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-character": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.1.0.tgz", + "integrity": "sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg==", + "dev": true, + "requires": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-chunked": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz", + "integrity": "sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g==", + "dev": true, + "requires": { + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-classify-character": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz", + "integrity": "sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA==", + "dev": true, + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-combine-extensions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz", + "integrity": "sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA==", + "dev": true, + "requires": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-decode-numeric-character-reference": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz", + "integrity": "sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w==", + "dev": true, + "requires": { + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-decode-string": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz", + "integrity": "sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q==", + "dev": true, + "requires": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-encode": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz", + "integrity": "sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA==", + "dev": true + }, + "micromark-util-events-to-acorn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-1.2.0.tgz", + "integrity": "sha512-WWp3bf7xT9MppNuw3yPjpnOxa8cj5ACivEzXJKu0WwnjBYfzaBvIAT9KfeyI0Qkll+bfQtfftSwdgTH6QhTOKw==", + "dev": true, + "requires": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "estree-util-visit": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0", + "vfile-location": "^4.0.0", + "vfile-message": "^3.0.0" + }, + "dependencies": { + "vfile-location": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-4.0.1.tgz", + "integrity": "sha512-JDxPlTbZrZCQXogGheBHjbRWjESSPEak770XwWPfw5mTc1v1nWGLB/apzZxsx8a0SJVfF8HK8ql8RD308vXRUw==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "vfile": "^5.0.0" + } + } + } + }, + "micromark-util-html-tag-name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.1.0.tgz", + "integrity": "sha512-BKlClMmYROy9UiV03SwNmckkjn8QHVaWkqoAqzivabvdGcwNGMMMH/5szAnywmsTBUzDsU57/mFi0sp4BQO6dA==", + "dev": true + }, + "micromark-util-normalize-identifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz", + "integrity": "sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg==", + "dev": true, + "requires": { + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-resolve-all": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz", + "integrity": "sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw==", + "dev": true, + "requires": { + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-sanitize-uri": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.1.0.tgz", + "integrity": "sha512-RoxtuSCX6sUNtxhbmsEFQfWzs8VN7cTctmBPvYivo98xb/kDEoTCtJQX5wyzIYEmk/lvNFTat4hL8oW0KndFpg==", + "dev": true, + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-subtokenize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz", + "integrity": "sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA==", + "dev": true, + "requires": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-util-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz", + "integrity": "sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ==", + "dev": true + }, + "micromark-util-types": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.0.2.tgz", + "integrity": "sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" + }, + "mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "requires": { + "mime-db": "~1.33.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, + "mini-css-extract-plugin": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz", + "integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==", + "requires": { + "schema-utils": "^4.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true + }, + "mrmime": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "requires": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + } + }, + "mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "dev": true + }, + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "requires": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "devOptional": true + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "requires": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "requires": { + "lodash": "^4.17.21" + } + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" + }, + "node-releases": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==" + }, + "normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==" + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "requires": { + "path-key": "^3.0.0" + } + }, + "nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==" + }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "requires": { + "boolbase": "^1.0.0" + } + }, + "null-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/null-loader/-/null-loader-4.0.1.tgz", + "integrity": "sha512-pxqVbi4U6N26lq+LmgIbB5XATP0VdZKOG25DhHi8btMmJJefGArFyDg1yc4U3hWCJbMqSrw0qyrz1UQX+qYXqg==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + }, + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", + "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.fromentries": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.hasown": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", + "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", + "dev": true, + "requires": { + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==" + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "devOptional": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "requires": { + "p-limit": "^3.0.2" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "requires": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "requires": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parse-numeric-range": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", + "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==" + }, + "parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "requires": { + "entities": "^4.4.0" + } + }, + "parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "requires": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "requires": { + "isarray": "0.0.1" + } + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "requires": { + "find-up": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + } + } + }, + "pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "requires": { + "find-up": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==" + } + } + }, + "postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "requires": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "requires": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-colormin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "requires": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "requires": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "requires": {} + }, + "postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "requires": {} + }, + "postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "requires": {} + }, + "postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "requires": {} + }, + "postcss-discard-unused": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-5.1.0.tgz", + "integrity": "sha512-KwLWymI9hbwXmJa0dkrzpRbSJEh0vVUd7r8t0yOGPcfKzyJJxFM8kLyC5Ev9avji6nY95pOp1W6HqIrfT+0VGw==", + "requires": { + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-loader": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.1.tgz", + "integrity": "sha512-VRviFEyYlLjctSM93gAZtcJJ/iSkPZ79zWbN/1fSH+NisBByEiVLqpdVDrPLVSi8DX0oJo12kL/GppTBdKVXiQ==", + "requires": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.7" + } + }, + "postcss-merge-idents": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-5.1.1.tgz", + "integrity": "sha512-pCijL1TREiCoog5nQp7wUe+TUonA2tC2sQ54UGeMmryK3UFGIYKqDyjnqd6RcuI4znFn9hWSLNN8xKE/vWcUQw==", + "requires": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "requires": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + } + }, + "postcss-merge-rules": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", + "requires": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "requires": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "requires": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "requires": { + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "requires": {} + }, + "postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "requires": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "requires": { + "icss-utils": "^5.0.0" + } + }, + "postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "requires": {} + }, + "postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "requires": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "requires": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "requires": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-reduce-idents": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-5.2.0.tgz", + "integrity": "sha512-BTrLjICoSB6gxbc58D5mdBK8OhXRDqud/zodYfdSi52qvDHdMwk+9kB9xsM8yJThH/sZU5A6QVSmMmaN001gIg==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-reduce-initial": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "requires": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + } + }, + "postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-sort-media-queries": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.4.1.tgz", + "integrity": "sha512-QDESFzDDGKgpiIh4GYXsSy6sek2yAwQx1JASl5AxBtU1Lq2JfKBljIPNdil989NcSKRQX1ToiaKphImtBuhXWw==", + "requires": { + "sort-css-media-queries": "2.1.0" + } + }, + "postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "requires": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + } + }, + "postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "requires": { + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "postcss-zindex": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-5.1.0.tgz", + "integrity": "sha512-fgFMf0OtVSBR1va1JNHYgMxYk73yhn/qb4uQDq1DLGYolz8gHCyr/sesEuGUaYs58E3ZJRcpoGuPVoB7Meiq9A==", + "requires": {} + }, + "prebuild-webpack-plugin": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/prebuild-webpack-plugin/-/prebuild-webpack-plugin-1.1.1.tgz", + "integrity": "sha512-H5/VnSl7KZm3NCGj1+8BrBHu0Bn9xzLREdpeE4TRYyp4t4qFnYPExzozk2sfD/CLJRGIuyOFrXbXgJJ4ETdz/g==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "glob": "^7.1.5", + "minimatch": "^3.0.4" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "devOptional": true + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==" + }, + "prettier": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz", + "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==", + "dev": true + }, + "pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "requires": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "pretty-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", + "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==" + }, + "prism-react-renderer": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.3.5.tgz", + "integrity": "sha512-IJ+MSwBWKG+SM3b2SUfdrhC+gu01QkV2KmRQgREThBfSQRoufqRfxfHUxpG1WcaFjP+kojcFyO9Qqtpgt3qLCg==", + "requires": {} + }, + "prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } + }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "requires": { + "xtend": "^4.0.0" + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "dependencies": { + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + } + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" + }, + "pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "requires": { + "escape-goat": "^2.0.0" + } + }, + "pure-color": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz", + "integrity": "sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA==" + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "requires": { + "inherits": "~2.0.3" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==" + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + } + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" + } + } + }, + "react": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "react-async": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/react-async/-/react-async-10.0.1.tgz", + "integrity": "sha512-ORUz5ca0B57QgBIzEZM5SuhJ6xFjkvEEs0gylLNlWf06vuVcLZsjIw3wx58jJkZG38p+0nUAxRgFW2b7mnVZzA==", + "requires": {} + }, + "react-base16-styling": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.6.0.tgz", + "integrity": "sha512-yvh/7CArceR/jNATXOKDlvTnPKPmGZz7zsenQ3jUwLzHkNUR0CvY3yGYJbWJ/nnxsL8Sgmt5cO3/SILVuPO6TQ==", + "requires": { + "base16": "^1.0.0", + "lodash.curry": "^4.0.1", + "lodash.flow": "^3.3.0", + "pure-color": "^1.2.0" + } + }, + "react-copy-to-clipboard": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz", + "integrity": "sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==", + "requires": { + "copy-to-clipboard": "^3.3.1", + "prop-types": "^15.8.1" + } + }, + "react-dev-utils": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", + "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", + "requires": { + "@babel/code-frame": "^7.16.0", + "address": "^1.1.2", + "browserslist": "^4.18.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "detect-port-alt": "^1.1.6", + "escape-string-regexp": "^4.0.0", + "filesize": "^8.0.6", + "find-up": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^6.5.0", + "global-modules": "^2.0.0", + "globby": "^11.0.4", + "gzip-size": "^6.0.0", + "immer": "^9.0.7", + "is-root": "^2.1.0", + "loader-utils": "^3.2.0", + "open": "^8.4.0", + "pkg-up": "^3.1.0", + "prompts": "^2.4.2", + "react-error-overlay": "^6.0.11", + "recursive-readdir": "^2.2.2", + "shell-quote": "^1.7.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "dependencies": { + "loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==" + } + } + }, + "react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + } + }, + "react-error-overlay": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" + }, + "react-fast-compare": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", + "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" + }, + "react-helmet-async": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.3.0.tgz", + "integrity": "sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==", + "requires": { + "@babel/runtime": "^7.12.5", + "invariant": "^2.2.4", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.2.0", + "shallowequal": "^1.1.0" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "react-json-view": { + "version": "1.21.3", + "resolved": "https://registry.npmjs.org/react-json-view/-/react-json-view-1.21.3.tgz", + "integrity": "sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw==", + "requires": { + "flux": "^4.0.1", + "react-base16-styling": "^0.6.0", + "react-lifecycles-compat": "^3.0.4", + "react-textarea-autosize": "^8.3.2" + } + }, + "react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "react-loadable": { + "version": "npm:@docusaurus/react-loadable@5.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", + "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", + "requires": { + "@types/react": "*", + "prop-types": "^15.6.2" + } + }, + "react-loadable-ssr-addon-v5-slorber": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz", + "integrity": "sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A==", + "requires": { + "@babel/runtime": "^7.10.3" + } + }, + "react-router": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", + "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", + "requires": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + } + }, + "react-router-config": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/react-router-config/-/react-router-config-5.1.1.tgz", + "integrity": "sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==", + "requires": { + "@babel/runtime": "^7.1.2" + } + }, + "react-router-dom": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz", + "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", + "requires": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.3.4", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + } + }, + "react-textarea-autosize": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.4.1.tgz", + "integrity": "sha512-aD2C+qK6QypknC+lCMzteOdIjoMbNlgSFmJjCV+DrfTPwp59i/it9mMNf2HDzvRjQgKAyBDPyLJhcrzElf2U4Q==", + "requires": { + "@babel/runtime": "^7.20.13", + "use-composed-ref": "^1.3.0", + "use-latest": "^1.2.1" + } + }, + "react-toastify": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-7.0.4.tgz", + "integrity": "sha512-Rol7+Cn39hZp5hQ/k6CbMNE2CKYV9E5OQdC/hBLtIQU2xz7DdAm7xil4NITQTHR6zEbE5RVFbpgSwTD7xRGLeQ==", + "requires": { + "clsx": "^1.1.1" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "requires": { + "picomatch": "^2.2.1" + } + }, + "reading-time": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", + "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==" + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "requires": { + "resolve": "^1.1.6" + } + }, + "recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "requires": { + "minimatch": "^3.0.5" + } + }, + "reflect.getprototypeof": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", + "integrity": "sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + } + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "regenerate-unicode-properties": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "requires": { + "regenerate": "^1.4.2" + } + }, + "regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "regenerator-transform": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + } + }, + "regexpu-core": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.1.tgz", + "integrity": "sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==", + "requires": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsgen": "^0.7.1", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" + } + }, + "registry-auth-token": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", + "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", + "requires": { + "rc": "1.2.8" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "requires": { + "rc": "^1.2.8" + } + }, + "regjsgen": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", + "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==" + }, + "regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==" + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==" + }, + "remark-emoji": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-2.2.0.tgz", + "integrity": "sha512-P3cj9s5ggsUvWw5fS2uzCHJMGuXYRb0NnZqYlNecewXt8QBU9n5vW3DUUKOhepS8F9CwdMx9B8a3i7pqFWAI5w==", + "requires": { + "emoticon": "^3.2.0", + "node-emoji": "^1.10.0", + "unist-util-visit": "^2.0.3" + } + }, + "remark-footnotes": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-2.0.0.tgz", + "integrity": "sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==" + }, + "remark-mdx": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-1.6.22.tgz", + "integrity": "sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==", + "requires": { + "@babel/core": "7.12.9", + "@babel/helper-plugin-utils": "7.10.4", + "@babel/plugin-proposal-object-rest-spread": "7.12.1", + "@babel/plugin-syntax-jsx": "7.12.1", + "@mdx-js/util": "1.6.22", + "is-alphabetical": "1.0.4", + "remark-parse": "8.0.3", + "unified": "9.2.0" + }, + "dependencies": { + "@babel/core": { + "version": "7.12.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", + "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.5", + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helpers": "^7.12.5", + "@babel/parser": "^7.12.7", + "@babel/template": "^7.12.7", + "@babel/traverse": "^7.12.9", + "@babel/types": "^7.12.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", + "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-transform-parameters": "^7.12.1" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", + "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" + }, + "unified": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", + "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", + "requires": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^2.0.0", + "trough": "^1.0.0", + "vfile": "^4.0.0" + } + }, + "vfile": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", + "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", + "requires": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-message": "^2.0.0" + } + }, + "vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + } + } + } + }, + "remark-parse": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz", + "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==", + "requires": { + "ccount": "^1.0.0", + "collapse-white-space": "^1.0.2", + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-whitespace-character": "^1.0.0", + "is-word-character": "^1.0.0", + "markdown-escapes": "^1.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.5.4", + "state-toggle": "^1.0.0", + "trim": "0.0.1", + "trim-trailing-lines": "^1.0.0", + "unherit": "^1.0.4", + "unist-util-remove-position": "^2.0.0", + "vfile-location": "^3.0.0", + "xtend": "^4.0.1" + } + }, + "remark-squeeze-paragraphs": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-4.0.0.tgz", + "integrity": "sha512-8qRqmL9F4nuLPIgl92XUuxI3pFxize+F1H0e/W3llTk0UsjJaj01+RrirkMw7P21RKe4X6goQhYRSvNWX+70Rw==", + "requires": { + "mdast-squeeze-paragraphs": "^4.0.0" + } + }, + "remark-stringify": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-10.0.2.tgz", + "integrity": "sha512-6wV3pvbPvHkbNnWB0wdDvVFHOe1hBRAx1Q/5g/EpH4RppAII6J8Gnwe7VbHuXaoKIF6LAg6ExTel/+kNqSQ7lw==", + "dev": true, + "requires": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.0.0", + "unified": "^10.0.0" + }, + "dependencies": { + "bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "dev": true + }, + "is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true + }, + "trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "dev": true + }, + "unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + } + } + } + }, + "renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "requires": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + } + } + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==" + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" + }, + "require-like": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", + "integrity": "sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==" + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, + "resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "rtl-detect": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.0.4.tgz", + "integrity": "sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ==" + }, + "rtlcss": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-3.5.0.tgz", + "integrity": "sha512-wzgMaMFHQTnyi9YOwsx9LjOxYXJPzS8sYnFaKm6R5ysvTkwzHiB0vxnbHwchHQT65PTdBjDG21/kQBWI7q9O7A==", + "requires": { + "find-up": "^5.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.3.11", + "strip-json-comments": "^3.1.1" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rxjs": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", + "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", + "requires": { + "tslib": "^2.1.0" + } + }, + "sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "requires": { + "mri": "^1.1.0" + } + }, + "safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + }, + "section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "requires": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" + }, + "selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "requires": { + "node-forge": "^1" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + } + } + }, + "serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-handler": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz", + "integrity": "sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==", + "requires": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "fast-url-parser": "1.1.3", + "mime-types": "2.1.18", + "minimatch": "3.1.2", + "path-is-inside": "1.0.2", + "path-to-regexp": "2.2.1", + "range-parser": "1.2.0" + }, + "dependencies": { + "path-to-regexp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", + "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==" + } + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" + } + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "requires": { + "kind-of": "^6.0.2" + } + }, + "shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "shell-quote": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.4.tgz", + "integrity": "sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==" + }, + "shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "sirv": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", + "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==", + "requires": { + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", + "totalist": "^1.0.0" + } + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "sitemap": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-7.1.1.tgz", + "integrity": "sha512-mK3aFtjz4VdJN0igpIJrinf3EO8U8mxOPsTBzSsy06UtjZQJ3YY3o3Xa7zSc5nMqcMrRwlChHZ18Kxg0caiPBg==", + "requires": { + "@types/node": "^17.0.5", + "@types/sax": "^1.2.1", + "arg": "^5.0.0", + "sax": "^1.2.4" + }, + "dependencies": { + "@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" + } + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + }, + "sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "sort-css-media-queries": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.1.0.tgz", + "integrity": "sha512-IeWvo8NkNiY2vVYdPa27MCQiR0MN0M80johAYFVxWWXQ44KU84WNxjslwBHmc/7ZL2ccwkM7/e6S5aiKZXm7jA==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==" + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" + }, + "state-toggle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz", + "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==" + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + }, + "std-env": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.3.0.tgz", + "integrity": "sha512-cNNS+VYsXIs5gI6gJipO4qZ8YYT274JHvNnQ1/R/x8Q8mdP0qj0zoMchRXmBNPqp/0eOEhX+3g7g6Fgb7meLIQ==" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "string-replace-loader": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-replace-loader/-/string-replace-loader-3.1.0.tgz", + "integrity": "sha512-5AOMUZeX5HE/ylKDnEa/KKBqvlnFmRZudSOjVJHxhoJg9QYTwl1rECx7SLR8BBH7tfxb4Rp7EM2XVfQFxIhsbQ==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, + "string.prototype.matchall": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", + "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4" + } + }, + "string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "stringify-entities": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.3.tgz", + "integrity": "sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==", + "dev": true, + "requires": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "dependencies": { + "character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true + } + } + }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==" + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" + }, + "style-to-object": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", + "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", + "requires": { + "inline-style-parser": "0.1.1" + } + }, + "stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "requires": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, + "svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + }, + "svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "requires": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + }, + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + } + } + }, + "synckit": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.4.tgz", + "integrity": "sha512-Dn2ZkzMdSX827QbowGbU/4yjWuvNaCoScLLoMo/yKbu+P4GBR6cRGKZH27k6a9bRzdqcyd1DE96pQtQ6uNkmyw==", + "dev": true, + "requires": { + "@pkgr/utils": "^2.3.1", + "tslib": "^2.4.0" + } + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" + }, + "terser": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.1.tgz", + "integrity": "sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw==", + "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + } + } + }, + "terser-webpack-plugin": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz", + "integrity": "sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==", + "requires": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.5" + }, + "dependencies": { + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + }, + "thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "requires": { + "any-promise": "^1.0.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "requires": { + "thenify": ">= 3.1.0 < 4" + } + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "timers-ext": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "dev": true, + "requires": { + "es5-ext": "~0.10.46", + "next-tick": "1" + } + }, + "tiny-glob": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", + "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", + "dev": true, + "requires": { + "globalyzer": "0.1.0", + "globrex": "^0.1.2" + } + }, + "tiny-invariant": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", + "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" + }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "totalist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", + "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==" + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "trim": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", + "integrity": "sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ==" + }, + "trim-trailing-lines": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz", + "integrity": "sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==" + }, + "trough": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", + "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==" + }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "devOptional": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "dependencies": { + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + } + } + }, + "typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typescript": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==" + }, + "ua-parser-js": { + "version": "0.7.35", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.35.tgz", + "integrity": "sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g==" + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "unherit": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz", + "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==", + "requires": { + "inherits": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==" + }, + "unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==" + }, + "unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==" + }, + "unified": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz", + "integrity": "sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ==", + "requires": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^2.0.0", + "trough": "^1.0.0", + "vfile": "^4.0.0" + }, + "dependencies": { + "vfile": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", + "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", + "requires": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-message": "^2.0.0" + } + }, + "vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + } + } + } + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "unist-builder": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-2.0.3.tgz", + "integrity": "sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==" + }, + "unist-util-generated": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.6.tgz", + "integrity": "sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg==" + }, + "unist-util-is": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==" + }, + "unist-util-position": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.1.0.tgz", + "integrity": "sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==" + }, + "unist-util-position-from-estree": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-1.1.1.tgz", + "integrity": "sha512-xtoY50b5+7IH8tFbkw64gisG9tMSpxDjhX9TmaJJae/XuxQ9R/Kc8Nv1eOsf43Gt4KV/LkriMy9mptDr7XLcaw==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0" + } + }, + "unist-util-remove": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-2.1.0.tgz", + "integrity": "sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q==", + "requires": { + "unist-util-is": "^4.0.0" + } + }, + "unist-util-remove-position": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz", + "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==", + "requires": { + "unist-util-visit": "^2.0.0" + } + }, + "unist-util-stringify-position": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", + "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", + "requires": { + "@types/unist": "^2.0.2" + } + }, + "unist-util-visit": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", + "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + } + }, + "unist-util-visit-parents": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + }, + "update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "update-notifier": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "requires": { + "boxen": "^5.0.0", + "chalk": "^4.1.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + } + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "requires": { + "string-width": "^4.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + } + } + }, + "url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "requires": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", + "requires": { + "prepend-http": "^2.0.0" + } + }, + "use-composed-ref": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.3.0.tgz", + "integrity": "sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==", + "requires": {} + }, + "use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "requires": {} + }, + "use-latest": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.1.tgz", + "integrity": "sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==", + "requires": { + "use-isomorphic-layout-effect": "^1.1.1" + } + }, + "use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "requires": {} + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" + }, + "utility-types": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", + "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "uvu": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", + "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", + "dev": true, + "requires": { + "dequal": "^2.0.0", + "diff": "^5.0.0", + "kleur": "^4.0.3", + "sade": "^1.7.3" + }, + "dependencies": { + "kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true + } + } + }, + "value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "vfile": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.5.tgz", + "integrity": "sha512-U1ho2ga33eZ8y8pkbQLH54uKqGhFJ6GYIHnnG5AhRpAh3OWjkrRHKa/KogbmQn8We+c0KVV3rTOgR9V/WowbXQ==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "dependencies": { + "unist-util-stringify-position": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", + "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0" + } + } + } + }, + "vfile-location": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.2.0.tgz", + "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==" + }, + "vfile-message": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.2.tgz", + "integrity": "sha512-QjSNP6Yxzyycd4SVOtmKKyTsSvClqBPJcd00Z0zuPj3hOIjg0rUPG6DbFGPvUKRgYyaIWLPKpuEclcuvb3H8qA==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" + }, + "dependencies": { + "unist-util-stringify-position": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", + "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0" + } + } + } + }, + "wait-on": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz", + "integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==", + "requires": { + "axios": "^0.25.0", + "joi": "^17.6.0", + "lodash": "^4.17.21", + "minimist": "^1.2.5", + "rxjs": "^7.5.4" + } + }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "web-namespaces": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz", + "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==" + }, + "web-tree-sitter": { + "version": "0.20.8", + "resolved": "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.20.8.tgz", + "integrity": "sha512-weOVgZ3aAARgdnb220GqYuh7+rZU0Ka9k9yfKtGAzEYMa6GgiCzW9JjQRJyCJakvibQW+dfjJdihjInKuuCAUQ==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "webpack": { + "version": "5.86.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.86.0.tgz", + "integrity": "sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==", + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.14.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.2", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "schema-utils": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", + "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "webpack-bundle-analyzer": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.6.1.tgz", + "integrity": "sha512-oKz9Oz9j3rUciLNfpGFjOb49/jEpXNmWdVH8Ls//zNcnLlQdTGXQQMsBbb/gR7Zl8WNLxVCq+0Hqbx3zv6twBw==", + "requires": { + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "chalk": "^4.1.0", + "commander": "^7.2.0", + "gzip-size": "^6.0.0", + "lodash": "^4.17.20", + "opener": "^1.5.2", + "sirv": "^1.0.7", + "ws": "^7.3.1" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + } + } + }, + "webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "requires": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "webpack-dev-server": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz", + "integrity": "sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==", + "requires": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.4.2" + }, + "dependencies": { + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + }, + "ws": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.10.0.tgz", + "integrity": "sha512-+s49uSmZpvtAsd2h37vIPy1RBusaLawVe8of+GyEPsaJTCMpj/2v8NpeK1SHXjBlQ95lQTmQofOJnFiLoaN3yw==", + "requires": {} + } + } + }, + "webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "requires": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==" + }, + "webpackbar": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-5.0.2.tgz", + "integrity": "sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==", + "requires": { + "chalk": "^4.1.0", + "consola": "^2.15.3", + "pretty-time": "^1.1.0", + "std-env": "^3.0.1" + } + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "requires": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } + }, + "which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, + "requires": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + } + }, + "which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "requires": { + "string-width": "^5.0.1" + } + }, + "wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==" + }, + "word-wrap": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", + "devOptional": true + }, + "wrap-ansi": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.0.1.tgz", + "integrity": "sha512-QFF+ufAqhoYHvoHdajT/Po7KoXVBPXS2bgjIam5isfWJPfIOnQZ50JtUiVvCv/sjgacf3yRrt2ZKUZ/V4itN4g==", + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" + }, + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==" + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "requires": {} + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" + }, + "xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "requires": { + "sax": "^1.2.4" + } + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + }, + "zwitch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", + "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==" + } + } +} diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 000000000000..aa48af24d3c9 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,66 @@ +{ + "name": "docs", + "version": "0.0.0", + "private": true, + "scripts": { + "start": "docusaurus start --host 0.0.0.0", + "build": "docusaurus build", + "serve": "docusaurus serve", + "swizzle": "docusaurus swizzle", + "deploy": "docusaurus deploy", + "clear": "docusaurus clear", + "lint": "eslint . --ext js,jsx,md,mdx", + "prettier:check": "prettier --check .", + "prettier:format": "prettier --write .", + "typecheck": "tsc" + }, + "dependencies": { + "@docusaurus/core": "^2.4.0", + "@docusaurus/preset-classic": "^2.4.0", + "@fortawesome/fontawesome-svg-core": "^6.4.2", + "@fortawesome/free-solid-svg-icons": "^6.4.0", + "@fortawesome/react-fontawesome": "^0.2.0", + "@mdx-js/react": "^1.6.22", + "classnames": "^2.2.6", + "js-yaml": "^4.1.0", + "react": "^17.0.2", + "react-async": "^10.0.1", + "react-copy-to-clipboard": "^5.0.3", + "react-dom": "^17.0.2", + "react-toastify": "^7.0.4", + "web-tree-sitter": "^0.20.8" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "^2.4.0", + "@docusaurus/types": "^2.4.0", + "@tsconfig/docusaurus": "^1.0.7", + "@types/js-yaml": "^4.0.5", + "@types/react": "^17.0.58", + "@types/react-helmet": "^6.1.6", + "@types/react-router-dom": "^5.1.7", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-mdx": "^2.0.5", + "eslint-plugin-react": "^7.33.2", + "json-schema-to-typescript": "^13.1.1", + "mustache": "^4.2.0", + "null-loader": "^4.0.0", + "prebuild-webpack-plugin": "^1.1.1", + "prettier": "^2.8.7", + "string-replace-loader": "^3.1.0", + "typescript": "^5.0.4", + "webpack": "^5.86.0" + } +} diff --git a/docs/sidebars.js b/docs/sidebars.js new file mode 100644 index 000000000000..19b0ad7e68ca --- /dev/null +++ b/docs/sidebars.js @@ -0,0 +1,96 @@ +module.exports = { + docs: { + "Getting Started": [ + "intro", + "hardware", + "faq", + "user-setup", + "customization", + "troubleshooting", + ], + Features: [ + "features/keymaps", + "features/bluetooth", + "features/combos", + "features/conditional-layers", + "features/debouncing", + "features/displays", + "features/encoders", + "features/underglow", + "features/backlight", + "features/battery", + "features/beta-testing", + ], + Behaviors: [ + "behaviors/key-press", + "behaviors/layers", + "behaviors/misc", + "behaviors/hold-tap", + "behaviors/mod-tap", + "behaviors/mod-morph", + "behaviors/macros", + "behaviors/key-toggle", + "behaviors/sticky-key", + "behaviors/sticky-layer", + "behaviors/tap-dance", + "behaviors/caps-word", + "behaviors/key-repeat", + "behaviors/sensor-rotate", + "behaviors/mouse-emulation", + "behaviors/reset", + "behaviors/bluetooth", + "behaviors/outputs", + "behaviors/underglow", + "behaviors/backlight", + "behaviors/power", + ], + Codes: [ + "codes/index", + "codes/keyboard-keypad", + "codes/modifiers", + "codes/editing", + "codes/media", + "codes/applications", + "codes/input-assist", + "codes/power", + "codes/keymap-upgrader", + ], + Configuration: [ + "config/index", + "config/backlight", + "config/battery", + "config/behaviors", + "config/bluetooth", + "config/combos", + "config/displays", + "config/encoders", + "config/keymap", + "config/kscan", + "config/power", + "config/underglow", + "config/system", + ], + Development: [ + "development/clean-room", + "development/pre-commit", + "development/documentation", + "development/setup", + "development/build-flash", + "development/boards-shields-keymaps", + "development/posix-board", + "development/tests", + "development/usb-logging", + "development/ide-integration", + { + type: "category", + label: "Guides", + collapsed: false, + items: [ + "development/new-shield", + "development/hardware-metadata-files", + "development/new-behavior", + ], + }, + ], + }, +}; diff --git a/docs/src/.gitignore b/docs/src/.gitignore new file mode 100644 index 000000000000..3a722c803feb --- /dev/null +++ b/docs/src/.gitignore @@ -0,0 +1 @@ +hardware-metadata.d.ts diff --git a/docs/src/components/KeymapUpgrader/index.jsx b/docs/src/components/KeymapUpgrader/index.jsx new file mode 100644 index 000000000000..8d3a60b2b82b --- /dev/null +++ b/docs/src/components/KeymapUpgrader/index.jsx @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import React from "react"; +import { useAsync } from "react-async"; + +import { initParser, upgradeKeymap } from "@site/src/keymap-upgrade"; +import CodeBlock from "@theme/CodeBlock"; + +import styles from "./styles.module.css"; + +export default function KeymapUpgrader() { + const { error, isPending } = useAsync(initParser); + + if (isPending) { + return

Loading...

; + } + + if (error) { + return

Error: {error.message}

; + } + + return ; +} + +function Editor() { + const [keymap, setKeymap] = React.useState(""); + const upgraded = upgradeKeymap(keymap); + + return ( +
+ +
+ {upgraded} +
+
+ ); +} diff --git a/docs/src/components/KeymapUpgrader/styles.module.css b/docs/src/components/KeymapUpgrader/styles.module.css new file mode 100644 index 000000000000..31e06b979924 --- /dev/null +++ b/docs/src/components/KeymapUpgrader/styles.module.css @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +.editor { + font-family: var(--ifm-font-family-monospace); + font-size: var(--ifm-font-size-base); + line-height: var(--ifm-pre-line-height); + tab-size: 4; + + color: var(--ifm-pre-color); + background-color: var(--ifm-pre-background); + + border: none; + border-radius: var(--ifm-pre-border-radius); + + width: 100%; + min-height: 10em; + padding: var(--ifm-pre-padding); +} + +.result { + tab-size: 4; +} diff --git a/docs/src/components/codes/Context.jsx b/docs/src/components/codes/Context.jsx new file mode 100644 index 000000000000..4fdcbfc03bbd --- /dev/null +++ b/docs/src/components/codes/Context.jsx @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import React from "react"; +import PropTypes from "prop-types"; + +export default function Context({ children }) { + return

{children}

; +} + +Context.propTypes = { + children: PropTypes.oneOfType([PropTypes.element, PropTypes.string]) + .isRequired, +}; diff --git a/docs/src/components/codes/Description.jsx b/docs/src/components/codes/Description.jsx new file mode 100644 index 000000000000..7ad5fc2cca94 --- /dev/null +++ b/docs/src/components/codes/Description.jsx @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import React from "react"; +import PropTypes from "prop-types"; + +const specialCharactersRegex = + /(?:^|\s)((?:&(?:(?:\w+)|(?:#\d+));)|[_]|[^\w\s])(?:\s*\[([^[\]]+?)\])/g; + +function renderSpecialCharacters(description) { + const matches = Array.from(description.matchAll(specialCharactersRegex)); + if (matches.length == 0) return description; + let lastIndex = 0; + const parts = matches.reduce((acc, match, i) => { + const { index } = match; + const str = match[0]; + const chars = match[1]; + const meaning = match[2]; + if (index != lastIndex) { + acc.push(description.substring(lastIndex, index)); + } + const pos = str.indexOf(chars); + if (pos > 0) { + acc.push(description.substr(index, pos)); + } + acc.push( + + {description.substr(index + pos, chars.length)} + {meaning ? {meaning} : undefined} + + ); + lastIndex = index + str.length; + return acc; + }, []); + if (lastIndex < description.length) { + parts.push(description.substr(lastIndex)); + } + return parts; +} + +export default function Description({ description = "" }) { + return ( + {renderSpecialCharacters(description)} + ); +} + +Description.propTypes = { + description: PropTypes.string.isRequired, +}; diff --git a/docs/src/components/codes/Footnote.jsx b/docs/src/components/codes/Footnote.jsx new file mode 100644 index 000000000000..c9396a30cd72 --- /dev/null +++ b/docs/src/components/codes/Footnote.jsx @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import React from "react"; +import PropTypes from "prop-types"; + +export default function Footnote({ children, symbol, id }) { + return ( +
+
{symbol}
+
{children}
+
+ ); +} + +Footnote.propTypes = { + children: PropTypes.element.isRequired, + symbol: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, + id: PropTypes.string.isRequired, +}; diff --git a/docs/src/components/codes/FootnoteRef.jsx b/docs/src/components/codes/FootnoteRef.jsx new file mode 100644 index 000000000000..c7b11a7d023a --- /dev/null +++ b/docs/src/components/codes/FootnoteRef.jsx @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import React from "react"; +import PropTypes from "prop-types"; + +export default function FootnoteRef({ children, anchor }) { + return ( + + {children} + + ); +} + +FootnoteRef.propTypes = { + children: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) + .isRequired, + anchor: PropTypes.string.isRequired, +}; diff --git a/docs/src/components/codes/FootnoteRefs.jsx b/docs/src/components/codes/FootnoteRefs.jsx new file mode 100644 index 000000000000..3782c13fba31 --- /dev/null +++ b/docs/src/components/codes/FootnoteRefs.jsx @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import React from "react"; +import PropTypes from "prop-types"; +import FootnoteRef from "./FootnoteRef"; + +function joinReactElements(arr, delimiter) { + return arr.reduce((acc, fragment) => { + if (acc === null) { + return fragment; + } + return ( + <> + {acc} + {delimiter} + {fragment} + + ); + }, null); +} + +export default function FootnoteRefs({ footnotes }) { + return ( + + {joinReactElements( + footnotes.map((footnote) => ( + + {footnote.symbol} + + )), + ", " + )} + + ); +} + +FootnoteRefs.propTypes = { + footnotes: PropTypes.array.isRequired, +}; diff --git a/docs/src/components/codes/Footnotes.jsx b/docs/src/components/codes/Footnotes.jsx new file mode 100644 index 000000000000..b382141f81d0 --- /dev/null +++ b/docs/src/components/codes/Footnotes.jsx @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import React from "react"; +import PropTypes from "prop-types"; +import Footnote from "./Footnote"; + +export default function Footnotes({ footnotes = [], id }) { + return ( + + ); +} + +Footnotes.propTypes = { + footnotes: PropTypes.array.isRequired, + id: PropTypes.string.isRequired, +}; diff --git a/docs/src/components/codes/LinkIcon.jsx b/docs/src/components/codes/LinkIcon.jsx new file mode 100644 index 000000000000..5bfeebd4a1f2 --- /dev/null +++ b/docs/src/components/codes/LinkIcon.jsx @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import React from "react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons"; +export default function LinkIcon() { + return ; +} + +LinkIcon.propTypes = {}; diff --git a/docs/src/components/codes/Name.jsx b/docs/src/components/codes/Name.jsx new file mode 100644 index 000000000000..52dc7347fd3a --- /dev/null +++ b/docs/src/components/codes/Name.jsx @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import React from "react"; +import PropTypes from "prop-types"; +import ToastyCopyToClipboard from "./ToastyCopyToClipboard"; + +export default function Name({ children, name }) { + return ( + + + {children} + + + ); +} + +Name.propTypes = { + children: PropTypes.oneOfType([PropTypes.element, PropTypes.string]) + .isRequired, + name: PropTypes.string.isRequired, +}; diff --git a/docs/src/components/codes/OsLegend.jsx b/docs/src/components/codes/OsLegend.jsx new file mode 100644 index 000000000000..c53907fa3bda --- /dev/null +++ b/docs/src/components/codes/OsLegend.jsx @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import React from "react"; +import operatingSystems from "@site/src/data/operating-systems"; + +export default function OsLegend() { + return ( +
+ {operatingSystems.map(({ key, className, heading, title }) => ( +
+ {heading} + {title} +
+ ))} +
+ ); +} + +OsLegend.propTypes = {}; diff --git a/docs/src/components/codes/OsSupport.jsx b/docs/src/components/codes/OsSupport.jsx new file mode 100644 index 000000000000..2cb60c974f0e --- /dev/null +++ b/docs/src/components/codes/OsSupport.jsx @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import React from "react"; +import PropTypes from "prop-types"; +import OsSupportIcon from "./OsSupportIcon"; +import FootnoteRefs from "./FootnoteRefs"; + +export default function OsSupport({ value, footnotes = [] }) { + return ( + <> + + {footnotes.length > 0 ? ( + + ) : undefined} + + ); +} + +OsSupport.propTypes = { + value: PropTypes.oneOf([true, false, null]), + footnotes: PropTypes.array.isRequired, +}; diff --git a/docs/src/components/codes/OsSupportIcon.jsx b/docs/src/components/codes/OsSupportIcon.jsx new file mode 100644 index 000000000000..a518d62a4a74 --- /dev/null +++ b/docs/src/components/codes/OsSupportIcon.jsx @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import React from "react"; +import PropTypes from "prop-types"; + +const Icon = ({ children, className, title }) => ( + + {children} + +); + +Icon.propTypes = { + children: PropTypes.oneOfType([PropTypes.element, PropTypes.string]) + .isRequired, + className: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, +}; + +export const Supported = () => ( + + ⭐ + +); +export const NotSupported = () => ( + + ❌ + +); +export const NotTested = () => ( + + ❔ + +); + +export default function OsSupportIcon({ value }) { + if (value === true) { + return ; + } + if (value === false) { + return ; + } + return ; +} + +OsSupportIcon.propTypes = { + value: PropTypes.oneOf([true, false, null]), +}; diff --git a/docs/src/components/codes/SpellingCaution.jsx b/docs/src/components/codes/SpellingCaution.jsx new file mode 100644 index 000000000000..15ba9488ecdd --- /dev/null +++ b/docs/src/components/codes/SpellingCaution.jsx @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import React from "react"; +import Admonition from "@theme/Admonition"; + +export default function SpellingCaution() { + return ( + +

+ Take extra notice of the spelling of the keycodes, especially the + shorthand spelling. Otherwise, it will result in an elusive parsing + error! +

+
+ ); +} + +SpellingCaution.propTypes = {}; diff --git a/docs/src/components/codes/Table.jsx b/docs/src/components/codes/Table.jsx new file mode 100644 index 000000000000..0596de6a205e --- /dev/null +++ b/docs/src/components/codes/Table.jsx @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import React from "react"; +import PropTypes from "prop-types"; +import TableRow from "./TableRow"; +import Footnotes from "./Footnotes"; +import LinkIcon from "./LinkIcon"; +import operatingSystems from "@site/src/data/operating-systems"; +import { getCodes } from "@site/src/hid"; +import { getGroup } from "@site/src/groups"; +import { getFootnote } from "@site/src/footnotes"; + +function extractFootnoteIds(codes) { + return Array.from( + new Set( + codes + .flatMap(({ footnotes }) => Object.values(footnotes)) + .flatMap((refs) => (Array.isArray(refs) ? refs.flat() : refs)) + ) + ); +} + +export default function Table({ group }) { + const codes = getCodes(getGroup(group)); + + const footnotesAnchor = group + "-" + "footnotes"; + + const tableFootnotes = extractFootnoteIds(codes).map((id, i) => { + const Component = getFootnote(id); + return { + id, + anchor: footnotesAnchor, + symbol: i + 1, + value: Component ? : undefined, + }; + }); + + return ( +
+ + + + + + + {operatingSystems.map(({ key, className, heading, title }) => ( + + ))} + + + + {Array.isArray(codes) + ? codes.map((code) => ( + + )) + : undefined} + +
NamesDescription + + + {heading} +
+ {tableFootnotes.length > 0 ? ( + + ) : undefined} +
+ ); +} + +Table.propTypes = { + group: PropTypes.string.isRequired, +}; diff --git a/docs/src/components/codes/TableRow.jsx b/docs/src/components/codes/TableRow.jsx new file mode 100644 index 000000000000..a560911f46ca --- /dev/null +++ b/docs/src/components/codes/TableRow.jsx @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import React from "react"; +import PropTypes from "prop-types"; +import Name from "./Name"; +import Description from "./Description"; +import Context from "./Context"; +import LinkIcon from "./LinkIcon"; +import OsSupport from "./OsSupport"; +import operatingSystems from "@site/src/data/operating-systems"; + +export default function TableRow({ + names, + description, + context = "", + clarify = false, + documentation, + os, + footnotes, + tableFootnotes, +}) { + return ( + + + {names.map((name) => ( + + {name} + + ))} + + + + {clarify && context ? {context} : undefined} + + +
+ + + + {operatingSystems.map(({ key, className, title }) => ( + + + (Array.isArray(footnotes[key]) && + footnotes[key].includes(id)) || + footnotes[key] == id + )} + /> + + ))} + + ); +} + +TableRow.propTypes = { + names: PropTypes.array.isRequired, + description: PropTypes.string.isRequired, + context: PropTypes.string.isRequired, + clarify: PropTypes.bool, + documentation: PropTypes.string.isRequired, + os: PropTypes.object.isRequired, + footnotes: PropTypes.object.isRequired, + tableFootnotes: PropTypes.array.isRequired, +}; diff --git a/docs/src/components/codes/ToastyContainer.jsx b/docs/src/components/codes/ToastyContainer.jsx new file mode 100644 index 000000000000..ee4e3bca21e3 --- /dev/null +++ b/docs/src/components/codes/ToastyContainer.jsx @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import React from "react"; +import { ToastContainer } from "react-toastify"; +import "react-toastify/dist/ReactToastify.css"; + +export default function ToastyContainer() { + return ( + + ); +} + +ToastyContainer.propTypes = {}; diff --git a/docs/src/components/codes/ToastyCopyToClipboard.jsx b/docs/src/components/codes/ToastyCopyToClipboard.jsx new file mode 100644 index 000000000000..b0e9809233ca --- /dev/null +++ b/docs/src/components/codes/ToastyCopyToClipboard.jsx @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import React from "react"; +import PropTypes from "prop-types"; +import { toast } from "react-toastify"; +import { CopyToClipboard } from "react-copy-to-clipboard"; + +export default function ToastyCopyToClipboard({ children, text }) { + const notify = () => + toast( + + 📋 Copied {text} + + ); + return ( +
+ {children} +
+ ); +} + +ToastyCopyToClipboard.propTypes = { + children: PropTypes.oneOfType([PropTypes.element, PropTypes.string]) + .isRequired, + text: PropTypes.string.isRequired, +}; diff --git a/docs/src/components/custom-board-form.js b/docs/src/components/custom-board-form.js new file mode 100644 index 000000000000..e8ae429454c2 --- /dev/null +++ b/docs/src/components/custom-board-form.js @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +import React from "react"; +import PropTypes from "prop-types"; + +function CustomBoardForm({ + bindPsuType, + bindOutputV, + bindEfficiency, + bindQuiescentMicroA, + bindOtherQuiescentMicroA, +}) { + return ( +
+

Custom Board

+
+
+
+ + +
+
+
+
+ + + {parseFloat(bindOutputV.value).toFixed(1)}V +
+ {bindPsuType.value === "SWITCHING" && ( +
+ + + {Math.round(bindEfficiency.value * 100)}% +
+ )} +
+
+
+ +
+ + µA +
+
+
+ +
+ + µA +
+
+
+
+
+ ); +} + +CustomBoardForm.propTypes = { + bindPsuType: PropTypes.Object, + bindOutputV: PropTypes.Object, + bindEfficiency: PropTypes.Object, + bindQuiescentMicroA: PropTypes.Object, + bindOtherQuiescentMicroA: PropTypes.Object, +}; + +export default CustomBoardForm; diff --git a/docs/src/components/hardware-list.tsx b/docs/src/components/hardware-list.tsx new file mode 100644 index 000000000000..54034ada3bfe --- /dev/null +++ b/docs/src/components/hardware-list.tsx @@ -0,0 +1,124 @@ +import React from "react"; + +import Heading from "@theme/Heading"; + +import { HardwareMetadata } from "../hardware-metadata"; +import { groupedMetadata, InterconnectDetails } from "./hardware-utils"; + +interface HardwareListProps { + items: HardwareMetadata[]; +} + +type ElementOrString = JSX.Element | string; + +function itemHasMultiple(item: HardwareMetadata) { + return ( + (item.type == "board" || item.type == "shield") && + (item.siblings?.length ?? 1) > 1 + ); +} + +function itemIds(item: HardwareMetadata) { + if (item.type == "board" || item.type == "shield") { + let nodes = (item.siblings ?? [item.id]) + .map((id) => {id}) + .reduce( + (prev, curr, index) => [...prev, index > 0 ? ", " : "", curr], + [] as ElementOrString[] + ); + return {nodes}; + } else { + return {item.id}; + } +} + +const TYPE_LABELS: Record< + HardwareMetadata["type"], + Record<"singular" | "plural", string> +> = { + board: { plural: "Boards: ", singular: "Board: " }, + shield: { singular: "Shield: ", plural: "Shields: " }, + interconnect: { singular: "Interconnect: ", plural: "Interconnects: " }, +}; + +function HardwareLineItem({ item }: { item: HardwareMetadata }) { + return ( +
  • + {item.name} ( + {TYPE_LABELS[item.type][itemHasMultiple(item) ? "plural" : "singular"]}{" "} + {itemIds(item)}) +
  • + ); +} + +function mapInterconnect({ + interconnect, + boards, + shields, +}: InterconnectDetails) { + if (!interconnect) { + return null; + } + + return ( +
    + + {interconnect.name} Interconnect + + {interconnect.description &&

    {interconnect.description}

    } + Boards +
      + {boards.map((s) => ( + + ))} +
    + Shields +
      + {shields.map((s) => ( + + ))} +
    +
    + ); +} + +function HardwareList({ items }: HardwareListProps) { + let grouped = groupedMetadata(items); + + return ( + <> +
    + + Onboard Controller Keyboards + +

    + Keyboards with onboard controllers are single PCBs that contain all + the components of a keyboard, including the controller chip, switch + footprints, etc. +

    +
      + {grouped["onboard"] + .sort((a, b) => a.name.localeCompare(b.name)) + .map((s) => ( + + ))} +
    +
    +
    + + Composite Keyboards + +

    + Composite keyboards are composed of two main PCBs: a small controller + board with exposed pads, and a larger keyboard PCB (a shield, in ZMK + lingo) with switch footprints and a location where the controller is + added. This location is called an interconnect. Multiple interconnects + can be found below. +

    + {Object.values(grouped.interconnects).map(mapInterconnect)} +
    + + ); +} + +export default HardwareList; diff --git a/docs/src/components/hardware-utils.ts b/docs/src/components/hardware-utils.ts new file mode 100644 index 000000000000..76452dc357de --- /dev/null +++ b/docs/src/components/hardware-utils.ts @@ -0,0 +1,74 @@ +import { + Board, + HardwareMetadata, + Interconnect, + Shield, +} from "../hardware-metadata"; + +export interface InterconnectDetails { + interconnect?: Interconnect; + boards: Board[]; + shields: Shield[]; +} + +export interface GroupedMetadata { + onboard: Board[]; + interconnects: Record; +} + +function groupedBoard(agg: GroupedMetadata, board: Board) { + if (board.features?.includes("keys")) { + agg.onboard.push(board); + } else if (board.exposes) { + board.exposes.forEach((element) => { + let ic = agg.interconnects[element] ?? { + boards: [], + shields: [], + }; + ic.boards.push(board); + agg.interconnects[element] = ic; + }); + } else { + console.error("Board without keys or interconnect"); + } + + return agg; +} + +function groupedShield(agg: GroupedMetadata, shield: Shield) { + shield.requires.forEach((id) => { + let ic = agg.interconnects[id] ?? { boards: [], shields: [] }; + ic.shields.push(shield); + agg.interconnects[id] = ic; + }); + shield.exposes?.forEach((id) => { + let ic = agg.interconnects[id] ?? { boards: [], shields: [] }; + ic.shields.push(shield); + agg.interconnects[id] = ic; + }); + return agg; +} + +function groupedInterconnect(agg: GroupedMetadata, item: Interconnect) { + let ic = agg.interconnects[item.id] ?? { boards: [], shields: [] }; + ic.interconnect = item; + agg.interconnects[item.id] = ic; + + return agg; +} + +export function groupedMetadata(items: HardwareMetadata[]) { + return items.reduce( + (agg, hm) => { + switch (hm.type) { + case "board": + return groupedBoard(agg, hm); + case "shield": + return groupedShield(agg, hm); + case "interconnect": + return groupedInterconnect(agg, hm); + } + }, + { onboard: [] as Board[], interconnects: {} } + ); +} diff --git a/docs/src/components/interconnect-tabs.tsx b/docs/src/components/interconnect-tabs.tsx new file mode 100644 index 000000000000..3ef69ebf2a73 --- /dev/null +++ b/docs/src/components/interconnect-tabs.tsx @@ -0,0 +1,74 @@ +import React from "react"; + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +import { HardwareMetadata, Interconnect } from "../hardware-metadata"; +import { groupedMetadata, InterconnectDetails } from "./hardware-utils"; + +interface InterconnectTabsProps { + items: HardwareMetadata[]; +} + +function mapInterconnect(interconnect: Interconnect) { + let content = require(`@site/src/data/interconnects/${interconnect.id}/design_guideline.md`); + let imageUrl = require(`@site/docs/assets/interconnects/${interconnect.id}/pinout.png`); + + return ( + + + + + + {interconnect.node_labels && ( + <> + The following node labels are available: +
      +
    • + GPIO: &{interconnect.node_labels.gpio} +
    • + {interconnect.node_labels.i2c && ( +
    • + I2C bus: &{interconnect.node_labels.i2c} +
    • + )} + {interconnect.node_labels.spi && ( +
    • + SPI bus: &{interconnect.node_labels.spi} +
    • + )} + {interconnect.node_labels.uart && ( +
    • + UART: &{interconnect.node_labels.uart} +
    • + )} + {interconnect.node_labels.adc && ( +
    • + ADC: &{interconnect.node_labels.adc} +
    • + )} +
    + + )} +
    + ); +} + +function mapInterconnectValue(interconnect: Interconnect) { + return { label: `${interconnect.name} Shields`, value: interconnect.id }; +} + +function InterconnectTabs({ items }: InterconnectTabsProps) { + let grouped = Object.values(groupedMetadata(items).interconnects) + .map((i) => i?.interconnect as Interconnect) + .filter((i) => i?.design_guideline) + .sort((a, b) => a.id.localeCompare(b.id)); + + return ( + + {grouped.map(mapInterconnect)} + + ); +} + +export default InterconnectTabs; diff --git a/docs/src/components/power-estimate.js b/docs/src/components/power-estimate.js new file mode 100644 index 000000000000..2c0a53cd2421 --- /dev/null +++ b/docs/src/components/power-estimate.js @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +import React from "react"; +import PropTypes from "prop-types"; +import { + displayPower, + underglowPower, + backlightPower, + zmkBase, +} from "../data/power"; +import "../css/power-estimate.css"; + +// Average monthly discharge percent +const lithiumIonMonthlyDischargePercent = 5; +// Average voltage of a lithium ion battery based of discharge graphs +const lithiumIonAverageVoltage = 3.8; +// Average discharge efficiency of li-ion https://en.wikipedia.org/wiki/Lithium-ion_battery +const lithiumIonDischargeEfficiency = 0.85; +// Range of the discharge efficiency +const lithiumIonDischargeEfficiencyRange = 0.05; + +// Proportion of time spent typing (keys being pressed down and scanning). Estimated to 2%. +const timeSpentTyping = 0.02; + +// Nordic power profiler kit accuracy +const measurementAccuracy = 0.2; + +const batVolt = lithiumIonAverageVoltage; + +const palette = [ + "#bbdefb", + "#90caf9", + "#64b5f6", + "#42a5f5", + "#2196f3", + "#1e88e5", + "#1976d2", +]; + +function formatUsage(microWatts) { + if (microWatts > 1000) { + return (microWatts / 1000).toFixed(1) + "mW"; + } + + return Math.round(microWatts) + "µW"; +} + +function voltageEquivalentCalc(powerSupply) { + if (powerSupply.type === "LDO") { + return batVolt; + } else if (powerSupply.type === "SWITCHING") { + return powerSupply.outputVoltage / powerSupply.efficiency; + } +} + +function formatMinutes(minutes, precision, floor) { + let message = ""; + let count = 0; + + let units = ["year", "month", "week", "day", "hour", "minute"]; + let multiples = [60 * 24 * 365, 60 * 24 * 30, 60 * 24 * 7, 60 * 24, 60, 1]; + + for (let i = 0; i < units.length; i++) { + if (minutes >= multiples[i]) { + const timeCount = floor + ? Math.floor(minutes / multiples[i]) + : Math.ceil(minutes / multiples[i]); + minutes -= timeCount * multiples[i]; + count++; + message += + timeCount + (timeCount > 1 ? ` ${units[i]}s ` : ` ${units[i]} `); + } + + if (count == precision) return message; + } + + return message || "0 minutes"; +} + +function PowerEstimate({ + board, + splitType, + batteryMilliAh, + usage, + underglow, + backlight, + display, +}) { + if (!board || !board.powerSupply.type || !batteryMilliAh) { + return ( +
    +

    + {splitType !== "standalone" ? splitType + ": " : " "}... +

    +
    +
    +
    +
    + ); + } + + const powerUsage = []; + let totalUsage = 0; + + const voltageEquivalent = voltageEquivalentCalc(board.powerSupply); + + // Lithium ion self discharge + const lithiumMonthlyDischargemAh = + parseInt(batteryMilliAh) * (lithiumIonMonthlyDischargePercent / 100); + const lithiumDischargeMicroA = (lithiumMonthlyDischargemAh * 1000) / 30 / 24; + const lithiumDischargeMicroW = lithiumDischargeMicroA * batVolt; + + totalUsage += lithiumDischargeMicroW; + powerUsage.push({ + title: "Battery Self Discharge", + usage: lithiumDischargeMicroW, + }); + + // Quiescent current + const quiescentMicroATotal = + parseInt(board.powerSupply.quiescentMicroA) + + parseInt(board.otherQuiescentMicroA); + const quiescentMicroW = quiescentMicroATotal * voltageEquivalent; + + totalUsage += quiescentMicroW; + powerUsage.push({ + title: "Board Quiescent Usage", + usage: quiescentMicroW, + }); + + // ZMK overall usage + const zmkMicroA = + zmkBase[splitType].idle + + (splitType !== "peripheral" ? zmkBase.hostConnection * usage.bondedQty : 0); + + const zmkMicroW = zmkMicroA * voltageEquivalent; + const zmkUsage = zmkMicroW * (1 - usage.percentAsleep); + + totalUsage += zmkUsage; + powerUsage.push({ + title: "ZMK Base Usage", + usage: zmkUsage, + }); + + // ZMK typing usage + const zmkTypingMicroA = zmkBase[splitType].typing * timeSpentTyping; + + const zmkTypingMicroW = zmkTypingMicroA * voltageEquivalent; + const zmkTypingUsage = zmkTypingMicroW * (1 - usage.percentAsleep); + + totalUsage += zmkTypingUsage; + powerUsage.push({ + title: "ZMK Typing Usage", + usage: zmkTypingUsage, + }); + + if (underglow.glowEnabled) { + const underglowAverageLedMicroA = + underglow.glowBrightness * + (underglowPower.ledOn - underglowPower.ledOff) + + underglowPower.ledOff; + + const underglowMicroA = + underglowPower.firmware + + underglow.glowQuantity * underglowAverageLedMicroA; + + const underglowMicroW = underglowMicroA * voltageEquivalent; + + const underglowUsage = underglowMicroW * (1 - usage.percentAsleep); + + totalUsage += underglowUsage; + powerUsage.push({ + title: "RGB Underglow", + usage: underglowUsage, + }); + } + + if (backlight.backlightEnabled) { + let backlightMicroA = + ((board.powerSupply.outputVoltage - backlight.backlightVoltage) / + backlight.backlightResistance) * + 1000000 * + backlight.backlightBrightness * + backlight.backlightQuantity; + + if ( + backlight.backlightBrightness > 0 && + backlight.backlightBrightness < 1 + ) { + backlightMicroA += backlightPower.pwmPower; + } + + const backlightMicroW = backlightMicroA * voltageEquivalent; + const backlightUsage = backlightMicroW * (1 - usage.percentAsleep); + + totalUsage += backlightUsage; + powerUsage.push({ + title: "Backlight", + usage: backlightUsage, + }); + } + + if (display.displayEnabled && display.displayType) { + const { activePercent, active, sleep } = displayPower[display.displayType]; + + const displayMicroA = active * activePercent + sleep * (1 - activePercent); + const displayMicroW = displayMicroA * voltageEquivalent; + const displayUsage = displayMicroW * (1 - usage.percentAsleep); + + totalUsage += displayUsage; + powerUsage.push({ + title: "Display", + usage: displayUsage, + }); + } + + // Calculate the average minutes of use + const estimatedAvgEffectiveMicroWH = + batteryMilliAh * batVolt * lithiumIonDischargeEfficiency * 1000; + + const estimatedAvgMinutes = Math.round( + (estimatedAvgEffectiveMicroWH / totalUsage) * 60 + ); + + // Calculate worst case for battery life + const worstLithiumIonDischargeEfficiency = + lithiumIonDischargeEfficiency - lithiumIonDischargeEfficiencyRange; + + const estimatedWorstEffectiveMicroWH = + batteryMilliAh * batVolt * worstLithiumIonDischargeEfficiency * 1000; + + const highestTotalUsage = totalUsage * (1 + measurementAccuracy); + + const estimatedWorstMinutes = Math.round( + (estimatedWorstEffectiveMicroWH / highestTotalUsage) * 60 + ); + + // Calculate range (+-) of minutes using average - worst + const estimatedRange = estimatedAvgMinutes - estimatedWorstMinutes; + + return ( +
    +

    + {splitType !== "standalone" ? splitType + ": " : " "} + {formatMinutes(estimatedAvgMinutes, 2, true)} (± + {formatMinutes(estimatedRange, 1, false).trim()}) +

    +
    + {powerUsage.map((p, i) => ( +
    1 ? " rightSection" : "") + } + style={{ + width: (p.usage / totalUsage) * 100 + "%", + background: palette[i], + }} + > +
    +
    +
    + {p.title} - {Math.round((p.usage / totalUsage) * 100)}% +
    +
    + ~{formatUsage(p.usage)} estimated avg. consumption +
    +
    +
    +
    + ))} +
    +
    + ); +} + +PowerEstimate.propTypes = { + board: PropTypes.Object, + splitType: PropTypes.string, + batteryMilliAh: PropTypes.number, + usage: PropTypes.Object, + underglow: PropTypes.Object, + backlight: PropTypes.Object, + display: PropTypes.Object, +}; + +export default PowerEstimate; diff --git a/docs/src/css/codes.css b/docs/src/css/codes.css new file mode 100644 index 000000000000..0e67ca9d0235 --- /dev/null +++ b/docs/src/css/codes.css @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +:root { + --codes-os-fg: black; + --codes-os-windows-bg: #caedfd; + --codes-os-linux-bg: #fff2ca; + --codes-os-android-bg: #d8eed9; + --codes-os-macos-bg: #ececec; + --codes-os-ios-bg: #ffffff; +} + +html[data-theme="dark"] { + --codes-os-fg: #f5f6f7; + --codes-os-windows-bg: #032535; + --codes-os-linux-bg: #332600; + --codes-os-android-bg: #112712; + --codes-os-macos-bg: #121212; + --codes-os-ios-bg: #000000; +} + +.codes.os.legend { + position: sticky; + z-index: 1; + top: var(--ifm-navbar-height); + width: 100%; + padding-top: 0.5em; + padding-bottom: 0.5em; + background: var(--ifm-background-color); + display: flex; + justify-content: space-between; +} + +html[data-theme="light"] .codes.os.legend { + background: white; +} + +.codes.os.legend .os { + flex: 1; + margin-left: 0.2em; + margin-right: 0.2em; + padding: 0.1em; + border: 1px var(--ifm-table-border-color) solid; + border-radius: 0.5em; + text-align: center; +} + +.codes.os.legend .os .heading { + font-weight: bold; +} + +.codes.os.legend .os .heading::after { + content: " : "; + font-weight: normal; +} + +.codes .name { + cursor: copy; +} + +.codes .name:hover { + opacity: 0.8; +} + +.codes .name:active { + color: var(--ifm-font-color-base-inverse); + background: var(--ifm-font-color-base); +} + +.codes.os.legend, +.codes table { + font-size: 0.8em; +} + +.codes table { + display: table; + font-size: 0.8em; + margin-bottom: 0; +} + +.codes th, +.codes td { + padding: 0.2rem; +} + +.codes td { + position: relative; +} + +.codes th.names, +.codes th.description { + text-align: left; +} + +.codes td.names code { + display: block; + float: left; + clear: both; + margin-top: 1px; + margin-bottom: 1px; + font-size: 0.85em; +} + +.codes .context { + display: inline; + margin: 0 0 0 0.5em; + font-size: 0.85em; +} + +.codes .context::before { + content: "("; +} + +.codes .context::after { + content: ")"; +} + +.codes .symbol { + display: inline-flex; + flex-direction: column; +} + +.codes .symbol code { + align-self: flex-start; + width: auto; +} + +.codes .symbol .meaning { + flex: 1; + font-size: 0.8em; + text-transform: uppercase; +} + +.codes td.documentation, +.codes td.os { + width: 0.1%; + min-width: 1.9rem; + text-align: center; +} + +.codes td.documentation { + font-size: 0.8em; +} + +.codes td.documentation a { + cursor: help; +} + +.codes .os { + color: var(--codes-os-fg); +} + +.codes td.os { + font-size: 0.8em; +} + +.codes .not-tested { + font-weight: bold; +} + +.codes .os.windows { + background: var(--codes-os-windows-bg); +} + +.codes .os.linux { + background: var(--codes-os-linux-bg); +} + +.codes .os.android { + background: var(--codes-os-android-bg); +} + +.codes .os.macos { + background: var(--codes-os-macos-bg); +} + +.codes .os.ios { + background: var(--codes-os-ios-bg); +} + +.codes .footnotes { + display: flex; + width: 100%; + margin-top: 0; + margin-bottom: 0.5rem; + padding: 0.2rem 0.5rem 0.2rem 0.5rem; + border: var(--ifm-table-border-width) dashed var(--ifm-table-border-color); + border-top: 0; + font-size: 0.8em; +} + +.codes .footnotes .label { + display: block; + margin-right: 1em; + font-style: italic; +} + +.codes .footnotes .label::after { + content: ":"; +} + +.codes .footnotes .anchor { + display: block; + position: relative; + top: calc(var(--ifm-navbar-height) * -1 - 6em); + visibility: hidden; +} + +.codes .footnote { + flex: 1; + display: flex; + margin-top: 0; + margin-bottom: 0; +} + +.codes .footnote .symbol { + flex: 0; + float: left; + margin-right: 0.4em; + font-size: 0.8em; +} + +.codes .footnote .content p { + margin-top: 0; + margin-bottom: 0; +} + +.codes .footnoteRefs { + float: right; + font-size: 0.8em; +} + +.codes .footnoteRefs a { + color: black; +} diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css new file mode 100644 index 000000000000..d9cddb854bcc --- /dev/null +++ b/docs/src/css/custom.css @@ -0,0 +1,43 @@ +/* stylelint-disable docusaurus/copyright-header */ +/** + * Any CSS included here will be global. The classic template + * bundles Infima by default. Infima is a CSS framework designed to + * work well for content-centric websites. + */ + +/* You can override the default Infima variables here. */ +:root { + --ifm-color-primary: #026fc5; + --ifm-color-primary-dark: #0264b1; + --ifm-color-primary-darker: #025ea7; + --ifm-color-primary-darkest: #014e8a; + --ifm-color-primary-light: #027ad9; + --ifm-color-primary-lighter: #0280e3; + --ifm-color-primary-lightest: #0690fc; + --ifm-code-font-size: 95%; +} + +.docusaurus-highlight-code-line { + background-color: rgb(72, 77, 91); + display: block; + margin: 0 calc(-1 * var(--ifm-pre-padding)); + padding: 0 var(--ifm-pre-padding); +} + +.video-container { + height: 0; + margin: 0; + margin-bottom: 30px; + overflow: hidden; + padding-bottom: 56.25%; + padding-top: 30px; + position: relative; +} + +.video-container iframe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} diff --git a/docs/src/css/power-estimate.css b/docs/src/css/power-estimate.css new file mode 100644 index 000000000000..e876ec28e718 --- /dev/null +++ b/docs/src/css/power-estimate.css @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +.powerEstimate { + margin: 20px 0; +} + +.powerEstimate > h3 > span { + text-transform: capitalize; +} + +.powerEstimateBar { + height: 64px; + width: 100%; + box-shadow: rgba(0, 0, 0, 0.03) 0px 10px 20px 0px, + rgba(0, 0, 0, 0.1) 0px 1px 4px 0px; + border-radius: 64px; + display: flex; + justify-content: flex-start; + overflow: hidden; +} + +.powerEstimateBarSection { + transition: all 0.2s ease; + flex-grow: 1; +} + +.powerEstimateBarSection.rightSection { + display: flex; + justify-content: flex-end; +} + +.powerEstimateTooltipWrap { + position: absolute; + visibility: hidden; + opacity: 0; + transform: translateY(calc(-100% - 8px)); + transition: opacity 0.2s ease; +} + +.powerEstimateBarSection:hover .powerEstimateTooltipWrap { + visibility: visible; + opacity: 1; +} + +.powerEstimateTooltip { + display: block; + position: relative; + box-shadow: var(--ifm-global-shadow-tl); + width: 260px; + padding: 10px; + border-radius: 4px; + background: var(--ifm-background-surface-color); + transform: translateX(-15px); +} + +.rightSection .powerEstimateTooltip { + transform: translateX(15px); +} + +.powerEstimateTooltip:after { + content: ""; + position: absolute; + top: 100%; + left: 27px; + margin-left: -8px; + width: 0; + height: 0; + border-top: 8px solid var(--ifm-background-surface-color); + border-right: 8px solid transparent; + border-left: 8px solid transparent; +} + +.rightSection .powerEstimateTooltip:after { + left: unset; + right: 27px; + margin-right: -8px; +} diff --git a/docs/src/css/power-profiler.css b/docs/src/css/power-profiler.css new file mode 100644 index 000000000000..a0c1892806bd --- /dev/null +++ b/docs/src/css/power-profiler.css @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +.profilerSection { + margin: 10px 0; + padding: 10px 20px; + background: var(--ifm-background-surface-color); + border-radius: 4px; + box-shadow: rgba(0, 0, 0, 0.03) 0px 10px 20px 0px, + rgba(0, 0, 0, 0.1) 0px 1px 4px 0px; +} + +.profilerInput { + margin-bottom: 12px; +} + +.profilerInput label { + display: block; +} + +.profilerDisclaimer { + padding: 20px 0; + font-size: 14px; +} + +span[data-tooltip] { + position: relative; +} + +span[data-tooltip]::before { + content: attr(data-tooltip); + font-size: 13px; + padding: 5px 10px; + position: absolute; + width: 220px; + border-radius: 4px; + background: var(--ifm-background-surface-color); + opacity: 0; + visibility: hidden; + box-shadow: rgba(0, 0, 0, 0.03) 0px 10px 20px 0px, + rgba(0, 0, 0, 0.1) 0px 1px 4px 0px; + transition: opacity 0.2s ease; + transform: translate(-50%, -100%); + left: 50%; +} + +span[data-tooltip]::after { + content: ""; + position: absolute; + border-top: 8px solid var(--ifm-background-surface-color); + border-right: 8px solid transparent; + border-left: 8px solid transparent; + width: 0; + height: 0; + opacity: 0; + visibility: hidden; + transition: opacity 0.2s ease; + transform: translateX(-50%); + left: 50%; +} + +span[data-tooltip]:hover::before { + opacity: 1; + visibility: visible; +} + +span[data-tooltip]:hover::after { + opacity: 1; + visibility: visible; +} + +input[type="checkbox"].toggleInput { + display: none; +} + +input[type="checkbox"] + .toggle { + margin: 6px 2px; + height: 20px; + width: 48px; + background: rgba(0, 0, 0, 0.5); + border-radius: 20px; + transition: all 0.2s ease; + user-select: none; +} + +input[type="checkbox"] + .toggle > .toggleThumb { + height: 16px; + border-radius: 20px; + transform: translate(2px, 2px); + width: 16px; + background: var(--ifm-color-white); + box-shadow: var(--ifm-global-shadow-lw); + transition: all 0.2s ease; +} + +input[type="checkbox"]:checked + .toggle { + background: var(--ifm-color-primary); +} + +input[type="checkbox"]:checked + .toggle > .toggleThumb { + transform: translate(30px, 2px); +} + +select { + border: solid 1px rgba(0, 0, 0, 0.5); + border-radius: 4px; + display: flex; + height: 34px; + width: 200px; + + background: inherit; + color: inherit; + font-size: inherit; + line-height: inherit; + margin: 0; + padding: 3px 5px; + outline: none; +} + +select > option { + background: var(--ifm-background-surface-color); +} + +.inputBox { + border: solid 1px rgba(0, 0, 0, 0.5); + border-radius: 4px; + display: flex; + width: 200px; +} + +.inputBox > input { + background: inherit; + color: inherit; + font-size: inherit; + line-height: inherit; + margin: 0; + padding: 3px 10px; + border: none; + width: 100%; + min-width: 0; + text-align: right; + outline: none; +} + +.inputBox > span { + background: rgba(0, 0, 0, 0.05); + border-left: solid 1px rgba(0, 0, 0, 0.5); + padding: 3px 10px; +} + +/* Chrome, Safari, Edge, Opera */ +.inputBox > input::-webkit-outer-spin-button, +.inputBox > input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +/* Firefox */ +.inputBox > input[type="number"] { + -moz-appearance: textfield; +} + +.disclaimerHolder { + position: absolute; + width: 100vw; + height: 100vh; + top: 0; + left: 0; + z-index: 99; + background: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; +} + +.disclaimer { + padding: 20px 20px; + background: var(--ifm-background-surface-color); + border-radius: 4px; + box-shadow: rgba(0, 0, 0, 0.03) 0px 10px 20px 0px, + rgba(0, 0, 0, 0.1) 0px 1px 4px 0px; + width: 500px; +} + +.disclaimer > button { + border: none; + background: var(--ifm-color-primary); + color: var(--ifm-color-white); + cursor: pointer; + border-radius: 4px; + padding: 5px 15px; +} diff --git a/docs/src/data/.gitignore b/docs/src/data/.gitignore new file mode 100644 index 000000000000..201a309813b3 --- /dev/null +++ b/docs/src/data/.gitignore @@ -0,0 +1 @@ +hardware-metadata.json diff --git a/docs/src/data/footnotes.js b/docs/src/data/footnotes.js new file mode 100644 index 000000000000..ab7f27243e89 --- /dev/null +++ b/docs/src/data/footnotes.js @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import example from "@site/docs/codes/_footnotes/example.mdx"; +import iosApplication from "@site/docs/codes/_footnotes/ios-application.mdx"; +import iosPower from "@site/docs/codes/_footnotes/ios-power.mdx"; +import macosPower from "@site/docs/codes/_footnotes/macos-power.mdx"; +import globe from "@site/docs/codes/_footnotes/globe.mdx"; + +export default { + example, + iosApplication, + iosPower, + macosPower, + globe, +}; diff --git a/docs/src/data/groups.js b/docs/src/data/groups.js new file mode 100644 index 000000000000..5a8dc3cfe754 --- /dev/null +++ b/docs/src/data/groups.js @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +export default { + "application-controls": [ + "K_MENU", + "C_AC_PROPERTIES", + "K_SELECT", + "C_AC_CANCEL", + "K_EXECUTE", + "C_AC_REFRESH", + "K_REFRESH", + "C_AC_STOP", + "K_STOP", + "C_AC_FORWARD", + "K_FORWARD", + "C_AC_BACK", + "K_BACK", + "C_AC_HOME", + "C_AC_BOOKMARKS", + "C_AC_NEW", + "C_AC_OPEN", + "C_AC_SAVE", + "C_AC_CLOSE", + "C_AC_EXIT", + "C_AC_PRINT", + "C_AC_FIND", + "K_FIND", + "K_FIND2", + "C_AC_SEARCH", + "C_AC_GOTO", + "C_AC_ZOOM", + "C_AC_ZOOM_IN", + "C_AC_ZOOM_OUT", + "C_AC_SCROLL_UP", + "K_SCROLL_UP", + "C_AC_SCROLL_DOWN", + "K_SCROLL_DOWN", + "C_AC_REPLY", + "C_AC_FORWARD_MAIL", + "C_AC_SEND", + "C_AC_EDIT", + "C_AC_INSERT", + "C_AC_DEL", + "C_AC_VIEW_TOGGLE", + "C_AC_DESKTOP_SHOW_ALL_WINDOWS", + "C_AC_DESKTOP_SHOW_ALL_APPLICATIONS", + "C_VOICE_COMMAND", + "C_AC_NEXT_KEYBOARD_LAYOUT_SELECT", + ], + applications: [ + "C_AL_NEXT_TASK", + "C_AL_PREVIOUS_TASK", + "C_AL_SELECT_TASK", + "C_AL_MY_COMPUTER", + "C_AL_DOCUMENTS", + "C_AL_FILE_BROWSER", + "C_AL_WWW", + "K_WWW", + "C_AL_EMAIL", + "C_AL_INSTANT_MESSAGING", + "C_AL_NETWORK_CHAT", + "C_AL_CONTACTS", + "C_AL_CALENDAR", + "C_AL_IMAGE_BROWSER", + "C_AL_AUDIO_BROWSER", + "C_AL_MOVIE_BROWSER", + "C_AL_TEXT_EDITOR", + "C_AL_WORD", + "C_AL_SPREADSHEET", + "C_AL_PRESENTATION", + "C_AL_GRAPHICS_EDITOR", + "C_AL_CALCULATOR", + "K_CALCULATOR", + "C_AL_NEWS", + "C_AL_DATABASE", + "C_AL_VOICEMAIL", + "C_AL_FINANCE", + "C_AL_TASK_MANAGER", + "C_AL_JOURNAL", + "C_AL_AV_CAPTURE_PLAYBACK", + "C_AL_SPELLCHECK", + "C_AL_SCREEN_SAVER", + "C_AL_KEYBOARD_LAYOUT", + "C_AL_CONTROL_PANEL", + "C_AL_HELP", + "K_HELP", + "C_AL_OEM_FEATURES", + "C_AL_CCC", + ], + "consumer-controls": [ + "C_CHANNEL_INC", + "C_CHANNEL_DEC", + "C_RECALL_LAST", + "C_MEDIA_VCR_PLUS", + "C_MEDIA_GUIDE", + "C_MEDIA_STEP", + "C_MEDIA_HOME", + "C_MEDIA_TV", + "C_MEDIA_CABLE", + "C_MEDIA_TUNER", + "C_MEDIA_DVD", + "C_MEDIA_CD", + "C_MEDIA_SATELLITE", + "C_MEDIA_VCR", + "C_MEDIA_TAPE", + "C_MEDIA_COMPUTER", + "C_MEDIA_WWW", + "C_MEDIA_GAMES", + "C_MEDIA_PHONE", + "C_MEDIA_VIDEOPHONE", + "C_MEDIA_MESSAGES", + "C_QUIT", + "C_HELP", + ], + "consumer-menus": [ + "C_MENU", + "C_MENU_PICK", + "C_MENU_UP", + "C_MENU_DOWN", + "C_MENU_LEFT", + "C_MENU_RIGHT", + "C_MENU_ESCAPE", + "C_MENU_INCREASE", + "C_MENU_DECREASE", + "C_RED_BUTTON", + "C_GREEN_BUTTON", + "C_BLUE_BUTTON", + "C_YELLOW_BUTTON", + ], + "cut-copy-paste": [ + "C_AC_CUT", + "K_CUT", + "C_AC_COPY", + "K_COPY", + "C_AC_PASTE", + "K_PASTE", + ], + display: [ + "C_BRIGHTNESS_INC", + "C_BRIGHTNESS_DEC", + "C_BRIGHTNESS_MINIMUM", + "C_BRIGHTNESS_MAXIMUM", + "C_BRIGHTNESS_AUTO", + "C_BACKLIGHT_TOGGLE", + "C_ASPECT", + "C_PIP", + ], + "input-assist": [ + "C_KEYBOARD_INPUT_ASSIST_NEXT", + "C_KEYBOARD_INPUT_ASSIST_PREVIOUS", + "C_KEYBOARD_INPUT_ASSIST_NEXT_GROUP", + "C_KEYBOARD_INPUT_ASSIST_PREVIOUS_GROUP", + "C_KEYBOARD_INPUT_ASSIST_ACCEPT", + "C_KEYBOARD_INPUT_ASSIST_CANCEL", + ], + "keyboard-control-whitespace": [ + "ESCAPE", + "RETURN", + "RETURN2", + "SPACE", + "TAB", + "BACKSPACE", + "DELETE", + "INSERT", + ], + "keyboard-fkeys": [ + "F1", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + "F8", + "F9", + "F10", + "F11", + "F12", + "F13", + "F14", + "F15", + "F16", + "F17", + "F18", + "F19", + "F20", + "F21", + "F22", + "F23", + "F24", + ], + "keyboard-international": [ + "INTERNATIONAL_1", + "INTERNATIONAL_2", + "INTERNATIONAL_3", + "INTERNATIONAL_4", + "INTERNATIONAL_5", + "INTERNATIONAL_6", + "INTERNATIONAL_7", + "INTERNATIONAL_8", + "INTERNATIONAL_9", + ], + "keyboard-language": [ + "LANGUAGE_1", + "LANGUAGE_2", + "LANGUAGE_3", + "LANGUAGE_4", + "LANGUAGE_5", + "LANGUAGE_6", + "LANGUAGE_7", + "LANGUAGE_8", + "LANGUAGE_9", + ], + "keyboard-letters": [ + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + ], + "keyboard-locks": [ + "CAPSLOCK", + "LOCKING_CAPS", + "SCROLLLOCK", + "LOCKING_SCROLL", + "LOCKING_NUM", + ], + "keyboard-miscellaneous": [ + "PRINTSCREEN", + "PAUSE_BREAK", + "ALT_ERASE", + "SYSREQ", + "K_CANCEL", + "CLEAR", + "CLEAR_AGAIN", + "CRSEL", + "PRIOR", + "SEPARATOR", + "OUT", + "OPER", + "EXSEL", + "K_EDIT", + ], + "keyboard-modifiers": [ + "LEFT_SHIFT", + "RIGHT_SHIFT", + "LEFT_CONTROL", + "RIGHT_CONTROL", + "LEFT_ALT", + "RIGHT_ALT", + "LEFT_GUI", + "RIGHT_GUI", + ], + "keyboard-navigation": [ + "HOME", + "END", + "PAGE_UP", + "PAGE_DOWN", + "UP_ARROW", + "DOWN_ARROW", + "LEFT_ARROW", + "RIGHT_ARROW", + "K_APPLICATION", + ], + "keyboard-numbers": [ + "NUMBER_1", + "NUMBER_2", + "NUMBER_3", + "NUMBER_4", + "NUMBER_5", + "NUMBER_6", + "NUMBER_7", + "NUMBER_8", + "NUMBER_9", + "NUMBER_0", + ], + "keyboard-symbols": [ + "EXCLAMATION", + "AT_SIGN", + "HASH", + "DOLLAR", + "PERCENT", + "CARET", + "AMPERSAND", + "ASTERISK", + "LEFT_PARENTHESIS", + "RIGHT_PARENTHESIS", + "EQUAL", + "PLUS", + "MINUS", + "UNDERSCORE", + "SLASH", + "QUESTION", + "BACKSLASH", + "PIPE", + "NON_US_BACKSLASH", + "PIPE2", + "SEMICOLON", + "COLON", + "SINGLE_QUOTE", + "DOUBLE_QUOTES", + "COMMA", + "LESS_THAN", + "PERIOD", + "GREATER_THAN", + "LEFT_BRACKET", + "LEFT_BRACE", + "RIGHT_BRACKET", + "RIGHT_BRACE", + "GRAVE", + "TILDE", + "NON_US_HASH", + "TILDE2", + ], + keypad: ["KP_NUMLOCK", "KP_CLEAR", "CLEAR2", "KP_ENTER"], + "keypad-numbers": [ + "KP_NUMBER_1", + "KP_NUMBER_2", + "KP_NUMBER_3", + "KP_NUMBER_4", + "KP_NUMBER_5", + "KP_NUMBER_6", + "KP_NUMBER_7", + "KP_NUMBER_8", + "KP_NUMBER_9", + "KP_NUMBER_0", + ], + "keypad-operations": [ + "KP_PLUS", + "KP_MINUS", + "KP_MULTIPLY", + "KP_DIVIDE", + "KP_EQUAL", + "KP_EQUAL_AS400", + "KP_DOT", + "KP_COMMA", + "KP_LEFT_PARENTHESIS", + "KP_RIGHT_PARENTHESIS", + ], + "media-controls": [ + "C_RECORD", + "C_PLAY", + "C_PLAY_PAUSE", + "K_PLAY_PAUSE", + "C_PAUSE", + "C_STOP", + "K_STOP2", + "K_STOP3", + "C_STOP_EJECT", + "C_EJECT", + "K_EJECT", + "C_NEXT", + "K_NEXT", + "C_PREVIOUS", + "K_PREVIOUS", + "C_FAST_FORWARD", + "C_REWIND", + "C_SLOW", + "C_SLOW_TRACKING", + "C_REPEAT", + "C_RANDOM_PLAY", + "C_CAPTIONS", + "C_DATA_ON_SCREEN", + "C_SNAPSHOT", + ], + power: [ + "C_POWER", + "K_POWER", + "C_RESET", + "C_SLEEP", + "K_SLEEP", + "C_SLEEP_MODE", + "C_AL_LOGOFF", + "C_AL_LOCK", + "K_LOCK", + ], + sound: [ + "C_VOLUME_UP", + "K_VOLUME_UP", + "K_VOLUME_UP2", + "C_VOLUME_DOWN", + "K_VOLUME_DOWN", + "K_VOLUME_DOWN2", + "C_MUTE", + "K_MUTE", + "K_MUTE2", + "C_ALTERNATE_AUDIO_INCREMENT", + "C_BASS_BOOST", + ], + "undo-redo": ["C_AC_UNDO", "K_UNDO", "C_AC_REDO", "K_AGAIN"], +}; diff --git a/docs/src/data/hid-applications.js b/docs/src/data/hid-applications.js new file mode 100644 index 000000000000..7cb7eda4838e --- /dev/null +++ b/docs/src/data/hid-applications.js @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import usage from "../hid-usage"; +import * as pages from "./hid-usage-pages"; + +export const keyboard = usage(pages.genericDesktop, 0x06); +export const consumer = usage(pages.consumer, 0x01); diff --git a/docs/src/data/hid-usage-pages.js b/docs/src/data/hid-usage-pages.js new file mode 100644 index 000000000000..ae11bc3b48c3 --- /dev/null +++ b/docs/src/data/hid-usage-pages.js @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +export const genericDesktop = 0x01; +export const key = 0x07; +export const consumer = 0x0c; diff --git a/docs/src/data/hid.js b/docs/src/data/hid.js new file mode 100644 index 000000000000..96697beebb63 --- /dev/null +++ b/docs/src/data/hid.js @@ -0,0 +1,7891 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import { + keyboard as keyboardApplication, + consumer as consumerApplication, +} from "./hid-applications"; + +import { key as keyPage, consumer as consumerPage } from "./hid-usage-pages"; + +import usage from "../hid-usage"; + +export default [ + { + names: ["A"], + description: "a and A", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x04), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["B"], + description: "b and B", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x05), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["C"], + description: "c and C", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x06), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["D"], + description: "d and D", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x07), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["E"], + description: "e and E", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x08), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F"], + description: "f and F", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x09), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["G"], + description: "g and G", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x0a), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["H"], + description: "h and H", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x0b), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["I"], + description: "i and I", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x0c), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["J"], + description: "j and J", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x0d), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["K"], + description: "k and K", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x0e), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["L"], + description: "l and L", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x0f), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["M"], + description: "m and M", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x10), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["N"], + description: "n and N", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x11), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["O"], + description: "o and O", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x12), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["P"], + description: "p and P", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x13), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["Q"], + description: "q and Q", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x14), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["R"], + description: "r and R", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x15), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["S"], + description: "s and S", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x16), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["T"], + description: "t and T", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x17), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["U"], + description: "u and U", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x18), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=83", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["V"], + description: "v and V", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x19), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["W"], + description: "w and W", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x1a), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["X"], + description: "x and X", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x1b), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["Y"], + description: "y and Y", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x1c), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["Z"], + description: "z and Z", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x1d), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["NUMBER_1", "N1"], + description: "1 and ! [Exclamation]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x1e), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["EXCLAMATION", "EXCL"], + description: "! [Exclamation]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x1e), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["NUMBER_2", "N2"], + description: "2 and @ [At Sign]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x1f), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["AT_SIGN", "AT"], + description: "@ [At Sign]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x1f), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["NUMBER_3", "N3"], + description: "3 and # [Hash / Pound]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x20), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["HASH", "POUND"], + description: "# [Hash / Pound]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x20), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["NUMBER_4", "N4"], + description: "4 and $ [Dollar]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x21), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["DOLLAR", "DLLR"], + description: "$ [Dollar]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x21), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["NUMBER_5", "N5"], + description: "5 and % [Percent]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x22), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["PERCENT", "PRCNT"], + description: "% [Percent]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x22), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["NUMBER_6", "N6"], + description: "6 and ^ [Caret]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x23), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["CARET"], + description: "^ [Caret]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x23), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["NUMBER_7", "N7"], + description: "7 and & [Ampersand]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x24), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["AMPERSAND", "AMPS"], + description: "& [Ampersand]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x24), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["NUMBER_8", "N8"], + description: "8 and * [Asterisk / Star]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x25), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["ASTERISK", "ASTRK", "STAR"], + description: "* [Asterisk / Star]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x25), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["NUMBER_9", "N9"], + description: "9 and ( [Left Parenthesis]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x26), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["LEFT_PARENTHESIS", "LPAR"], + description: "( [Left Parenthesis]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x26), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["NUMBER_0", "N0"], + description: "0 and ) [Right Parenthesis]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x27), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["RIGHT_PARENTHESIS", "RPAR"], + description: ") [Right Parenthesis]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x27), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["RETURN", "ENTER", "RET"], + description: "Return (Enter)", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x28), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["ESCAPE", "ESC"], + description: "Escape", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x29), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["BACKSPACE", "BSPC"], + description: "Backspace", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x2a), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["TAB"], + description: "Tab", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x2b), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["SPACE"], + description: "Space", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x2c), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["MINUS"], + description: "- [Minus] and _ [Underscore]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x2d), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["UNDERSCORE", "UNDER"], + description: "_ [Underscore]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x2d), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["EQUAL"], + description: "= [Equal] and + [Plus]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x2e), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["PLUS"], + description: "+ [Plus]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x2e), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["LEFT_BRACKET", "LBKT"], + description: "[ [Left Bracket] and { [Left Brace]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x2f), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["LEFT_BRACE", "LBRC"], + description: "{ [Left Brace]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x2f), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["RIGHT_BRACKET", "RBKT"], + description: "] [Right Bracket] and } [Right Brace]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x30), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["RIGHT_BRACE", "RBRC"], + description: "} [Right Brace]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x30), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["BACKSLASH", "BSLH"], + description: "\\ [Backslash] and | [Pipe]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x31), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["PIPE"], + description: "| [Pipe]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x31), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["NON_US_HASH", "NUHS"], + description: "Non-US # [Hash/Pound] and ~ [Tilde]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x32), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["TILDE2"], + description: "~ [Tilde]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x32), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["SEMICOLON", "SEMI"], + description: "; [Semicolon] and : [Colon]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x33), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["COLON"], + description: ": [Colon]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x33), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["SINGLE_QUOTE", "SQT", "APOSTROPHE", "APOS"], + description: "' [Apostrophe] and \" [Quote (Double)]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x34), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["DOUBLE_QUOTES", "DQT"], + description: '" [Quote (Double)]', + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x34), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["GRAVE"], + description: "` [Grave Accent] and ~ [Tilde]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x35), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["TILDE"], + description: "~ [Tilde]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x35), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["COMMA"], + description: ", [Comma] and < [Less Than]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x36), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["LESS_THAN", "LT"], + description: "< [Less Than]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x36), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["PERIOD", "DOT"], + description: ". [Period] and > [Greater Than]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x37), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["GREATER_THAN", "GT"], + description: "> [Greater Than]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x37), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["SLASH", "FSLH"], + description: "/ [Forward Slash] and ? [Question Mark]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x38), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["QUESTION", "QMARK"], + description: "? [Question Mark]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x38), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["CAPSLOCK", "CAPS", "CLCK"], + description: "Caps Lock", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x39), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F1"], + description: "F1", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x3a), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F2"], + description: "F2", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x3b), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F3"], + description: "F3", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x3c), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F4"], + description: "F4", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x3d), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=84", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F5"], + description: "F5", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x3e), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F6"], + description: "F6", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x3f), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F7"], + description: "F7", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x40), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F8"], + description: "F8", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x41), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F9"], + description: "F9", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x42), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F10"], + description: "F10", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x43), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F11"], + description: "F11", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x44), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F12"], + description: "F12", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x45), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["PRINTSCREEN", "PSCRN"], + description: "Print Screen", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x46), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["SCROLLLOCK", "SLCK"], + description: "Scroll Lock", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x47), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["PAUSE_BREAK"], + description: "Pause / Break", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x48), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["INSERT", "INS"], + description: "Insert", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x49), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["HOME"], + description: "Home", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x4a), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["PAGE_UP", "PG_UP"], + description: "Page Up", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x4b), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["DELETE", "DEL"], + description: "Delete", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x4c), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["END"], + description: "End", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x4d), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["PAGE_DOWN", "PG_DN"], + description: "Page Down", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x4e), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["RIGHT_ARROW", "RIGHT"], + description: "⮕ [Right Arrow]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x4f), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["LEFT_ARROW", "LEFT"], + description: "⬅ [Left Arrow]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x50), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["DOWN_ARROW", "DOWN"], + description: "⬇ [Down Arrow]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x51), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["UP_ARROW", "UP"], + description: "⬆ [Up Arrow]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x52), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["KP_NUMLOCK", "KP_NUM", "KP_NLCK"], + description: "Numlock and Clear", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x53), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["CLEAR2"], + description: "Clear", + context: "Keypad", + clarify: null, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x53), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["KP_DIVIDE", "KP_SLASH"], + description: "/ [Divide]", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x54), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["KP_MULTIPLY", "KP_ASTERISK"], + description: "* [Multiply]", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x55), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["KP_MINUS", "KP_SUBTRACT"], + description: "- [Minus]", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x56), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["KP_PLUS"], + description: "+ [Plus]", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x57), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["KP_ENTER"], + description: "Enter", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x58), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["KP_NUMBER_1", "KP_N1"], + description: "1", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x59), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["KP_NUMBER_2", "KP_N2"], + description: "2", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x5a), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["KP_NUMBER_3", "KP_N3"], + description: "3", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x5b), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["KP_NUMBER_4", "KP_N4"], + description: "4", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x5c), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["KP_NUMBER_5", "KP_N5"], + description: "5", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x5d), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["KP_NUMBER_6", "KP_N6"], + description: "6", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x5e), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["KP_NUMBER_7", "KP_N7"], + description: "7", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x5f), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["KP_NUMBER_8", "KP_N8"], + description: "8", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x60), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["KP_NUMBER_9", "KP_N9"], + description: "9", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x61), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["KP_NUMBER_0", "KP_N0"], + description: "0", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x62), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=85", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["KP_DOT"], + description: ". [Dot]", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x63), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["NON_US_BACKSLASH", "NON_US_BSLH", "NUBS"], + description: "Non-US \\ [Backslash] and | [Pipe]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x64), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["PIPE2"], + description: "| [Pipe]", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x64), + }, + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["K_APPLICATION", "K_APP", "K_CONTEXT_MENU", "K_CMENU"], + description: "Application (Context Menu)", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x65), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: { + ios: ["iosApplication"], + }, + }, + { + names: ["K_POWER", "K_PWR"], + description: "Power", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x66), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: null, + linux: false, + android: true, + macos: true, + ios: true, + }, + footnotes: { + macos: ["macosPower"], + ios: ["iosPower"], + }, + }, + { + names: ["KP_EQUAL"], + description: "= [Equal]", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x67), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: false, + linux: true, + android: true, + macos: null, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F13"], + description: "F13", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x68), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: true, + linux: true, + android: false, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F14"], + description: "F14", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x69), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: true, + linux: true, + android: false, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F15"], + description: "F15", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x6a), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: true, + linux: true, + android: false, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F16"], + description: "F16", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x6b), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: true, + linux: true, + android: false, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F17"], + description: "F17", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x6c), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: true, + linux: true, + android: false, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F18"], + description: "F18", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x6d), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: true, + linux: true, + android: false, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F19"], + description: "F19", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x6e), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: true, + linux: true, + android: false, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F20"], + description: "F20", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x6f), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: true, + linux: true, + android: false, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F21"], + description: "F21", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x70), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: true, + linux: true, + android: false, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F22"], + description: "F22", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x71), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: true, + linux: true, + android: false, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F23"], + description: "F23", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x72), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: true, + linux: true, + android: false, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["F24"], + description: "F24", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x73), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: true, + linux: true, + android: false, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["K_EXECUTE", "K_EXEC"], + description: "Execute", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x74), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["K_HELP"], + description: "Help", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x75), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["K_MENU"], + description: "Menu", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x76), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["K_SELECT"], + description: "Select", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x77), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["K_STOP"], + description: "Stop", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x78), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["K_AGAIN", "K_REDO"], + description: "Again", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x79), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["K_UNDO"], + description: "Undo", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x7a), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["K_CUT"], + description: "Cut", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x7b), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["K_COPY"], + description: "Copy", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x7c), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["K_PASTE"], + description: "Paste", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x7d), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["K_FIND"], + description: "Find", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x7e), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["K_MUTE"], + description: "Mute", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x7f), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: false, + linux: true, + android: true, + macos: true, + ios: null, + }, + footnotes: {}, + }, + { + names: ["K_VOLUME_UP", "K_VOL_UP"], + description: "Volume Up", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x80), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: false, + linux: true, + android: true, + macos: false, + ios: null, + }, + footnotes: {}, + }, + { + names: ["K_VOLUME_DOWN", "K_VOL_DN"], + description: "Volume Down", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x81), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: false, + linux: true, + android: true, + macos: false, + ios: null, + }, + footnotes: {}, + }, + { + names: ["LOCKING_CAPS", "LCAPS"], + description: "Locking Caps Lock", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x82), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: false, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["LOCKING_NUM", "LNLCK"], + description: "Locking Num Lock", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x83), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: null, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["LOCKING_SCROLL", "LSLCK"], + description: "Locking Scroll Lock", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x84), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: true, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["KP_COMMA"], + description: ", [Comma]", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x85), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: false, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["KP_EQUAL_AS400"], + description: "= [Equal] (AS/400 keyboards)", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x86), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: false, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["INTERNATIONAL_1", "INT1", "INT_RO"], + description: "ろ (International 1)", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x87), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["INTERNATIONAL_2", "INT2", "INT_KATAKANAHIRAGANA", "INT_KANA"], + description: "かな (International 2)", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x88), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["INTERNATIONAL_3", "INT3", "INT_YEN"], + description: "¥ (International 3)", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x89), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["INTERNATIONAL_4", "INT4", "INT_HENKAN"], + description: "変換 (International 4)", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x8a), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=86", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["INTERNATIONAL_5", "INT5", "INT_MUHENKAN"], + description: "無変換 (International 5)", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x8b), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["INTERNATIONAL_6", "INT6", "INT_KPJPCOMMA"], + description: ", [カンマ] (International 6)", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x8c), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["INTERNATIONAL_7", "INT7"], + description: "International 7", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x8d), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: null, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["INTERNATIONAL_8", "INT8"], + description: "International 8", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x8e), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: null, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["INTERNATIONAL_9", "INT9"], + description: "International 9", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x8f), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: null, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["LANGUAGE_1", "LANG1", "LANG_HANGEUL"], + description: "한/영 (Language 1)", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x90), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: true, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["LANGUAGE_2", "LANG2", "LANG_HANJA"], + description: "한자 (Language 2)", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x91), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: true, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["LANGUAGE_3", "LANG3", "LANG_KATAKANA"], + description: "カタカナ (Language 3)", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x92), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["LANGUAGE_4", "LANG4", "LANG_HIRAGANA"], + description: "ひらがな (Language 4)", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x93), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["LANGUAGE_5", "LANG5", "LANG_ZENKAKUHANKAKU"], + description: "半角/全角 (Language 5)", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x94), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["LANGUAGE_6", "LANG6"], + description: "Language 6", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x95), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: null, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["LANGUAGE_7", "LANG7"], + description: "Language 7", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x96), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: null, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["LANGUAGE_8", "LANG8"], + description: "Language 8", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x97), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: null, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["LANGUAGE_9", "LANG9"], + description: "Language 9", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x98), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: null, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["ALT_ERASE"], + description: "Alternate Erase", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x99), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: null, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["SYSREQ", "ATTENTION"], + description: "SysReq / Attention", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x9a), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: null, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["K_CANCEL"], + description: "Cancel", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x9b), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: null, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["CLEAR"], + description: "Clear", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x9c), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["PRIOR"], + description: "Prior", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x9d), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: null, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["RETURN2", "RET2"], + description: "Return", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x9e), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: false, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["SEPARATOR"], + description: "Separator", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0x9f), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: null, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["OUT"], + description: "Out", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xa0), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: null, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["OPER"], + description: "Oper", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xa1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: null, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["CLEAR_AGAIN"], + description: "Clear / Again", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xa2), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: null, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["CRSEL"], + description: "CrSel / Props", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xa3), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: null, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["EXSEL"], + description: "ExSel", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xa4), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: null, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["KP_LEFT_PARENTHESIS", "KP_LPAR"], + description: "( [Left Parenthesis]", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xb6), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: false, + linux: true, + android: true, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["KP_RIGHT_PARENTHESIS", "KP_RPAR"], + description: ") [Right Parenthesis]", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xb7), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=87", + os: { + windows: false, + linux: true, + android: true, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["KP_CLEAR"], + description: "Clear", + context: "Keypad", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xd8), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=88", + os: { + windows: null, + linux: true, + android: false, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["LEFT_CONTROL", "LCTRL", "LC(code)"], + description: "Left Control", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xe0), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=88", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["LEFT_SHIFT", "LSHIFT", "LSHFT", "LS(code)"], + description: "Left Shift ⇧", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xe1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=88", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["LEFT_ALT", "LALT", "LA(code)"], + description: "Left Alt", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xe2), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=88", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: [ + "LEFT_GUI", + "LGUI", + "LG(code)", + "LEFT_WIN", + "LWIN", + "LEFT_COMMAND", + "LCMD", + "LEFT_META", + "LMETA", + ], + description: "Left GUI (Windows / Command / Meta)", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xe3), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=88", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["RIGHT_CONTROL", "RCTRL", "RC(code)"], + description: "Right Control", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xe4), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=88", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["RIGHT_SHIFT", "RSHIFT", "RSHFT", "RS(code)"], + description: "Right Shift ⇧", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xe5), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=89", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["RIGHT_ALT", "RALT", "RA(code)"], + description: "Right Alt", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xe6), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=89", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: [ + "RIGHT_GUI", + "RGUI", + "RG(code)", + "RIGHT_WIN", + "RWIN", + "RIGHT_COMMAND", + "RCMD", + "RIGHT_META", + "RMETA", + ], + description: "Right GUI (Windows / Command / Meta)", + context: "Keyboard", + clarify: false, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xe7), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=89", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: true, + }, + footnotes: {}, + }, + { + names: ["K_PLAY_PAUSE", "K_PP"], + description: "Play / Pause", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xe8), + }, + ], + documentation: + "https://source.android.com/devices/input/keyboard-devices#hid-keyboard-and-keypad-page-0x07", + os: { + windows: false, + linux: true, + android: true, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["K_STOP2"], + description: "Stop", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xe9), + }, + ], + documentation: + "https://source.android.com/devices/input/keyboard-devices#hid-keyboard-and-keypad-page-0x07", + os: { + windows: false, + linux: true, + android: true, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["K_PREVIOUS", "K_PREV"], + description: "Previous", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xea), + }, + ], + documentation: + "https://source.android.com/devices/input/keyboard-devices#hid-keyboard-and-keypad-page-0x07", + os: { + windows: false, + linux: true, + android: true, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["K_NEXT"], + description: "Next", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xeb), + }, + ], + documentation: + "https://source.android.com/devices/input/keyboard-devices#hid-keyboard-and-keypad-page-0x07", + os: { + windows: false, + linux: true, + android: true, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["K_EJECT"], + description: "Eject", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xec), + }, + ], + documentation: + "https://source.android.com/devices/input/keyboard-devices#hid-keyboard-and-keypad-page-0x07", + os: { + windows: null, + linux: true, + android: true, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["K_VOLUME_UP2", "K_VOL_UP2"], + description: "Volume Up", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xed), + }, + ], + documentation: + "https://source.android.com/devices/input/keyboard-devices#hid-keyboard-and-keypad-page-0x07", + os: { + windows: false, + linux: true, + android: true, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["K_VOLUME_DOWN2", "K_VOL_DN2"], + description: "Volume Down", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xee), + }, + ], + documentation: + "https://source.android.com/devices/input/keyboard-devices#hid-keyboard-and-keypad-page-0x07", + os: { + windows: false, + linux: true, + android: true, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["K_MUTE2"], + description: "Mute", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xef), + }, + ], + documentation: + "https://source.android.com/devices/input/keyboard-devices#hid-keyboard-and-keypad-page-0x07", + os: { + windows: false, + linux: true, + android: true, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["K_WWW"], + description: "Internet Browser", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xf0), + }, + ], + documentation: + "https://source.android.com/devices/input/keyboard-devices#hid-keyboard-and-keypad-page-0x07", + os: { + windows: null, + linux: true, + android: true, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["K_BACK"], + description: "Back", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xf1), + }, + ], + documentation: + "https://source.android.com/devices/input/keyboard-devices#hid-keyboard-and-keypad-page-0x07", + os: { + windows: null, + linux: true, + android: true, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["K_FORWARD"], + description: "Forward", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xf2), + }, + ], + documentation: + "https://source.android.com/devices/input/keyboard-devices#hid-keyboard-and-keypad-page-0x07", + os: { + windows: null, + linux: true, + android: true, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["K_STOP3"], + description: "Stop", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xf3), + }, + ], + documentation: + "https://source.android.com/devices/input/keyboard-devices#hid-keyboard-and-keypad-page-0x07", + os: { + windows: false, + linux: true, + android: true, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["K_FIND2"], + description: "Find", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xf4), + }, + ], + documentation: + "https://source.android.com/devices/input/keyboard-devices#hid-keyboard-and-keypad-page-0x07", + os: { + windows: null, + linux: true, + android: false, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["K_SCROLL_UP"], + description: "Scroll Up", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xf5), + }, + ], + documentation: + "https://source.android.com/devices/input/keyboard-devices#hid-keyboard-and-keypad-page-0x07", + os: { + windows: null, + linux: true, + android: true, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["K_SCROLL_DOWN"], + description: "Scroll Down", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xf6), + }, + ], + documentation: + "https://source.android.com/devices/input/keyboard-devices#hid-keyboard-and-keypad-page-0x07", + os: { + windows: null, + linux: true, + android: true, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["K_EDIT"], + description: "Edit", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xf7), + }, + ], + documentation: + "https://source.android.com/devices/input/keyboard-devices#hid-keyboard-and-keypad-page-0x07", + os: { + windows: null, + linux: true, + android: false, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["K_SLEEP"], + description: "Sleep", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xf8), + }, + ], + documentation: + "https://source.android.com/devices/input/keyboard-devices#hid-keyboard-and-keypad-page-0x07", + os: { + windows: null, + linux: true, + android: false, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["K_LOCK", "K_SCREENSAVER", "K_COFFEE"], + description: "Lock", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xf9), + }, + ], + documentation: + "https://source.android.com/devices/input/keyboard-devices#hid-keyboard-and-keypad-page-0x07", + os: { + windows: null, + linux: true, + android: true, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["K_REFRESH"], + description: "Refresh", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xfa), + }, + ], + documentation: + "https://source.android.com/devices/input/keyboard-devices#hid-keyboard-and-keypad-page-0x07", + os: { + windows: null, + linux: true, + android: false, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["K_CALCULATOR", "K_CALC"], + description: "Calculator", + context: "Keyboard", + clarify: true, + usages: [ + { + application: keyboardApplication, + item: usage(keyPage, 0xfb), + }, + ], + documentation: + "https://source.android.com/devices/input/keyboard-devices#hid-keyboard-and-keypad-page-0x07", + os: { + windows: null, + linux: true, + android: true, + macos: false, + ios: false, + }, + footnotes: {}, + }, + { + names: ["C_POWER", "C_PWR"], + description: "Power", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x30), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=132", + os: { + windows: null, + linux: true, + android: false, + macos: true, + ios: true, + }, + footnotes: { + macos: ["macosPower"], + ios: ["iosPower"], + }, + }, + { + names: ["C_RESET"], + description: "Reset", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x31), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=132", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_SLEEP"], + description: "Sleep", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x32), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=132", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_SLEEP_MODE"], + description: "Sleep Mode", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x34), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=132", + os: { + windows: null, + linux: false, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MENU"], + description: "Menu", + context: "Consumer Menu", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x40), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=133", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MENU_PICK", "C_MENU_SELECT"], + description: "Pick", + context: "Consumer Menu", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x41), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=133", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MENU_UP"], + description: "Up", + context: "Consumer Menu", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x42), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=133", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MENU_DOWN"], + description: "Down", + context: "Consumer Menu", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x43), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=133", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MENU_LEFT"], + description: "Left", + context: "Consumer Menu", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x44), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=133", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MENU_RIGHT"], + description: "Right", + context: "Consumer Menu", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x45), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=133", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MENU_ESCAPE", "C_MENU_ESC"], + description: "Escape", + context: "Consumer Menu", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x46), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=133", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MENU_INCREASE", "C_MENU_INC"], + description: "Value Increase", + context: "Consumer Menu", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x47), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=133", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MENU_DECREASE", "C_MENU_DEC"], + description: "Value Decrease", + context: "Consumer Menu", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x48), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=133", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_DATA_ON_SCREEN"], + description: "Data On Screen", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x60), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=134", + os: { + windows: null, + linux: true, + android: null, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_CAPTIONS", "C_SUBTITLES"], + description: "Closed Caption", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x61), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=134", + os: { + windows: false, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_SNAPSHOT"], + description: "Snapshot", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x65), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=134", + os: { + windows: false, + linux: true, + android: null, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_PIP"], + description: "Picture-in-Picture Toggle", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x67), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=134", + os: { + windows: false, + linux: false, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_RED_BUTTON", "C_RED"], + description: "Red Button", + context: "Consumer Menu", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x69), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=133", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_GREEN_BUTTON", "C_GREEN"], + description: "Green Button", + context: "Consumer Menu", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x6a), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=133", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_BLUE_BUTTON", "C_BLUE"], + description: "Blue Button", + context: "Consumer Menu", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x6b), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=133", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_YELLOW_BUTTON", "C_YELLOW"], + description: "Yellow Button", + context: "Consumer Menu", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x6c), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=133", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_ASPECT"], + description: "Aspect", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x6d), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=134", + os: { + windows: false, + linux: true, + android: null, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_BRIGHTNESS_INC", "C_BRI_INC", "C_BRI_UP"], + description: "Increase Brightness", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x6f), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=134", + os: { + windows: true, + linux: true, + android: null, + macos: true, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_BRIGHTNESS_DEC", "C_BRI_DEC", "C_BRI_DN"], + description: "Decrease Brightness", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x70), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=134", + os: { + windows: true, + linux: true, + android: null, + macos: true, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_BACKLIGHT_TOGGLE", "C_BKLT_TOG"], + description: "Backlight Toggle", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x72), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=134", + os: { + windows: false, + linux: true, + android: null, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_BRIGHTNESS_MINIMUM", "C_BRI_MIN"], + description: "Minimum Brightness", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x73), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=134", + os: { + windows: false, + linux: true, + android: null, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_BRIGHTNESS_MAXIMUM", "C_BRI_MAX"], + description: "Maximum Brightness", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x74), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=134", + os: { + windows: false, + linux: true, + android: null, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_BRIGHTNESS_AUTO", "C_BRI_AUTO"], + description: "Auto Brightness", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x75), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=134", + os: { + windows: false, + linux: true, + android: null, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MEDIA_STEP", "C_MODE_STEP"], + description: "Mode Step", + context: "Consumer Media", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x82), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=135", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_RECALL_LAST", "C_CHAN_LAST"], + description: "Recall Last", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x83), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=135", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MEDIA_COMPUTER"], + description: "Computer", + context: "Consumer Media", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x88), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=135", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MEDIA_TV"], + description: "TV", + context: "Consumer Media", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x89), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=135", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MEDIA_WWW"], + description: "WWW", + context: "Consumer Media", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x8a), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=135", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MEDIA_DVD"], + description: "DVD", + context: "Consumer Media", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x8b), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=135", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MEDIA_PHONE"], + description: "Telephone", + context: "Consumer Media", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x8c), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=135", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MEDIA_GUIDE"], + description: "Program Guide", + context: "Consumer Media", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x8d), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=135", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MEDIA_VIDEOPHONE"], + description: "Video Phone", + context: "Consumer Media", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x8e), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=135", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MEDIA_GAMES"], + description: "Games", + context: "Consumer Media", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x8f), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=135", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MEDIA_MESSAGES"], + description: "Messages", + context: "Consumer Media", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x90), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=135", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MEDIA_CD"], + description: "CD", + context: "Consumer Media", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x91), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=135", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MEDIA_VCR"], + description: "VCR", + context: "Consumer Media", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x92), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=135", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MEDIA_TUNER"], + description: "Tuner", + context: "Consumer Media", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x93), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=135", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_QUIT"], + description: "Quit", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x94), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=135", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_HELP"], + description: "Help", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x95), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=135", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MEDIA_TAPE"], + description: "Tape", + context: "Consumer Media", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x96), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=135", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MEDIA_CABLE"], + description: "Cable", + context: "Consumer Media", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x97), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=135", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MEDIA_SATELLITE"], + description: "Satellite", + context: "Consumer Media", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x98), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=135", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MEDIA_HOME"], + description: "Home", + context: "Consumer Media", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x9a), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=136", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_CHANNEL_INC", "C_CHAN_INC"], + description: "Channel Increment", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x9c), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=136", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_CHANNEL_DEC", "C_CHAN_DEC"], + description: "Channel Decrement", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x9d), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=136", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MEDIA_VCR_PLUS"], + description: "VCR Plus", + context: "Consumer Media", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xa0), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=135", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_PLAY"], + description: "Play", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xb0), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=137", + os: { + windows: true, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_PAUSE"], + description: "Pause", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xb1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=137", + os: { + windows: true, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_RECORD", "C_REC"], + description: "Record", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xb2), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=137", + os: { + windows: false, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_FAST_FORWARD", "C_FF"], + description: "Fast Forward", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xb3), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=137", + os: { + windows: true, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_REWIND", "C_RW"], + description: "Rewind", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xb4), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=137", + os: { + windows: true, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_NEXT"], + description: "Next", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xb5), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=137", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_PREVIOUS", "C_PREV"], + description: "Previous", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xb6), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=137", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_STOP"], + description: "Stop", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xb7), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=137", + os: { + windows: false, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_EJECT"], + description: "Eject", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xb8), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=137", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_RANDOM_PLAY", "C_SHUFFLE"], + description: "Random Play", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xb9), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=137", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_REPEAT"], + description: "Repeat", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xbc), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=137", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_SLOW_TRACKING", "C_SLOW2"], + description: "Slow Tracking", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xbf), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=137", + os: { + windows: false, + linux: true, + android: null, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_STOP_EJECT"], + description: "Stop / Eject", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xcc), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=137", + os: { + windows: null, + linux: false, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_PLAY_PAUSE", "C_PP"], + description: "Play / Pause", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xcd), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=137", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_VOICE_COMMAND"], + description: "Voice Command", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xcf), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=132", + os: { + windows: null, + linux: true, + android: null, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_MUTE"], + description: "Mute", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xe2), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=139", + os: { + windows: true, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_BASS_BOOST"], + description: "Bass Boost", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xe5), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=139", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_VOLUME_UP", "C_VOL_UP"], + description: "Volume Up", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xe9), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=139", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_VOLUME_DOWN", "C_VOL_DN"], + description: "Volume Down", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xea), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=139", + os: { + windows: true, + linux: true, + android: true, + macos: true, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_SLOW"], + description: "Slow", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0xf5), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=141", + os: { + windows: false, + linux: true, + android: null, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_ALTERNATE_AUDIO_INCREMENT", "C_ALT_AUDIO_INC"], + description: "Alternate Audio Increment", + context: "Consumer", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x173), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf", + os: { + windows: null, + linux: false, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_CCC"], + description: "Consumer Control Configuration", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x183), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=147", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_WORD"], + description: "Word Processor", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x184), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=147", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_TEXT_EDITOR"], + description: "Text Editor", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x185), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=147", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_SPREADSHEET", "C_AL_SHEET"], + description: "Spreadsheet", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x186), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=147", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_GRAPHICS_EDITOR"], + description: "Graphics Editor", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x187), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=147", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_PRESENTATION"], + description: "Presentation", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x188), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=147", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_DATABASE", "C_AL_DB"], + description: "Database App", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x189), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=147", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_EMAIL", "C_AL_MAIL"], + description: "Email Reader", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x18a), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=147", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_NEWS"], + description: "Newsreader", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x18b), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=147", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_VOICEMAIL"], + description: "Voicemail", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x18c), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=147", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_CONTACTS", "C_AL_ADDRESS_BOOK"], + description: "Contacts / Address Book", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x18d), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=147", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_CALENDAR", "C_AL_CAL"], + description: "Calendar / Schedule", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x18e), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=147", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_TASK_MANAGER"], + description: "Task / Project Manager", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x18f), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=147", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_JOURNAL"], + description: "Log / Journal / Timecard", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x190), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=147", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_FINANCE"], + description: "Checkbook / Finance", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x191), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=147", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_CALCULATOR", "C_AL_CALC"], + description: "Calculator", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x192), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=147", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_AV_CAPTURE_PLAYBACK"], + description: "A/V Capture / Playback", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x193), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=147", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_MY_COMPUTER"], + description: "Local Machine Browser", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x194), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=147", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_WWW"], + description: "Internet Browser", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x196), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=147", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_NETWORK_CHAT", "C_AL_CHAT"], + description: "Network Chat", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x199), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=148", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_LOGOFF"], + description: "Logoff", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x19c), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=148", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_LOCK", "C_AL_SCREENSAVER", "C_AL_COFFEE"], + description: "Terminal Lock / Screensaver", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x19e), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=148", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_CONTROL_PANEL"], + description: "Control Panel", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x19f), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=148", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_SELECT_TASK"], + description: "Select Task / Application", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x1a2), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=148", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_NEXT_TASK"], + description: "Next Task / Application", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x1a3), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=148", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_PREVIOUS_TASK", "C_AL_PREV_TASK"], + description: "Previous Task / Application", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x1a4), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=148", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_HELP"], + description: "Integrated Help Center", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x1a6), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=148", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_DOCUMENTS", "C_AL_DOCS"], + description: "Documents", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x1a7), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=148", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_SPELLCHECK", "C_AL_SPELL"], + description: "Spell Check", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x1ab), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=148", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_KEYBOARD_LAYOUT"], + description: "Keyboard Layout", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x1ae), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=148", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_SCREEN_SAVER"], + description: "Screen Saver", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x1b1), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=148", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_FILE_BROWSER", "C_AL_FILES"], + description: "File Browser", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x1b4), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=148", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_IMAGE_BROWSER", "C_AL_IMAGES"], + description: "Image Browser", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x1b6), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=148", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_AUDIO_BROWSER", "C_AL_AUDIO", "C_AL_MUSIC"], + description: "Audio Browser", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x1b7), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=148", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_MOVIE_BROWSER", "C_AL_MOVIES"], + description: "Movie Browser", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x1b8), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=148", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_INSTANT_MESSAGING", "C_AL_IM"], + description: "Instant Messaging", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x1bc), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=149", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AL_OEM_FEATURES", "C_AL_TIPS", "C_AL_TUTORIAL"], + description: "OEM Features / Tips / Tutorial Browser", + context: "Consumer AL", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x1bd), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=149", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_NEW"], + description: "New", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x201), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_OPEN"], + description: "Open", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x202), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_CLOSE"], + description: "Close", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x203), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_EXIT"], + description: "Exit", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x204), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_SAVE"], + description: "Save", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x207), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_PRINT"], + description: "Print", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x208), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_PROPERTIES", "C_AC_PROPS"], + description: "Properties", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x209), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_UNDO"], + description: "Undo", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x21a), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_COPY"], + description: "Copy", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x21b), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_CUT"], + description: "Cut", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x21c), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_PASTE"], + description: "Paste", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x21d), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_FIND"], + description: "Find", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x21f), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_SEARCH"], + description: "Search", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x221), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: null, + linux: true, + android: true, + macos: true, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_GOTO"], + description: "Go To", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x222), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_HOME"], + description: "Home", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x223), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_BACK"], + description: "Back", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x224), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_FORWARD"], + description: "Forward", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x225), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_STOP"], + description: "Stop", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x226), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_REFRESH"], + description: "Refresh", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x227), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_BOOKMARKS", "C_AC_FAVORITES", "C_AC_FAVOURITES"], + description: "Bookmarks", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x22a), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_ZOOM_IN"], + description: "Zoom In", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x22d), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_ZOOM_OUT"], + description: "Zoom Out", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x22e), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_ZOOM"], + description: "Zoom", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x22f), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=150", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_VIEW_TOGGLE"], + description: "View Toggle", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x232), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=151", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_SCROLL_UP"], + description: "Scroll Up", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x233), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=151", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_SCROLL_DOWN"], + description: "Scroll Down", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x234), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=151", + os: { + windows: null, + linux: true, + android: true, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_EDIT"], + description: "Edit", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x23d), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=151", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_CANCEL"], + description: "Cancel", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x25f), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=152", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_INSERT", "C_AC_INS"], + description: "Insert Mode", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x269), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=152", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_DEL"], + description: "Delete", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x26a), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=152", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_REDO"], + description: "Redo / Repeat", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x279), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=152", + os: { + windows: false, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_REPLY"], + description: "Reply", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x289), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=153", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_FORWARD_MAIL"], + description: "Forward", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x28b), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=153", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_SEND"], + description: "Send", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x28c), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=153", + os: { + windows: null, + linux: true, + android: false, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_DESKTOP_SHOW_ALL_WINDOWS"], + description: "Desktop Show All Windows", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x29f), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=153", + os: { + windows: null, + linux: true, + android: null, + macos: true, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_DESKTOP_SHOW_ALL_APPLICATIONS"], + description: "Desktop Show All Applications", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x2a2), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=153", + os: { + windows: null, + linux: true, + android: null, + macos: true, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_KEYBOARD_INPUT_ASSIST_PREVIOUS", "C_KBIA_PREV"], + description: "Previous", + context: "Consumer KBIA", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x2c7), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=157", + os: { + windows: null, + linux: true, + android: null, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_KEYBOARD_INPUT_ASSIST_NEXT", "C_KBIA_NEXT"], + description: "Next", + context: "Consumer KBIA", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x2c8), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=157", + os: { + windows: null, + linux: true, + android: null, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_KEYBOARD_INPUT_ASSIST_PREVIOUS_GROUP", "C_KBIA_PREV_GRP"], + description: "Previous Group", + context: "Consumer KBIA", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x2c9), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=157", + os: { + windows: null, + linux: true, + android: null, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_KEYBOARD_INPUT_ASSIST_NEXT_GROUP", "C_KBIA_NEXT_GRP"], + description: "Next Group", + context: "Consumer KBIA", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x2ca), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=157", + os: { + windows: null, + linux: true, + android: null, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_KEYBOARD_INPUT_ASSIST_ACCEPT", "C_KBIA_ACCEPT"], + description: "Accept", + context: "Consumer KBIA", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x2cb), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=157", + os: { + windows: null, + linux: true, + android: null, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_KEYBOARD_INPUT_ASSIST_CANCEL", "C_KBIA_CANCEL"], + description: "Cancel", + context: "Consumer KBIA", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x2cc), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=157", + os: { + windows: null, + linux: true, + android: null, + macos: null, + ios: null, + }, + footnotes: {}, + }, + { + names: ["C_AC_NEXT_KEYBOARD_LAYOUT_SELECT", "GLOBE"], + description: "AC Next Keyboard Layout Select (Apple Globe)", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x29d), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=153", + os: { + windows: null, + linux: null, + android: null, + macos: true, + ios: true, + }, + footnotes: { + macos: ["globe"], + }, + }, +]; diff --git a/docs/src/data/interconnects/.gitignore b/docs/src/data/interconnects/.gitignore new file mode 100644 index 000000000000..0a00d70141f2 --- /dev/null +++ b/docs/src/data/interconnects/.gitignore @@ -0,0 +1 @@ +*/ \ No newline at end of file diff --git a/docs/src/data/keymap-upgrade.js b/docs/src/data/keymap-upgrade.js new file mode 100644 index 000000000000..8e1538281ff5 --- /dev/null +++ b/docs/src/data/keymap-upgrade.js @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +export const Codes = { + NUM_1: "N1", + NUM_2: "N2", + NUM_3: "N3", + NUM_4: "N4", + NUM_5: "N5", + NUM_6: "N6", + NUM_7: "N7", + NUM_8: "N8", + NUM_9: "N9", + NUM_0: "N0", + BKSP: "BSPC", + SPC: "SPACE", + EQL: "EQUAL", + TILD: "TILDE", + SCLN: "SEMI", + QUOT: "SQT", + GRAV: "GRAVE", + CMMA: "COMMA", + PRSC: "PSCRN", + SCLK: "SLCK", + PAUS: "PAUSE_BREAK", + PGUP: "PG_UP", + PGDN: "PG_DN", + RARW: "RIGHT", + LARW: "LEFT", + DARW: "DOWN", + UARW: "UP", + KDIV: "KP_DIVIDE", + KMLT: "KP_MULTIPLY", + KMIN: "KP_MINUS", + KPLS: "KP_PLUS", + UNDO: "K_UNDO", + CUT: "K_CUT", + COPY: "K_COPY", + PSTE: "K_PASTE", + VOLU: "K_VOL_UP", + VOLD: "K_VOL_DN", + CURU: "DLLR", + LPRN: "LPAR", + RPRN: "RPAR", + LCUR: "LBRC", + RCUR: "RBRC", + CRRT: "CARET", + PRCT: "PRCNT", + LABT: "LT", + RABT: "GT", + COLN: "COLON", + KSPC: null, + ATSN: "AT", + BANG: "EXCL", + LCTL: "LCTRL", + LSFT: "LSHIFT", + RCTL: "RCTRL", + RSFT: "RSHIFT", + M_NEXT: "C_NEXT", + M_PREV: "C_PREV", + M_STOP: "C_STOP", + M_EJCT: "C_EJECT", + M_PLAY: "C_PP", + M_MUTE: "C_MUTE", + M_VOLU: "C_VOL_UP", + M_VOLD: "C_VOL_DN", + GUI: "K_CMENU", + MOD_LCTL: "LCTRL", + MOD_LSFT: "LSHIFT", + MOD_LALT: "LALT", + MOD_LGUI: "LGUI", + MOD_RCTL: "RCTRL", + MOD_RSFT: "RSHIFT", + MOD_RALT: "RALT", + MOD_RGUI: "RGUI", +}; + +export const Behaviors = { + cp: "kp", + inc_dec_cp: "inc_dec_kp", + reset: "sys_reset", +}; diff --git a/docs/src/data/operating-systems.js b/docs/src/data/operating-systems.js new file mode 100644 index 000000000000..0631766de556 --- /dev/null +++ b/docs/src/data/operating-systems.js @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +export default [ + { + key: "windows", + className: "windows", + heading: "W", + title: "Windows", + }, + { + key: "linux", + className: "linux", + heading: "L", + title: "Linux", + }, + { + key: "android", + className: "android", + heading: "A", + title: "Android", + }, + { + key: "macos", + className: "macos", + heading: "m", + title: "macOS", + }, + { + key: "ios", + className: "ios", + heading: "i", + title: "iOS", + }, +]; diff --git a/docs/src/data/power.js b/docs/src/data/power.js new file mode 100644 index 000000000000..354f0511eea5 --- /dev/null +++ b/docs/src/data/power.js @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/** + * This file holds all current measurements related to ZMK features and hardware + * All current measurements are in micro amps. Measurements were taken on a Nordic Power Profiler Kit + * The test device to get these values was three nice!nanos (nRF52840). + */ + +export const zmkBase = { + hostConnection: 23, // How much current it takes to have an idle host connection + standalone: { + idle: 0, // No extra idle current + typing: 315, // Current while holding down a key. Represents polling+BLE notification power + }, + central: { + idle: 490, // Idle current for connection to right half + typing: 380, // Current while holding down a key. Represents polling+BLE notification power + }, + peripheral: { + idle: 20, // Idle current for connection to left half + typing: 365, // Current while holding down a key. Represents polling+BLE notification power + }, +}; + +/** + * ZMK board power measurements + * + * Power supply can be an LDO or switching + * Quiescent and other quiescent are measured in micro amps + * + * Switching efficiency represents the efficiency of converting from + * 3.8V (average li-ion voltage) to the output voltage of the power supply + */ +export const zmkBoards = { + "nice!nano": { + name: "nice!nano v1", + powerSupply: { + type: "LDO", + outputVoltage: 3.3, + quiescentMicroA: 55, + }, + otherQuiescentMicroA: 4, + }, + "nice!nano v2": { + name: "nice!nano v2", + powerSupply: { + type: "LDO", + outputVoltage: 3.3, + quiescentMicroA: 15, + }, + otherQuiescentMicroA: 3, + }, + "nice!60": { + powerSupply: { + type: "SWITCHING", + outputVoltage: 3.3, + efficiency: 0.95, + quiescentMicroA: 4, + }, + otherQuiescentMicroA: 4, + }, +}; + +export const underglowPower = { + firmware: 60, // ZMK power usage while underglow feature is turned on (SPIM mostly) + ledOn: 20000, // Estimated power consumption of a WS2812B at 100% (can be anywhere from 10mA to 30mA) + ledOff: 460, // Quiescent current of a WS2812B +}; + +export const backlightLEDs = { + White: 3.2, + Blue: 3.0, + Green: 2.2, + Yellow: 2.1, + Red: 1.8, +}; + +export const backlightPower = { + pwmPower: 510, // Estimated power consumption of PWM module +}; + +export const displayPower = { + // Based on GoodDisplay's 1.02in epaper + EPAPER: { + activePercent: 0.05, // Estimated one refresh per minute taking three seconds + active: 1500, // Power draw during refresh + sleep: 5, // Idle power draw of an epaper + }, + // 128x32 SSD1306 + OLED: { + activePercent: 0.5, // Estimated sleeping half the time (based on idle) + active: 10000, // Estimated power draw when about half the pixels are on + sleep: 7, // Deep sleep power draw (display off) + }, + // Based on the nice!view using Sharp's LS011B7DH01 + NICEVIEW: { + activePercent: 0.01, // Estimated two refreshes per second taking five milliseconds each + active: 1425, // Power draw during refresh (225uA display + 1200uA SPIM) + sleep: 1, // Idle power draw of the display + }, +}; diff --git a/docs/src/docusaurus-tree-sitter-plugin/index.js b/docs/src/docusaurus-tree-sitter-plugin/index.js new file mode 100644 index 000000000000..a6952ce7c544 --- /dev/null +++ b/docs/src/docusaurus-tree-sitter-plugin/index.js @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +module.exports = function () { + return { + configureWebpack(config, isServer) { + let rules = []; + + // Tree-sitter is only used for client-side code. + // Don't try to load it on the server. + if (isServer) { + rules.push({ + test: /web-tree-sitter/, + loader: "null-loader", + }); + } + + return { + // web-tree-sitter tries to import "fs", which can be ignored. + // https://github.com/tree-sitter/tree-sitter/issues/466 + resolve: { + fallback: { + fs: false, + path: false, + }, + }, + module: { rules }, + }; + }, + }; +}; diff --git a/docs/src/footnotes.js b/docs/src/footnotes.js new file mode 100644 index 000000000000..c6fdbaa77849 --- /dev/null +++ b/docs/src/footnotes.js @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import footnotes from "./data/footnotes"; + +export function getFootnote(id) { + const footnote = footnotes[id]; + if (typeof footnote != "undefined") { + return footnote; + } +} diff --git a/docs/src/groups.js b/docs/src/groups.js new file mode 100644 index 000000000000..a5ea294f8221 --- /dev/null +++ b/docs/src/groups.js @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import groups from "./data/groups.js"; + +export function getGroup(id) { + return groups[id] ?? null; +} diff --git a/docs/src/hardware-metadata-collection-plugin/index.js b/docs/src/hardware-metadata-collection-plugin/index.js new file mode 100644 index 000000000000..f118c0baf5c9 --- /dev/null +++ b/docs/src/hardware-metadata-collection-plugin/index.js @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +var PrebuildPlugin = require("prebuild-webpack-plugin"); +const fs = require("fs"); +const yaml = require("js-yaml"); +const glob = require("glob"); + +function generateHardwareMetadataAggregate() { + glob("../app/boards/**/*.zmk.yml", (error, files) => { + const aggregated = files.flatMap((f) => + yaml.loadAll(fs.readFileSync(f, "utf8")) + ); + + aggregated + .filter((agg) => agg.type === "interconnect") + .forEach((agg) => { + let baseDir = `src/data/interconnects/${agg.id}`; + if (!fs.existsSync(baseDir)) { + fs.mkdirSync(baseDir); + } + + if (agg.design_guideline) { + fs.writeFileSync( + `${baseDir}/design_guideline.md`, + agg.design_guideline + ); + } + }); + fs.writeFileSync( + "src/data/hardware-metadata.json", + JSON.stringify(aggregated) + ); + }); +} + +module.exports = function () { + return { + name: "hardware-metadata-collection-plugin", + configureWebpack() { + return { + plugins: [ + new PrebuildPlugin({ + build: generateHardwareMetadataAggregate, + }), + ], + }; + }, + }; +}; diff --git a/docs/src/hardware-metadata-static-plugin/index.js b/docs/src/hardware-metadata-static-plugin/index.js new file mode 100644 index 000000000000..7fb6ad83ffd3 --- /dev/null +++ b/docs/src/hardware-metadata-static-plugin/index.js @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +//@ts-check +"use strict"; + +/** @typedef {import('../hardware-metadata').HardwareMetadata} HardwareMetadata */ +/** @typedef {HardwareMetadata & { directory: string}} LocatedHardwareMetadata */ + +const fs = require("fs").promises; +const glob = require("util").promisify(require("glob")); +const path = require("path"); +const yaml = require("js-yaml"); + +const BASE_DIR = ".."; +const METADATA_GLOB = path.posix.join(BASE_DIR, "app/boards/**/*.zmk.yml"); + +/** + * @param {string} file + */ +async function readMetadata(file) { + /** @type HardwareMetadata[] */ + // @ts-ignore + const documents = yaml.loadAll(await fs.readFile(file, "utf-8")); + + return documents.map( + (metadata) => + /** @type LocatedHardwareMetadata */ + ({ + ...metadata, + // External tools need a way to locate this hardware within the repo. + // Append each item's relative path. + directory: path.posix.dirname(path.posix.relative(BASE_DIR, file)), + }) + ); +} + +async function aggregateMetadata() { + const files = await glob(METADATA_GLOB); + const data = await Promise.all(files.map(readMetadata)); + + return data.flat(); +} + +/** + * Aggregates .zmk.yml files and writes hardware-metadata.json to the site's + * static files post-build. + * + * This is very similar to hardware-metadata-collection-plugin but adjusts the + * output for consumption by external tools rather than the website build system. + * + * @type {import('@docusaurus/types').PluginModule} + */ +module.exports = function () { + return { + name: "hardware-metadata-static-plugin", + + async postBuild({ outDir }) { + const hardware = await aggregateMetadata(); + + const hardwarePath = path.join(outDir, "hardware-metadata.json"); + await fs.writeFile(hardwarePath, JSON.stringify(hardware)); + }, + }; +}; diff --git a/docs/src/hardware-schema-typescript-plugin/index.js b/docs/src/hardware-schema-typescript-plugin/index.js new file mode 100644 index 000000000000..728d501dc06e --- /dev/null +++ b/docs/src/hardware-schema-typescript-plugin/index.js @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +var PrebuildPlugin = require("prebuild-webpack-plugin"); +const fs = require("fs"); +const { compileFromFile } = require("json-schema-to-typescript"); + +async function generateHardwareMetadataTypescript() { + const ts = await compileFromFile("../schema/hardware-metadata.schema.json"); + fs.writeFileSync("src/hardware-metadata.d.ts", ts); +} + +module.exports = function () { + return { + name: "hardware-metadata-typescript-plugin", + configureWebpack() { + return { + plugins: [ + new PrebuildPlugin({ + build: generateHardwareMetadataTypescript, + }), + ], + }; + }, + }; +}; diff --git a/docs/src/hid-usage.js b/docs/src/hid-usage.js new file mode 100644 index 000000000000..d6423589e92f --- /dev/null +++ b/docs/src/hid-usage.js @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +export default function usage(page, id) { + return (page << 16) | id; +} diff --git a/docs/src/hid.js b/docs/src/hid.js new file mode 100644 index 000000000000..583ce7a5356f --- /dev/null +++ b/docs/src/hid.js @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: CC-BY-NC-SA-4.0 + */ + +import codes from "./data/hid"; + +export const map = codes.reduce((map, item) => { + item.names.forEach((name) => (map[name] = item)); + return map; +}, {}); + +export function getCode(id) { + return map[id] ?? null; +} + +export function getCodes(ids) { + return ids.reduce((result, id) => [...result, map[id]], []); +} diff --git a/docs/src/keymap-upgrade.js b/docs/src/keymap-upgrade.js new file mode 100644 index 000000000000..788ab31ab541 --- /dev/null +++ b/docs/src/keymap-upgrade.js @@ -0,0 +1,245 @@ +import Parser from "web-tree-sitter"; + +import { Codes, Behaviors } from "./data/keymap-upgrade"; + +const TREE_SITTER_WASM_URL = new URL( + "/node_modules/web-tree-sitter/tree-sitter.wasm", + import.meta.url +); + +let Devicetree; + +export async function initParser() { + await Parser.init({ + locateFile: (path, prefix) => { + // When locating tree-sitter.wasm, use a path that Webpack can map to the correct URL. + if (path == "tree-sitter.wasm") { + return TREE_SITTER_WASM_URL.href; + } + return prefix + path; + }, + }); + Devicetree = await Parser.Language.load("/tree-sitter-devicetree.wasm"); +} + +function createParser() { + if (!Devicetree) { + throw new Error("Parser not loaded. Call initParser() first."); + } + + const parser = new Parser(); + parser.setLanguage(Devicetree); + return parser; +} + +export function upgradeKeymap(text) { + const parser = createParser(); + const tree = parser.parse(text); + + const edits = [...upgradeBehaviors(tree), ...upgradeKeycodes(tree)]; + + return applyEdits(text, edits); +} + +class TextEdit { + /** + * Creates a text edit to replace a range or node with new text. + * Construct with one of: + * + * * `Edit(startIndex, endIndex, newText)` + * * `Edit(node, newText)` + */ + constructor(startIndex, endIndex, newText) { + if (typeof startIndex !== "number") { + const node = startIndex; + newText = endIndex; + startIndex = node.startIndex; + endIndex = node.endIndex; + } + + /** @type number */ + this.startIndex = startIndex; + /** @type number */ + this.endIndex = endIndex; + /** @type string */ + this.newText = newText; + } +} + +/** + * Upgrades deprecated behavior references. + * @param {Parser.Tree} tree + */ +function upgradeBehaviors(tree) { + /** @type TextEdit[] */ + let edits = []; + + const query = Devicetree.query("(reference label: (identifier) @ref)"); + const matches = query.matches(tree.rootNode); + + for (const { captures } of matches) { + const node = findCapture("ref", captures); + if (node) { + edits.push(...getUpgradeEdits(node, Behaviors)); + } + } + + return edits; +} + +/** + * Upgrades deprecated key code identifiers. + * @param {Parser.Tree} tree + */ +function upgradeKeycodes(tree) { + /** @type TextEdit[] */ + let edits = []; + + // No need to filter to the bindings array. The C preprocessor would have + // replaced identifiers anywhere, so upgrading all identifiers preserves the + // original behavior of the keymap (even if that behavior wasn't intended). + const query = Devicetree.query("(identifier) @name"); + const matches = query.matches(tree.rootNode); + + for (const { captures } of matches) { + const node = findCapture("name", captures); + if (node) { + edits.push(...getUpgradeEdits(node, Codes, keycodeReplaceHandler)); + } + } + + return edits; +} + +/** + * @param {Parser.SyntaxNode} node + * @param {string | null} replacement + * @returns TextEdit[] + */ +function keycodeReplaceHandler(node, replacement) { + if (replacement) { + return [new TextEdit(node, replacement)]; + } + + const nodes = findBehaviorNodes(node); + + if (nodes.length === 0) { + console.warn( + `Found deprecated code "${node.text}" but it is not a parameter to a behavior` + ); + return [new TextEdit(node, `/* "${node.text}" no longer exists */`)]; + } + + const oldText = nodes.map((n) => n.text).join(" "); + const newText = `&none /* "${oldText}" no longer exists */`; + + const startIndex = nodes[0].startIndex; + const endIndex = nodes[nodes.length - 1].endIndex; + + return [new TextEdit(startIndex, endIndex, newText)]; +} + +/** + * Returns the node for the named capture. + * @param {string} name + * @param {any[]} captures + * @returns {Parser.SyntaxNode | null} + */ +function findCapture(name, captures) { + for (const c of captures) { + if (c.name === name) { + return c.node; + } + } + + return null; +} + +/** + * Given a parameter to a keymap behavior, returns a list of nodes beginning + * with the behavior and including all parameters. + * Returns an empty array if no behavior was found. + * @param {Parser.SyntaxNode} paramNode + */ +function findBehaviorNodes(paramNode) { + // Walk backwards from the given parameter to find the behavior reference. + let behavior = paramNode.previousNamedSibling; + while (behavior && behavior.type !== "reference") { + behavior = behavior.previousNamedSibling; + } + + if (!behavior) { + return []; + } + + // Walk forward from the behavior to collect all its parameters. + + let nodes = [behavior]; + let param = behavior.nextNamedSibling; + while (param && param.type !== "reference") { + nodes.push(param); + param = param.nextNamedSibling; + } + + return nodes; +} + +/** + * Gets a list of text edits to apply based on a node and a map of text + * replacements. + * + * If replaceHandler is given, it will be called if the node matches a + * deprecated value and it should return the text edits to apply. + * + * @param {Parser.SyntaxNode} node + * @param {Map} replacementMap + * @param {(node: Parser.SyntaxNode, replacement: string | null) => TextEdit[]} replaceHandler + */ +function getUpgradeEdits(node, replacementMap, replaceHandler = undefined) { + for (const [deprecated, replacement] of Object.entries(replacementMap)) { + if (node.text === deprecated) { + if (replaceHandler) { + return replaceHandler(node, replacement); + } else { + return [new TextEdit(node, replacement)]; + } + } + } + return []; +} + +/** + * Sorts a list of text edits in ascending order by position. + * @param {TextEdit[]} edits + */ +function sortEdits(edits) { + return edits.sort((a, b) => a.startIndex - b.startIndex); +} + +/** + * Returns a string with text replacements applied. + * @param {string} text + * @param {TextEdit[]} edits + */ +function applyEdits(text, edits) { + edits = sortEdits(edits); + + /** @type string[] */ + const chunks = []; + let currentIndex = 0; + + for (const edit of edits) { + if (edit.startIndex < currentIndex) { + console.warn("discarding overlapping edit", edit); + continue; + } + + chunks.push(text.substring(currentIndex, edit.startIndex)); + chunks.push(edit.newText); + currentIndex = edit.endIndex; + } + + chunks.push(text.substring(currentIndex)); + + return chunks.join(""); +} diff --git a/docs/src/pages/index.js b/docs/src/pages/index.js new file mode 100644 index 000000000000..ccaab5086852 --- /dev/null +++ b/docs/src/pages/index.js @@ -0,0 +1,98 @@ +import React from "react"; +import classnames from "classnames"; +import Layout from "@theme/Layout"; +import Link from "@docusaurus/Link"; +import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; +import useBaseUrl from "@docusaurus/useBaseUrl"; +import styles from "./styles.module.css"; +import PropTypes from "prop-types"; + +const features = [ + { + title: <>Powered by Zephyr™, + imageUrl: "img/undraw_zephyr.svg", + description: ( + <> + With a wide range of architecture support, ZMK is ready for many + existing keyboards. + + ), + }, + { + title: <>Permissive Licensing, + imageUrl: "img/undraw_open_source.svg", + description: ( + <>MIT licensed to remove any future limitations in innovation. + ), + }, + { + title: <>Wireless First, + imageUrl: "img/undraw_wireless.svg", + description: <>Designed for the future, including wireless support., + }, +]; + +function Feature({ imageUrl, title, description }) { + const imgUrl = useBaseUrl(imageUrl); + return ( +
    + {imgUrl && ( +
    + {title} +
    + )} +

    {title}

    +

    {description}

    +
    + ); +} + +Feature.propTypes = { + imageUrl: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + description: PropTypes.string.isRequired, +}; + +function Home() { + const context = useDocusaurusContext(); + const { siteConfig = {} } = context; + return ( + +
    +
    +

    {siteConfig.title}

    +

    {siteConfig.tagline}

    +
    + + Get Started + +
    +
    +
    +
    + {features && features.length > 0 && ( +
    +
    +
    + {features.map((props, idx) => ( + + ))} +
    +
    +
    + )} +
    +
    + ); +} + +export default Home; diff --git a/docs/src/pages/power-profiler.js b/docs/src/pages/power-profiler.js new file mode 100644 index 000000000000..d28886efb852 --- /dev/null +++ b/docs/src/pages/power-profiler.js @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +import React, { useState } from "react"; +import classnames from "classnames"; +import Layout from "@theme/Layout"; +import styles from "./styles.module.css"; +import PowerEstimate from "../components/power-estimate"; +import CustomBoardForm from "../components/custom-board-form"; +import { useInput } from "../utils/hooks"; +import { zmkBoards, backlightLEDs } from "../data/power"; +import "../css/power-profiler.css"; + +const Disclaimer = `This profiler makes many assumptions about typing + activity, battery characteristics, hardware behavior, and + doesn't account for error of user inputs. For example battery + mAh, which is often incorrectly advertised higher than it's actual capacity. + While it tries to estimate power usage using real power readings of ZMK, + every person will have different results that may be worse or even + better than the estimation given here.`; + +function PowerProfiler() { + const { value: board, bind: bindBoard } = useInput(""); + const { value: split, bind: bindSplit } = useInput(false); + const { value: batteryMilliAh, bind: bindBatteryMilliAh } = useInput(110); + + const { value: psuType, bind: bindPsuType } = useInput(""); + const { value: outputV, bind: bindOutputV } = useInput(3.3); + const { value: quiescentMicroA, bind: bindQuiescentMicroA } = useInput(55); + const { value: otherQuiescentMicroA, bind: bindOtherQuiescentMicroA } = + useInput(0); + const { value: efficiency, bind: bindEfficiency } = useInput(0.9); + + const { value: bondedQty, bind: bindBondedQty } = useInput(1); + const { value: percentAsleep, bind: bindPercentAsleep } = useInput(0.5); + + const { value: glowEnabled, bind: bindGlowEnabled } = useInput(false); + const { value: glowQuantity, bind: bindGlowQuantity } = useInput(10); + const { value: glowBrightness, bind: bindGlowBrightness } = useInput(1); + + const { value: backlightEnabled, bind: bindBacklightEnabled } = + useInput(false); + const { value: backlightQuantity, bind: bindBacklightQuantity } = + useInput(60); + const { value: backlightColor, bind: bindBacklightColor } = useInput(""); + const { value: backlightVoltage, bind: bindBacklightVoltage } = useInput(2.2); + const { value: backlightResistance, bind: bindBacklightResistance } = + useInput(100); + const { value: backlightBrightness, bind: bindBacklightBrightness } = + useInput(1); + + const { value: displayEnabled, bind: bindDisplayEnabled } = useInput(false); + const { value: displayType, bind: bindDisplayType } = useInput(""); + + const [disclaimerAcknowledged, setDisclaimerAcknowledged] = useState( + typeof window !== "undefined" + ? localStorage.getItem("zmkPowerProfilerDisclaimer") === "true" + : false + ); + + const currentBoard = + board === "custom" + ? { + powerSupply: { + type: psuType, + outputVoltage: outputV, + quiescentMicroA: quiescentMicroA, + efficiency, + }, + otherQuiescentMicroA: otherQuiescentMicroA, + } + : zmkBoards[board]; + + const currentBacklightVoltage = + backlightColor === "custom" + ? backlightVoltage + : backlightLEDs[backlightColor || "White"]; + + return ( + +
    +
    +

    ZMK Power Profiler

    +

    + {"Estimate your keyboard's power usage and battery life on ZMK."} +

    +
    +
    +
    +
    +
    +

    Keyboard Specifications

    +
    +
    +
    + + +
    +
    +
    +
    + + +
    +
    +
    + +
    + + mAh +
    +
    +
    +
    +
    + + {board === "custom" && ( + + )} + +
    +

    Usage Values

    +
    +
    +
    + + + {bondedQty} +
    +
    +
    +
    + + + {Math.round(percentAsleep * 100)}% +
    +
    +
    +
    + +
    +

    Features

    +
    +
    +
    + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    +
    + {split ? ( + <> + + + + ) : ( + + )} +
    +
    + Disclaimer: {Disclaimer} +
    +
    +
    +
    + {!disclaimerAcknowledged && ( +
    +
    +

    Disclaimer

    +

    {Disclaimer}

    + +
    +
    + )} +
    + ); +} + +export default PowerProfiler; diff --git a/docs/src/pages/styles.module.css b/docs/src/pages/styles.module.css new file mode 100644 index 000000000000..9e3ab9999067 --- /dev/null +++ b/docs/src/pages/styles.module.css @@ -0,0 +1,51 @@ +/* stylelint-disable docusaurus/copyright-header */ + +/** + * CSS files with the .module.css suffix will be treated as CSS modules + * and scoped locally. + */ + +.heroBanner { + padding: 4rem 0; + text-align: center; + position: relative; + overflow: hidden; + background: linear-gradient(150deg, #026fc5, #7929d2); + color: #fff; +} + +@media screen and (max-width: 966px) { + .heroBanner { + padding: 2rem; + } +} + +.getStarted { + color: #fff; + border-color: #fff; + border: solid 1px; +} + +.getStarted:hover { + background: #fff; + color: #000; + border-color: #fff; +} + +.buttons { + display: flex; + align-items: center; + justify-content: center; +} + +.features { + display: flex; + align-items: center; + padding: 2rem 0; + width: 100%; +} + +.featureImage { + height: 200px; + width: 200px; +} diff --git a/docs/src/setup-script-generation-plugin/index.js b/docs/src/setup-script-generation-plugin/index.js new file mode 100644 index 000000000000..87e77141a93b --- /dev/null +++ b/docs/src/setup-script-generation-plugin/index.js @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +var PrebuildPlugin = require("prebuild-webpack-plugin"); +const path = require("path"); +const fs = require("fs"); +const glob = require("glob"); +const yaml = require("js-yaml"); +const Mustache = require("mustache"); + +function generateSetupScripts() { + return glob("../app/boards/**/*.zmk.yml", (error, files) => { + const aggregated = files.map((f) => ({ + ...yaml.load(fs.readFileSync(f, "utf8")), + __base_dir: path.basename(path.dirname(f)), + })); + + const data = aggregated.reduce( + (agg, item) => { + switch (item.type) { + case "shield": + item.compatible = true; + item.split = item.siblings?.length > 1; + agg.keyboards.push(item); + break; + case "board": + if (item.features?.includes("keys")) { + agg.keyboards.push(item); + } else { + item.usb_only = !item.outputs?.includes("ble"); + agg.boards.push(item); + } + break; + } + return agg; + }, + { keyboards: [], boards: [] } + ); + + data.keyboards.sort((a, b) => a.name.localeCompare(b.name)); + data.boards.sort((a, b) => a.name.localeCompare(b.name)); + + for (let script_ext of ["sh", "ps1"]) { + const templateBuffer = fs.readFileSync( + `src/templates/setup.${script_ext}.mustache`, + "utf8" + ); + const script = Mustache.render(templateBuffer, data); + fs.writeFileSync(`static/setup.${script_ext}`, script); + } + }); +} + +module.exports = function () { + return { + name: "setup-script-generation-plugin", + configureWebpack() { + return { + plugins: [ + new PrebuildPlugin({ + build: generateSetupScripts, + }), + ], + }; + }, + }; +}; diff --git a/docs/src/templates/setup.ps1.mustache b/docs/src/templates/setup.ps1.mustache new file mode 100644 index 000000000000..90f9cdcfaec5 --- /dev/null +++ b/docs/src/templates/setup.ps1.mustache @@ -0,0 +1,284 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +$ErrorActionPreference = "Stop" + +function Get-Choice-From-Options { + param( + [String[]] $Options, + [String] $Prompt + ) + + while ($true) { + for ($i = 0; $i -lt $Options.length; $i++) { + Write-Host "$($i + 1)) $($Options[$i])" + } + + Write-Host "$($Options.length + 1)) Quit" + $selection = (Read-Host $Prompt) -as [int] + + if ($selection -eq $Options.length + 1) { + Write-Host "Goodbye!" + exit 1 + } + elseif ($selection -le $Options.length -and $selection -gt 0) { + $choice = $($selection - 1) + break + } + else { + Write-Host "Invalid Option. Try another one." + } + } + + return $choice +} + +function Test-Git-Config { + param( + [String] $Option, + [String] $ErrMsg + ) + + git config $Option | Out-Null + + if ($lastExitCode -ne 0) { + Write-Host $ErrMsg + exit 1 + } +} + +try { + git | Out-Null +} +catch [System.Management.Automation.CommandNotFoundException] { + Write-Host "Git is not installed, and is required for this script!" + exit 1 +} + +Test-Git-Config -Option "user.name" -ErrMsg "Git username not set!`nRun: git config --global user.name 'My Name'" +Test-Git-Config -Option "user.email" -ErrMsg "Git email not set!`nRun: git config --global user.email 'example@myemail.com'" + +function Test-CommandExists { + param ($command) + + $oldPreference = $ErrorActionPreference + $ErrorActionPreference = "stop" + + try { + if(Get-Command $command){ return $true } + } Catch { return $false } + Finally { $ErrorActionPreference=$oldPreference } +} + +if (Test-CommandExists Get-Acl) { + $permission = (Get-Acl $pwd).Access | + ?{$_.IdentityReference -match $env:UserName ` + -and $_.FileSystemRights -match "FullControl" ` + -or $_.FileSystemRights -match "Write" } | + Select IdentityReference,FileSystemRights + + If (-Not $permission){ + Write-Host "Sorry, you do not have write permissions in this directory." + Write-Host "Please try running this script again from a directory that you do have write permissions for." + exit 1 + } +} + +$repo_path = "https://github.com/zmkfirmware/unified-zmk-config-template.git" + +$title = "ZMK Config Setup:" +Write-Host "" +Write-Host "Keyboard Shield Selection:" +$prompt = "Pick a keyboard" + +$keyboards = [ordered]@{ + {{#keyboards}} + "{{id}}" = @{ + name = "{{{name}}}"; + type = "{{type}}"; + basedir = "{{__base_dir}}"; + split = "{{split}}"; + arch = "{{arch}}"; + siblings = {{#siblings.0}}@( + {{#siblings}} + "{{.}}" + {{/siblings}} + ){{/siblings.0}}{{^siblings.0}}( "{{id}}" ){{/siblings.0}}; + } + {{/keyboards}} +} +# TODO: Add support for "Other" and linking to docs on adding custom shields in user config repos. + +$choice = Get-Choice-From-Options -Options ($keyboards.values | % { $_['name'] }) -Prompt $prompt +$keyboard = $($($keyboards.keys)[$choice]) +$keyboard_title = $keyboards[$keyboard].name +$basedir = $keyboards[$keyboard].basedir +$keyboard_split = $keyboards[$keyboard].split +$keyboard_arch = $keyboards[$keyboard].arch +$keyboard_siblings = $keyboards[$keyboard].siblings +$keyboard_type = $keyboards[$keyboard].type + +if ($keyboard_type -eq "shield") { + $prompt = "Pick an MCU board" + $boards = [ordered]@{ + {{#boards}} + {{id}} = "{{{name}}}"; + {{/boards}} + } + $boards_usb_only = [ordered]@{ + {{#boards}} + {{id}} = "{{usb_only}}"; + {{/boards}} + } + + Write-Host "$title" + Write-Host "" + Write-Host "MCU Board Selection:" + + $choice = Get-Choice-From-Options -Options $boards.values -Prompt $prompt + + if ($keyboard_split -eq "true" -and $($($boards_usb_only.values)[$choice]) -eq "true") { + Write-Host "Wired split is not yet supported by ZMK." + exit 1 + } + + $shields = $keyboard_siblings + $board = $($($boards.keys)[$choice]) + $boards = ( $board ) +} else { + $boards = ( $keyboard_siblings ) + $shields = @( ) +} + +$copy_keymap = Read-Host "Copy in the stock keymap for customisation? [Yn]" + +if ($copy_keymap -eq "" -or $copy_keymap -eq "Y" -or $copy_keymap -eq "y") { + $copy_keymap = "yes" +} + +$github_user = Read-Host "GitHub Username (leave empty to skip GitHub repo creation)" + +if ($github_user -ne "") { + $repo_name = Read-Host "GitHub Repo Name [zmk-config]" + + if ($repo_name -eq "") { + $repo_name = "zmk-config" + } + + $github_repo = Read-Host "GitHub Repo [https://github.com/$github_user/$repo_name.git]" + + if ($github_repo -eq "") { + $github_repo = "https://github.com/$github_user/$repo_name.git" + } +} +else { + $repo_name = "zmk-config" + $github_repo = "" +} + +Write-Host "" +Write-Host "Preparing a user config for:" +if ($keyboard_type -eq "shield") { + Write-Host "* MCU Board: ${boards}" + Write-Host "* Shield(s): ${shields}" +} else { + Write-Host "* Board(s): ${boards}" +} + +if ($copy_keymap -eq "yes") { + Write-Host "* Copy Keymap?: Yes" +} +else { + Write-Host "* Copy Keymap?: No" +} + +if ($github_repo -ne "") { + Write-Host "* GitHub Repo to Push (please create this in GH first!): $github_repo" +} + +Write-Host "" +$do_it = Read-Host "Continue? [Yn]" + +if ($do_it -ne "" -and $do_it -ne "Y" -and $do_it -ne "y") { + Write-Host "Aborting..." + exit 1 +} + +git clone --single-branch "$repo_path" "$repo_name" +Set-Location "$repo_name" + +Push-Location config + +if ($keyboard_type -eq "shield") { + $url_base = "https://raw.githubusercontent.com/zmkfirmware/zmk/main/app/boards/shields/${basedir}" +} else { + $url_base = "https://raw.githubusercontent.com/zmkfirmware/zmk/main/app/boards/${keyboard_arch}/${basedir}" +} + +Write-Host "Downloading config file (${url_base}/${keyboard}.conf)" +Try { + Invoke-RestMethod -Uri "${url_base}/${keyboard}.conf" -OutFile "${keyboard}.conf" +} Catch { + Try { + Write-Host "Could not find it, falling back to ${url_base}/${basedir}.conf" + Invoke-RestMethod -Uri "${url_base}/${basedir}.conf" -OutFile "${basedir}.conf" + } Catch { + Set-Content -Path "${keyboard}.conf" "# Put configuration options here" + } +} + +if ($copy_keymap -eq "yes") { + Write-Host "Downloading keymap file (${url_base}/${keyboard}.keymap)" + Try { + Invoke-RestMethod -Uri "${url_base}/${keyboard}.keymap" -OutFile "${keyboard}.keymap" + } Catch { + Write-Host "Could not find it, falling back to ${url_base}/${basedir}.keymap" + Try { + Invoke-RestMethod -Uri "${url_base}/${basedir}.keymap" -OutFile "${basedir}.keymap" + } Catch { + Write-Host "Warning: Could not find a keymap file to download!" + } + } +} + +Pop-Location + +Add-Content -Path "build.yaml" -Value "include:" +foreach ($b in ${boards}) { + if ($keyboard_type -eq "shield") { + foreach ($s in ${shields}) { + Add-Content -Path "build.yaml" -Value " - board: $b" + Add-Content -Path "build.yaml" -Value " shield: $s" + } + } else { + Add-Content -Path "build.yaml" -Value " - board: $b" + } +} + +Remove-Item -Recurse -Force .git +git init . +git add . +git commit -m "Initial User Config." + +if ($github_repo -ne "") { + git remote add origin "$github_repo" + + git push --set-upstream origin $(git symbolic-ref --short HEAD) + + # If push failed, assume that the origin was incorrect and give instructions on fixing. + if ($lastExitCode -ne 0) { + Write-Host "Remote repository $github_repo not found..." + Write-Host "Check GitHub URL, and try adding again." + Write-Host "Run the following: " + Write-Host " git remote rm origin" + Write-Host " git remote add origin FIXED_URL" + Write-Host " git push --set-upstream origin $(git symbolic-ref --short HEAD)" + Write-Host "Once pushed, your firmware should be available from GitHub Actions at: $actions" + exit 1 + } + + if ($github_repo -imatch "https") { + $actions = "$($github_repo.substring(0, $github_repo.length - 4))/actions" + Write-Host "Your firmware should be availalbe from GitHub Actions shortly: $actions" + } +} diff --git a/docs/src/templates/setup.sh.mustache b/docs/src/templates/setup.sh.mustache new file mode 100644 index 000000000000..c711dbc5b1c1 --- /dev/null +++ b/docs/src/templates/setup.sh.mustache @@ -0,0 +1,269 @@ +#!/bin/bash + +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +set -e + +check_exists() { + command_to_run=$1 + error_message=$2 + local __resultvar=$3 + + if ! eval "$command_to_run" &> /dev/null; then + if [[ "$__resultvar" != "" ]]; then + eval $__resultvar="'false'" + else + printf "%s\n" "$error_message" + exit 1 + fi + else + if [[ "$__resultvar" != "" ]]; then + eval $__resultvar="'true'" + fi + fi +} + +check_exists "command -v git" "git is not installed, and is required for this script!" +check_exists "command -v curl" "curl is not installed, and is required for this script!" curl_exists +check_exists "command -v wget" "wget is not installed, and is required for this script!" wget_exists + +check_exists "git config user.name" "Git username not set!\nRun: git config --global user.name 'My Name'" +check_exists "git config user.email" "Git email not set!\nRun: git config --global user.email 'example@myemail.com'" + +# Check to see if the user has write permissions in this directory to prevent a cryptic error later on +if [ ! -w `pwd` ]; then + echo 'Sorry, you do not have write permissions in this directory.'; + echo 'Please try running this script again from a directory that you do have write permissions for.'; + exit 1 +fi + +# Parse all commandline options +while [[ "$#" -gt 0 ]]; do + case $1 in + -w|--wget) force_wget="true"; break;; + *) echo "Unknown parameter: $1"; exit 1;; + esac + shift +done + +if [[ $curl_exists == "true" && $wget_exists == "true" ]]; then + if [[ $force_wget == "true" ]]; then + download_command="wget " + else + download_command="curl -fsOL " + fi +elif [[ $curl_exists == "true" ]]; then + download_command="curl -fsOL " +elif [[ $wget_exists == "true" ]]; then + download_command="wget " +else + echo 'Neither curl nor wget are installed. One of the two is required for this script!' + exit 1 +fi + +repo_path="https://github.com/zmkfirmware/unified-zmk-config-template.git" +title="ZMK Config Setup:" + +echo "" +echo "Keyboard Selection:" +PS3="Pick a keyboard: " +options=({{#keyboards}}"{{{name}}}" {{/keyboards}}) +keyboards_id=({{#keyboards}}"{{id}}" {{/keyboards}}) +keyboards_type=({{#keyboards}}"{{type}}" {{/keyboards}}) +keyboards_arch=({{#keyboards}}"{{arch}}" {{/keyboards}}) +keyboards_basedir=({{#keyboards}}"{{__base_dir}}" {{/keyboards}}) +keyboards_split=({{#keyboards}}"{{#split}}y{{/split}}{{^split}}n{{/split}}" {{/keyboards}}) +keyboards_shield=({{#keyboards}}"{{#compatible}}y{{/compatible}}{{^compatible}}n{{/compatible}}" {{/keyboards}}) + +{{#keyboards}} +{{#siblings.0}} +{{id}}_siblings=({{#siblings}}"{{.}}" {{/siblings}}) +{{/siblings.0}} +{{/keyboards}} + +select opt in "${options[@]}" "Quit"; do + case "$REPLY" in + ''|*[!0-9]*) echo "Invalid option. Try another one."; continue;; + + $(( ${#options[@]}+1 )) ) echo "Goodbye!"; exit 1;; + *) + if [ $REPLY -gt $(( ${#options[@]}+1 )) ] || [ $REPLY -lt 0 ]; then + echo "Invalid option. Try another one." + continue + fi + keyboard_index=$(( $REPLY-1 )) + keyboard=${keyboards_id[$keyboard_index]} + keyboard_arch=${keyboards_arch[$keyboard_index]} + keyboard_basedir=${keyboards_basedir[$keyboard_index]} + keyboard_title=${options[$keyboard_index]} + keyboard_sibling_var=${keyboard}_siblings[@] + keyboard_sibling_first=${keyboard}_siblings[0] + if [ -n "${!keyboard_sibling_first}" ]; then + keyboard_siblings=${!keyboard_sibling_var} + else + keyboard_siblings=( "${keyboard}" ) + fi + split=${keyboards_split[$keyboard_index]} + keyboard_shield=${keyboards_shield[$keyboard_index]} + break + ;; + + esac +done + +if [ "$keyboard_shield" == "y" ]; then + shields=$keyboard_siblings + shield=${keyboard} + shield_title=${keyboard_title} + + prompt="Pick an MCU board:" + options=({{#boards}}"{{{name}}}" {{/boards}}) + board_ids=({{#boards}}"{{id}}" {{/boards}}) + boards_usb_only=({{#boards}}"{{#usb_only}}y{{/usb_only}}{{^usb_only}}n{{/usb_only}}" {{/boards}}) + + echo "" + echo "MCU Board Selection:" + PS3="$prompt " + select opt in "${options[@]}" "Quit"; do + case "$REPLY" in + ''|*[!0-9]*) echo "Invalid option. Try another one."; continue;; + + $(( ${#options[@]}+1 )) ) echo "Goodbye!"; exit 1;; + *) + if [ $REPLY -gt $(( ${#options[@]}+1 )) ] || [ $REPLY -lt 0 ]; then + echo "Invalid option. Try another one." + continue + fi + + board_index=$(( $REPLY-1 )) + + if [ -n "${!keyboard_sibling_first}" ] && [ "${boards_usb_only[$board_index]}" = "y" ] ; then + echo "Wired split is not yet supported by ZMK." + exit 1 + fi + + board=${board_ids[$board_index]} + board_title=${options[$board_index]} + boards=( "${board}" ) + break + ;; + + esac + done +else + board=${keyboard} + boards=$keyboard_siblings +fi + +read -r -e -p "Copy in the stock keymap for customization? [Yn]: " copy_keymap + +if [ -z "$copy_keymap" ] || [ "$copy_keymap" == "Y" ] || [ "$copy_keymap" == "y" ]; then copy_keymap="yes"; fi + +read -r -e -p "GitHub Username (leave empty to skip GitHub repo creation): " github_user +if [ -n "$github_user" ]; then + read -r -p "GitHub Repo Name [zmk-config]: " repo_name + if [ -z "$repo_name" ]; then repo_name="zmk-config"; fi + + read -r -p "GitHub Repo [https://github.com/${github_user}/${repo_name}.git]: " github_repo + + if [ -z "$github_repo" ]; then github_repo="https://github.com/${github_user}/${repo_name}.git"; fi +else + repo_name="zmk-config" +fi + +echo "" +echo "Preparing a user config for:" +if [ "$keyboard_shield" == "y" ]; then + echo "* MCU Board: ${boards}" + echo "* Shield(s): ${shields}" +else + echo "* Board(s): ${boards}" +fi + +if [ "$copy_keymap" == "yes" ]; then + echo "* Copy Keymap?: ✓" +else + echo "* Copy Keymap?: ❌" +fi + +if [ -n "$github_repo" ]; then + echo "* GitHub Repo To Push (please create this in GH first!): ${github_repo}" +fi + +echo "" +read -r -p "Continue? [Yn]: " do_it + +if [ -n "$do_it" ] && [ "$do_it" != "y" ] && [ "$do_it" != "Y" ]; then + echo "Aborting..." + exit 1 +fi + +git clone --single-branch $repo_path ${repo_name} +cd ${repo_name} + +pushd config + +if [ "$keyboard_shield" == "y" ]; then + url_base="https://raw.githubusercontent.com/zmkfirmware/zmk/main/app/boards/shields/${keyboard_basedir}" +else + url_base="https://raw.githubusercontent.com/zmkfirmware/zmk/main/app/boards/${keyboard_arch}/${keyboard_basedir}" +fi + +echo "Downloading config file (${url_base}/${keyboard}.conf)" +if ! $download_command "${url_base}/${keyboard}.conf"; then + echo "Could not find it, falling back to ${url_base}/${keyboard_basedir}.conf" + $download_command "${url_base}/${keyboard_basedir}.conf" || echo "# Put configuration options here" > "${keyboard}.conf" +fi + +if [ "$copy_keymap" == "yes" ]; then + echo "Downloading keymap file (${url_base}/${keyboard}.keymap)" + if ! $download_command "${url_base}/${keyboard}.keymap"; then + echo "Could not find it, falling back to ${url_base}/${keyboard_basedir}.keymap" + $download_command "${url_base}/${keyboard_basedir}.keymap" || echo "Warning: Could not find a keymap file to download!" + fi +fi + +popd + +echo "include:" >> build.yaml + +for b in ${boards}; do + if [ -n "${shields}" ]; + then + for s in ${shields}; do + echo " - board: ${b}" >> build.yaml + echo " shield: ${s}" >> build.yaml + done + else + echo " - board: ${b}" >> build.yaml + fi +done + +rm -rf .git +git init . +git add . +git commit -m "Initial User Config." + +if [ -n "$github_repo" ]; then + git remote add origin "$github_repo" + git push --set-upstream origin "$(git symbolic-ref --short HEAD)" + push_return_code=$? + + # If push failed, assume that the origin was incorrect and give instructions on fixing. + if [ ${push_return_code} -ne 0 ]; then + echo "Remote repository $github_repo not found..." + echo "Check GitHub URL, and try adding again." + echo "Run the following: " + echo " git remote rm origin" + echo " git remote add origin FIXED_URL" + echo " git push --set-upstream origin $(git symbolic-ref --short HEAD)" + echo "Once pushed, your firmware should be available from GitHub Actions at: ${github_repo%.git}/actions" + exit 1 + fi + + # TODO: Support determing the actions URL when non-https:// repo URL is used. + if [ "${github_repo}" != "${github_repo#https://}" ]; then + echo "Your firmware should be available from GitHub Actions shortly: ${github_repo%.git}/actions" + fi +fi diff --git a/docs/src/theme/prism-include-languages.js b/docs/src/theme/prism-include-languages.js new file mode 100644 index 000000000000..c073923b92a4 --- /dev/null +++ b/docs/src/theme/prism-include-languages.js @@ -0,0 +1,23 @@ +import siteConfig from "@generated/docusaurus.config"; +export default function prismIncludeLanguages(PrismObject) { + const { + themeConfig: { prism }, + } = siteConfig; + const { additionalLanguages } = prism; + // Prism components work on the Prism instance on the window, while prism- + // react-renderer uses its own Prism instance. We temporarily mount the + // instance onto window, import components to enhance it, then remove it to + // avoid polluting global namespace. + // You can mutate PrismObject: registering plugins, deleting languages... As + // long as you don't re-assign it + globalThis.Prism = PrismObject; + additionalLanguages.forEach((lang) => { + // eslint-disable-next-line global-require + require(`prismjs/components/prism-${lang}`); + }); + + require("./prism/components/prism-devicetree.js"); + require("./prism/components/prism-kconfig.js"); + + delete globalThis.Prism; +} diff --git a/docs/src/theme/prism/components/prism-devicetree.js b/docs/src/theme/prism/components/prism-devicetree.js new file mode 100644 index 000000000000..22e638c6ae48 --- /dev/null +++ b/docs/src/theme/prism/components/prism-devicetree.js @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/* eslint-disable no-undef */ + +Prism.languages.devicetree = { + comment: Prism.languages.c["comment"], + string: Prism.languages.c["string"], + keyword: + /\/(?:bits|delete-node|delete-property|dts-v1|incbin|include|memreserve|omit-if-no-ref|plugin)\//, + label: { + pattern: /\b(?:[a-z_]\w*):/i, + alias: "symbol", + }, + reference: { + pattern: /&(?:[a-z_]\w*|\{[\w,.+*#?@/-]*\})/i, + alias: "variable", + }, + node: { + pattern: /(?:\/|\b[\w,.+\-@]+)(?=\s*\{)/, + alias: "class-name", + inside: { + // Node address + number: { + pattern: /(@)[0-9a-f,]/i, + lookbehind: true, + }, + }, + }, + function: Prism.languages.c["function"], + "attr-name": /\\?[\w,.+*#?@-]+(?=\s*[=;])/, + number: [/\b[0-9a-f]{2}\b/i, /\b(?:0[xX][0-9a-fA-F]+|\d+)(?:ULL|UL|LL|U|L)?/], + macro: Prism.languages.c["macro"], + operator: /<<|>>|[<>]=?|[!=]=?|&&?|\|\|?|[+\-*/%~?^]/, + punctuation: /[{}[\];(),.]/, +}; + +Prism.languages.dts = Prism.languages.devicetree; diff --git a/docs/src/theme/prism/components/prism-kconfig.js b/docs/src/theme/prism/components/prism-kconfig.js new file mode 100644 index 000000000000..f911d6e32be1 --- /dev/null +++ b/docs/src/theme/prism/components/prism-kconfig.js @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/* eslint-disable no-undef */ + +Prism.languages.kconfig = { + comment: { + pattern: /(^|[^\\])#.*/, + lookbehind: true, + greedy: true, + }, + string: /"(?:\\.|[^\\\r\n"])*"/, + helptext: { + // help text ends at the first line at a lower level of indentation than the + // first line of text. + pattern: /(^\s*)(?:help|---help---)\s*^(\s+)(?:.+)(?:\s*^\2[^\n]*)*/m, + lookbehind: true, + alias: "string", + inside: { + keyword: /^(?:help|---help---)/, + }, + }, + keyword: + /\b(?:allnoconfig_y|bool|boolean|choice|comment|config|def_bool|def_hex|def_int|def_string|def_tristate|default|defconfig_list|depends|endchoice|endif|endmenu|env|hex|if|imply|int|mainmenu|menu|menuconfig|modules|on|option|optional|orsource|osource|prompt|range|rsource|select|source|string|tristate|visible)\b/, + expansion: { + pattern: /\$\([\s\S]+\)/, + alias: "variable", + inside: { + function: /\$\(|\)/, + punctuation: /,/, + }, + }, + number: /\b(?:0[xX][0-9a-fA-F]+|\d+)/, + boolean: { + pattern: /\b(?:y|n|m)\b/, + alias: "number", + }, + variable: /\b[A-Z_]+\b/, + operator: /[<>]=?|[!=]=?|&&|\|\|/, + punctuation: /[()]/, +}; diff --git a/docs/src/theme/prism/themes/github-dark-dimmed.js b/docs/src/theme/prism/themes/github-dark-dimmed.js new file mode 100644 index 000000000000..210742bba0b7 --- /dev/null +++ b/docs/src/theme/prism/themes/github-dark-dimmed.js @@ -0,0 +1,73 @@ +/* + Converted from https://github.com/highlightjs/highlight.js/blob/main/src/styles/github-dark-dimmed.css + + BSD 3-Clause License + + Copyright (c) 2006, Ivan Sagalaev. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** @type {import("prism-react-renderer").PrismTheme} */ +const theme = { + plain: { color: "#adbac7", backgroundColor: "#22272e" }, + styles: [ + { types: ["keyword", "atrule"], style: { color: "#f47067" } }, + { types: ["class-name", "function"], style: { color: "#dcbdfb" } }, + { + types: [ + "attr-name", + "boolean", + "important", + "doctype", + "prolog", + "cdata", + "number", + "operator", + "variable", + "selector", + ], + style: { color: "#6cb6ff" }, + }, + { types: ["regex", "string", "char", "url"], style: { color: "#96d0ff" } }, + { types: ["builtin", "symbol", "entity"], style: { color: "#f69d50" } }, + { types: ["comment"], style: { color: "#768390" } }, + { types: ["italic"], style: { color: "#adbac7", fontStyle: "italic" } }, + { types: ["bold"], style: { color: "#adbac7", fontWeight: "bold" } }, + { + types: ["inserted"], + style: { color: "#b4f1b4", backgroundColor: "#1b4721" }, + }, + { + types: ["deleted"], + style: { color: "#ffd8d3", backgroundColor: "#78191b" }, + }, + { types: ["property", "punctuation", "tag"], style: {} }, + ], +}; + +module.exports = theme; diff --git a/docs/src/theme/prism/themes/github.js b/docs/src/theme/prism/themes/github.js new file mode 100644 index 000000000000..b0be14c35ab4 --- /dev/null +++ b/docs/src/theme/prism/themes/github.js @@ -0,0 +1,73 @@ +/* + Converted from https://github.com/highlightjs/highlight.js/blob/main/src/styles/github.css + + BSD 3-Clause License + + Copyright (c) 2006, Ivan Sagalaev. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** @type {import("prism-react-renderer").PrismTheme} */ +const theme = { + plain: { color: "#24292e", backgroundColor: "#f9f9f9" }, + styles: [ + { types: ["keyword", "atrule"], style: { color: "#d73a49" } }, + { types: ["class-name", "function"], style: { color: "#6f42c1" } }, + { + types: [ + "attr-name", + "boolean", + "important", + "doctype", + "prolog", + "cdata", + "number", + "operator", + "variable", + "selector", + ], + style: { color: "#005cc5" }, + }, + { types: ["regex", "string", "char", "url"], style: { color: "#032f62" } }, + { types: ["builtin", "symbol", "entity"], style: { color: "#e36209" } }, + { types: ["comment"], style: { color: "#6a737d" } }, + { types: ["italic"], style: { color: "#24292e", fontStyle: "italic" } }, + { types: ["bold"], style: { color: "#24292e", fontWeight: "bold" } }, + { + types: ["inserted"], + style: { color: "#22863a", backgroundColor: "#f0fff4" }, + }, + { + types: ["deleted"], + style: { color: "#b31d28", backgroundColor: "#ffeef0" }, + }, + { types: ["property", "punctuation", "tag"], style: {} }, + ], +}; + +module.exports = theme; diff --git a/docs/src/utils/hooks.js b/docs/src/utils/hooks.js new file mode 100644 index 000000000000..b8fb27b84b32 --- /dev/null +++ b/docs/src/utils/hooks.js @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +import { useState } from "react"; + +export const useInput = (initialValue) => { + const [value, setValue] = useState(initialValue); + + return { + value, + setValue, + bind: { + value, + onChange: (event) => { + const target = event.target; + setValue(target.type === "checkbox" ? target.checked : target.value); + }, + }, + }; +}; diff --git a/docs/static/.gitignore b/docs/static/.gitignore new file mode 100644 index 000000000000..fc7d2745100b --- /dev/null +++ b/docs/static/.gitignore @@ -0,0 +1,5 @@ + +# Ignore generated setup script + +setup.ps1 +setup.sh diff --git a/docs/static/img/favicon.ico b/docs/static/img/favicon.ico new file mode 100644 index 000000000000..faec05fa7b2d Binary files /dev/null and b/docs/static/img/favicon.ico differ diff --git a/docs/static/img/undraw_open_source.svg b/docs/static/img/undraw_open_source.svg new file mode 100644 index 000000000000..80887c88cfbb --- /dev/null +++ b/docs/static/img/undraw_open_source.svg @@ -0,0 +1 @@ +open source \ No newline at end of file diff --git a/docs/static/img/undraw_wireless.svg b/docs/static/img/undraw_wireless.svg new file mode 100644 index 000000000000..5a7a9282be29 --- /dev/null +++ b/docs/static/img/undraw_wireless.svg @@ -0,0 +1 @@ +moving forward \ No newline at end of file diff --git a/docs/static/img/undraw_zephyr.svg b/docs/static/img/undraw_zephyr.svg new file mode 100644 index 000000000000..beb01d7b276f --- /dev/null +++ b/docs/static/img/undraw_zephyr.svg @@ -0,0 +1 @@ +programmer \ No newline at end of file diff --git a/docs/static/img/zmk_logo.svg b/docs/static/img/zmk_logo.svg new file mode 100644 index 000000000000..31977a60a003 --- /dev/null +++ b/docs/static/img/zmk_logo.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/docs/static/tree-sitter-devicetree.wasm b/docs/static/tree-sitter-devicetree.wasm new file mode 100644 index 000000000000..cce5ac9656c9 Binary files /dev/null and b/docs/static/tree-sitter-devicetree.wasm differ diff --git a/docs/tsconfig.json b/docs/tsconfig.json new file mode 100644 index 000000000000..a9844e97c53b --- /dev/null +++ b/docs/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "@tsconfig/docusaurus/tsconfig.json", + "include": ["src/"], + "compilerOptions": { + "types": ["node", "@docusaurus/theme-classic"], + "moduleResolution": "Node16", + "esModuleInterop": true, + "resolveJsonModule": true, + "strict": true, + "noEmit": true, + "target": "ES6", + "lib": ["ES2019.Array", "DOM", "DOM.Iterable"] + } +} diff --git a/schema/hardware-metadata.schema.json b/schema/hardware-metadata.schema.json new file mode 100644 index 000000000000..4c2bdf3b7304 --- /dev/null +++ b/schema/hardware-metadata.schema.json @@ -0,0 +1,262 @@ +{ + "$id": "https://zmkfirmware.dev/zmk.metadata.json", + "title": "HardwareMetadata", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "oneOf": [ + { + "$ref": "#/$defs/board" + }, + { + "$ref": "#/$defs/shield" + }, + { + "$ref": "#/$defs/interconnect" + } + ], + "$defs": { + "id": { + "type": "string", + "pattern": "^[a-z0-9_]+$" + }, + "keyboard_siblings": { + "type": "array", + "items": { + "type": "string" + } + }, + "variant": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "required": ["id", "features"], + "properties": { + "id": { + "$ref": "#/$defs/id" + }, + "features": { + "$ref": "#/$defs/features" + } + } + } + ] + }, + "features": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "keys", + "display", + "encoder", + "underglow", + "backlight", + "pointer" + ] + } + }, + "interconnects": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/$defs/id" + } + }, + "sibling_details": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/id" + }, + "features": { + "$ref": "#/$defs/features" + }, + "variants": { + "type": "array", + "items": { + "$ref": "#/$defs/variant" + } + } + } + }, + "interconnect_node_labels": { + "title": "InterconnectNodeLabels", + "type": "object", + "additionalProperties": false, + "required": ["gpio"], + "properties": { + "gpio": { "type": "string" }, + "i2c": { "type": "string" }, + "spi": { "type": "string" }, + "uart": { "type": "string" }, + "adc": { "type": "string" } + } + }, + "interconnect": { + "title": "Interconnect", + "type": "object", + "additionalProperties": false, + "required": ["file_format", "id", "name", "description", "url", "type"], + "properties": { + "file_format": { + "type": "string", + "const": "1" + }, + "id": { + "$ref": "#/$defs/id" + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + }, + "node_labels": { + "$ref": "#/$defs/interconnect_node_labels" + }, + "design_guideline": { + "type": "string" + }, + "manufacturer": { + "type": "string" + }, + "type": { + "type": "string", + "const": "interconnect" + } + } + }, + "board": { + "title": "Board", + "type": "object", + "additionalProperties": false, + "required": [ + "file_format", + "id", + "name", + "url", + "arch", + "type", + "outputs" + ], + "properties": { + "file_format": { + "type": "string", + "const": "1" + }, + "id": { + "$ref": "#/$defs/id" + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + }, + "manufacturer": { + "type": "string" + }, + "arch": { + "type": "string", + "pattern": "^[a-z0-9_]+$" + }, + "type": { + "type": "string", + "const": "board" + }, + "siblings": { + "$ref": "#/$defs/keyboard_siblings" + }, + "outputs": { + "type": "array", + "items": { + "type": "string", + "enum": ["usb", "ble"] + } + }, + "features": { + "$ref": "#/$defs/features" + }, + "variants": { + "type": "array", + "items": { + "$ref": "#/$defs/variant" + } + }, + "exposes": { + "$ref": "#/$defs/interconnects" + } + } + }, + "shield": { + "title": "Shield", + "type": "object", + "additionalProperties": false, + "required": ["file_format", "id", "name", "url", "type", "requires"], + "properties": { + "file_format": { + "type": "string", + "const": "1" + }, + "id": { + "$ref": "#/$defs/id" + }, + "name": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + }, + "manufacturer": { + "type": "string" + }, + "version": { + "type": "string" + }, + "type": { + "type": "string", + "const": "shield" + }, + "features": { + "$ref": "#/$defs/features" + }, + "variants": { + "type": "array", + "items": { + "$ref": "#/$defs/variant" + } + }, + "siblings": { + "$ref": "#/$defs/keyboard_siblings" + }, + "requires": { + "$ref": "#/$defs/interconnects" + }, + "exposes": { + "$ref": "#/$defs/interconnects" + } + } + } + } +} diff --git a/src/main.c b/src/main.c deleted file mode 100644 index e487325ac849..000000000000 --- a/src/main.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2016 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include - -#include "zmk_lib.h" - -/* 1000 msec = 1 sec */ -#define SLEEP_TIME_MS 1000 - -/* The devicetree node identifier for the "led0" alias. */ -#define LED0_NODE DT_ALIAS(led0) - -#if DT_HAS_NODE(LED0_NODE) -#define LED0 DT_GPIO_LABEL(LED0_NODE, gpios) -#define PIN DT_GPIO_PIN(LED0_NODE, gpios) -#if DT_PHA_HAS_CELL(LED0_NODE, gpios, flags) -#define FLAGS DT_GPIO_FLAGS(LED0_NODE, gpios) -#endif -#else -/* A build error here means your board isn't set up to blink an LED. */ -#error "Unsupported board: led0 devicetree alias is not defined" -#define LED0 "" -#define PIN 0 -#endif - -#ifndef FLAGS -#define FLAGS 0 -#endif - - -void main(void) -{ - struct device *dev; - bool led_is_on = true; - int ret; - - dev = device_get_binding(LED0); - if (dev == NULL) { - return; - } - - ret = gpio_pin_configure(dev, PIN, GPIO_OUTPUT_ACTIVE | FLAGS); - if (ret < 0) { - return; - } - - zmk_run(); - // while (1) { - // gpio_pin_set(dev, PIN, (int)led_is_on); - // led_is_on = !led_is_on; - // k_msleep(SLEEP_TIME_MS); - // } -} diff --git a/src/zmk_lib.h b/src/zmk_lib.h deleted file mode 100644 index 0b7706edd3e1..000000000000 --- a/src/zmk_lib.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef ZMK_LIB_H -#define ZMK_LIB_H - -void zmk_run(void); - -#endif - diff --git a/zephyr-rust b/zephyr-rust deleted file mode 160000 index 78b433aa9e02..000000000000 --- a/zephyr-rust +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 78b433aa9e0255a719fb0c3c9ac303f3924c1348